1
0
mirror of https://github.com/golang/go synced 2024-11-22 06:24:38 -07:00

go/parser: resolve identifiers properly

Correctly distinguish between lhs and rhs identifiers
and resolve/declare them accordingly.

Collect field and method names in respective scopes
(will be available after some minor AST API changes).

Also collect imports since it's useful to have that
list directly w/o having to re-traverse the AST
(will also be available after some minor AST API changes).

No external API changes in this CL.

R=rsc, rog
CC=golang-dev
https://golang.org/cl/4271061
This commit is contained in:
Robert Griesemer 2011-03-24 11:45:52 -07:00
parent 0ac151fd5c
commit 1b2c3e664b
2 changed files with 213 additions and 101 deletions

View File

@ -69,7 +69,7 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr,
var p parser var p parser
p.init(fset, filename, data, 0) p.init(fset, filename, data, 0)
x := p.parseExpr() x := p.parseRhs()
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next() // consume automatically inserted semicolon, if any p.next() // consume automatically inserted semicolon, if any
} }

View File

@ -55,9 +55,10 @@ type parser struct {
exprLev int // < 0: in control clause, >= 0: in expression exprLev int // < 0: in control clause, >= 0: in expression
// Ordinary identifer scopes // Ordinary identifer scopes
pkgScope *ast.Scope // pkgScope.Outer == nil pkgScope *ast.Scope // pkgScope.Outer == nil
topScope *ast.Scope // top-most scope; may be pkgScope topScope *ast.Scope // top-most scope; may be pkgScope
unresolved []*ast.Ident // unresolved global identifiers unresolved []*ast.Ident // unresolved identifiers
imports []*ast.ImportSpec // list of imports
// Label scope // Label scope
// (maintained by open/close LabelScope) // (maintained by open/close LabelScope)
@ -141,6 +142,7 @@ func (p *parser) closeLabelScope() {
func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) { func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
for _, ident := range idents { for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
if ident.Name != "_" { if ident.Name != "_" {
obj := ast.NewObj(kind, ident.Name) obj := ast.NewObj(kind, ident.Name)
// remember the corresponding declaration for redeclaration // remember the corresponding declaration for redeclaration
@ -166,6 +168,7 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
// the same type, and at least one of the non-blank variables is new. // the same type, and at least one of the non-blank variables is new.
n := 0 // number of new variables n := 0 // number of new variables
for _, ident := range idents { for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
if ident.Name != "_" { if ident.Name != "_" {
obj := ast.NewObj(ast.Var, ident.Name) obj := ast.NewObj(ast.Var, ident.Name)
// short var declarations cannot have redeclaration errors // short var declarations cannot have redeclaration errors
@ -184,7 +187,19 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
} }
func (p *parser) resolve(ident *ast.Ident) { // The unresolved object is a sentinel to mark identifiers that have been added
// to the list of unresolved identifiers. The sentinel is only used for verifying
// internal consistency.
var unresolved = new(ast.Object)
func (p *parser) resolve(x ast.Expr) {
// nothing to do if x is not an identifier or the blank identifier
ident, _ := x.(*ast.Ident)
if ident == nil {
return
}
assert(ident.Obj == nil, "identifier already declared or resolved")
if ident.Name == "_" { if ident.Name == "_" {
return return
} }
@ -195,10 +210,12 @@ func (p *parser) resolve(ident *ast.Ident) {
return return
} }
} }
// collect unresolved global identifiers; ignore the others // all local scopes are known, so any unresolved identifier
if p.topScope == p.pkgScope { // must be found either in the file scope, package scope
p.unresolved = append(p.unresolved, ident) // (perhaps in another file), or universe scope --- collect
} // them so that they can be resolved later
ident.Obj = unresolved
p.unresolved = append(p.unresolved, ident)
} }
@ -388,6 +405,13 @@ func (p *parser) expectSemi() {
} }
func assert(cond bool, msg string) {
if !cond {
panic("go/parser internal error: " + msg)
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Identifiers // Identifiers
@ -422,21 +446,51 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Common productions // Common productions
func (p *parser) parseExprList() (list []ast.Expr) { // If lhs is set, result list elements which are identifiers are not resolved.
func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
if p.trace { if p.trace {
defer un(trace(p, "ExpressionList")) defer un(trace(p, "ExpressionList"))
} }
list = append(list, p.parseExpr()) list = append(list, p.parseExpr(lhs))
for p.tok == token.COMMA { for p.tok == token.COMMA {
p.next() p.next()
list = append(list, p.parseExpr()) list = append(list, p.parseExpr(lhs))
} }
return return
} }
func (p *parser) parseLhsList() []ast.Expr {
list := p.parseExprList(true)
switch p.tok {
case token.DEFINE:
// lhs of a short variable declaration
p.shortVarDecl(p.makeIdentList(list))
case token.COLON:
// lhs of a label declaration or a communication clause of a select
// statement (parseLhsList is not called when parsing the case clause
// of a switch statement):
// - labels are declared by the caller of parseLhsList
// - for communication clauses, if there is a stand-alone identifier
// followed by a colon, we have a syntax error; there is no need
// to resolve the identifier in that case
default:
// identifiers must be declared elsewhere
for _, x := range list {
p.resolve(x)
}
}
return list
}
func (p *parser) parseRhsList() []ast.Expr {
return p.parseExprList(false)
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Types // Types
@ -458,31 +512,24 @@ func (p *parser) parseType() ast.Expr {
} }
func (p *parser) parseQualifiedIdent() ast.Expr { // If the result is an identifier, it is not resolved.
if p.trace {
defer un(trace(p, "QualifiedIdent"))
}
ident := p.parseIdent()
p.resolve(ident)
var x ast.Expr = ident
if p.tok == token.PERIOD {
// first identifier is a package identifier
p.next()
sel := p.parseIdent()
x = &ast.SelectorExpr{x, sel}
}
return x
}
func (p *parser) parseTypeName() ast.Expr { func (p *parser) parseTypeName() ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "TypeName")) defer un(trace(p, "TypeName"))
} }
return p.parseQualifiedIdent() ident := p.parseIdent()
// don't resolve ident yet - it may be a parameter or field name
if p.tok == token.PERIOD {
// ident is a package name
p.next()
p.resolve(ident)
sel := p.parseIdent()
return &ast.SelectorExpr{ident, sel}
}
return ident
} }
@ -497,7 +544,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
len = &ast.Ellipsis{p.pos, nil} len = &ast.Ellipsis{p.pos, nil}
p.next() p.next()
} else if p.tok != token.RBRACK { } else if p.tok != token.RBRACK {
len = p.parseExpr() len = p.parseRhs()
} }
p.expect(token.RBRACK) p.expect(token.RBRACK)
elt := p.parseType() elt := p.parseType()
@ -521,7 +568,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
} }
func (p *parser) parseFieldDecl() *ast.Field { func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if p.trace { if p.trace {
defer un(trace(p, "FieldDecl")) defer un(trace(p, "FieldDecl"))
} }
@ -546,6 +593,7 @@ func (p *parser) parseFieldDecl() *ast.Field {
} else { } else {
// ["*"] TypeName (AnonymousField) // ["*"] TypeName (AnonymousField)
typ = list[0] // we always have at least one element typ = list[0] // we always have at least one element
p.resolve(typ)
if n := len(list); n > 1 || !isTypeName(deref(typ)) { if n := len(list); n > 1 || !isTypeName(deref(typ)) {
pos := typ.Pos() pos := typ.Pos()
p.errorExpected(pos, "anonymous field") p.errorExpected(pos, "anonymous field")
@ -555,7 +603,10 @@ func (p *parser) parseFieldDecl() *ast.Field {
p.expectSemi() // call before accessing p.linecomment p.expectSemi() // call before accessing p.linecomment
return &ast.Field{doc, idents, typ, tag, p.lineComment} field := &ast.Field{doc, idents, typ, tag, p.lineComment}
p.declare(field, scope, ast.Var, idents...)
return field
} }
@ -566,15 +617,17 @@ func (p *parser) parseStructType() *ast.StructType {
pos := p.expect(token.STRUCT) pos := p.expect(token.STRUCT)
lbrace := p.expect(token.LBRACE) lbrace := p.expect(token.LBRACE)
scope := ast.NewScope(nil) // struct scope
var list []*ast.Field var list []*ast.Field
for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN { for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN {
// a field declaration cannot start with a '(' but we accept // a field declaration cannot start with a '(' but we accept
// it here for more robust parsing and better error messages // it here for more robust parsing and better error messages
// (parseFieldDecl will check and complain if necessary) // (parseFieldDecl will check and complain if necessary)
list = append(list, p.parseFieldDecl()) list = append(list, p.parseFieldDecl(scope))
} }
rbrace := p.expect(token.RBRACE) rbrace := p.expect(token.RBRACE)
// TODO(gri): store struct scope in AST
return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false} return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
} }
@ -595,7 +648,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
if isParam && p.tok == token.ELLIPSIS { if isParam && p.tok == token.ELLIPSIS {
pos := p.pos pos := p.pos
p.next() p.next()
typ := p.tryType() // don't use parseType so we can provide better error message typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
if typ == nil { if typ == nil {
p.error(pos, "'...' parameter is missing type") p.error(pos, "'...' parameter is missing type")
typ = &ast.BadExpr{pos, p.pos} typ = &ast.BadExpr{pos, p.pos}
@ -605,7 +658,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
} }
return &ast.Ellipsis{pos, typ} return &ast.Ellipsis{pos, typ}
} }
return p.tryType() return p.tryIdentOrType(false)
} }
@ -641,6 +694,9 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
// if we had a list of identifiers, it must be followed by a type // if we had a list of identifiers, it must be followed by a type
typ = p.tryVarType(isParam) typ = p.tryVarType(isParam)
if typ != nil {
p.resolve(typ)
}
return return
} }
@ -682,6 +738,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
// Type { "," Type } (anonymous parameters) // Type { "," Type } (anonymous parameters)
params = make([]*ast.Field, len(list)) params = make([]*ast.Field, len(list))
for i, x := range list { for i, x := range list {
p.resolve(x)
params[i] = &ast.Field{Type: x} params[i] = &ast.Field{Type: x}
} }
} }
@ -751,7 +808,7 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
} }
func (p *parser) parseMethodSpec() *ast.Field { func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
if p.trace { if p.trace {
defer un(trace(p, "MethodSpec")) defer un(trace(p, "MethodSpec"))
} }
@ -759,7 +816,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
doc := p.leadComment doc := p.leadComment
var idents []*ast.Ident var idents []*ast.Ident
var typ ast.Expr var typ ast.Expr
x := p.parseQualifiedIdent() x := p.parseTypeName()
if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN { if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
// method // method
idents = []*ast.Ident{ident} idents = []*ast.Ident{ident}
@ -772,7 +829,10 @@ func (p *parser) parseMethodSpec() *ast.Field {
} }
p.expectSemi() // call before accessing p.linecomment p.expectSemi() // call before accessing p.linecomment
return &ast.Field{doc, idents, typ, nil, p.lineComment} spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
p.declare(spec, scope, ast.Fun, idents...)
return spec
} }
@ -783,12 +843,14 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
pos := p.expect(token.INTERFACE) pos := p.expect(token.INTERFACE)
lbrace := p.expect(token.LBRACE) lbrace := p.expect(token.LBRACE)
scope := ast.NewScope(nil) // interface scope
var list []*ast.Field var list []*ast.Field
for p.tok == token.IDENT { for p.tok == token.IDENT {
list = append(list, p.parseMethodSpec()) list = append(list, p.parseMethodSpec(scope))
} }
rbrace := p.expect(token.RBRACE) rbrace := p.expect(token.RBRACE)
// TODO(gri): store interface scope in AST
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false} return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
} }
@ -832,7 +894,8 @@ func (p *parser) parseChanType() *ast.ChanType {
} }
func (p *parser) tryRawType(ellipsisOk bool) ast.Expr { // If the result is an identifier, it is not resolved.
func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
switch p.tok { switch p.tok {
case token.IDENT: case token.IDENT:
return p.parseTypeName() return p.parseTypeName()
@ -864,7 +927,13 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
} }
func (p *parser) tryType() ast.Expr { return p.tryRawType(false) } func (p *parser) tryType() ast.Expr {
typ := p.tryIdentOrType(false)
if typ != nil {
p.resolve(typ)
}
return typ
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -939,17 +1008,20 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
// parseOperand may return an expression or a raw type (incl. array // parseOperand may return an expression or a raw type (incl. array
// types of the form [...]T. Callers must verify the result. // types of the form [...]T. Callers must verify the result.
// If lhs is set and the result is an identifier, it is not resolved.
// //
func (p *parser) parseOperand() ast.Expr { func (p *parser) parseOperand(lhs bool) ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "Operand")) defer un(trace(p, "Operand"))
} }
switch p.tok { switch p.tok {
case token.IDENT: case token.IDENT:
ident := p.parseIdent() x := p.parseIdent()
p.resolve(ident) if !lhs {
return ident p.resolve(x)
}
return x
case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING: case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
x := &ast.BasicLit{p.pos, p.tok, p.lit()} x := &ast.BasicLit{p.pos, p.tok, p.lit()}
@ -960,7 +1032,7 @@ func (p *parser) parseOperand() ast.Expr {
lparen := p.pos lparen := p.pos
p.next() p.next()
p.exprLev++ p.exprLev++
x := p.parseExpr() x := p.parseRhs()
p.exprLev-- p.exprLev--
rparen := p.expect(token.RPAREN) rparen := p.expect(token.RPAREN)
return &ast.ParenExpr{lparen, x, rparen} return &ast.ParenExpr{lparen, x, rparen}
@ -969,9 +1041,11 @@ func (p *parser) parseOperand() ast.Expr {
return p.parseFuncTypeOrLit() return p.parseFuncTypeOrLit()
default: default:
t := p.tryRawType(true) // could be type for composite literal or conversion if typ := p.tryIdentOrType(true); typ != nil {
if t != nil { // could be type for composite literal or conversion
return t _, isIdent := typ.(*ast.Ident)
assert(!isIdent, "type cannot be identifier")
return typ
} }
} }
@ -982,19 +1056,22 @@ func (p *parser) parseOperand() ast.Expr {
} }
func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { func (p *parser) parseSelector(x ast.Expr) ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "SelectorOrTypeAssertion")) defer un(trace(p, "Selector"))
} }
p.expect(token.PERIOD) sel := p.parseIdent()
if p.tok == token.IDENT {
// selector return &ast.SelectorExpr{x, sel}
sel := p.parseIdent() }
return &ast.SelectorExpr{x, sel}
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "TypeAssertion"))
} }
// type assertion
p.expect(token.LPAREN) p.expect(token.LPAREN)
var typ ast.Expr var typ ast.Expr
if p.tok == token.TYPE { if p.tok == token.TYPE {
@ -1019,13 +1096,13 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
var low, high ast.Expr var low, high ast.Expr
isSlice := false isSlice := false
if p.tok != token.COLON { if p.tok != token.COLON {
low = p.parseExpr() low = p.parseRhs()
} }
if p.tok == token.COLON { if p.tok == token.COLON {
isSlice = true isSlice = true
p.next() p.next()
if p.tok != token.RBRACK { if p.tok != token.RBRACK {
high = p.parseExpr() high = p.parseRhs()
} }
} }
p.exprLev-- p.exprLev--
@ -1048,7 +1125,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
var list []ast.Expr var list []ast.Expr
var ellipsis token.Pos var ellipsis token.Pos
for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() { for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
list = append(list, p.parseExpr()) list = append(list, p.parseRhs())
if p.tok == token.ELLIPSIS { if p.tok == token.ELLIPSIS {
ellipsis = p.pos ellipsis = p.pos
p.next() p.next()
@ -1074,7 +1151,7 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
return p.parseLiteralValue(nil) return p.parseLiteralValue(nil)
} }
x := p.parseExpr() x := p.parseRhs()
if keyOk && p.tok == token.COLON { if keyOk && p.tok == token.COLON {
colon := p.pos colon := p.pos
p.next() p.next()
@ -1231,23 +1308,47 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
} }
func (p *parser) parsePrimaryExpr() ast.Expr { // If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "PrimaryExpr")) defer un(trace(p, "PrimaryExpr"))
} }
x := p.parseOperand() x := p.parseOperand(lhs)
L: L:
for { for {
switch p.tok { switch p.tok {
case token.PERIOD: case token.PERIOD:
x = p.parseSelectorOrTypeAssertion(p.checkExpr(x)) p.next()
if lhs {
p.resolve(x)
}
switch p.tok {
case token.IDENT:
x = p.parseSelector(p.checkExpr(x))
case token.LPAREN:
x = p.parseTypeAssertion(p.checkExpr(x))
default:
pos := p.pos
p.next() // make progress
p.errorExpected(pos, "selector or type assertion")
x = &ast.BadExpr{pos, p.pos}
}
case token.LBRACK: case token.LBRACK:
if lhs {
p.resolve(x)
}
x = p.parseIndexOrSlice(p.checkExpr(x)) x = p.parseIndexOrSlice(p.checkExpr(x))
case token.LPAREN: case token.LPAREN:
if lhs {
p.resolve(x)
}
x = p.parseCallOrConversion(p.checkExprOrType(x)) x = p.parseCallOrConversion(p.checkExprOrType(x))
case token.LBRACE: case token.LBRACE:
if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) { if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
if lhs {
p.resolve(x)
}
x = p.parseLiteralValue(x) x = p.parseLiteralValue(x)
} else { } else {
break L break L
@ -1255,13 +1356,15 @@ L:
default: default:
break L break L
} }
lhs = false // no need to try to resolve again
} }
return x return x
} }
func (p *parser) parseUnaryExpr() ast.Expr { // If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "UnaryExpr")) defer un(trace(p, "UnaryExpr"))
} }
@ -1270,7 +1373,7 @@ func (p *parser) parseUnaryExpr() ast.Expr {
case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE: case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE:
pos, op := p.pos, p.tok pos, op := p.pos, p.tok
p.next() p.next()
x := p.parseUnaryExpr() x := p.parseUnaryExpr(false)
return &ast.UnaryExpr{pos, op, p.checkExpr(x)} return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
case token.ARROW: case token.ARROW:
@ -1283,32 +1386,37 @@ func (p *parser) parseUnaryExpr() ast.Expr {
return &ast.ChanType{pos, ast.RECV, value} return &ast.ChanType{pos, ast.RECV, value}
} }
x := p.parseUnaryExpr() x := p.parseUnaryExpr(false)
return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)} return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
case token.MUL: case token.MUL:
// pointer type or unary "*" expression // pointer type or unary "*" expression
pos := p.pos pos := p.pos
p.next() p.next()
x := p.parseUnaryExpr() x := p.parseUnaryExpr(false)
return &ast.StarExpr{pos, p.checkExprOrType(x)} return &ast.StarExpr{pos, p.checkExprOrType(x)}
} }
return p.parsePrimaryExpr() return p.parsePrimaryExpr(lhs)
} }
func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { // If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "BinaryExpr")) defer un(trace(p, "BinaryExpr"))
} }
x := p.parseUnaryExpr() x := p.parseUnaryExpr(lhs)
for prec := p.tok.Precedence(); prec >= prec1; prec-- { for prec := p.tok.Precedence(); prec >= prec1; prec-- {
for p.tok.Precedence() == prec { for p.tok.Precedence() == prec {
pos, op := p.pos, p.tok pos, op := p.pos, p.tok
p.next() p.next()
y := p.parseBinaryExpr(prec + 1) if lhs {
p.resolve(x)
lhs = false
}
y := p.parseBinaryExpr(false, prec+1)
x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)} x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
} }
} }
@ -1317,14 +1425,20 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
} }
// If lhs is set and the result is an identifier, it is not resolved.
// TODO(gri): parseExpr may return a type or even a raw type ([..]int) - // TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
// should reject when a type/raw type is obviously not allowed // should reject when a type/raw type is obviously not allowed
func (p *parser) parseExpr() ast.Expr { func (p *parser) parseExpr(lhs bool) ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "Expression")) defer un(trace(p, "Expression"))
} }
return p.parseBinaryExpr(token.LowestPrec + 1) return p.parseBinaryExpr(lhs, token.LowestPrec+1)
}
func (p *parser) parseRhs() ast.Expr {
return p.parseExpr(false)
} }
@ -1336,7 +1450,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
defer un(trace(p, "SimpleStmt")) defer un(trace(p, "SimpleStmt"))
} }
x := p.parseExprList() x := p.parseLhsList()
switch p.tok { switch p.tok {
case case
@ -1347,10 +1461,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
// assignment statement // assignment statement
pos, tok := p.pos, p.tok pos, tok := p.pos, p.tok
p.next() p.next()
y := p.parseExprList() y := p.parseRhsList()
if tok == token.DEFINE {
p.shortVarDecl(p.makeIdentList(x))
}
return &ast.AssignStmt{x, pos, tok, y} return &ast.AssignStmt{x, pos, tok, y}
} }
@ -1379,7 +1490,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
// send statement // send statement
arrow := p.pos arrow := p.pos
p.next() // consume "<-" p.next() // consume "<-"
y := p.parseExpr() y := p.parseRhs()
return &ast.SendStmt{x[0], arrow, y} return &ast.SendStmt{x[0], arrow, y}
case token.INC, token.DEC: case token.INC, token.DEC:
@ -1395,7 +1506,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
func (p *parser) parseCallExpr() *ast.CallExpr { func (p *parser) parseCallExpr() *ast.CallExpr {
x := p.parseExpr() x := p.parseRhs()
if call, isCall := x.(*ast.CallExpr); isCall { if call, isCall := x.(*ast.CallExpr); isCall {
return call return call
} }
@ -1445,7 +1556,7 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
p.expect(token.RETURN) p.expect(token.RETURN)
var x []ast.Expr var x []ast.Expr
if p.tok != token.SEMICOLON && p.tok != token.RBRACE { if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
x = p.parseExprList() x = p.parseRhsList()
} }
p.expectSemi() p.expectSemi()
@ -1500,12 +1611,12 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.exprLev = -1 p.exprLev = -1
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next() p.next()
x = p.parseExpr() x = p.parseRhs()
} else { } else {
s = p.parseSimpleStmt(false) s = p.parseSimpleStmt(false)
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next() p.next()
x = p.parseExpr() x = p.parseRhs()
} else { } else {
x = p.makeExpr(s) x = p.makeExpr(s)
s = nil s = nil
@ -1552,7 +1663,7 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
if p.tok == token.CASE { if p.tok == token.CASE {
p.next() p.next()
if exprSwitch { if exprSwitch {
list = p.parseExprList() list = p.parseRhsList()
} else { } else {
list = p.parseTypeList() list = p.parseTypeList()
} }
@ -1639,7 +1750,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
var comm ast.Stmt var comm ast.Stmt
if p.tok == token.CASE { if p.tok == token.CASE {
p.next() p.next()
lhs := p.parseExprList() lhs := p.parseLhsList()
if p.tok == token.ARROW { if p.tok == token.ARROW {
// SendStmt // SendStmt
if len(lhs) > 1 { if len(lhs) > 1 {
@ -1648,7 +1759,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
} }
arrow := p.pos arrow := p.pos
p.next() p.next()
rhs := p.parseExpr() rhs := p.parseRhs()
comm = &ast.SendStmt{lhs[0], arrow, rhs} comm = &ast.SendStmt{lhs[0], arrow, rhs}
} else { } else {
// RecvStmt // RecvStmt
@ -1663,10 +1774,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
lhs = lhs[0:2] lhs = lhs[0:2]
} }
p.next() p.next()
rhs = p.parseExpr() rhs = p.parseRhs()
if tok == token.DEFINE {
p.shortVarDecl(p.makeIdentList(lhs))
}
} else { } else {
// rhs must be single receive operation // rhs must be single receive operation
if len(lhs) > 1 { if len(lhs) > 1 {
@ -1873,7 +1981,11 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
} }
p.expectSemi() // call before accessing p.linecomment p.expectSemi() // call before accessing p.linecomment
return &ast.ImportSpec{doc, ident, path, p.lineComment} // collect imports
spec := &ast.ImportSpec{doc, ident, path, p.lineComment}
p.imports = append(p.imports, spec)
return spec
} }
@ -1887,7 +1999,7 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
var values []ast.Expr var values []ast.Expr
if typ != nil || p.tok == token.ASSIGN || iota == 0 { if typ != nil || p.tok == token.ASSIGN || iota == 0 {
p.expect(token.ASSIGN) p.expect(token.ASSIGN)
values = p.parseExprList() values = p.parseRhsList()
} }
p.expectSemi() // call before accessing p.linecomment p.expectSemi() // call before accessing p.linecomment
@ -1932,7 +2044,7 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
var values []ast.Expr var values []ast.Expr
if typ == nil || p.tok == token.ASSIGN { if typ == nil || p.tok == token.ASSIGN {
p.expect(token.ASSIGN) p.expect(token.ASSIGN)
values = p.parseExprList() values = p.parseRhsList()
} }
p.expectSemi() // call before accessing p.linecomment p.expectSemi() // call before accessing p.linecomment
@ -2120,20 +2232,20 @@ func (p *parser) parseFile() *ast.File {
} }
} }
if p.topScope != p.pkgScope { assert(p.topScope == p.pkgScope, "imbalanced scopes")
panic("internal error: imbalanced scopes")
}
// resolve global identifiers within the same file // resolve global identifiers within the same file
i := 0 i := 0
for _, ident := range p.unresolved { for _, ident := range p.unresolved {
// i <= index for current ident // i <= index for current ident
ident.Obj = p.pkgScope.Lookup(ident.Name) assert(ident.Obj == unresolved, "object already resolved")
ident.Obj = p.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel
if ident.Obj == nil { if ident.Obj == nil {
p.unresolved[i] = ident p.unresolved[i] = ident
i++ i++
} }
} }
// TODO(gri): store p.imports in AST
return &ast.File{doc, pos, ident, decls, p.pkgScope, p.unresolved[0:i], p.comments} return &ast.File{doc, pos, ident, decls, p.pkgScope, p.unresolved[0:i], p.comments}
} }