• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stackus / goht / 14768173832

01 May 2025 02:03AM UTC coverage: 79.722% (+0.2%) from 79.532%
14768173832

push

github

stackus
update documentation

2693 of 3378 relevant lines covered (79.72%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.63
/compiler/lexers_ego.go
1
package compiler
2

3
import (
4
        "fmt"
5
        "strings"
6
        "text/scanner"
7
)
8

9
func lexEgoStart(l *lexer) lexFn {
1✔
10
        return lexEgoLineStart(lexEgoText)
1✔
11
}
1✔
12

13
func increaseEgoIndent(l *lexer) lexFn {
1✔
14
        if l.current() != "" {
1✔
15
                return l.errorf("uncommitted content during block start: %q", l.current())
×
16
        }
×
17
        l.indent++
1✔
18
        l.s = strings.Repeat("\t", l.indent)
1✔
19
        l.emit(tIndent)
1✔
20
        return nil
1✔
21
}
22

23
func decreaseEgoIndent(l *lexer) lexFn {
1✔
24
        if l.current() != "" {
1✔
25
                return l.errorf("uncommitted content during block end: %q", l.current())
×
26
        }
×
27
        l.indent--
1✔
28
        l.s = strings.Repeat("\t", l.indent)
1✔
29
        l.emit(tIndent)
1✔
30
        return nil
1✔
31
}
32

33
func lexEgoLineStart(next lexFn) lexFn {
1✔
34
        return func(l *lexer) lexFn {
2✔
35
                switch l.peek() {
1✔
36
                case scanner.EOF:
×
37
                        l.emit(tEOF)
×
38
                        return nil
×
39
                case '\n', '\r':
1✔
40
                        l.acceptRun("\n\r")
1✔
41
                        return lexEgoLineStart(next)
1✔
42
                case '\t':
1✔
43
                        // we require all templates to be indented with one tab; the rest of the line is content
1✔
44
                        l.skip()
1✔
45
                        return next
1✔
46
                case '}':
1✔
47
                        // end of the template
1✔
48
                        if l.current() != "" {
2✔
49
                                // if the indent is not at 1, then we know that we're ending early and should report an error
1✔
50
                                if l.indent != 0 {
1✔
51
                                        fmt.Println("indent", l.indent)
×
52
                                        fmt.Printf("current %q\n", l.current())
×
53
                                        return l.errorf("unexpected closing brace: %q", l.current())
×
54
                                }
×
55
                                // assumption: if there is anything in the buffer, then it is text, AND we can trim it
56
                                l.s = strings.TrimRight(l.s, " \t\n\r")
1✔
57
                                l.emit(tRawText)
1✔
58
                        }
59
                        l.emit(tTemplateEnd)
1✔
60
                        l.skip()
1✔
61
                        return lexGoLineStart
1✔
62
                default:
×
63
                        return l.errorf("unexpected character: %q", l.peek())
×
64
                }
65
        }
66
}
67

68
func lexEgoText(l *lexer) lexFn {
1✔
69
        for {
2✔
70
                l.acceptUntil("<\n\r")
1✔
71
                switch l.peek() {
1✔
72
                case '\n', '\r':
1✔
73
                        return lexEgoLineStart(lexEgoText)
1✔
74
                case '<':
1✔
75
                        if l.peekAhead(2) == "<%" {
2✔
76
                                return lexEgoTagStart
1✔
77
                        }
1✔
78
                        l.next()
1✔
79
                case scanner.EOF:
1✔
80
                        if l.current() != "" {
2✔
81
                                l.emit(tRawText)
1✔
82
                        }
1✔
83
                        l.emit(tEOF)
1✔
84
                        return nil
1✔
85
                }
86
        }
87
}
88

89
func lexEgoTagStart(l *lexer) lexFn {
1✔
90
        l.skipAhead(2) // consume the '<%'
1✔
91
        r := l.peek()
1✔
92
        switch r {
1✔
93
        case '#':
1✔
94
                if l.current() != "" {
2✔
95
                        l.emit(tRawText)
1✔
96
                }
1✔
97
                // comment
98
                l.skip() // consume the '#'
1✔
99
                return lexEgoCommentStart
1✔
100
        case '=':
1✔
101
                if l.current() != "" {
2✔
102
                        l.emit(tRawText)
1✔
103
                }
1✔
104
                // output
105
                l.skip() // consume the '='
1✔
106
                return lexEgoOutputStart
1✔
107
        case '!':
1✔
108
                if l.current() != "" {
2✔
109
                        l.emit(tRawText)
1✔
110
                }
1✔
111
                // unescaped output
112
                l.skip() // consume the '!'
1✔
113
                return lexEgoUnescapedOutputStart
1✔
114
        case '@':
1✔
115
                if l.current() != "" {
2✔
116
                        l.emit(tRawText)
1✔
117
                }
1✔
118
                // command
119
                l.skip() // consume the '@'
1✔
120
                return lexEgoCommandStart
1✔
121
        case '%':
1✔
122
                // literal "<%"
1✔
123
                l.s += "<%"
1✔
124
                l.skip() // consume the '%'
1✔
125
                return lexEgoText
1✔
126
        case scanner.EOF:
1✔
127
                return l.errorf("unexpected EOF in tag")
1✔
128
        default:
1✔
129
                // script
1✔
130
                if r == '-' {
2✔
131
                        // strip the whitespace on current()
1✔
132
                        l.s = strings.TrimRight(l.s, " \t\n\r")
1✔
133
                        l.emit(tRawText)
1✔
134
                        l.skip() // consume the '-'
1✔
135
                        return lexEgoScriptStart
1✔
136
                }
1✔
137
                if l.current() != "" {
2✔
138
                        l.emit(tRawText)
1✔
139
                }
1✔
140
                return lexEgoScriptStart
1✔
141
        }
142
}
143

144
func findClosingTag(l *lexer, next lexFn) lexFn {
1✔
145
        for {
2✔
146
                l.acceptRun(" \t")
1✔
147
                l.acceptUntil("-$%\n\r")
1✔
148
                if l.peek() == scanner.EOF {
2✔
149
                        return l.errorf("unexpected EOF in tag")
1✔
150
                }
1✔
151
                switch l.peek() {
1✔
152
                case '\n', '\r':
1✔
153
                        // enforce indents even inside of multiline tags
1✔
154
                        l.acceptRun("\n\r") // skip newlines
1✔
155
                        if l.peek() != '\t' {
1✔
156
                                return l.errorf("unexpected character at start of line: %q", l.peek())
×
157
                        }
×
158
                        l.skip() // skip the tab
1✔
159
                        continue
1✔
160
                case '-':
1✔
161
                        if l.peekAhead(3) != "-%>" {
2✔
162
                                l.next()
1✔
163
                                continue
1✔
164
                        }
165
                case '$':
1✔
166
                        if l.peekAhead(3) != "$%>" {
2✔
167
                                l.next()
1✔
168
                                continue
1✔
169
                        }
170
                case '%':
1✔
171
                        if l.peekAhead(2) != "%>" {
2✔
172
                                l.next()
1✔
173
                                continue
1✔
174
                        }
175
                }
176
                if err := next(l); err != nil {
2✔
177
                        return err
1✔
178
                }
1✔
179
                return lexEgoClosingTag
1✔
180
        }
181
}
182

183
func lexEgoClosingTag(l *lexer) lexFn {
1✔
184
        switch l.peek() {
1✔
185
        case '%':
1✔
186
                // just a closing tag
1✔
187
                l.skipAhead(2) // consume the '%>'
1✔
188
                return lexEgoText
1✔
189
        case '$':
1✔
190
                // closing tag with next newline removal
1✔
191
                l.skipAhead(3) // consume the '$%>'
1✔
192
                switch l.peek() {
1✔
193
                case '\n':
1✔
194
                        l.skip() // skip the newline
1✔
195
                        if l.peek() == '\r' {
2✔
196
                                l.skip() // skip the carriage return
1✔
197
                        }
1✔
198
                case '\r':
1✔
199
                        l.skip() // skip the carriage return
1✔
200
                }
201
                return lexEgoLineStart(lexEgoText)
1✔
202
        case '-':
1✔
203
                // closing tag with whitespace removal
1✔
204
                l.skipAhead(3) // consume the '-%>'
1✔
205
                return lexStripWhitespace
1✔
206
        default:
×
207
                // unexpected character
×
208
                return l.errorf("unexpected character in closing tag: %q", l.peek())
×
209
        }
210
}
211

212
func lexEgoCommentStart(l *lexer) lexFn {
1✔
213
        l.skipRun(" \t\n\r") // skip whitespace
1✔
214

1✔
215
        return findClosingTag(l, func(l *lexer) lexFn {
2✔
216
                l.ignore() // ignore the comment
1✔
217
                return nil
1✔
218
        })
1✔
219
}
220

221
func lexEgoOutputStart(l *lexer) lexFn {
1✔
222
        l.skipRun(" \t\n\r") // skip whitespace
1✔
223

1✔
224
        return findClosingTag(l, func(l *lexer) lexFn {
2✔
225
                l.s = strings.TrimSpace(l.s)
1✔
226
                l.emit(tScript)
1✔
227
                return nil
1✔
228
        })
1✔
229
}
230

231
func lexEgoUnescapedOutputStart(l *lexer) lexFn {
1✔
232
        l.skipRun(" \t\n\r") // skip whitespace
1✔
233

1✔
234
        l.emit(tUnescaped)
1✔
235
        return findClosingTag(l, func(l *lexer) lexFn {
2✔
236
                l.s = strings.TrimSpace(l.s)
1✔
237
                l.emit(tScript)
1✔
238
                return nil
1✔
239
        })
1✔
240
}
241

242
func lexEgoCommandStart(l *lexer) lexFn {
1✔
243
        l.skipRun(" \t\n\r") // skip whitespace
1✔
244

1✔
245
        // TODO look for the command text
1✔
246
        l.acceptUntil(" \t%")
1✔
247
        if l.current() == "" {
2✔
248
                return l.errorf("command name expected")
1✔
249
        }
1✔
250
        switch l.current() {
1✔
251
        case "render":
1✔
252
                return lexEgoRenderStart
1✔
253
        case "children":
1✔
254
                return lexEgoChildrenStart
1✔
255
        case "slot":
1✔
256
                return lexEgoSlotStart
1✔
257
        default:
1✔
258
                return l.errorf("unknown command: %q", l.current())
1✔
259
        }
260
}
261

262
func lexEgoRenderStart(l *lexer) lexFn {
1✔
263
        l.skipRun(" \t") // skip whitespace
1✔
264
        l.ignore()       // ignore the command keyword and the whitespace
1✔
265

1✔
266
        return findClosingTag(l, func(l *lexer) lexFn {
2✔
267
                l.s = strings.TrimSpace(l.s)
1✔
268
                s := l.current()
1✔
269
                l.emit(tRenderCommand)
1✔
270
                // if the content ends with a '{' then increase the indent (after emitting)
1✔
271
                if strings.HasSuffix(s, "{") {
2✔
272
                        if err := increaseEgoIndent(l); err != nil {
1✔
273
                                return err
×
274
                        }
×
275
                }
276
                return nil
1✔
277
        })
278
}
279

280
func lexEgoChildrenStart(l *lexer) lexFn {
1✔
281
        l.skipRun(" \t") // skip whitespace
1✔
282
        l.ignore()       // ignore the command keyword and the whitespace
1✔
283

1✔
284
        return findClosingTag(l, func(l *lexer) lexFn {
2✔
285
                if strings.TrimSpace(l.s) != "" {
2✔
286
                        return l.errorf("unexpected content in children command: %q", l.s)
1✔
287
                }
1✔
288
                l.ignore()
1✔
289
                l.emit(tChildrenCommand)
1✔
290
                return nil
1✔
291
        })
292
}
293

294
func lexEgoSlotStart(l *lexer) lexFn {
1✔
295
        l.skipRun(" \t") // skip whitespace
1✔
296
        l.ignore()       // ignore the command keyword and the whitespace
1✔
297

1✔
298
        return findClosingTag(l, func(l *lexer) lexFn {
2✔
299
                l.s = strings.TrimSpace(l.s)
1✔
300
                s := l.current()
1✔
301
                l.s = strings.TrimRight(l.s, " \t{") // remove trailing whitespace and '{'
1✔
302
                if l.current() == "" {
2✔
303
                        return l.errorf("slot name expected")
1✔
304
                }
1✔
305
                l.emit(tSlotCommand)
1✔
306
                // if the content originally ends with a '{' then increase the indent (after emitting)
1✔
307
                if strings.HasSuffix(s, "{") {
2✔
308
                        if err := increaseEgoIndent(l); err != nil {
1✔
309
                                return err
×
310
                        }
×
311
                }
312
                return nil
1✔
313
        })
314
}
315

316
func lexEgoScriptStart(l *lexer) lexFn {
1✔
317
        l.skipRun(" \t\n\r") // skip whitespace
1✔
318

1✔
319
        // if the content starts with a '}' then decrease the indent (before emitting)
1✔
320
        if l.peek() == '}' {
2✔
321
                if err := decreaseEgoIndent(l); err != nil {
1✔
322
                        return err
×
323
                }
×
324
        }
325

326
        return findClosingTag(l, func(l *lexer) lexFn {
2✔
327
                l.s = strings.TrimSpace(l.s)
1✔
328
                s := l.current()
1✔
329
                l.emit(tSilentScript)
1✔
330
                // if the content ends with a '{' then increase the indent (after emitting)
1✔
331
                if strings.HasSuffix(s, "{") {
2✔
332
                        return increaseEgoIndent(l)
1✔
333
                }
1✔
334
                return nil
1✔
335
        })
336
}
337

338
func lexStripWhitespace(l *lexer) lexFn {
1✔
339
        for {
2✔
340
                l.skipRun(" \t") // skip whitespace
1✔
341
                switch l.peek() {
1✔
342
                case scanner.EOF:
×
343
                        l.emit(tEOF)
×
344
                        return nil
×
345
                case '\n', '\r':
1✔
346
                        // enforce indents even when we are stripping whitespace
1✔
347
                        l.skipRun("\n\r") // skip newlines
1✔
348
                        if l.peek() != '\t' {
2✔
349
                                return l.errorf("unexpected character at start of line: %q", l.peek())
1✔
350
                        }
1✔
351
                        l.skip() // skip the tab
1✔
352
                        continue
1✔
353
                default:
1✔
354
                        return lexEgoText
1✔
355
                }
356
        }
357
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc