aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/syntax/parser.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2018-01-03 15:52:22 -0800
committerRobert Griesemer <gri@golang.org>2018-02-12 22:57:52 +0000
commitac45cb9aa0154a84a63d18d87161dd39a2885449 (patch)
treea285e290586fc9d2fd534f2284c84922ce17f749 /src/cmd/compile/internal/syntax/parser.go
parente87f2a1b70f4751551ea5bd33e0db3417e76ac4c (diff)
downloadgo-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.go54
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 {