From e015b91f2629f3276e199cb5a549c8ad9dcdc275 Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Thu, 29 Nov 2018 13:51:30 -0500 Subject: [PATCH] go/expect: allow multi-line expectations This allows for multi-line comments where a new line is allowed between expectations. It also allows trailing new lines and commas in expectation lists. Change-Id: I714f8ad483a0238281f26ceb74ce9e73d922af69 Reviewed-on: https://go-review.googlesource.com/c/151718 Reviewed-by: Rebecca Stambler --- go/expect/extract.go | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/go/expect/extract.go b/go/expect/extract.go index b214b218..f2e3f0f4 100644 --- a/go/expect/extract.go +++ b/go/expect/extract.go @@ -77,6 +77,7 @@ func parse(fset *token.FileSet, base token.Pos, text string) ([]*Note, error) { var scanErr error s := new(scanner.Scanner).Init(strings.NewReader(text)) s.Mode = scanner.GoTokens + s.Whitespace ^= 1 << '\n' // don't skip new lines s.Error = func(s *scanner.Scanner, msg string) { scanErr = fmt.Errorf("%v:%s", fset.Position(base+token.Pos(s.Position.Offset)), msg) } @@ -100,10 +101,13 @@ func parseComment(s *scanner.Scanner) ([]*Note, error) { if err != nil { return nil, err } - notes = append(notes, n) - tok := s.Scan() + var tok rune = scanner.EOF + if n != nil { + notes = append(notes, n) + tok = s.Scan() + } switch tok { - case ',': + case ',', '\n': // continue case scanner.EOF: return notes, nil @@ -114,7 +118,11 @@ func parseComment(s *scanner.Scanner) ([]*Note, error) { } func parseNote(s *scanner.Scanner) (*Note, error) { - if tok := s.Scan(); tok != scanner.Ident { + tok := s.Scan() + if tok == scanner.EOF || tok == '\n' { + return nil, nil + } + if tok != scanner.Ident { return nil, fmt.Errorf("expected identifier, got %s", scanner.TokenString(tok)) } n := &Note{ @@ -122,19 +130,17 @@ func parseNote(s *scanner.Scanner) (*Note, error) { Name: s.TokenText(), } switch s.Peek() { - case ',', scanner.EOF: + case ',', '\n', scanner.EOF: // no argument list present return n, nil case '(': - // parse the argument list - if tok := s.Scan(); tok != '(' { - return nil, fmt.Errorf("expected ( got %s", scanner.TokenString(tok)) + s.Scan() // consume the '(' + for s.Peek() == '\n' { + s.Scan() // consume all '\n' } // special case the empty argument list if s.Peek() == ')' { - if tok := s.Scan(); tok != ')' { - return nil, fmt.Errorf("expected ) got %s", scanner.TokenString(tok)) - } + s.Scan() // consume the ')' n.Args = []interface{}{} // @name() is represented by a non-nil empty slice. return n, nil } @@ -147,15 +153,13 @@ func parseNote(s *scanner.Scanner) (*Note, error) { n.Args = append(n.Args, arg) switch s.Peek() { case ')': - if tok := s.Scan(); tok != ')' { - return nil, fmt.Errorf("expected ) got %s", scanner.TokenString(tok)) - } + s.Scan() // consume the ')' return n, nil case ',': - if tok := s.Scan(); tok != ',' { - return nil, fmt.Errorf("expected , got %s", scanner.TokenString(tok)) + s.Scan() // consume the ',' + for s.Peek() == '\n' { + s.Scan() // consume all '\n' } - // continue default: return nil, fmt.Errorf("unexpected %s parsing argument list", scanner.TokenString(s.Scan())) }