Skip to content

Commit dcc70af

Browse files
committed
Simplify whitespace handling and collapse needless states
1 parent 53609f6 commit dcc70af

File tree

4 files changed

+48
-64
lines changed

4 files changed

+48
-64
lines changed

v2/codetags/extractor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func findNameEnd(s string) int {
7676
return 0
7777
}
7878
idx := strings.IndexFunc(s, func(r rune) bool {
79-
return !(isIdentInterior(r) || r == ':')
79+
return !(isTagNameInterior(r))
8080
})
8181
if idx == -1 {
8282
return len(s)

v2/codetags/parser.go

Lines changed: 36 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,13 @@ func RawValues(enabled bool) ParseOption {
143143
}
144144

145145
const (
146-
stBegin = "stBegin"
147-
stTag = "stTag"
148-
stMaybeArgs = "stMaybeArgs"
149-
stArg = "stArg"
150-
stArgEndOfToken = "stArgEndOfToken"
151-
stMaybeValue = "stMaybeValue"
152-
stValue = "stValue"
153-
stMaybeComment = "stMaybeComment"
154-
stTrailingSlash = "stTrailingSlash"
155-
stTrailingComment = "stTrailingComment"
146+
stTag = "stTag"
147+
stMaybeArgs = "stMaybeArgs"
148+
stArg = "stArg"
149+
stArgEndOfToken = "stArgEndOfToken"
150+
stMaybeValue = "stMaybeValue"
151+
stValue = "stValue"
152+
stMaybeComment = "stMaybeComment"
156153
)
157154

158155
func parseTag(input string, opts parseOpts) (Tag, error) {
@@ -216,56 +213,44 @@ func parseTag(input string, opts parseOpts) (Tag, error) {
216213
endTag.Value = value
217214
endTag.ValueType = valueType
218215
}
219-
st := stBegin
216+
var err error
217+
st := stTag
220218
parseLoop:
221-
for r := s.peek(); r != EOF; r = s.peek() {
219+
for r := s.skipWhitespacePeek(); r != EOF; r = s.skipWhitespacePeek() {
222220
switch st {
223-
case stBegin:
224-
switch {
225-
case s.skipWhitespace():
226-
case isIdentBegin(r):
227-
// did not consume
228-
st = stTag
229-
default:
230-
break parseLoop
231-
}
232221
case stTag:
233222
switch {
234-
case s.skipWhitespace():
235223
case isIdentBegin(r):
236-
ident, err := s.nextIdent(isTagNameInterior)
224+
tagName, err = s.nextIdent(isTagNameInterior)
237225
if err != nil {
238226
return Tag{}, err
239227
}
240-
tagName = ident
241228
st = stMaybeArgs
242229
default:
243230
break parseLoop
244231
}
245232
case stMaybeArgs:
246233
switch {
247234
case r == '(':
248-
s.next()
235+
s.next() // consume (
249236
incomplete = true
250237
st = stArg
251238
case r == '=':
252-
s.next()
239+
s.next() // consume =
253240
if opts.rawValues {
241+
// only raw values support empty values following =
254242
valueType = ValueTypeRaw
255243
} else {
256244
incomplete = true
257245
}
258246
st = stValue
259-
case s.skipWhitespace():
260-
st = stMaybeComment
261247
default:
262-
break parseLoop
248+
st = stMaybeComment
263249
}
264250
case stArg:
265251
switch {
266-
case s.skipWhitespace():
267252
case r == ')':
268-
s.next()
253+
s.next() // consume )
269254
incomplete = false
270255
st = stMaybeValue
271256
case r == '-' || r == '+' || unicode.IsDigit(r):
@@ -288,26 +273,28 @@ parseLoop:
288273
return Tag{}, err
289274
}
290275
r = s.peek() // reset r after nextIdent
276+
291277
switch {
292-
case r == ',' || r == ')' || s.skipWhitespace():
278+
case r == ',' || r == ')': // positional arg
293279
saveBoolOrString(identifier)
294280
st = stArgEndOfToken
295-
case r == ':':
296-
s.next()
281+
case r == ':': // named arg
282+
s.next() // consume :
297283
saveName(identifier)
298284
st = stArg
285+
default:
286+
break parseLoop
299287
}
300288
default:
301289
break parseLoop
302290
}
303291
case stArgEndOfToken:
304292
switch {
305-
case s.skipWhitespace():
306293
case r == ',':
307-
s.next()
294+
s.next() // consume ,
308295
st = stArg
309296
case r == ')':
310-
s.next()
297+
s.next() // consume )
311298
incomplete = false
312299
st = stMaybeValue
313300
default:
@@ -316,29 +303,32 @@ parseLoop:
316303
case stMaybeValue:
317304
switch {
318305
case r == '=':
319-
s.next()
306+
s.next() // consume =
320307
if opts.rawValues {
308+
// Empty values are allowed for raw.
309+
// Since = might be the last char in the input, we need
310+
// to record the valueType as raw immediately.
321311
valueType = ValueTypeRaw
322312
}
323313
st = stValue
324-
case s.skipWhitespace():
325-
st = stMaybeComment
326314
default:
327-
break parseLoop
315+
st = stMaybeComment
328316
}
329317
case stValue:
330-
incomplete = false
331318
switch {
332319
case opts.rawValues: // When enabled, consume all remaining chars
320+
incomplete = false
333321
value = s.remainder()
334322
break parseLoop
335323
case r == '+' && isIdentBegin(s.peekN(1)): // tag value
324+
incomplete = false
336325
s.next() // consume +
337326
if err := saveTag(); err != nil {
338327
return Tag{}, err
339328
}
340329
st = stTag
341330
case r == '-' || r == '+' || unicode.IsDigit(r):
331+
incomplete = false
342332
number, err := s.nextNumber()
343333
valueType = ValueTypeInt
344334
if err != nil {
@@ -347,6 +337,7 @@ parseLoop:
347337
value = number
348338
st = stMaybeComment
349339
case r == '"' || r == '`':
340+
incomplete = false
350341
str, err := s.nextString()
351342
if err != nil {
352343
return Tag{}, err
@@ -355,6 +346,7 @@ parseLoop:
355346
valueType = ValueTypeString
356347
st = stMaybeComment
357348
case isIdentBegin(r):
349+
incomplete = false
358350
str, err := s.nextIdent(isIdentInterior)
359351
if err != nil {
360352
return Tag{}, err
@@ -371,27 +363,11 @@ parseLoop:
371363
}
372364
case stMaybeComment:
373365
switch {
374-
case s.skipWhitespace():
375-
case r == '/':
376-
s.next()
377-
incomplete = true
378-
st = stTrailingSlash
379-
default:
380-
break parseLoop
381-
}
382-
case stTrailingSlash:
383-
switch {
384-
case r == '/':
385-
s.next()
386-
incomplete = false
387-
st = stTrailingComment
366+
case r == '/' && s.peekN(1) == '/':
367+
s.remainder()
388368
default:
389369
break parseLoop
390370
}
391-
case stTrailingComment:
392-
s.next()
393-
s.pos = len(s.buf)
394-
break parseLoop
395371
default:
396372
return Tag{}, fmt.Errorf("unexpected internal parser error: unknown state: %s at position %d", st, s.pos)
397373
}

v2/codetags/parser_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func TestParse(t *testing.T) {
176176
{
177177
name: "space in argument",
178178
input: "name(has space)",
179-
wantError: "unexpected character 's'",
179+
wantError: "unexpected character ' '",
180180
},
181181
{
182182
name: "multiple positional args",
@@ -191,7 +191,7 @@ func TestParse(t *testing.T) {
191191
{
192192
name: "unclosed raw string",
193193
input: "badRaw(missing`)",
194-
wantError: "unterminated string",
194+
wantError: "unexpected character '`'",
195195
},
196196
{
197197
name: "nested: comma-separated args",
@@ -201,7 +201,7 @@ func TestParse(t *testing.T) {
201201
{
202202
name: "nested: unclosed raw string",
203203
input: "name=+badRaw(missing`)",
204-
wantError: "unterminated string",
204+
wantError: "unexpected character '`'",
205205
},
206206

207207
// Named arguments tests

v2/codetags/scanner.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ func (s *scanner) skipWhitespace() bool {
5858
return found
5959
}
6060

61+
func (s *scanner) skipWhitespacePeek() rune {
62+
s.skipWhitespace()
63+
return s.peek()
64+
}
65+
6166
func (s *scanner) remainder() string {
6267
result := string(s.buf[s.pos:])
6368
s.pos = len(s.buf)
@@ -70,6 +75,7 @@ const (
7075

7176
func (s *scanner) nextNumber() (string, error) {
7277
const (
78+
stBegin = "stBegin"
7379
stPrefix = "stPrefix"
7480
stPosNeg = "stPosNeg"
7581
stNumber = "stNumber"
@@ -137,6 +143,7 @@ parseLoop:
137143

138144
func (s *scanner) nextString() (string, error) {
139145
const (
146+
stBegin = "stBegin"
140147
stQuotedString = "stQuotedString"
141148
stEscape = "stEscape"
142149
)
@@ -189,6 +196,7 @@ parseLoop:
189196

190197
func (s *scanner) nextIdent(isInteriorChar func(r rune) bool) (string, error) {
191198
const (
199+
stBegin = "stBegin"
192200
stInterior = "stInterior"
193201
)
194202
var buf bytes.Buffer

0 commit comments

Comments
 (0)