aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/syntax/parser.go
diff options
context:
space:
mode:
authorgriesemer <gri@golang.org>2017-10-11 16:57:39 -0700
committerRobert Griesemer <gri@golang.org>2017-10-16 17:20:25 +0000
commit645c661a54e35cf0e4ee7fb480b00a4b4d2b1ba0 (patch)
treeecb666da1f344e2e9bdaabe85b18dd4fe591aa5e /src/cmd/compile/internal/syntax/parser.go
parentf8f0d6c4deab0837b03ddccfe0edf775c3bbd49f (diff)
downloadgo-645c661a54e35cf0e4ee7fb480b00a4b4d2b1ba0.tar.gz
go-645c661a54e35cf0e4ee7fb480b00a4b4d2b1ba0.zip
cmd/compile/internal/syntax: factor out list parsing
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>
Diffstat (limited to 'src/cmd/compile/internal/syntax/parser.go')
-rw-r--r--src/cmd/compile/internal/syntax/parser.go141
1 files changed, 58 insertions, 83 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index c7c86be27f..cda2cf42da 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -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 {