1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
16 var fset
= token
.NewFileSet()
25 func tokenclass(tok token
.Token
) int {
29 case tok
.IsOperator():
43 var tokens
= [...]elt
{
45 {token
.COMMENT
, "/* a comment */", special
},
46 {token
.COMMENT
, "// a comment \n", special
},
47 {token
.COMMENT
, "/*\r*/", special
},
48 {token
.COMMENT
, "//\r\n", special
},
50 // Identifiers and basic type literals
51 {token
.IDENT
, "foobar", literal
},
52 {token
.IDENT
, "a۰۱۸", literal
},
53 {token
.IDENT
, "foo६४", literal
},
54 {token
.IDENT
, "bar9876", literal
},
55 {token
.IDENT
, "ŝ", literal
}, // was bug (issue 4000)
56 {token
.IDENT
, "ŝfoo", literal
}, // was bug (issue 4000)
57 {token
.INT
, "0", literal
},
58 {token
.INT
, "1", literal
},
59 {token
.INT
, "123456789012345678890", literal
},
60 {token
.INT
, "01234567", literal
},
61 {token
.INT
, "0xcafebabe", literal
},
62 {token
.FLOAT
, "0.", literal
},
63 {token
.FLOAT
, ".0", literal
},
64 {token
.FLOAT
, "3.14159265", literal
},
65 {token
.FLOAT
, "1e0", literal
},
66 {token
.FLOAT
, "1e+100", literal
},
67 {token
.FLOAT
, "1e-100", literal
},
68 {token
.FLOAT
, "2.71828e-1000", literal
},
69 {token
.IMAG
, "0i", literal
},
70 {token
.IMAG
, "1i", literal
},
71 {token
.IMAG
, "012345678901234567889i", literal
},
72 {token
.IMAG
, "123456789012345678890i", literal
},
73 {token
.IMAG
, "0.i", literal
},
74 {token
.IMAG
, ".0i", literal
},
75 {token
.IMAG
, "3.14159265i", literal
},
76 {token
.IMAG
, "1e0i", literal
},
77 {token
.IMAG
, "1e+100i", literal
},
78 {token
.IMAG
, "1e-100i", literal
},
79 {token
.IMAG
, "2.71828e-1000i", literal
},
80 {token
.CHAR
, "'a'", literal
},
81 {token
.CHAR
, "'\\000'", literal
},
82 {token
.CHAR
, "'\\xFF'", literal
},
83 {token
.CHAR
, "'\\uff16'", literal
},
84 {token
.CHAR
, "'\\U0000ff16'", literal
},
85 {token
.STRING
, "`foobar`", literal
},
86 {token
.STRING
, "`" + `foo
91 {token
.STRING
, "`\r`", literal
},
92 {token
.STRING
, "`foo\r\nbar`", literal
},
94 // Operators and delimiters
95 {token
.ADD
, "+", operator
},
96 {token
.SUB
, "-", operator
},
97 {token
.MUL
, "*", operator
},
98 {token
.QUO
, "/", operator
},
99 {token
.REM
, "%", operator
},
101 {token
.AND
, "&", operator
},
102 {token
.OR
, "|", operator
},
103 {token
.XOR
, "^", operator
},
104 {token
.SHL
, "<<", operator
},
105 {token
.SHR
, ">>", operator
},
106 {token
.AND_NOT
, "&^", operator
},
108 {token
.ADD_ASSIGN
, "+=", operator
},
109 {token
.SUB_ASSIGN
, "-=", operator
},
110 {token
.MUL_ASSIGN
, "*=", operator
},
111 {token
.QUO_ASSIGN
, "/=", operator
},
112 {token
.REM_ASSIGN
, "%=", operator
},
114 {token
.AND_ASSIGN
, "&=", operator
},
115 {token
.OR_ASSIGN
, "|=", operator
},
116 {token
.XOR_ASSIGN
, "^=", operator
},
117 {token
.SHL_ASSIGN
, "<<=", operator
},
118 {token
.SHR_ASSIGN
, ">>=", operator
},
119 {token
.AND_NOT_ASSIGN
, "&^=", operator
},
121 {token
.LAND
, "&&", operator
},
122 {token
.LOR
, "||", operator
},
123 {token
.ARROW
, "<-", operator
},
124 {token
.INC
, "++", operator
},
125 {token
.DEC
, "--", operator
},
127 {token
.EQL
, "==", operator
},
128 {token
.LSS
, "<", operator
},
129 {token
.GTR
, ">", operator
},
130 {token
.ASSIGN
, "=", operator
},
131 {token
.NOT
, "!", operator
},
133 {token
.NEQ
, "!=", operator
},
134 {token
.LEQ
, "<=", operator
},
135 {token
.GEQ
, ">=", operator
},
136 {token
.DEFINE
, ":=", operator
},
137 {token
.ELLIPSIS
, "...", operator
},
139 {token
.LPAREN
, "(", operator
},
140 {token
.LBRACK
, "[", operator
},
141 {token
.LBRACE
, "{", operator
},
142 {token
.COMMA
, ",", operator
},
143 {token
.PERIOD
, ".", operator
},
145 {token
.RPAREN
, ")", operator
},
146 {token
.RBRACK
, "]", operator
},
147 {token
.RBRACE
, "}", operator
},
148 {token
.SEMICOLON
, ";", operator
},
149 {token
.COLON
, ":", operator
},
152 {token
.BREAK
, "break", keyword
},
153 {token
.CASE
, "case", keyword
},
154 {token
.CHAN
, "chan", keyword
},
155 {token
.CONST
, "const", keyword
},
156 {token
.CONTINUE
, "continue", keyword
},
158 {token
.DEFAULT
, "default", keyword
},
159 {token
.DEFER
, "defer", keyword
},
160 {token
.ELSE
, "else", keyword
},
161 {token
.FALLTHROUGH
, "fallthrough", keyword
},
162 {token
.FOR
, "for", keyword
},
164 {token
.FUNC
, "func", keyword
},
165 {token
.GO
, "go", keyword
},
166 {token
.GOTO
, "goto", keyword
},
167 {token
.IF
, "if", keyword
},
168 {token
.IMPORT
, "import", keyword
},
170 {token
.INTERFACE
, "interface", keyword
},
171 {token
.MAP
, "map", keyword
},
172 {token
.PACKAGE
, "package", keyword
},
173 {token
.RANGE
, "range", keyword
},
174 {token
.RETURN
, "return", keyword
},
176 {token
.SELECT
, "select", keyword
},
177 {token
.STRUCT
, "struct", keyword
},
178 {token
.SWITCH
, "switch", keyword
},
179 {token
.TYPE
, "type", keyword
},
180 {token
.VAR
, "var", keyword
},
183 const whitespace
= " \t \n\n\n" // to separate tokens
185 var source
= func() []byte {
187 for _
, t
:= range tokens
{
188 src
= append(src
, t
.lit
...)
189 src
= append(src
, whitespace
...)
194 func newlineCount(s
string) int {
196 for i
:= 0; i
< len(s
); i
++ {
204 func checkPos(t
*testing
.T
, lit
string, p token
.Pos
, expected token
.Position
) {
205 pos
:= fset
.Position(p
)
206 if pos
.Filename
!= expected
.Filename
{
207 t
.Errorf("bad filename for %q: got %s, expected %s", lit
, pos
.Filename
, expected
.Filename
)
209 if pos
.Offset
!= expected
.Offset
{
210 t
.Errorf("bad position for %q: got %d, expected %d", lit
, pos
.Offset
, expected
.Offset
)
212 if pos
.Line
!= expected
.Line
{
213 t
.Errorf("bad line for %q: got %d, expected %d", lit
, pos
.Line
, expected
.Line
)
215 if pos
.Column
!= expected
.Column
{
216 t
.Errorf("bad column for %q: got %d, expected %d", lit
, pos
.Column
, expected
.Column
)
220 // Verify that calling Scan() provides the correct results.
221 func TestScan(t
*testing
.T
) {
222 whitespace_linecount
:= newlineCount(whitespace
)
225 eh
:= func(_ token
.Position
, msg
string) {
226 t
.Errorf("error handler called (msg = %s)", msg
)
231 s
.Init(fset
.AddFile("", fset
.Base(), len(source
)), source
, eh
, ScanComments|dontInsertSemis
)
233 // set up expected position
234 epos
:= token
.Position
{
243 pos
, tok
, lit
:= s
.Scan()
246 if tok
== token
.EOF
{
247 // correction for EOF
248 epos
.Line
= newlineCount(string(source
))
251 checkPos(t
, lit
, pos
, epos
)
254 e
:= elt
{token
.EOF
, "", special
}
255 if index
< len(tokens
) {
260 t
.Errorf("bad token for %q: got %s, expected %s", lit
, tok
, e
.tok
)
264 if tokenclass(tok
) != e
.class
{
265 t
.Errorf("bad class for %q: got %d, expected %d", lit
, tokenclass(tok
), e
.class
)
272 // no CRs in comments
273 elit
= string(stripCR([]byte(e
.lit
)))
274 //-style comment literal doesn't contain newline
276 elit
= elit
[0 : len(elit
)-1]
280 case token
.SEMICOLON
:
283 if e
.tok
.IsLiteral() {
284 // no CRs in raw string literals
287 elit
= string(stripCR([]byte(elit
)))
289 } else if e
.tok
.IsKeyword() {
294 t
.Errorf("bad literal for %q: got %q, expected %q", lit
, lit
, elit
)
297 if tok
== token
.EOF
{
302 epos
.Offset
+= len(e
.lit
) + len(whitespace
)
303 epos
.Line
+= newlineCount(e
.lit
) + whitespace_linecount
307 if s
.ErrorCount
!= 0 {
308 t
.Errorf("found %d errors", s
.ErrorCount
)
312 func checkSemi(t
*testing
.T
, line
string, mode Mode
) {
314 file
:= fset
.AddFile("TestSemis", fset
.Base(), len(line
))
315 S
.Init(file
, []byte(line
), nil, mode
)
316 pos
, tok
, lit
:= S
.Scan()
317 for tok
!= token
.EOF
{
318 if tok
== token
.ILLEGAL
{
319 // the illegal token literal indicates what
320 // kind of semicolon literal to expect
325 // next token must be a semicolon
326 semiPos
:= file
.Position(pos
)
329 pos
, tok
, lit
= S
.Scan()
330 if tok
== token
.SEMICOLON
{
332 t
.Errorf(`bad literal for %q: got %q, expected %q`, line
, lit
, semiLit
)
334 checkPos(t
, line
, pos
, semiPos
)
336 t
.Errorf("bad token for %q: got %s, expected ;", line
, tok
)
338 } else if tok
== token
.SEMICOLON
{
339 t
.Errorf("bad token for %q: got ;, expected no ;", line
)
341 pos
, tok
, lit
= S
.Scan()
345 var lines
= []string{
346 // # indicates a semicolon present in the source
347 // $ indicates an automatically inserted semicolon
349 "\ufeff#;", // first BOM is ignored
448 "foo$/*comment*/ \n",
453 "foo $/*comment*/\n",
455 "foo $/* */ /* \n */ bar$/**/\n",
456 "foo $/*0*/ /*1*/ /*2*/\n",
458 "foo $/*comment*/ \n",
459 "foo $/*0*/ /*1*/ /*2*/ \n",
460 "foo $/**/ /*-------------*/ /*----\n*/bar $/* \n*/baa$\n",
461 "foo $/* an EOF terminates a line */",
462 "foo $/* an EOF terminates a line */ /*",
463 "foo $/* an EOF terminates a line */ //",
465 "package main$\n\nfunc main() {\n\tif {\n\t\treturn /* */ }$\n}$\n",
469 func TestSemis(t
*testing
.T
) {
470 for _
, line
:= range lines
{
471 checkSemi(t
, line
, 0)
472 checkSemi(t
, line
, ScanComments
)
474 // if the input ended in newlines, the input must tokenize the
475 // same with or without those newlines
476 for i
:= len(line
) - 1; i
>= 0 && line
[i
] == '\n'; i
-- {
477 checkSemi(t
, line
[0:i
], 0)
478 checkSemi(t
, line
[0:i
], ScanComments
)
483 type segment
struct {
484 srcline
string // a line of source text
485 filename
string // filename for current token
486 line
int // line number for current token
489 var segments
= []segment
{
490 // exactly one token per line since the test consumes one token per segment
491 {" line1", filepath
.Join("dir", "TestLineComments"), 1},
492 {"\nline2", filepath
.Join("dir", "TestLineComments"), 2},
493 {"\nline3 //line File1.go:100", filepath
.Join("dir", "TestLineComments"), 3}, // bad line comment, ignored
494 {"\nline4", filepath
.Join("dir", "TestLineComments"), 4},
495 {"\n//line File1.go:100\n line100", filepath
.Join("dir", "File1.go"), 100},
496 {"\n//line \t :42\n line1", "", 42},
497 {"\n//line File2.go:200\n line200", filepath
.Join("dir", "File2.go"), 200},
498 {"\n//line foo\t:42\n line42", filepath
.Join("dir", "foo"), 42},
499 {"\n //line foo:42\n line44", filepath
.Join("dir", "foo"), 44}, // bad line comment, ignored
500 {"\n//line foo 42\n line46", filepath
.Join("dir", "foo"), 46}, // bad line comment, ignored
501 {"\n//line foo:42 extra text\n line48", filepath
.Join("dir", "foo"), 48}, // bad line comment, ignored
502 {"\n//line ./foo:42\n line42", filepath
.Join("dir", "foo"), 42},
503 {"\n//line a/b/c/File1.go:100\n line100", filepath
.Join("dir", "a", "b", "c", "File1.go"), 100},
506 var unixsegments
= []segment
{
507 {"\n//line /bar:42\n line42", "/bar", 42},
510 var winsegments
= []segment
{
511 {"\n//line c:\\bar:42\n line42", "c:\\bar", 42},
512 {"\n//line c:\\dir\\File1.go:100\n line100", "c:\\dir\\File1.go", 100},
515 // Verify that comments of the form "//line filename:line" are interpreted correctly.
516 func TestLineComments(t
*testing
.T
) {
518 if runtime
.GOOS
== "windows" {
519 segs
= append(segs
, winsegments
...)
521 segs
= append(segs
, unixsegments
...)
526 for _
, e
:= range segs
{
532 file
:= fset
.AddFile(filepath
.Join("dir", "TestLineComments"), fset
.Base(), len(src
))
533 S
.Init(file
, []byte(src
), nil, dontInsertSemis
)
534 for _
, s
:= range segs
{
535 p
, _
, lit
:= S
.Scan()
536 pos
:= file
.Position(p
)
537 checkPos(t
, lit
, p
, token
.Position
{
538 Filename
: s
.filename
,
545 if S
.ErrorCount
!= 0 {
546 t
.Errorf("found %d errors", S
.ErrorCount
)
550 // Verify that initializing the same scanner more than once works correctly.
551 func TestInit(t
*testing
.T
) {
555 src1
:= "if true { }"
556 f1
:= fset
.AddFile("src1", fset
.Base(), len(src1
))
557 s
.Init(f1
, []byte(src1
), nil, dontInsertSemis
)
558 if f1
.Size() != len(src1
) {
559 t
.Errorf("bad file size: got %d, expected %d", f1
.Size(), len(src1
))
563 _
, tok
, _
:= s
.Scan() // {
564 if tok
!= token
.LBRACE
{
565 t
.Errorf("bad token: got %s, expected %s", tok
, token
.LBRACE
)
569 src2
:= "go true { ]"
570 f2
:= fset
.AddFile("src2", fset
.Base(), len(src2
))
571 s
.Init(f2
, []byte(src2
), nil, dontInsertSemis
)
572 if f2
.Size() != len(src2
) {
573 t
.Errorf("bad file size: got %d, expected %d", f2
.Size(), len(src2
))
575 _
, tok
, _
= s
.Scan() // go
577 t
.Errorf("bad token: got %s, expected %s", tok
, token
.GO
)
580 if s
.ErrorCount
!= 0 {
581 t
.Errorf("found %d errors", s
.ErrorCount
)
585 func TestStdErrorHander(t
*testing
.T
) {
586 const src
= "@\n" + // illegal character, cause an error
587 "@ @\n" + // two errors on the same line
588 "//line File2:20\n" +
589 "@\n" + // different file, but same line
591 "@ @\n" + // same file, decreasing line number
593 "@ @ @" // original file, line 1 again
596 eh
:= func(pos token
.Position
, msg
string) { list
.Add(pos
, msg
) }
599 s
.Init(fset
.AddFile("File1", fset
.Base(), len(src
)), []byte(src
), eh
, dontInsertSemis
)
601 if _
, tok
, _
:= s
.Scan(); tok
== token
.EOF
{
606 if len(list
) != s
.ErrorCount
{
607 t
.Errorf("found %d errors, expected %d", len(list
), s
.ErrorCount
)
611 t
.Errorf("found %d raw errors, expected 9", len(list
))
612 PrintError(os
.Stderr
, list
)
617 t
.Errorf("found %d sorted errors, expected 9", len(list
))
618 PrintError(os
.Stderr
, list
)
621 list
.RemoveMultiples()
623 t
.Errorf("found %d one-per-line errors, expected 4", len(list
))
624 PrintError(os
.Stderr
, list
)
628 type errorCollector
struct {
629 cnt
int // number of errors encountered
630 msg
string // last error message encountered
631 pos token
.Position
// last error position encountered
634 func checkError(t
*testing
.T
, src
string, tok token
.Token
, pos
int, lit
, err
string) {
637 eh
:= func(pos token
.Position
, msg
string) {
642 s
.Init(fset
.AddFile("", fset
.Base(), len(src
)), []byte(src
), eh
, ScanComments|dontInsertSemis
)
643 _
, tok0
, lit0
:= s
.Scan()
645 t
.Errorf("%q: got %s, expected %s", src
, tok0
, tok
)
647 if tok0
!= token
.ILLEGAL
&& lit0
!= lit
{
648 t
.Errorf("%q: got literal %q, expected %q", src
, lit0
, lit
)
655 t
.Errorf("%q: got cnt %d, expected %d", src
, h
.cnt
, cnt
)
658 t
.Errorf("%q: got msg %q, expected %q", src
, h
.msg
, err
)
660 if h
.pos
.Offset
!= pos
{
661 t
.Errorf("%q: got offset %d, expected %d", src
, h
.pos
.Offset
, pos
)
665 var errors
= []struct {
672 {"\a", token
.ILLEGAL
, 0, "", "illegal character U+0007"},
673 {`#`, token
.ILLEGAL
, 0, "", "illegal character U+0023 '#'"},
674 {`…`, token
.ILLEGAL
, 0, "", "illegal character U+2026 '…'"},
675 {`' '`, token
.CHAR
, 0, `' '`, ""},
676 {`''`, token
.CHAR
, 0, `''`, "illegal rune literal"},
677 {`'12'`, token
.CHAR
, 0, `'12'`, "illegal rune literal"},
678 {`'123'`, token
.CHAR
, 0, `'123'`, "illegal rune literal"},
679 {`'\0'`, token
.CHAR
, 3, `'\0'`, "illegal character U+0027 ''' in escape sequence"},
680 {`'\07'`, token
.CHAR
, 4, `'\07'`, "illegal character U+0027 ''' in escape sequence"},
681 {`'\8'`, token
.CHAR
, 2, `'\8'`, "unknown escape sequence"},
682 {`'\08'`, token
.CHAR
, 3, `'\08'`, "illegal character U+0038 '8' in escape sequence"},
683 {`'\x'`, token
.CHAR
, 3, `'\x'`, "illegal character U+0027 ''' in escape sequence"},
684 {`'\x0'`, token
.CHAR
, 4, `'\x0'`, "illegal character U+0027 ''' in escape sequence"},
685 {`'\x0g'`, token
.CHAR
, 4, `'\x0g'`, "illegal character U+0067 'g' in escape sequence"},
686 {`'\u'`, token
.CHAR
, 3, `'\u'`, "illegal character U+0027 ''' in escape sequence"},
687 {`'\u0'`, token
.CHAR
, 4, `'\u0'`, "illegal character U+0027 ''' in escape sequence"},
688 {`'\u00'`, token
.CHAR
, 5, `'\u00'`, "illegal character U+0027 ''' in escape sequence"},
689 {`'\u000'`, token
.CHAR
, 6, `'\u000'`, "illegal character U+0027 ''' in escape sequence"},
690 {`'\u000`, token
.CHAR
, 6, `'\u000`, "escape sequence not terminated"},
691 {`'\u0000'`, token
.CHAR
, 0, `'\u0000'`, ""},
692 {`'\U'`, token
.CHAR
, 3, `'\U'`, "illegal character U+0027 ''' in escape sequence"},
693 {`'\U0'`, token
.CHAR
, 4, `'\U0'`, "illegal character U+0027 ''' in escape sequence"},
694 {`'\U00'`, token
.CHAR
, 5, `'\U00'`, "illegal character U+0027 ''' in escape sequence"},
695 {`'\U000'`, token
.CHAR
, 6, `'\U000'`, "illegal character U+0027 ''' in escape sequence"},
696 {`'\U0000'`, token
.CHAR
, 7, `'\U0000'`, "illegal character U+0027 ''' in escape sequence"},
697 {`'\U00000'`, token
.CHAR
, 8, `'\U00000'`, "illegal character U+0027 ''' in escape sequence"},
698 {`'\U000000'`, token
.CHAR
, 9, `'\U000000'`, "illegal character U+0027 ''' in escape sequence"},
699 {`'\U0000000'`, token
.CHAR
, 10, `'\U0000000'`, "illegal character U+0027 ''' in escape sequence"},
700 {`'\U0000000`, token
.CHAR
, 10, `'\U0000000`, "escape sequence not terminated"},
701 {`'\U00000000'`, token
.CHAR
, 0, `'\U00000000'`, ""},
702 {`'\Uffffffff'`, token
.CHAR
, 2, `'\Uffffffff'`, "escape sequence is invalid Unicode code point"},
703 {`'`, token
.CHAR
, 0, `'`, "rune literal not terminated"},
704 {`'\`, token
.CHAR
, 2, `'\`, "escape sequence not terminated"},
705 {"'\n", token
.CHAR
, 0, "'", "rune literal not terminated"},
706 {"'\n ", token
.CHAR
, 0, "'", "rune literal not terminated"},
707 {`""`, token
.STRING
, 0, `""`, ""},
708 {`"abc`, token
.STRING
, 0, `"abc`, "string literal not terminated"},
709 {"\"abc\n", token
.STRING
, 0, `"abc`, "string literal not terminated"},
710 {"\"abc\n ", token
.STRING
, 0, `"abc`, "string literal not terminated"},
711 {"``", token
.STRING
, 0, "``", ""},
712 {"`", token
.STRING
, 0, "`", "raw string literal not terminated"},
713 {"/**/", token
.COMMENT
, 0, "/**/", ""},
714 {"/*", token
.COMMENT
, 0, "/*", "comment not terminated"},
715 {"077", token
.INT
, 0, "077", ""},
716 {"078.", token
.FLOAT
, 0, "078.", ""},
717 {"07801234567.", token
.FLOAT
, 0, "07801234567.", ""},
718 {"078e0", token
.FLOAT
, 0, "078e0", ""},
719 {"0E", token
.FLOAT
, 0, "0E", "illegal floating-point exponent"}, // issue 17621
720 {"078", token
.INT
, 0, "078", "illegal octal number"},
721 {"07800000009", token
.INT
, 0, "07800000009", "illegal octal number"},
722 {"0x", token
.INT
, 0, "0x", "illegal hexadecimal number"},
723 {"0X", token
.INT
, 0, "0X", "illegal hexadecimal number"},
724 {"\"abc\x00def\"", token
.STRING
, 4, "\"abc\x00def\"", "illegal character NUL"},
725 {"\"abc\x80def\"", token
.STRING
, 4, "\"abc\x80def\"", "illegal UTF-8 encoding"},
726 {"\ufeff\ufeff", token
.ILLEGAL
, 3, "\ufeff\ufeff", "illegal byte order mark"}, // only first BOM is ignored
727 {"//\ufeff", token
.COMMENT
, 2, "//\ufeff", "illegal byte order mark"}, // only first BOM is ignored
728 {"'\ufeff" + `'`, token
.CHAR
, 1, "'\ufeff" + `'`, "illegal byte order mark"}, // only first BOM is ignored
729 {`"` + "abc\ufeffdef" + `"`, token
.STRING
, 4, `"` + "abc\ufeffdef" + `"`, "illegal byte order mark"}, // only first BOM is ignored
732 func TestScanErrors(t
*testing
.T
) {
733 for _
, e
:= range errors
{
734 checkError(t
, e
.src
, e
.tok
, e
.pos
, e
.lit
, e
.err
)
738 // Verify that no comments show up as literal values when skipping comments.
739 func TestIssue10213(t
*testing
.T
) {
760 s
.Init(fset
.AddFile("", fset
.Base(), len(src
)), []byte(src
), nil, 0)
762 pos
, tok
, lit
:= s
.Scan()
763 class
:= tokenclass(tok
)
764 if lit
!= "" && class
!= keyword
&& class
!= literal
&& tok
!= token
.SEMICOLON
{
765 t
.Errorf("%s: tok = %s, lit = %q", fset
.Position(pos
), tok
, lit
)
767 if tok
<= token
.EOF
{
773 func BenchmarkScan(b
*testing
.B
) {
775 fset
:= token
.NewFileSet()
776 file
:= fset
.AddFile("", fset
.Base(), len(source
))
779 for i
:= 0; i
< b
.N
; i
++ {
780 s
.Init(file
, source
, nil, ScanComments
)
782 _
, tok
, _
:= s
.Scan()
783 if tok
== token
.EOF
{
790 func BenchmarkScanFile(b
*testing
.B
) {
792 const filename
= "scanner.go"
793 src
, err
:= ioutil
.ReadFile(filename
)
797 fset
:= token
.NewFileSet()
798 file
:= fset
.AddFile(filename
, fset
.Base(), len(src
))
799 b
.SetBytes(int64(len(src
)))
802 for i
:= 0; i
< b
.N
; i
++ {
803 s
.Init(file
, src
, nil, ScanComments
)
805 _
, tok
, _
:= s
.Scan()
806 if tok
== token
.EOF
{