]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/syntax: factor out list parsing
authorgriesemer <gri@golang.org>
Wed, 11 Oct 2017 23:57:39 +0000 (16:57 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 16 Oct 2017 17:20:25 +0000 (17:20 +0000)
Instead of repeating the same list parsing pattern for parenthesized
of braced comma or semicolon-separated lists, introduce a single list
parsing function that can be parametrized and which takes a closure
to parse list elements.

This ensures the same error handling and recovery logic is used across
all lists and simplifies the code.

No semantic change.

Change-Id: Ia738d354d6c2e0c3d84a5f1c7269a6eb95685edc
Reviewed-on: https://go-review.googlesource.com/70492
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/syntax/parser.go

index c7c86be27fb9b21828c423d7f59806a085029901..cda2cf42da31b0bea5dd056a536eccd3d1ff3a5d 100644 (file)
@@ -175,7 +175,7 @@ func tokstring(tok token) string {
        case _Comma:
                return "comma"
        case _Semi:
-               return "semicolon"
+               return "semicolon or newline"
        }
        return tok.String()
 }
@@ -351,17 +351,51 @@ func isEmptyFuncDecl(dcl Decl) bool {
 // ----------------------------------------------------------------------------
 // Declarations
 
-// appendGroup(f) = f | "(" { f ";" } ")" .
+// list parses a possibly empty, sep-separated list, optionally
+// followed by sep and enclosed by ( and ) or { and }. open is
+// one of _Lparen, or _Lbrace, sep is one of _Comma or _Semi,
+// and close is expected to be the (closing) opposite of open.
+// For each list element, f is called. After f returns true, no
+// more list elements are accepted. list returns the position
+// of the closing token.
+//
+// list = "(" { f sep } ")" |
+//        "{" { f sep } "}" . // sep is optional before ")" or "}"
+//
+func (p *parser) list(open, sep, close token, f func() bool) src.Pos {
+       p.want(open)
+
+       var done bool
+       for p.tok != _EOF && p.tok != close && !done {
+               done = f()
+               switch p.tok {
+               case sep:
+                       p.next()
+               case _Rparen, _Rbrace:
+                       // comma is optional before ) or } - nothing to do
+                       // TODO(gri): consider restricting this case
+                       //            to the expected close token only
+               default:
+                       p.syntax_error(fmt.Sprintf("expecting %s or %s", tokstring(sep), tokstring(close)))
+                       p.advance(close)
+                       done = true
+               }
+       }
+
+       pos := p.pos()
+       p.want(close)
+
+       return pos
+}
+
+// appendGroup(f) = f | "(" { f ";" } ")" . // ";" is optional before ")"
 func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
-       if p.got(_Lparen) {
+       if p.tok == _Lparen {
                g := new(Group)
-               for p.tok != _EOF && p.tok != _Rparen {
+               p.list(_Lparen, _Semi, _Rparen, func() bool {
                        list = append(list, f(g))
-                       if !p.osemi(_Rparen) {
-                               break
-                       }
-               }
-               p.want(_Rparen)
+                       return false
+               })
        } else {
                list = append(list, f(nil))
        }
@@ -939,10 +973,8 @@ func (p *parser) complitexpr() *CompositeLit {
        x := new(CompositeLit)
        x.pos = p.pos()
 
-       p.want(_Lbrace)
        p.xnest++
-
-       for p.tok != _EOF && p.tok != _Rbrace {
+       x.Rbrace = p.list(_Lbrace, _Comma, _Rbrace, func() bool {
                // value
                e := p.bare_complitexpr()
                if p.tok == _Colon {
@@ -956,14 +988,9 @@ func (p *parser) complitexpr() *CompositeLit {
                        x.NKeys++
                }
                x.ElemList = append(x.ElemList, e)
-               if !p.ocomma(_Rbrace) {
-                       break
-               }
-       }
-
-       x.Rbrace = p.pos()
+               return false
+       })
        p.xnest--
-       p.want(_Rbrace)
 
        return x
 }
@@ -1149,14 +1176,10 @@ func (p *parser) structType() *StructType {
        typ.pos = p.pos()
 
        p.want(_Struct)
-       p.want(_Lbrace)
-       for p.tok != _EOF && p.tok != _Rbrace {
+       p.list(_Lbrace, _Semi, _Rbrace, func() bool {
                p.fieldDecl(typ)
-               if !p.osemi(_Rbrace) {
-                       break
-               }
-       }
-       p.want(_Rbrace)
+               return false
+       })
 
        return typ
 }
@@ -1171,16 +1194,12 @@ func (p *parser) interfaceType() *InterfaceType {
        typ.pos = p.pos()
 
        p.want(_Interface)
-       p.want(_Lbrace)
-       for p.tok != _EOF && p.tok != _Rbrace {
+       p.list(_Lbrace, _Semi, _Rbrace, func() bool {
                if m := p.methodDecl(); m != nil {
                        typ.MethodList = append(typ.MethodList, m)
                }
-               if !p.osemi(_Rbrace) {
-                       break
-               }
-       }
-       p.want(_Rbrace)
+               return false
+       })
 
        return typ
 }
@@ -1433,10 +1452,9 @@ func (p *parser) paramList() (list []*Field) {
        }
 
        pos := p.pos()
-       p.want(_Lparen)
 
        var named int // number of parameters that have an explicit name and type
-       for p.tok != _EOF && p.tok != _Rparen {
+       p.list(_Lparen, _Comma, _Rparen, func() bool {
                if par := p.paramDeclOrNil(); par != nil {
                        if debug && par.Name == nil && par.Type == nil {
                                panic("parameter without name or type")
@@ -1446,10 +1464,8 @@ func (p *parser) paramList() (list []*Field) {
                        }
                        list = append(list, par)
                }
-               if !p.ocomma(_Rparen) {
-                       break
-               }
-       }
+               return false
+       })
 
        // distribute parameter types
        if named == 0 {
@@ -1488,7 +1504,6 @@ func (p *parser) paramList() (list []*Field) {
                }
        }
 
-       p.want(_Rparen)
        return
 }
 
@@ -2071,19 +2086,13 @@ func (p *parser) argList() (list []Expr, hasDots bool) {
                defer p.trace("argList")()
        }
 
-       p.want(_Lparen)
        p.xnest++
-
-       for p.tok != _EOF && p.tok != _Rparen {
+       p.list(_Lparen, _Comma, _Rparen, func() bool {
                list = append(list, p.expr())
                hasDots = p.got(_DotDotDot)
-               if !p.ocomma(_Rparen) || hasDots {
-                       break
-               }
-       }
-
+               return hasDots
+       })
        p.xnest--
-       p.want(_Rparen)
 
        return
 }
@@ -2172,40 +2181,6 @@ func (p *parser) exprList() Expr {
        return x
 }
 
-// osemi parses an optional semicolon.
-func (p *parser) osemi(follow token) bool {
-       switch p.tok {
-       case _Semi:
-               p.next()
-               return true
-
-       case _Rparen, _Rbrace:
-               // semicolon is optional before ) or }
-               return true
-       }
-
-       p.syntax_error("expecting semicolon, newline, or " + tokstring(follow))
-       p.advance(follow)
-       return false
-}
-
-// ocomma parses an optional comma.
-func (p *parser) ocomma(follow token) bool {
-       switch p.tok {
-       case _Comma:
-               p.next()
-               return true
-
-       case _Rparen, _Rbrace:
-               // comma is optional before ) or }
-               return true
-       }
-
-       p.syntax_error("expecting comma or " + tokstring(follow))
-       p.advance(follow)
-       return false
-}
-
 // unparen removes all parentheses around an expression.
 func unparen(x Expr) Expr {
        for {