From: Robert Griesemer Date: Tue, 15 Mar 2016 23:55:48 +0000 (-0700) Subject: cmd/compile: factor parameter parsing X-Git-Tag: go1.7beta1~1294 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=9f301643bd3111f6a4e64b6fa400fa329ccb5a83;p=gostls13.git cmd/compile: factor parameter parsing Step 1 of streamlining parameter parsing. Change-Id: If9fd38295ccc08aafc7f1d26188d0926dd73058b Reviewed-on: https://go-review.googlesource.com/20747 Reviewed-by: Matthew Dempsky Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot --- diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 6a5bb66542..0800b7a03f 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -1662,6 +1662,30 @@ func (p *parser) ntype() *Node { return nil } +// signature parses a function signature and returns an OTFUNC node. +// +// Signature = Parameters [ Result ] . +func (p *parser) signature(recv *Node) *Node { + if trace && Debug['x'] != 0 { + defer p.trace("signature")() + } + + params := p.param_list(true) + + var result []*Node + if p.tok == '(' { + result = p.param_list(false) + } else if t := p.try_ntype(); t != nil { + result = []*Node{Nod(ODCLFIELD, nil, t)} + } + + typ := Nod(OTFUNC, recv, nil) + typ.List.Set(params) + typ.Rlist.Set(result) + + return typ +} + // try_ntype is like ntype but it returns nil if there was no type // instead of reporting an error. // @@ -1686,13 +1710,7 @@ func (p *parser) try_ntype() *Node { case LFUNC: // fntype p.next() - params := p.param_list() - result := p.fnres() - params = checkarglist(params, 1) - t := Nod(OTFUNC, nil, nil) - t.List.Set(params) - t.Rlist.Set(result) - return t + return p.signature(nil) case '[': // '[' oexpr ']' ntype @@ -1882,30 +1900,23 @@ func (p *parser) fndcl(nointerface bool) *Node { switch p.tok { case LNAME, '@', '?': - // sym '(' oarg_type_list_ocomma ')' fnres + // FunctionName Signature name := p.sym() - params := p.param_list() - result := p.fnres() - - params = checkarglist(params, 1) + t := p.signature(nil) if name.Name == "init" { name = renameinit() - if len(params) != 0 || len(result) != 0 { + if t.List.Len() > 0 || t.Rlist.Len() > 0 { Yyerror("func init must have no arguments and no return values") } } if localpkg.Name == "main" && name.Name == "main" { - if len(params) != 0 || len(result) != 0 { + if t.List.Len() > 0 || t.Rlist.Len() > 0 { Yyerror("func main must have no arguments and no return values") } } - t := Nod(OTFUNC, nil, nil) - t.List.Set(params) - t.Rlist.Set(result) - f := Nod(ODCLFUNC, nil, nil) f.Func.Nname = newfuncname(name) f.Func.Nname.Name.Defn = f @@ -1916,16 +1927,17 @@ func (p *parser) fndcl(nointerface bool) *Node { return f case '(': - // '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres - rparam := p.param_list() + // Receiver MethodName Signature + rparam := p.param_list(false) + var recv *Node + if len(rparam) > 0 { + recv = rparam[0] + } name := p.sym() - params := p.param_list() - result := p.fnres() + t := p.signature(recv) - rparam = checkarglist(rparam, 0) - params = checkarglist(params, 1) - - if len(rparam) == 0 { + // check after parsing header for fault-tolerance + if recv == nil { Yyerror("method has no receiver") return nil } @@ -1935,19 +1947,14 @@ func (p *parser) fndcl(nointerface bool) *Node { return nil } - rcvr := rparam[0] - if rcvr.Op != ODCLFIELD { + if recv.Op != ODCLFIELD { Yyerror("bad receiver in method") return nil } - t := Nod(OTFUNC, rcvr, nil) - t.List.Set(params) - t.Rlist.Set(result) - f := Nod(ODCLFUNC, nil, nil) f.Func.Shortname = newfuncname(name) - f.Func.Nname = methodname1(f.Func.Shortname, rcvr.Right) + f.Func.Nname = methodname1(f.Func.Shortname, recv.Right) f.Func.Nname.Name.Defn = f f.Func.Nname.Name.Param.Ntype = t f.Func.Nname.Nointerface = nointerface @@ -2043,24 +2050,6 @@ func (p *parser) fnbody() []*Node { return nil } -// Result = Parameters | Type . -func (p *parser) fnres() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("fnres")() - } - - if p.tok == '(' { - result := p.param_list() - return checkarglist(result, 0) - } - - if result := p.try_ntype(); result != nil { - return []*Node{Nod(ODCLFIELD, nil, result)} - } - - return nil -} - // Declaration = ConstDecl | TypeDecl | VarDecl . // TopLevelDecl = Declaration | FunctionDecl | MethodDecl . func (p *parser) xdcl_list() (l []*Node) { @@ -2302,16 +2291,17 @@ func (p *parser) interfacedcl() *Node { return Nod(ODCLFIELD, nil, oldname(pname)) } - // newname indcl + // MethodName Signature mname := newname(sym) - sig := p.indcl() + sig := p.signature(fakethis()) meth := Nod(ODCLFIELD, mname, sig) ifacedcl(meth) return meth case '@', '?': - // newname indcl + // MethodName Signature + // // We arrive here when parsing an interface type declared inside // an exported and inlineable function and the interface declares // unexported methods (which are then package-qualified). @@ -2322,7 +2312,7 @@ func (p *parser) interfacedcl() *Node { // // See also issue 14164. mname := newname(p.sym()) - sig := p.indcl() + sig := p.signature(fakethis()) meth := Nod(ODCLFIELD, mname, sig) ifacedcl(meth) @@ -2343,29 +2333,10 @@ func (p *parser) interfacedcl() *Node { } } -// MethodSpec = MethodName Signature . -// MethodName = identifier . -func (p *parser) indcl() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("indcl")() - } - - params := p.param_list() - result := p.fnres() - - // without func keyword - params = checkarglist(params, 1) - t := Nod(OTFUNC, fakethis(), nil) - t.List.Set(params) - t.Rlist.Set(result) - - return t -} - -// ParameterDecl = [ IdentifierList ] [ "..." ] Type . -func (p *parser) arg_type() *Node { +// [ParameterName] Type +func (p *parser) par_type() *Node { if trace && Debug['x'] != 0 { - defer p.trace("arg_type")() + defer p.trace("par_type")() } switch p.tok { @@ -2413,22 +2384,28 @@ func (p *parser) arg_type() *Node { // Parameters = "(" [ ParameterList [ "," ] ] ")" . // ParameterList = ParameterDecl { "," ParameterDecl } . -func (p *parser) param_list() (l []*Node) { +// ParameterDecl = [ IdentifierList ] [ "..." ] Type . +func (p *parser) param_list(dddOk bool) []*Node { if trace && Debug['x'] != 0 { defer p.trace("param_list")() } p.want('(') - + var l []*Node for p.tok != EOF && p.tok != ')' { - l = append(l, p.arg_type()) + l = append(l, p.par_type()) if !p.ocomma(')') { break } } - p.want(')') - return + + // TODO(gri) remove this with next commit + input := 0 + if dddOk { + input = 1 + } + return checkarglist(l, input) } var missing_stmt = Nod(OXXX, nil, nil)