in resolve/resolve.go [485:585]
func (r *resolver) stmt(stmt syntax.Stmt) {
switch stmt := stmt.(type) {
case *syntax.ExprStmt:
r.expr(stmt.X)
case *syntax.BranchStmt:
if r.loops == 0 && (stmt.Token == syntax.BREAK || stmt.Token == syntax.CONTINUE) {
r.errorf(stmt.TokenPos, "%s not in a loop", stmt.Token)
}
case *syntax.IfStmt:
if !AllowGlobalReassign && r.container().function == nil {
r.errorf(stmt.If, "if statement not within a function")
}
r.expr(stmt.Cond)
r.ifstmts++
r.stmts(stmt.True)
r.stmts(stmt.False)
r.ifstmts--
case *syntax.AssignStmt:
r.expr(stmt.RHS)
isAugmented := stmt.Op != syntax.EQ
r.assign(stmt.LHS, isAugmented)
case *syntax.DefStmt:
r.bind(stmt.Name)
fn := &Function{
Name: stmt.Name.Name,
Pos: stmt.Def,
Params: stmt.Params,
Body: stmt.Body,
}
stmt.Function = fn
r.function(fn, stmt.Def)
case *syntax.ForStmt:
if !AllowGlobalReassign && r.container().function == nil {
r.errorf(stmt.For, "for loop not within a function")
}
r.expr(stmt.X)
const isAugmented = false
r.assign(stmt.Vars, isAugmented)
r.loops++
r.stmts(stmt.Body)
r.loops--
case *syntax.WhileStmt:
if !AllowRecursion {
r.errorf(stmt.While, doesnt+"support while loops")
}
if !AllowGlobalReassign && r.container().function == nil {
r.errorf(stmt.While, "while loop not within a function")
}
r.expr(stmt.Cond)
r.loops++
r.stmts(stmt.Body)
r.loops--
case *syntax.ReturnStmt:
if r.container().function == nil {
r.errorf(stmt.Return, "return statement not within a function")
}
if stmt.Result != nil {
r.expr(stmt.Result)
}
case *syntax.LoadStmt:
// A load statement may not be nested in any other statement.
if r.container().function != nil {
r.errorf(stmt.Load, "load statement within a function")
} else if r.loops > 0 {
r.errorf(stmt.Load, "load statement within a loop")
} else if r.ifstmts > 0 {
r.errorf(stmt.Load, "load statement within a conditional")
}
for i, from := range stmt.From {
if from.Name == "" {
r.errorf(from.NamePos, "load: empty identifier")
continue
}
if from.Name[0] == '_' {
r.errorf(from.NamePos, "load: names with leading underscores are not exported: %s", from.Name)
}
id := stmt.To[i]
if LoadBindsGlobally {
r.bind(id)
} else if r.bindLocal(id) && !AllowGlobalReassign {
// "Global" in AllowGlobalReassign is a misnomer for "toplevel".
// Sadly we can't report the previous declaration
// as id.Binding may not be set yet.
r.errorf(id.NamePos, "cannot reassign top-level %s", id.Name)
}
}
default:
log.Panicf("unexpected stmt %T", stmt)
}
}