diff options
| author | Robert Griesemer <gri@golang.org> | 2018-01-03 15:52:22 -0800 |
|---|---|---|
| committer | Robert Griesemer <gri@golang.org> | 2018-02-12 22:57:52 +0000 |
| commit | ac45cb9aa0154a84a63d18d87161dd39a2885449 (patch) | |
| tree | a285e290586fc9d2fd534f2284c84922ce17f749 /src/cmd/compile/internal/syntax/parser.go | |
| parent | e87f2a1b70f4751551ea5bd33e0db3417e76ac4c (diff) | |
| download | go-ac45cb9aa0154a84a63d18d87161dd39a2885449.tar.xz | |
cmd/compile/internal/syntax: permit /*line file:line:col*/ directives
R=go1.11
This implements parsing of /*line file:line*/ and /*line file:line:col*/
directives and also extends the optional column format to regular //line
directives, per #22662.
For a line directive to be recognized, its comment text must start with
the prefix "line " which is followed by one of the following:
:line
:line:col
filename:line
filename:line:col
with at least one : present. The line and col values must be unsigned
decimal integers; everything before is considered part of the filename.
Valid line directives are:
//line :123
//line :123:8
//line foo.go:123
//line C:foo.go:123 (filename is "C:foo.go")
//line C:foo.go:123:8 (filename is "C:foo.go")
/*line ::123*/ (filename is ":")
No matter the comment format, at the moment all directives act as if
they were in //line comments, and column information is ignored.
To be addressed in subsequent CLs.
For #22662.
Change-Id: I1a2dc54bacc94bc6cdedc5229ee13278971f314e
Reviewed-on: https://go-review.googlesource.com/86037
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/cmd/compile/internal/syntax/parser.go')
| -rw-r--r-- | src/cmd/compile/internal/syntax/parser.go | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index c8dfc967e6..6b52950b94 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -47,8 +47,9 @@ func (p *parser) init(base *src.PosBase, r io.Reader, errh ErrorHandler, pragh P p.error_at(p.pos_at(line, col), msg) }, func(line, col uint, text string) { - if strings.HasPrefix(text, "line ") { - p.updateBase(line, col+5, text[5:]) + const prefix = "line " + if strings.HasPrefix(text, prefix) { + p.updateBase(line, col+uint(len(prefix)), text[len(prefix):]) return } if pragh != nil { @@ -69,23 +70,54 @@ func (p *parser) init(base *src.PosBase, r io.Reader, errh ErrorHandler, pragh P const lineMax = 1<<24 - 1 // TODO(gri) this limit is defined for src.Pos - fix func (p *parser) updateBase(line, col uint, text string) { - // Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails. - i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':') - if i < 0 { + i, n, ok := trailingDigits(text) + if i == 0 { return // ignore (not a line directive) } - nstr := text[i+1:] - n, err := strconv.Atoi(nstr) - if err != nil || n <= 0 || n > lineMax { - p.error_at(p.pos_at(line, col+uint(i+1)), "invalid line number: "+nstr) + // i > 0 + + if !ok { + // text has a suffix :xxx but xxx is not a number + p.error_at(p.pos_at(line, col+i), "invalid line number: "+text[i:]) + return + } + + i2, n2, ok2 := trailingDigits(text[:i-1]) + if ok2 { + //line filename:line:col + i, i2 = i2, i + n, n2 = n2, n + if n2 == 0 { + p.error_at(p.pos_at(line, col+i2), "invalid column number: "+text[i2:]) + return + } + text = text[:i2-1] // lop off :col + } + + if n == 0 || n > lineMax { + p.error_at(p.pos_at(line, col+i), "invalid line number: "+text[i:]) return } - filename := text[:i] + + filename := text[:i-1] // lop off :line absFilename := filename if p.fileh != nil { absFilename = p.fileh(filename) } - p.base = src.NewLinePragmaBase(src.MakePos(p.base.Pos().Base(), line, col), filename, absFilename, uint(n)) + + // TODO(gri) pass column n2 to NewLinePragmaBase + p.base = src.NewLinePragmaBase(src.MakePos(p.base.Pos().Base(), line, col), filename, absFilename, uint(n) /*uint(n2)*/) +} + +func trailingDigits(text string) (uint, uint, bool) { + // Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails. + i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':') + if i < 0 { + return 0, 0, false // no ":" + } + // i >= 0 + n, err := strconv.ParseUint(text[i+1:], 10, 0) + return uint(i + 1), uint(n), err == nil } func (p *parser) got(tok token) bool { |
