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>
This commit is contained in:
Robert Griesemer 2018-01-03 15:52:22 -08:00
parent e87f2a1b70
commit ac45cb9aa0
4 changed files with 170 additions and 37 deletions

View file

@ -577,6 +577,7 @@ func (s *scanner) skipLine(r rune) {
func (s *scanner) lineComment() {
r := s.getr()
// directives must start at the beginning of the line (s.col == colbase)
if s.col != colbase || s.pragh == nil || (r != 'g' && r != 'l') {
s.skipLine(r)
@ -608,20 +609,47 @@ func (s *scanner) lineComment() {
s.pragh(s.line, s.col+2, prefix+string(text)) // +2 since directive text starts after //
}
func (s *scanner) fullComment() {
for {
r := s.getr()
func (s *scanner) skipComment(r rune) {
for r >= 0 {
for r == '*' {
r = s.getr()
if r == '/' {
return
}
}
if r < 0 {
s.errh(s.line, s.col, "comment not terminated")
r = s.getr()
}
s.errh(s.line, s.col, "comment not terminated")
}
func (s *scanner) fullComment() {
r := s.getr()
if s.pragh == nil || r != 'l' {
s.skipComment(r)
return
}
// s.pragh != nil && r == 'l'
// recognize line directive
const prefix = "line "
for _, m := range prefix {
if r != m {
s.skipComment(r)
return
}
r = s.getr()
}
// directive text without comment ending
s.startLit()
s.skipComment(r)
text := s.stopLit()
if i := len(text) - 2; i >= 0 && text[i] == '*' && text[i+1] == '/' {
text = text[:i]
}
s.pragh(s.line, s.col+2, prefix+string(text)) // +2 since directive text starts after /*
}
func (s *scanner) escape(quote rune) bool {