in resolve/resolve.go [629:797]
func (r *resolver) expr(e syntax.Expr) {
switch e := e.(type) {
case *syntax.Ident:
r.use(e)
case *syntax.Literal:
case *syntax.ListExpr:
for _, x := range e.List {
r.expr(x)
}
case *syntax.CondExpr:
r.expr(e.Cond)
r.expr(e.True)
r.expr(e.False)
case *syntax.IndexExpr:
r.expr(e.X)
r.expr(e.Y)
case *syntax.DictEntry:
r.expr(e.Key)
r.expr(e.Value)
case *syntax.SliceExpr:
r.expr(e.X)
if e.Lo != nil {
r.expr(e.Lo)
}
if e.Hi != nil {
r.expr(e.Hi)
}
if e.Step != nil {
r.expr(e.Step)
}
case *syntax.Comprehension:
// The 'in' operand of the first clause (always a ForClause)
// is resolved in the outer block; consider: [x for x in x].
clause := e.Clauses[0].(*syntax.ForClause)
r.expr(clause.X)
// A list/dict comprehension defines a new lexical block.
// Locals defined within the block will be allotted
// distinct slots in the locals array of the innermost
// enclosing container (function/module) block.
r.push(&block{comp: e})
const isAugmented = false
r.assign(clause.Vars, isAugmented)
for _, clause := range e.Clauses[1:] {
switch clause := clause.(type) {
case *syntax.IfClause:
r.expr(clause.Cond)
case *syntax.ForClause:
r.assign(clause.Vars, isAugmented)
r.expr(clause.X)
}
}
r.expr(e.Body) // body may be *DictEntry
r.pop()
case *syntax.TupleExpr:
for _, x := range e.List {
r.expr(x)
}
case *syntax.DictExpr:
for _, entry := range e.List {
entry := entry.(*syntax.DictEntry)
r.expr(entry.Key)
r.expr(entry.Value)
}
case *syntax.UnaryExpr:
r.expr(e.X)
case *syntax.BinaryExpr:
r.expr(e.X)
r.expr(e.Y)
case *syntax.DotExpr:
r.expr(e.X)
// ignore e.Name
case *syntax.CallExpr:
r.expr(e.Fn)
var seenVarargs, seenKwargs bool
var seenName map[string]bool
var n, p int
for _, arg := range e.Args {
pos, _ := arg.Span()
if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR {
// **kwargs
if seenKwargs {
r.errorf(pos, "multiple **kwargs not allowed")
}
seenKwargs = true
r.expr(arg)
} else if ok && unop.Op == syntax.STAR {
// *args
if seenKwargs {
r.errorf(pos, "*args may not follow **kwargs")
} else if seenVarargs {
r.errorf(pos, "multiple *args not allowed")
}
seenVarargs = true
r.expr(arg)
} else if binop, ok := arg.(*syntax.BinaryExpr); ok && binop.Op == syntax.EQ {
// k=v
n++
if seenKwargs {
r.errorf(pos, "keyword argument may not follow **kwargs")
} else if seenVarargs {
r.errorf(pos, "keyword argument may not follow *args")
}
x := binop.X.(*syntax.Ident)
if seenName[x.Name] {
r.errorf(x.NamePos, "keyword argument %s repeated", x.Name)
} else {
if seenName == nil {
seenName = make(map[string]bool)
}
seenName[x.Name] = true
}
r.expr(binop.Y)
} else {
// positional argument
p++
if seenVarargs {
r.errorf(pos, "positional argument may not follow *args")
} else if seenKwargs {
r.errorf(pos, "positional argument may not follow **kwargs")
} else if len(seenName) > 0 {
r.errorf(pos, "positional argument may not follow named")
}
r.expr(arg)
}
}
// Fail gracefully if compiler-imposed limit is exceeded.
if p >= 256 {
pos, _ := e.Span()
r.errorf(pos, "%v positional arguments in call, limit is 255", p)
}
if n >= 256 {
pos, _ := e.Span()
r.errorf(pos, "%v keyword arguments in call, limit is 255", n)
}
case *syntax.LambdaExpr:
fn := &Function{
Name: "lambda",
Pos: e.Lambda,
Params: e.Params,
Body: []syntax.Stmt{&syntax.ReturnStmt{Result: e.Body}},
}
e.Function = fn
r.function(fn, e.Lambda)
case *syntax.ParenExpr:
r.expr(e.X)
default:
log.Panicf("unexpected expr %T", e)
}
}