mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/syntax: establish principled position information
Until now, the parser set the position for each Node to the position of the first token belonging to that node. For compatibility with the now defunct gc parser, in many places that position information was modified when the gcCompat flag was set (which it was, by default). Furthermore, in some places, position information was not set at all. This change removes the gcCompat flag and all associated code, and sets position information for all nodes in a more principled way, as proposed by mdempsky (see #16943 for details). Specifically, the position of a node may not be at the very beginning of the respective production. For instance for an Operation `a + b`, the position associated with the node is the position of the `+`. Thus, for `a + b + c` we now get different positions for the two additions. This change does not pass toolstash -cmp because position information recorded in export data and pcline tables is different. There are no other functional changes. Added test suite testing the position of all nodes. Fixes #16943. Change-Id: I3fc02bf096bc3b3d7d2fa655dfd4714a1a0eb90c Reviewed-on: https://go-review.googlesource.com/37017 Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
6910756f9b
commit
5267ac2732
4 changed files with 466 additions and 172 deletions
|
|
@ -15,11 +15,6 @@ import (
|
|||
const debug = false
|
||||
const trace = false
|
||||
|
||||
// The old gc parser assigned line numbers very inconsistently depending
|
||||
// on when it happened to construct AST nodes. To make transitioning to the
|
||||
// new AST easier, we try to mimick the behavior as much as possible.
|
||||
const gcCompat = true
|
||||
|
||||
type parser struct {
|
||||
base *src.PosBase
|
||||
errh ErrorHandler
|
||||
|
|
@ -248,7 +243,7 @@ func (p *parser) file() *File {
|
|||
}
|
||||
|
||||
f := new(File)
|
||||
f.init(p)
|
||||
f.pos = p.pos()
|
||||
|
||||
// PackageClause
|
||||
if !p.got(_Package) {
|
||||
|
|
@ -346,14 +341,14 @@ func (p *parser) importDecl(group *Group) Decl {
|
|||
}
|
||||
|
||||
d := new(ImportDecl)
|
||||
d.init(p)
|
||||
d.pos = p.pos()
|
||||
|
||||
switch p.tok {
|
||||
case _Name:
|
||||
d.LocalPkgName = p.name()
|
||||
case _Dot:
|
||||
n := new(Name)
|
||||
n.init(p)
|
||||
n.pos = p.pos()
|
||||
n.Value = "."
|
||||
d.LocalPkgName = n
|
||||
p.next()
|
||||
|
|
@ -376,7 +371,7 @@ func (p *parser) constDecl(group *Group) Decl {
|
|||
}
|
||||
|
||||
d := new(ConstDecl)
|
||||
d.init(p)
|
||||
d.pos = p.pos()
|
||||
|
||||
d.NameList = p.nameList(p.name())
|
||||
if p.tok != _EOF && p.tok != _Semi && p.tok != _Rparen {
|
||||
|
|
@ -397,7 +392,7 @@ func (p *parser) typeDecl(group *Group) Decl {
|
|||
}
|
||||
|
||||
d := new(TypeDecl)
|
||||
d.init(p)
|
||||
d.pos = p.pos()
|
||||
|
||||
d.Name = p.name()
|
||||
d.Alias = p.got(_Assign)
|
||||
|
|
@ -419,7 +414,7 @@ func (p *parser) varDecl(group *Group) Decl {
|
|||
}
|
||||
|
||||
d := new(VarDecl)
|
||||
d.init(p)
|
||||
d.pos = p.pos()
|
||||
|
||||
d.NameList = p.nameList(p.name())
|
||||
if p.got(_Assign) {
|
||||
|
|
@ -431,9 +426,6 @@ func (p *parser) varDecl(group *Group) Decl {
|
|||
}
|
||||
}
|
||||
d.Group = group
|
||||
if gcCompat {
|
||||
d.init(p)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
|
@ -449,7 +441,7 @@ func (p *parser) funcDecl() *FuncDecl {
|
|||
}
|
||||
|
||||
f := new(FuncDecl)
|
||||
f.init(p)
|
||||
f.pos = p.pos()
|
||||
|
||||
badRecv := false
|
||||
if p.tok == _Lparen {
|
||||
|
|
@ -488,9 +480,6 @@ func (p *parser) funcDecl() *FuncDecl {
|
|||
|
||||
f.Name = p.name()
|
||||
f.Type = p.funcType()
|
||||
if gcCompat {
|
||||
f.node = f.Type.node
|
||||
}
|
||||
f.Body = p.funcBody()
|
||||
|
||||
f.Pragma = p.pragma
|
||||
|
|
@ -525,15 +514,12 @@ func (p *parser) binaryExpr(prec int) Expr {
|
|||
x := p.unaryExpr()
|
||||
for (p.tok == _Operator || p.tok == _Star) && p.prec > prec {
|
||||
t := new(Operation)
|
||||
t.init(p)
|
||||
t.pos = p.pos()
|
||||
t.Op = p.op
|
||||
t.X = x
|
||||
tprec := p.prec
|
||||
p.next()
|
||||
t.Y = p.binaryExpr(tprec)
|
||||
if gcCompat {
|
||||
t.init(p)
|
||||
}
|
||||
x = t
|
||||
}
|
||||
return x
|
||||
|
|
@ -550,20 +536,17 @@ func (p *parser) unaryExpr() Expr {
|
|||
switch p.op {
|
||||
case Mul, Add, Sub, Not, Xor:
|
||||
x := new(Operation)
|
||||
x.init(p)
|
||||
x.pos = p.pos()
|
||||
x.Op = p.op
|
||||
p.next()
|
||||
x.X = p.unaryExpr()
|
||||
if gcCompat {
|
||||
x.init(p)
|
||||
}
|
||||
return x
|
||||
|
||||
case And:
|
||||
p.next()
|
||||
x := new(Operation)
|
||||
x.init(p)
|
||||
x.pos = p.pos()
|
||||
x.Op = And
|
||||
p.next()
|
||||
// unaryExpr may have returned a parenthesized composite literal
|
||||
// (see comment in operand) - remove parentheses if any
|
||||
x.X = unparen(p.unaryExpr())
|
||||
|
|
@ -572,6 +555,7 @@ func (p *parser) unaryExpr() Expr {
|
|||
|
||||
case _Arrow:
|
||||
// receive op (<-x) or receive-only channel (<-chan E)
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
|
||||
// If the next token is _Chan we still don't know if it is
|
||||
|
|
@ -620,7 +604,11 @@ func (p *parser) unaryExpr() Expr {
|
|||
}
|
||||
|
||||
// x is not a channel type => we have a receive op
|
||||
return &Operation{Op: Recv, X: x}
|
||||
o := new(Operation)
|
||||
o.pos = pos
|
||||
o.Op = Recv
|
||||
o.X = x
|
||||
return o
|
||||
}
|
||||
|
||||
// TODO(mdempsky): We need parens here so we can report an
|
||||
|
|
@ -636,7 +624,7 @@ func (p *parser) callStmt() *CallStmt {
|
|||
}
|
||||
|
||||
s := new(CallStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
s.Tok = p.tok // _Defer or _Go
|
||||
p.next()
|
||||
|
||||
|
|
@ -672,6 +660,7 @@ func (p *parser) operand(keep_parens bool) Expr {
|
|||
return p.oliteral()
|
||||
|
||||
case _Lparen:
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
p.xnest++
|
||||
x := p.expr() // expr_or_type
|
||||
|
|
@ -700,21 +689,27 @@ func (p *parser) operand(keep_parens bool) Expr {
|
|||
// in a go/defer statement. In that case, operand is called
|
||||
// with keep_parens set.
|
||||
if keep_parens {
|
||||
x = &ParenExpr{X: x}
|
||||
px := new(ParenExpr)
|
||||
px.pos = pos
|
||||
px.X = x
|
||||
x = px
|
||||
}
|
||||
return x
|
||||
|
||||
case _Func:
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
t := p.funcType()
|
||||
if p.tok == _Lbrace {
|
||||
p.fnest++
|
||||
p.xnest++
|
||||
|
||||
f := new(FuncLit)
|
||||
f.init(p)
|
||||
f.pos = pos
|
||||
f.Type = t
|
||||
f.Body = p.funcBody()
|
||||
f.EndLine = p.line
|
||||
|
||||
p.xnest--
|
||||
p.fnest--
|
||||
return f
|
||||
|
|
@ -767,6 +762,7 @@ func (p *parser) pexpr(keep_parens bool) Expr {
|
|||
|
||||
loop:
|
||||
for {
|
||||
pos := p.pos()
|
||||
switch p.tok {
|
||||
case _Dot:
|
||||
p.next()
|
||||
|
|
@ -774,7 +770,7 @@ loop:
|
|||
case _Name:
|
||||
// pexpr '.' sym
|
||||
t := new(SelectorExpr)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Sel = p.name()
|
||||
x = t
|
||||
|
|
@ -783,12 +779,12 @@ loop:
|
|||
p.next()
|
||||
if p.got(_Type) {
|
||||
t := new(TypeSwitchGuard)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
x = t
|
||||
} else {
|
||||
t := new(AssertExpr)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Type = p.expr()
|
||||
x = t
|
||||
|
|
@ -799,9 +795,6 @@ loop:
|
|||
p.syntax_error("expecting name or (")
|
||||
p.advance(_Semi, _Rparen)
|
||||
}
|
||||
if gcCompat && x != nil {
|
||||
x.init(p)
|
||||
}
|
||||
|
||||
case _Lbrack:
|
||||
p.next()
|
||||
|
|
@ -813,7 +806,7 @@ loop:
|
|||
if p.got(_Rbrack) {
|
||||
// x[i]
|
||||
t := new(IndexExpr)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Index = i
|
||||
x = t
|
||||
|
|
@ -824,7 +817,7 @@ loop:
|
|||
|
||||
// x[i:...
|
||||
t := new(SliceExpr)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Index[0] = i
|
||||
p.want(_Colon)
|
||||
|
|
@ -909,7 +902,7 @@ func (p *parser) complitexpr() *CompositeLit {
|
|||
}
|
||||
|
||||
x := new(CompositeLit)
|
||||
x.init(p)
|
||||
x.pos = p.pos()
|
||||
|
||||
p.want(_Lbrace)
|
||||
p.xnest++
|
||||
|
|
@ -917,15 +910,13 @@ func (p *parser) complitexpr() *CompositeLit {
|
|||
for p.tok != _EOF && p.tok != _Rbrace {
|
||||
// value
|
||||
e := p.bare_complitexpr()
|
||||
if p.got(_Colon) {
|
||||
if p.tok == _Colon {
|
||||
// key ':' value
|
||||
l := new(KeyValueExpr)
|
||||
l.init(p)
|
||||
l.pos = p.pos()
|
||||
p.next()
|
||||
l.Key = e
|
||||
l.Value = p.bare_complitexpr()
|
||||
if gcCompat {
|
||||
l.init(p)
|
||||
}
|
||||
e = l
|
||||
x.NKeys++
|
||||
}
|
||||
|
|
@ -954,13 +945,17 @@ func (p *parser) type_() Expr {
|
|||
return typ
|
||||
}
|
||||
|
||||
p.syntax_error("")
|
||||
p.syntax_error("expecting type")
|
||||
p.advance()
|
||||
return nil
|
||||
}
|
||||
|
||||
func indirect(typ Expr) Expr {
|
||||
return &Operation{Op: Mul, X: typ}
|
||||
func indirect(pos src.Pos, typ Expr) Expr {
|
||||
o := new(Operation)
|
||||
o.pos = pos
|
||||
o.Op = Mul
|
||||
o.X = typ
|
||||
return o
|
||||
}
|
||||
|
||||
// tryType is like type_ but it returns nil if there was no type
|
||||
|
|
@ -975,18 +970,19 @@ func (p *parser) tryType() Expr {
|
|||
defer p.trace("tryType")()
|
||||
}
|
||||
|
||||
pos := p.pos()
|
||||
switch p.tok {
|
||||
case _Star:
|
||||
// ptrtype
|
||||
p.next()
|
||||
return indirect(p.type_())
|
||||
return indirect(pos, p.type_())
|
||||
|
||||
case _Arrow:
|
||||
// recvchantype
|
||||
p.next()
|
||||
p.want(_Chan)
|
||||
t := new(ChanType)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.Dir = RecvOnly
|
||||
t.Elem = p.chanElem()
|
||||
return t
|
||||
|
|
@ -1005,14 +1001,14 @@ func (p *parser) tryType() Expr {
|
|||
// []T
|
||||
p.xnest--
|
||||
t := new(SliceType)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.Elem = p.type_()
|
||||
return t
|
||||
}
|
||||
|
||||
// [n]T
|
||||
t := new(ArrayType)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
if !p.got(_DotDotDot) {
|
||||
t.Len = p.expr()
|
||||
}
|
||||
|
|
@ -1026,7 +1022,7 @@ func (p *parser) tryType() Expr {
|
|||
// _Chan _Comm ntype
|
||||
p.next()
|
||||
t := new(ChanType)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
if p.got(_Arrow) {
|
||||
t.Dir = SendOnly
|
||||
}
|
||||
|
|
@ -1038,7 +1034,7 @@ func (p *parser) tryType() Expr {
|
|||
p.next()
|
||||
p.want(_Lbrack)
|
||||
t := new(MapType)
|
||||
t.init(p)
|
||||
t.pos = pos
|
||||
t.Key = p.type_()
|
||||
p.want(_Rbrack)
|
||||
t.Value = p.type_()
|
||||
|
|
@ -1069,12 +1065,10 @@ func (p *parser) funcType() *FuncType {
|
|||
}
|
||||
|
||||
typ := new(FuncType)
|
||||
typ.init(p)
|
||||
typ.pos = p.pos()
|
||||
typ.ParamList = p.paramList()
|
||||
typ.ResultList = p.funcResult()
|
||||
if gcCompat {
|
||||
typ.init(p)
|
||||
}
|
||||
|
||||
return typ
|
||||
}
|
||||
|
||||
|
|
@ -1097,9 +1091,10 @@ func (p *parser) dotname(name *Name) Expr {
|
|||
defer p.trace("dotname")()
|
||||
}
|
||||
|
||||
if p.got(_Dot) {
|
||||
if p.tok == _Dot {
|
||||
s := new(SelectorExpr)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
p.next()
|
||||
s.X = name
|
||||
s.Sel = p.name()
|
||||
return s
|
||||
|
|
@ -1114,7 +1109,7 @@ func (p *parser) structType() *StructType {
|
|||
}
|
||||
|
||||
typ := new(StructType)
|
||||
typ.init(p)
|
||||
typ.pos = p.pos()
|
||||
|
||||
p.want(_Struct)
|
||||
p.want(_Lbrace)
|
||||
|
|
@ -1136,7 +1131,7 @@ func (p *parser) interfaceType() *InterfaceType {
|
|||
}
|
||||
|
||||
typ := new(InterfaceType)
|
||||
typ.init(p)
|
||||
typ.pos = p.pos()
|
||||
|
||||
p.want(_Interface)
|
||||
p.want(_Lbrace)
|
||||
|
|
@ -1183,9 +1178,10 @@ func (p *parser) funcResult() []*Field {
|
|||
return p.paramList()
|
||||
}
|
||||
|
||||
pos := p.pos()
|
||||
if result := p.tryType(); result != nil {
|
||||
f := new(Field)
|
||||
f.init(p)
|
||||
f.pos = pos
|
||||
f.Type = result
|
||||
return []*Field{f}
|
||||
}
|
||||
|
|
@ -1193,7 +1189,7 @@ func (p *parser) funcResult() []*Field {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) addField(styp *StructType, name *Name, typ Expr, tag *BasicLit) {
|
||||
func (p *parser) addField(styp *StructType, pos src.Pos, name *Name, typ Expr, tag *BasicLit) {
|
||||
if tag != nil {
|
||||
for i := len(styp.FieldList) - len(styp.TagList); i > 0; i-- {
|
||||
styp.TagList = append(styp.TagList, nil)
|
||||
|
|
@ -1202,15 +1198,11 @@ func (p *parser) addField(styp *StructType, name *Name, typ Expr, tag *BasicLit)
|
|||
}
|
||||
|
||||
f := new(Field)
|
||||
f.init(p)
|
||||
f.pos = pos
|
||||
f.Name = name
|
||||
f.Type = typ
|
||||
styp.FieldList = append(styp.FieldList, f)
|
||||
|
||||
if gcCompat && name != nil {
|
||||
f.node = name.node
|
||||
}
|
||||
|
||||
if debug && tag != nil && len(styp.FieldList) != len(styp.TagList) {
|
||||
panic("inconsistent struct field list")
|
||||
}
|
||||
|
|
@ -1224,15 +1216,15 @@ func (p *parser) fieldDecl(styp *StructType) {
|
|||
defer p.trace("fieldDecl")()
|
||||
}
|
||||
|
||||
var name *Name
|
||||
pos := p.pos()
|
||||
switch p.tok {
|
||||
case _Name:
|
||||
name = p.name()
|
||||
name := p.name()
|
||||
if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
|
||||
// embed oliteral
|
||||
typ := p.qualifiedName(name)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, nil, typ, tag)
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1242,18 +1234,19 @@ func (p *parser) fieldDecl(styp *StructType) {
|
|||
tag := p.oliteral()
|
||||
|
||||
for _, name := range names {
|
||||
p.addField(styp, name, typ, tag)
|
||||
p.addField(styp, name.Pos(), name, typ, tag)
|
||||
}
|
||||
|
||||
case _Lparen:
|
||||
p.next()
|
||||
if p.tok == _Star {
|
||||
// '(' '*' embed ')' oliteral
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
typ := indirect(p.qualifiedName(nil))
|
||||
typ := indirect(pos, p.qualifiedName(nil))
|
||||
p.want(_Rparen)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, nil, typ, tag)
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
p.syntax_error("cannot parenthesize embedded type")
|
||||
|
||||
} else {
|
||||
|
|
@ -1261,7 +1254,7 @@ func (p *parser) fieldDecl(styp *StructType) {
|
|||
typ := p.qualifiedName(nil)
|
||||
p.want(_Rparen)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, nil, typ, tag)
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
p.syntax_error("cannot parenthesize embedded type")
|
||||
}
|
||||
|
||||
|
|
@ -1269,17 +1262,17 @@ func (p *parser) fieldDecl(styp *StructType) {
|
|||
p.next()
|
||||
if p.got(_Lparen) {
|
||||
// '*' '(' embed ')' oliteral
|
||||
typ := indirect(p.qualifiedName(nil))
|
||||
typ := indirect(pos, p.qualifiedName(nil))
|
||||
p.want(_Rparen)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, nil, typ, tag)
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
p.syntax_error("cannot parenthesize embedded type")
|
||||
|
||||
} else {
|
||||
// '*' embed oliteral
|
||||
typ := indirect(p.qualifiedName(nil))
|
||||
typ := indirect(pos, p.qualifiedName(nil))
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, nil, typ, tag)
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
@ -1291,7 +1284,7 @@ func (p *parser) fieldDecl(styp *StructType) {
|
|||
func (p *parser) oliteral() *BasicLit {
|
||||
if p.tok == _Literal {
|
||||
b := new(BasicLit)
|
||||
b.init(p)
|
||||
b.pos = p.pos()
|
||||
b.Value = p.lit
|
||||
b.Kind = p.kind
|
||||
p.next()
|
||||
|
|
@ -1324,7 +1317,7 @@ func (p *parser) methodDecl() *Field {
|
|||
}
|
||||
|
||||
f := new(Field)
|
||||
f.init(p)
|
||||
f.pos = name.Pos()
|
||||
if p.tok != _Lparen {
|
||||
// packname
|
||||
f.Type = p.qualifiedName(name)
|
||||
|
|
@ -1336,16 +1329,16 @@ func (p *parser) methodDecl() *Field {
|
|||
return f
|
||||
|
||||
case _Lparen:
|
||||
p.next()
|
||||
p.syntax_error("cannot parenthesize embedded type")
|
||||
f := new(Field)
|
||||
f.init(p)
|
||||
f.pos = p.pos()
|
||||
p.next()
|
||||
f.Type = p.qualifiedName(nil)
|
||||
p.want(_Rparen)
|
||||
p.syntax_error("cannot parenthesize embedded type")
|
||||
return f
|
||||
|
||||
default:
|
||||
p.syntax_error("")
|
||||
p.syntax_error("expecting method or interface name")
|
||||
p.advance(_Semi, _Rbrace)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1358,7 +1351,7 @@ func (p *parser) paramDecl() *Field {
|
|||
}
|
||||
|
||||
f := new(Field)
|
||||
f.init(p)
|
||||
f.pos = p.pos()
|
||||
|
||||
switch p.tok {
|
||||
case _Name:
|
||||
|
|
@ -1403,7 +1396,7 @@ func (p *parser) dotsType() *DotsType {
|
|||
}
|
||||
|
||||
t := new(DotsType)
|
||||
t.init(p)
|
||||
t.pos = p.pos()
|
||||
|
||||
p.want(_DotDotDot)
|
||||
t.Elem = p.tryType()
|
||||
|
|
@ -1486,7 +1479,7 @@ func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt {
|
|||
defer p.trace("simpleStmt")()
|
||||
}
|
||||
|
||||
if rangeOk && p.got(_Range) {
|
||||
if rangeOk && p.tok == _Range {
|
||||
// _Range expr
|
||||
if debug && lhs != nil {
|
||||
panic("invalid call of simpleStmt")
|
||||
|
|
@ -1500,55 +1493,60 @@ func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt {
|
|||
|
||||
if _, ok := lhs.(*ListExpr); !ok && p.tok != _Assign && p.tok != _Define {
|
||||
// expr
|
||||
pos := p.pos()
|
||||
switch p.tok {
|
||||
case _AssignOp:
|
||||
// lhs op= rhs
|
||||
op := p.op
|
||||
p.next()
|
||||
return p.newAssignStmt(op, lhs, p.expr())
|
||||
return p.newAssignStmt(pos, op, lhs, p.expr())
|
||||
|
||||
case _IncOp:
|
||||
// lhs++ or lhs--
|
||||
op := p.op
|
||||
p.next()
|
||||
return p.newAssignStmt(op, lhs, ImplicitOne)
|
||||
return p.newAssignStmt(pos, op, lhs, ImplicitOne)
|
||||
|
||||
case _Arrow:
|
||||
// lhs <- rhs
|
||||
p.next()
|
||||
s := new(SendStmt)
|
||||
s.init(p)
|
||||
s.pos = pos
|
||||
p.next()
|
||||
s.Chan = lhs
|
||||
s.Value = p.expr()
|
||||
if gcCompat {
|
||||
s.init(p)
|
||||
}
|
||||
return s
|
||||
|
||||
default:
|
||||
// expr
|
||||
return &ExprStmt{X: lhs}
|
||||
s := new(ExprStmt)
|
||||
if lhs != nil { // be cautious (test/syntax/semi4.go)
|
||||
s.pos = lhs.Pos()
|
||||
} else {
|
||||
s.pos = p.pos()
|
||||
}
|
||||
s.X = lhs
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// expr_list
|
||||
pos := p.pos()
|
||||
switch p.tok {
|
||||
case _Assign:
|
||||
p.next()
|
||||
|
||||
if rangeOk && p.got(_Range) {
|
||||
if rangeOk && p.tok == _Range {
|
||||
// expr_list '=' _Range expr
|
||||
return p.rangeClause(lhs, false)
|
||||
}
|
||||
|
||||
// expr_list '=' expr_list
|
||||
return p.newAssignStmt(0, lhs, p.exprList())
|
||||
return p.newAssignStmt(pos, 0, lhs, p.exprList())
|
||||
|
||||
case _Define:
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
|
||||
if rangeOk && p.got(_Range) {
|
||||
if rangeOk && p.tok == _Range {
|
||||
// expr_list ':=' range expr
|
||||
return p.rangeClause(lhs, true)
|
||||
}
|
||||
|
|
@ -1566,10 +1564,13 @@ func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt {
|
|||
// TODO(mdempsky): Have Expr types implement Stringer?
|
||||
p.error(fmt.Sprintf("invalid variable name %s in type switch", lhs))
|
||||
}
|
||||
return &ExprStmt{X: x}
|
||||
s := new(ExprStmt)
|
||||
s.pos = x.Pos()
|
||||
s.X = x
|
||||
return s
|
||||
}
|
||||
|
||||
as := p.newAssignStmt(Def, lhs, rhs)
|
||||
as := p.newAssignStmt(pos, Def, lhs, rhs)
|
||||
as.pos = pos // TODO(gri) pass this into newAssignStmt
|
||||
return as
|
||||
|
||||
|
|
@ -1582,19 +1583,17 @@ func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt {
|
|||
|
||||
func (p *parser) rangeClause(lhs Expr, def bool) *RangeClause {
|
||||
r := new(RangeClause)
|
||||
r.init(p)
|
||||
r.pos = p.pos()
|
||||
p.next() // consume _Range
|
||||
r.Lhs = lhs
|
||||
r.Def = def
|
||||
r.X = p.expr()
|
||||
if gcCompat {
|
||||
r.init(p)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *parser) newAssignStmt(op Operator, lhs, rhs Expr) *AssignStmt {
|
||||
func (p *parser) newAssignStmt(pos src.Pos, op Operator, lhs, rhs Expr) *AssignStmt {
|
||||
a := new(AssignStmt)
|
||||
a.init(p)
|
||||
a.pos = pos
|
||||
a.Op = op
|
||||
a.Lhs = lhs
|
||||
a.Rhs = rhs
|
||||
|
|
@ -1607,7 +1606,7 @@ func (p *parser) labeledStmt(label *Name) Stmt {
|
|||
}
|
||||
|
||||
s := new(LabeledStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
s.Label = label
|
||||
|
||||
p.want(_Colon)
|
||||
|
|
@ -1631,7 +1630,7 @@ func (p *parser) blockStmt() *BlockStmt {
|
|||
}
|
||||
|
||||
s := new(BlockStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
p.want(_Lbrace)
|
||||
s.Body = p.stmtList()
|
||||
p.want(_Rbrace)
|
||||
|
|
@ -1645,7 +1644,7 @@ func (p *parser) declStmt(f func(*Group) Decl) *DeclStmt {
|
|||
}
|
||||
|
||||
s := new(DeclStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
|
||||
p.next() // _Const, _Type, or _Var
|
||||
s.DeclList = p.appendGroup(nil, f)
|
||||
|
|
@ -1659,13 +1658,9 @@ func (p *parser) forStmt() Stmt {
|
|||
}
|
||||
|
||||
s := new(ForStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
|
||||
p.want(_For)
|
||||
s.Init, s.Cond, s.Post = p.header(_For)
|
||||
if gcCompat {
|
||||
s.init(p)
|
||||
}
|
||||
s.Body = p.stmtBody("for clause")
|
||||
|
||||
return s
|
||||
|
|
@ -1689,7 +1684,7 @@ func (p *parser) stmtBody(context string) []Stmt {
|
|||
}
|
||||
|
||||
func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) {
|
||||
// TODO(gri) move caller's p.want(keyword) here, once we removed gcCompat
|
||||
p.want(keyword)
|
||||
|
||||
if p.tok == _Lbrace {
|
||||
if keyword == _If {
|
||||
|
|
@ -1765,15 +1760,9 @@ func (p *parser) ifStmt() *IfStmt {
|
|||
}
|
||||
|
||||
s := new(IfStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
|
||||
p.want(_If)
|
||||
s.Init, s.Cond, _ = p.header(_If)
|
||||
|
||||
if gcCompat {
|
||||
s.init(p)
|
||||
}
|
||||
|
||||
s.Then = p.stmtBody("if clause")
|
||||
|
||||
if p.got(_Else) {
|
||||
|
|
@ -1796,9 +1785,8 @@ func (p *parser) switchStmt() *SwitchStmt {
|
|||
defer p.trace("switchStmt")()
|
||||
}
|
||||
|
||||
p.want(_Switch)
|
||||
s := new(SwitchStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
|
||||
s.Init, s.Tag, _ = p.header(_Switch)
|
||||
|
||||
|
|
@ -1819,10 +1807,10 @@ func (p *parser) selectStmt() *SelectStmt {
|
|||
defer p.trace("selectStmt")()
|
||||
}
|
||||
|
||||
p.want(_Select)
|
||||
s := new(SelectStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
|
||||
p.want(_Select)
|
||||
if !p.got(_Lbrace) {
|
||||
p.syntax_error("missing { after select clause")
|
||||
p.advance(_Case, _Default, _Rbrace)
|
||||
|
|
@ -1841,7 +1829,7 @@ func (p *parser) caseClause() *CaseClause {
|
|||
}
|
||||
|
||||
c := new(CaseClause)
|
||||
c.init(p)
|
||||
c.pos = p.pos()
|
||||
|
||||
switch p.tok {
|
||||
case _Case:
|
||||
|
|
@ -1868,7 +1856,7 @@ func (p *parser) commClause() *CommClause {
|
|||
}
|
||||
|
||||
c := new(CommClause)
|
||||
c.init(p)
|
||||
c.pos = p.pos()
|
||||
|
||||
switch p.tok {
|
||||
case _Case:
|
||||
|
|
@ -1895,9 +1883,6 @@ func (p *parser) commClause() *CommClause {
|
|||
p.advance(_Case, _Default, _Rbrace)
|
||||
}
|
||||
|
||||
if gcCompat {
|
||||
c.init(p)
|
||||
}
|
||||
p.want(_Colon)
|
||||
c.Body = p.stmtList()
|
||||
|
||||
|
|
@ -1966,22 +1951,17 @@ func (p *parser) stmt() Stmt {
|
|||
return p.ifStmt()
|
||||
|
||||
case _Fallthrough:
|
||||
p.next()
|
||||
s := new(BranchStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
p.next()
|
||||
s.Tok = _Fallthrough
|
||||
return s
|
||||
// // will be converted to OFALL
|
||||
// stmt := nod(OXFALL, nil, nil)
|
||||
// stmt.Xoffset = int64(block)
|
||||
// return stmt
|
||||
|
||||
case _Break, _Continue:
|
||||
tok := p.tok
|
||||
p.next()
|
||||
s := new(BranchStmt)
|
||||
s.init(p)
|
||||
s.Tok = tok
|
||||
s.pos = p.pos()
|
||||
s.Tok = p.tok
|
||||
p.next()
|
||||
if p.tok == _Name {
|
||||
s.Label = p.name()
|
||||
}
|
||||
|
|
@ -1991,31 +1971,25 @@ func (p *parser) stmt() Stmt {
|
|||
return p.callStmt()
|
||||
|
||||
case _Goto:
|
||||
p.next()
|
||||
s := new(BranchStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
s.Tok = _Goto
|
||||
p.next()
|
||||
s.Label = p.name()
|
||||
return s
|
||||
// stmt := nod(OGOTO, p.new_name(p.name()), nil)
|
||||
// stmt.Sym = dclstack // context, for goto restrictions
|
||||
// return stmt
|
||||
|
||||
case _Return:
|
||||
p.next()
|
||||
s := new(ReturnStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
p.next()
|
||||
if p.tok != _Semi && p.tok != _Rbrace {
|
||||
s.Results = p.exprList()
|
||||
}
|
||||
if gcCompat {
|
||||
s.init(p)
|
||||
}
|
||||
return s
|
||||
|
||||
case _Semi:
|
||||
s := new(EmptyStmt)
|
||||
s.init(p)
|
||||
s.pos = p.pos()
|
||||
return s
|
||||
}
|
||||
|
||||
|
|
@ -2056,7 +2030,7 @@ func (p *parser) call(fun Expr) *CallExpr {
|
|||
// call or conversion
|
||||
// convtype '(' expr ocomma ')'
|
||||
c := new(CallExpr)
|
||||
c.init(p)
|
||||
c.pos = p.pos()
|
||||
c.Fun = fun
|
||||
|
||||
p.want(_Lparen)
|
||||
|
|
@ -2071,9 +2045,6 @@ func (p *parser) call(fun Expr) *CallExpr {
|
|||
}
|
||||
|
||||
p.xnest--
|
||||
if gcCompat {
|
||||
c.init(p)
|
||||
}
|
||||
p.want(_Rparen)
|
||||
|
||||
return c
|
||||
|
|
@ -2086,7 +2057,7 @@ func (p *parser) name() *Name {
|
|||
// no tracing to avoid overly verbose output
|
||||
|
||||
n := new(Name)
|
||||
n.init(p)
|
||||
n.pos = p.pos()
|
||||
|
||||
if p.tok == _Name {
|
||||
n.Value = p.lit
|
||||
|
|
@ -2132,7 +2103,7 @@ func (p *parser) qualifiedName(name *Name) Expr {
|
|||
name = p.name()
|
||||
default:
|
||||
name = new(Name)
|
||||
name.init(p)
|
||||
name.pos = p.pos()
|
||||
p.syntax_error("expecting name")
|
||||
p.advance(_Dot, _Semi, _Rbrace)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue