summaryrefslogtreecommitdiff
path: root/src/pkg/exp/eval/stmt.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exp/eval/stmt.go')
-rw-r--r--src/pkg/exp/eval/stmt.go618
1 files changed, 309 insertions, 309 deletions
diff --git a/src/pkg/exp/eval/stmt.go b/src/pkg/exp/eval/stmt.go
index 60c6b9ee6..53757f7de 100644
--- a/src/pkg/exp/eval/stmt.go
+++ b/src/pkg/exp/eval/stmt.go
@@ -5,15 +5,15 @@
package eval
import (
- "bignum";
- "log";
- "go/ast";
- "go/token";
+ "bignum"
+ "log"
+ "go/ast"
+ "go/token"
)
const (
- returnPC = ^uint(0);
- badPC = ^uint(1);
+ returnPC = ^uint(0)
+ badPC = ^uint(1)
)
/*
@@ -21,10 +21,10 @@ const (
*/
type stmtCompiler struct {
- *blockCompiler;
- pos token.Position;
+ *blockCompiler
+ pos token.Position
// This statement's label, or nil if it is not labeled.
- stmtLabel *label;
+ stmtLabel *label
}
func (a *stmtCompiler) diag(format string, args ...) {
@@ -38,39 +38,39 @@ func (a *stmtCompiler) diag(format string, args ...) {
type flowEnt struct {
// Whether this flow entry is conditional. If true, flow can
// continue to the next PC.
- cond bool;
+ cond bool
// True if this will terminate flow (e.g., a return statement).
// cond must be false and jumps must be nil if this is true.
- term bool;
+ term bool
// PC's that can be reached from this flow entry.
- jumps []*uint;
+ jumps []*uint
// Whether this flow entry has been visited by reachesEnd.
- visited bool;
+ visited bool
}
type flowBlock struct {
// If this is a goto, the target label.
- target string;
+ target string
// The inner-most block containing definitions.
- block *block;
+ block *block
// The numVars from each block leading to the root of the
// scope, starting at block.
- numVars []int;
+ numVars []int
}
type flowBuf struct {
- cb *codeBuf;
+ cb *codeBuf
// ents is a map from PC's to flow entries. Any PC missing
// from this map is assumed to reach only PC+1.
- ents map[uint]*flowEnt;
+ ents map[uint]*flowEnt
// gotos is a map from goto positions to information on the
// block at the point of the goto.
- gotos map[*token.Position]*flowBlock;
+ gotos map[*token.Position]*flowBlock
// labels is a map from label name to information on the block
// at the point of the label. labels are tracked by name,
// since mutliple labels at the same PC can have different
// blocks.
- labels map[string]*flowBlock;
+ labels map[string]*flowBlock
}
func newFlowBuf(cb *codeBuf) *flowBuf {
@@ -80,16 +80,16 @@ func newFlowBuf(cb *codeBuf) *flowBuf {
// put creates a flow control point for the next PC in the code buffer.
// This should be done before pushing the instruction into the code buffer.
func (f *flowBuf) put(cond bool, term bool, jumps []*uint) {
- pc := f.cb.nextPC();
+ pc := f.cb.nextPC()
if ent, ok := f.ents[pc]; ok {
log.Crashf("Flow entry already exists at PC %d: %+v", pc, ent)
}
- f.ents[pc] = &flowEnt{cond, term, jumps, false};
+ f.ents[pc] = &flowEnt{cond, term, jumps, false}
}
// putTerm creates a flow control point at the next PC that
// unconditionally terminates execution.
-func (f *flowBuf) putTerm() { f.put(false, true, nil) }
+func (f *flowBuf) putTerm() { f.put(false, true, nil) }
// put1 creates a flow control point at the next PC that jumps to one
// PC and, if cond is true, can also continue to the PC following the
@@ -105,20 +105,20 @@ func newFlowBlock(target string, b *block) *flowBlock {
}
// Count parents leading to the root of the scope
- n := 0;
+ n := 0
for bp := b; bp.scope == b.scope; bp = bp.outer {
n++
}
// Capture numVars from each block to the root of the scope
- numVars := make([]int, n);
- i := 0;
+ numVars := make([]int, n)
+ i := 0
for bp := b; i < n; bp = bp.outer {
- numVars[i] = bp.numVars;
- i++;
+ numVars[i] = bp.numVars
+ i++
}
- return &flowBlock{target, b, numVars};
+ return &flowBlock{target, b, numVars}
}
// putGoto captures the block at a goto statement. This should be
@@ -136,13 +136,13 @@ func (f *flowBuf) putLabel(name string, b *block) {
// reached from the given program counter. Error reporting is the
// caller's responsibility.
func (f *flowBuf) reachesEnd(pc uint) bool {
- endPC := f.cb.nextPC();
+ endPC := f.cb.nextPC()
if pc > endPC {
log.Crashf("Reached bad PC %d past end PC %d", pc, endPC)
}
for ; pc < endPC; pc++ {
- ent, ok := f.ents[pc];
+ ent, ok := f.ents[pc]
if !ok {
continue
}
@@ -150,7 +150,7 @@ func (f *flowBuf) reachesEnd(pc uint) bool {
if ent.visited {
return false
}
- ent.visited = true;
+ ent.visited = true
if ent.term {
return false
@@ -168,9 +168,9 @@ func (f *flowBuf) reachesEnd(pc uint) bool {
if ent.cond {
continue
}
- return false;
+ return false
}
- return true;
+ return true
}
// gotosObeyScopes returns true if no goto statement causes any
@@ -178,28 +178,28 @@ func (f *flowBuf) reachesEnd(pc uint) bool {
// the goto. Reports any errors using the given compiler.
func (f *flowBuf) gotosObeyScopes(a *compiler) {
for pos, src := range f.gotos {
- tgt := f.labels[src.target];
+ tgt := f.labels[src.target]
// The target block must be a parent of this block
- numVars := src.numVars;
- b := src.block;
+ numVars := src.numVars
+ b := src.block
for len(numVars) > 0 && b != tgt.block {
- b = b.outer;
- numVars = numVars[1:];
+ b = b.outer
+ numVars = numVars[1:]
}
if b != tgt.block {
// We jumped into a deeper block
- a.diagAt(pos, "goto causes variables to come into scope");
- return;
+ a.diagAt(pos, "goto causes variables to come into scope")
+ return
}
// There must be no variables in the target block that
// did not exist at the jump
- tgtNumVars := tgt.numVars;
+ tgtNumVars := tgt.numVars
for i := range numVars {
if tgtNumVars[i] > numVars[i] {
- a.diagAt(pos, "goto causes variables to come into scope");
- return;
+ a.diagAt(pos, "goto causes variables to come into scope")
+ return
}
}
}
@@ -210,25 +210,25 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) {
*/
func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
- v, prev := a.block.DefineVar(ident.Value, ident.Pos(), t);
+ v, prev := a.block.DefineVar(ident.Value, ident.Pos(), t)
if prev != nil {
// TODO(austin) It's silly that we have to capture
// Pos() in a variable.
- pos := prev.Pos();
+ pos := prev.Pos()
if pos.IsValid() {
a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Value, &pos)
} else {
a.diagAt(ident, "variable %s redeclared in this block", ident.Value)
}
- return nil;
+ return nil
}
// Initialize the variable
- index := v.Index;
+ index := v.Index
if v.Index >= 0 {
a.push(func(v *Thread) { v.f.Vars[index] = t.Zero() })
}
- return v;
+ return v
}
// TODO(austin) Move doAssign to here
@@ -242,7 +242,7 @@ func (a *stmtCompiler) compile(s ast.Stmt) {
log.Crash("Child scope still entered")
}
- notimpl := false;
+ notimpl := false
switch s := s.(type) {
case *ast.BadStmt:
// Error already reported by parser.
@@ -340,30 +340,30 @@ func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
default:
log.Crashf("Unexpected Decl type %T", s.Decl)
}
- a.compileDecl(s.Decl);
+ a.compileDecl(s.Decl)
}
func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) {
for _, spec := range decl.Specs {
- spec := spec.(*ast.ValueSpec);
+ spec := spec.(*ast.ValueSpec)
if spec.Values == nil {
// Declaration without assignment
if spec.Type == nil {
// Parser should have caught
log.Crash("Type and Values nil")
}
- t := a.compileType(a.block, spec.Type);
+ t := a.compileType(a.block, spec.Type)
// Define placeholders even if type compile failed
for _, n := range spec.Names {
a.defineVar(n, t)
}
} else {
// Declaration with assignment
- lhs := make([]ast.Expr, len(spec.Names));
+ lhs := make([]ast.Expr, len(spec.Names))
for i, n := range spec.Names {
lhs[i] = n
}
- a.doAssign(lhs, spec.Values, decl.Tok, spec.Type);
+ a.doAssign(lhs, spec.Values, decl.Tok, spec.Type)
}
}
}
@@ -375,27 +375,27 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) {
a.silentErrors++
case *ast.FuncDecl:
- decl := a.compileFuncType(a.block, d.Type);
+ decl := a.compileFuncType(a.block, d.Type)
if decl == nil {
return
}
// Declare and initialize v before compiling func
// so that body can refer to itself.
- c, prev := a.block.DefineConst(d.Name.Value, a.pos, decl.Type, decl.Type.Zero());
+ c, prev := a.block.DefineConst(d.Name.Value, a.pos, decl.Type, decl.Type.Zero())
if prev != nil {
- pos := prev.Pos();
+ pos := prev.Pos()
if pos.IsValid() {
a.diagAt(d.Name, "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Value, &pos)
} else {
a.diagAt(d.Name, "identifier %s redeclared in this block", d.Name.Value)
}
}
- fn := a.compileFunc(a.block, decl, d.Body);
+ fn := a.compileFunc(a.block, decl, d.Body)
if c == nil || fn == nil {
return
}
- var zeroThread Thread;
- c.Value.(FuncValue).Set(nil, fn(&zeroThread));
+ var zeroThread Thread
+ c.Value.(FuncValue).Set(nil, fn(&zeroThread))
case *ast.GenDecl:
switch d.Tok {
@@ -416,119 +416,119 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) {
func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
// Define label
- l, ok := a.labels[s.Label.Value];
+ l, ok := a.labels[s.Label.Value]
if ok {
if l.resolved.IsValid() {
a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Value, &l.resolved)
}
} else {
- pc := badPC;
- l = &label{name: s.Label.Value, gotoPC: &pc};
- a.labels[l.name] = l;
+ pc := badPC
+ l = &label{name: s.Label.Value, gotoPC: &pc}
+ a.labels[l.name] = l
}
- l.desc = "regular label";
- l.resolved = s.Pos();
+ l.desc = "regular label"
+ l.resolved = s.Pos()
// Set goto PC
- *l.gotoPC = a.nextPC();
+ *l.gotoPC = a.nextPC()
// Define flow entry so we can check for jumps over declarations.
- a.flow.putLabel(l.name, a.block);
+ a.flow.putLabel(l.name, a.block)
// Compile the statement. Reuse our stmtCompiler for simplicity.
- sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l};
- sc.compile(s.Stmt);
+ sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l}
+ sc.compile(s.Stmt)
}
func (a *stmtCompiler) compileExprStmt(s *ast.ExprStmt) {
- bc := a.enterChild();
- defer bc.exit();
+ bc := a.enterChild()
+ defer bc.exit()
- e := a.compileExpr(bc.block, false, s.X);
+ e := a.compileExpr(bc.block, false, s.X)
if e == nil {
return
}
if e.exec == nil {
- a.diag("%s cannot be used as expression statement", e.desc);
- return;
+ a.diag("%s cannot be used as expression statement", e.desc)
+ return
}
- a.push(e.exec);
+ a.push(e.exec)
}
func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
// Create temporary block for extractEffect
- bc := a.enterChild();
- defer bc.exit();
+ bc := a.enterChild()
+ defer bc.exit()
- l := a.compileExpr(bc.block, false, s.X);
+ l := a.compileExpr(bc.block, false, s.X)
if l == nil {
return
}
if l.evalAddr == nil {
- l.diag("cannot assign to %s", l.desc);
- return;
+ l.diag("cannot assign to %s", l.desc)
+ return
}
if !(l.t.isInteger() || l.t.isFloat()) {
- l.diagOpType(s.Tok, l.t);
- return;
+ l.diagOpType(s.Tok, l.t)
+ return
}
- var op token.Token;
- var desc string;
+ var op token.Token
+ var desc string
switch s.Tok {
case token.INC:
- op = token.ADD;
- desc = "increment statement";
+ op = token.ADD
+ desc = "increment statement"
case token.DEC:
- op = token.SUB;
- desc = "decrement statement";
+ op = token.SUB
+ desc = "decrement statement"
default:
log.Crashf("Unexpected IncDec token %v", s.Tok)
}
- effect, l := l.extractEffect(bc.block, desc);
+ effect, l := l.extractEffect(bc.block, desc)
- one := l.newExpr(IdealIntType, "constant");
- one.pos = s.Pos();
- one.eval = func() *bignum.Integer { return bignum.Int(1) };
+ one := l.newExpr(IdealIntType, "constant")
+ one.pos = s.Pos()
+ one.eval = func() *bignum.Integer { return bignum.Int(1) }
- binop := l.compileBinaryExpr(op, l, one);
+ binop := l.compileBinaryExpr(op, l, one)
if binop == nil {
return
}
- assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "");
+ assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "")
if assign == nil {
log.Crashf("compileAssign type check failed")
}
- lf := l.evalAddr;
+ lf := l.evalAddr
a.push(func(v *Thread) {
- effect(v);
- assign(lf(v), v);
- });
+ effect(v)
+ assign(lf(v), v)
+ })
}
func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
- nerr := a.numError();
+ nerr := a.numError()
// Compile right side first so we have the types when
// compiling the left side and so we don't see definitions
// made on the left side.
- rs := make([]*expr, len(rhs));
+ rs := make([]*expr, len(rhs))
for i, re := range rhs {
rs[i] = a.compileExpr(a.block, false, re)
}
- errOp := "assignment";
+ errOp := "assignment"
if tok == token.DEFINE || tok == token.VAR {
errOp = "declaration"
}
- ac, ok := a.checkAssign(a.pos, rs, errOp, "value");
- ac.allowMapForms(len(lhs));
+ ac, ok := a.checkAssign(a.pos, rs, errOp, "value")
+ ac.allowMapForms(len(lhs))
// If this is a definition and the LHS is too big, we won't be
// able to produce the usual error message because we can't
@@ -538,35 +538,35 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
}
// Compile left type if there is one
- var declType Type;
+ var declType Type
if declTypeExpr != nil {
declType = a.compileType(a.block, declTypeExpr)
}
// Compile left side
- ls := make([]*expr, len(lhs));
- nDefs := 0;
+ ls := make([]*expr, len(lhs))
+ nDefs := 0
for i, le := range lhs {
// If this is a definition, get the identifier and its type
- var ident *ast.Ident;
- var lt Type;
+ var ident *ast.Ident
+ var lt Type
switch tok {
case token.DEFINE:
// Check that it's an identifier
- ident, ok = le.(*ast.Ident);
+ ident, ok = le.(*ast.Ident)
if !ok {
- a.diagAt(le, "left side of := must be a name");
+ a.diagAt(le, "left side of := must be a name")
// Suppress new defitions errors
- nDefs++;
- continue;
+ nDefs++
+ continue
}
// Is this simply an assignment?
if _, ok := a.block.defs[ident.Value]; ok {
- ident = nil;
- break;
+ ident = nil
+ break
}
- nDefs++;
+ nDefs++
case token.VAR:
ident = le.(*ast.Ident)
@@ -623,7 +623,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
}
// Compile LHS
- ls[i] = a.compileExpr(a.block, false, le);
+ ls[i] = a.compileExpr(a.block, false, le)
if ls[i] == nil {
continue
}
@@ -635,23 +635,23 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
// TODO(austin) Now that the expression
// compiler uses semantic values, this might
// be easier to implement as a function call.
- sub := ls[i];
- ls[i] = ls[i].newExpr(sub.t, sub.desc);
- ls[i].evalMapValue = sub.evalMapValue;
- mvf := sub.evalMapValue;
- et := sub.t;
+ sub := ls[i]
+ ls[i] = ls[i].newExpr(sub.t, sub.desc)
+ ls[i].evalMapValue = sub.evalMapValue
+ mvf := sub.evalMapValue
+ et := sub.t
ls[i].evalAddr = func(t *Thread) Value {
- m, k := mvf(t);
- e := m.Elem(t, k);
+ m, k := mvf(t)
+ e := m.Elem(t, k)
if e == nil {
- e = et.Zero();
- m.SetElem(t, k, e);
+ e = et.Zero()
+ m.SetElem(t, k, e)
}
- return e;
- };
+ return e
+ }
} else if ls[i].evalAddr == nil {
- ls[i].diag("cannot assign to %s", ls[i].desc);
- continue;
+ ls[i].diag("cannot assign to %s", ls[i].desc)
+ continue
}
}
@@ -660,8 +660,8 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
// with the same type, and at least one of the variables is
// new.
if tok == token.DEFINE && nDefs == 0 {
- a.diag("at least one new variable must be declared");
- return;
+ a.diag("at least one new variable must be declared")
+ return
}
// If there have been errors, our arrays are full of nil's so
@@ -672,27 +672,27 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
// Check for 'a[x] = r, ok'
if len(ls) == 1 && len(rs) == 2 && ls[0].evalMapValue != nil {
- a.diag("a[x] = r, ok form not implemented");
- return;
+ a.diag("a[x] = r, ok form not implemented")
+ return
}
// Create assigner
- var lt Type;
- n := len(lhs);
+ var lt Type
+ n := len(lhs)
if n == 1 {
lt = ls[0].t
} else {
- lts := make([]Type, len(ls));
+ lts := make([]Type, len(ls))
for i, l := range ls {
if l != nil {
lts[i] = l.t
}
}
- lt = NewMultiType(lts);
+ lt = NewMultiType(lts)
}
- bc := a.enterChild();
- defer bc.exit();
- assign := ac.compile(bc.block, lt);
+ bc := a.enterChild()
+ defer bc.exit()
+ assign := ac.compile(bc.block, lt)
if assign == nil {
return
}
@@ -700,38 +700,38 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
// Compile
if n == 1 {
// Don't need temporaries and can avoid []Value.
- lf := ls[0].evalAddr;
- a.push(func(t *Thread) { assign(lf(t), t) });
+ lf := ls[0].evalAddr
+ a.push(func(t *Thread) { assign(lf(t), t) })
} else if tok == token.VAR || (tok == token.DEFINE && nDefs == n) {
// Don't need temporaries
- lfs := make([]func(*Thread) Value, n);
+ lfs := make([]func(*Thread) Value, n)
for i, l := range ls {
lfs[i] = l.evalAddr
}
a.push(func(t *Thread) {
- dest := make([]Value, n);
+ dest := make([]Value, n)
for i, lf := range lfs {
dest[i] = lf(t)
}
- assign(multiV(dest), t);
- });
+ assign(multiV(dest), t)
+ })
} else {
// Need temporaries
- lmt := lt.(*MultiType);
- lfs := make([]func(*Thread) Value, n);
+ lmt := lt.(*MultiType)
+ lfs := make([]func(*Thread) Value, n)
for i, l := range ls {
lfs[i] = l.evalAddr
}
a.push(func(t *Thread) {
- temp := lmt.Zero().(multiV);
- assign(temp, t);
+ temp := lmt.Zero().(multiV)
+ assign(temp, t)
// Copy to destination
for i := 0; i < n; i++ {
// TODO(austin) Need to evaluate LHS
// before RHS
lfs[i](t).Assign(t, temp[i])
}
- });
+ })
}
}
@@ -752,42 +752,42 @@ var assignOpToOp = map[token.Token]token.Token{
func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
- a.diag("tuple assignment cannot be combined with an arithmetic operation");
- return;
+ a.diag("tuple assignment cannot be combined with an arithmetic operation")
+ return
}
// Create temporary block for extractEffect
- bc := a.enterChild();
- defer bc.exit();
+ bc := a.enterChild()
+ defer bc.exit()
- l := a.compileExpr(bc.block, false, s.Lhs[0]);
- r := a.compileExpr(bc.block, false, s.Rhs[0]);
+ l := a.compileExpr(bc.block, false, s.Lhs[0])
+ r := a.compileExpr(bc.block, false, s.Rhs[0])
if l == nil || r == nil {
return
}
if l.evalAddr == nil {
- l.diag("cannot assign to %s", l.desc);
- return;
+ l.diag("cannot assign to %s", l.desc)
+ return
}
- effect, l := l.extractEffect(bc.block, "operator-assignment");
+ effect, l := l.extractEffect(bc.block, "operator-assignment")
- binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r);
+ binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r)
if binop == nil {
return
}
- assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value");
+ assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value")
if assign == nil {
log.Crashf("compileAssign type check failed")
}
- lf := l.evalAddr;
+ lf := l.evalAddr
a.push(func(t *Thread) {
- effect(t);
- assign(lf(t), t);
- });
+ effect(t)
+ assign(lf(t), t)
+ })
}
func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) {
@@ -802,25 +802,25 @@ func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) {
func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) {
if a.fnType == nil {
- a.diag("cannot return at the top level");
- return;
+ a.diag("cannot return at the top level")
+ return
}
if len(s.Results) == 0 && (len(a.fnType.Out) == 0 || a.outVarsNamed) {
// Simple case. Simply exit from the function.
- a.flow.putTerm();
- a.push(func(v *Thread) { v.pc = returnPC });
- return;
+ a.flow.putTerm()
+ a.push(func(v *Thread) { v.pc = returnPC })
+ return
}
- bc := a.enterChild();
- defer bc.exit();
+ bc := a.enterChild()
+ defer bc.exit()
// Compile expressions
- bad := false;
- rs := make([]*expr, len(s.Results));
+ bad := false
+ rs := make([]*expr, len(s.Results))
for i, re := range s.Results {
- rs[i] = a.compileExpr(bc.block, false, re);
+ rs[i] = a.compileExpr(bc.block, false, re)
if rs[i] == nil {
bad = true
}
@@ -835,38 +835,38 @@ func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) {
// is a single call to a multi-valued function, the values
// returned from the called function will be returned from
// this one.
- assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value");
+ assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value")
// XXX(Spec) "The result types of the current function and the
// called function must match." Match is fuzzy. It should
// say that they must be assignment compatible.
// Compile
- start := len(a.fnType.In);
- nout := len(a.fnType.Out);
- a.flow.putTerm();
+ start := len(a.fnType.In)
+ nout := len(a.fnType.Out)
+ a.flow.putTerm()
a.push(func(t *Thread) {
- assign(multiV(t.f.Vars[start:start+nout]), t);
- t.pc = returnPC;
- });
+ assign(multiV(t.f.Vars[start:start+nout]), t)
+ t.pc = returnPC
+ })
}
func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label {
- bc := a.blockCompiler;
+ bc := a.blockCompiler
for ; bc != nil; bc = bc.parent {
if bc.label == nil {
continue
}
- l := bc.label;
+ l := bc.label
if name == nil && pred(l) {
return l
}
if name != nil && l.name == name.Value {
if !pred(l) {
- a.diag("cannot %s to %s %s", errOp, l.desc, l.name);
- return nil;
+ a.diag("cannot %s to %s %s", errOp, l.desc, l.name)
+ return nil
}
- return l;
+ return l
}
}
if name == nil {
@@ -874,54 +874,54 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool,
} else {
a.diag("%s label %s not defined", errOp, name.Value)
}
- return nil;
+ return nil
}
func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
- var pc *uint;
+ var pc *uint
switch s.Tok {
case token.BREAK:
- l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select");
+ l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select")
if l == nil {
return
}
- pc = l.breakPC;
+ pc = l.breakPC
case token.CONTINUE:
- l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop");
+ l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop")
if l == nil {
return
}
- pc = l.continuePC;
+ pc = l.continuePC
case token.GOTO:
- l, ok := a.labels[s.Label.Value];
+ l, ok := a.labels[s.Label.Value]
if !ok {
- pc := badPC;
- l = &label{name: s.Label.Value, desc: "unresolved label", gotoPC: &pc, used: s.Pos()};
- a.labels[l.name] = l;
+ pc := badPC
+ l = &label{name: s.Label.Value, desc: "unresolved label", gotoPC: &pc, used: s.Pos()}
+ a.labels[l.name] = l
}
- pc = l.gotoPC;
- a.flow.putGoto(s.Pos(), l.name, a.block);
+ pc = l.gotoPC
+ a.flow.putGoto(s.Pos(), l.name, a.block)
case token.FALLTHROUGH:
- a.diag("fallthrough outside switch");
- return;
+ a.diag("fallthrough outside switch")
+ return
default:
log.Crash("Unexpected branch token %v", s.Tok)
}
- a.flow.put1(false, pc);
- a.push(func(v *Thread) { v.pc = *pc });
+ a.flow.put1(false, pc)
+ a.push(func(v *Thread) { v.pc = *pc })
}
func (a *stmtCompiler) compileBlockStmt(s *ast.BlockStmt) {
- bc := a.enterChild();
- bc.compileStmts(s);
- bc.exit();
+ bc := a.enterChild()
+ bc.compileStmts(s)
+ bc.exit()
}
func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) {
@@ -935,59 +935,59 @@ func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) {
// says when there's a non-block else clause, because that
// else claus has to execute in a scope that is *not* the
// surrounding scope.
- bc := a.enterChild();
- defer bc.exit();
+ bc := a.enterChild()
+ defer bc.exit()
// Compile init statement, if any
if s.Init != nil {
bc.compileStmt(s.Init)
}
- elsePC := badPC;
- endPC := badPC;
+ elsePC := badPC
+ endPC := badPC
// Compile condition, if any. If there is no condition, we
// fall through to the body.
if s.Cond != nil {
- e := bc.compileExpr(bc.block, false, s.Cond);
+ e := bc.compileExpr(bc.block, false, s.Cond)
switch {
case e == nil:
// Error reported by compileExpr
case !e.t.isBoolean():
e.diag("'if' condition must be boolean\n\t%v", e.t)
default:
- eval := e.asBool();
- a.flow.put1(true, &elsePC);
+ eval := e.asBool()
+ a.flow.put1(true, &elsePC)
a.push(func(t *Thread) {
if !eval(t) {
t.pc = elsePC
}
- });
+ })
}
}
// Compile body
- body := bc.enterChild();
- body.compileStmts(s.Body);
- body.exit();
+ body := bc.enterChild()
+ body.compileStmts(s.Body)
+ body.exit()
// Compile else
if s.Else != nil {
// Skip over else if we executed the body
- a.flow.put1(false, &endPC);
- a.push(func(v *Thread) { v.pc = endPC });
- elsePC = a.nextPC();
- bc.compileStmt(s.Else);
+ a.flow.put1(false, &endPC)
+ a.push(func(v *Thread) { v.pc = endPC })
+ elsePC = a.nextPC()
+ bc.compileStmt(s.Else)
} else {
elsePC = a.nextPC()
}
- endPC = a.nextPC();
+ endPC = a.nextPC()
}
func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
// Create implicit scope around switch
- bc := a.enterChild();
- defer bc.exit();
+ bc := a.enterChild()
+ defer bc.exit()
// Compile init statement, if any
if s.Init != nil {
@@ -995,46 +995,46 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
}
// Compile condition, if any, and extract its effects
- var cond *expr;
- condbc := bc.enterChild();
+ var cond *expr
+ condbc := bc.enterChild()
if s.Tag != nil {
- e := condbc.compileExpr(condbc.block, false, s.Tag);
+ e := condbc.compileExpr(condbc.block, false, s.Tag)
if e != nil {
- var effect func(*Thread);
- effect, cond = e.extractEffect(condbc.block, "switch");
- a.push(effect);
+ var effect func(*Thread)
+ effect, cond = e.extractEffect(condbc.block, "switch")
+ a.push(effect)
}
}
// Count cases
- ncases := 0;
- hasDefault := false;
+ ncases := 0
+ hasDefault := false
for _, c := range s.Body.List {
- clause, ok := c.(*ast.CaseClause);
+ clause, ok := c.(*ast.CaseClause)
if !ok {
- a.diagAt(clause, "switch statement must contain case clauses");
- continue;
+ a.diagAt(clause, "switch statement must contain case clauses")
+ continue
}
if clause.Values == nil {
if hasDefault {
a.diagAt(clause, "switch statement contains more than one default case")
}
- hasDefault = true;
+ hasDefault = true
} else {
ncases += len(clause.Values)
}
}
// Compile case expressions
- cases := make([]func(*Thread) bool, ncases);
- i := 0;
+ cases := make([]func(*Thread) bool, ncases)
+ i := 0
for _, c := range s.Body.List {
- clause, ok := c.(*ast.CaseClause);
+ clause, ok := c.(*ast.CaseClause)
if !ok {
continue
}
for _, v := range clause.Values {
- e := condbc.compileExpr(condbc.block, false, v);
+ e := condbc.compileExpr(condbc.block, false, v)
switch {
case e == nil:
// Error reported by compileExpr
@@ -1045,45 +1045,45 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
case cond != nil:
// Create comparison
// TOOD(austin) This produces bad error messages
- compare := e.compileBinaryExpr(token.EQL, cond, e);
+ compare := e.compileBinaryExpr(token.EQL, cond, e)
if compare != nil {
cases[i] = compare.asBool()
}
}
- i++;
+ i++
}
}
// Emit condition
- casePCs := make([]*uint, ncases+1);
- endPC := badPC;
+ casePCs := make([]*uint, ncases+1)
+ endPC := badPC
- a.flow.put(false, false, casePCs);
+ a.flow.put(false, false, casePCs)
a.push(func(t *Thread) {
for i, c := range cases {
if c(t) {
- t.pc = *casePCs[i];
- return;
+ t.pc = *casePCs[i]
+ return
}
}
- t.pc = *casePCs[ncases];
- });
- condbc.exit();
+ t.pc = *casePCs[ncases]
+ })
+ condbc.exit()
// Compile cases
- i = 0;
+ i = 0
for _, c := range s.Body.List {
- clause, ok := c.(*ast.CaseClause);
+ clause, ok := c.(*ast.CaseClause)
if !ok {
continue
}
// Save jump PC's
- pc := a.nextPC();
+ pc := a.nextPC()
if clause.Values != nil {
for _ = range clause.Values {
- casePCs[i] = &pc;
- i++;
+ casePCs[i] = &pc
+ i++
}
} else {
// Default clause
@@ -1091,7 +1091,7 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
}
// Compile body
- fall := false;
+ fall := false
for j, s := range clause.Body {
if br, ok := s.(*ast.BranchStmt); ok && br.Tok == token.FALLTHROUGH {
// println("Found fallthrough");
@@ -1104,24 +1104,24 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
// empty blocks to be empty
// statements.
if _, ok := s2.(*ast.EmptyStmt); !ok {
- a.diagAt(s, "fallthrough statement must be final statement in case");
- break;
+ a.diagAt(s, "fallthrough statement must be final statement in case")
+ break
}
}
- fall = true;
+ fall = true
} else {
bc.compileStmt(s)
}
}
// Jump out of switch, unless there was a fallthrough
if !fall {
- a.flow.put1(false, &endPC);
- a.push(func(v *Thread) { v.pc = endPC });
+ a.flow.put1(false, &endPC)
+ a.push(func(v *Thread) { v.pc = endPC })
}
}
// Get end PC
- endPC = a.nextPC();
+ endPC = a.nextPC()
if !hasDefault {
casePCs[ncases] = &endPC
}
@@ -1129,40 +1129,40 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
// Wrap the entire for in a block.
- bc := a.enterChild();
- defer bc.exit();
+ bc := a.enterChild()
+ defer bc.exit()
// Compile init statement, if any
if s.Init != nil {
bc.compileStmt(s.Init)
}
- bodyPC := badPC;
- postPC := badPC;
- checkPC := badPC;
- endPC := badPC;
+ bodyPC := badPC
+ postPC := badPC
+ checkPC := badPC
+ endPC := badPC
// Jump to condition check. We generate slightly less code by
// placing the condition check after the body.
- a.flow.put1(false, &checkPC);
- a.push(func(v *Thread) { v.pc = checkPC });
+ a.flow.put1(false, &checkPC)
+ a.push(func(v *Thread) { v.pc = checkPC })
// Compile body
- bodyPC = a.nextPC();
- body := bc.enterChild();
+ bodyPC = a.nextPC()
+ body := bc.enterChild()
if a.stmtLabel != nil {
body.label = a.stmtLabel
} else {
body.label = &label{resolved: s.Pos()}
}
- body.label.desc = "for loop";
- body.label.breakPC = &endPC;
- body.label.continuePC = &postPC;
- body.compileStmts(s.Body);
- body.exit();
+ body.label.desc = "for loop"
+ body.label.breakPC = &endPC
+ body.label.continuePC = &postPC
+ body.compileStmts(s.Body)
+ body.exit()
// Compile post, if any
- postPC = a.nextPC();
+ postPC = a.nextPC()
if s.Post != nil {
// TODO(austin) Does the parser disallow short
// declarations in s.Post?
@@ -1170,30 +1170,30 @@ func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
}
// Compile condition check, if any
- checkPC = a.nextPC();
+ checkPC = a.nextPC()
if s.Cond == nil {
// If the condition is absent, it is equivalent to true.
- a.flow.put1(false, &bodyPC);
- a.push(func(v *Thread) { v.pc = bodyPC });
+ a.flow.put1(false, &bodyPC)
+ a.push(func(v *Thread) { v.pc = bodyPC })
} else {
- e := bc.compileExpr(bc.block, false, s.Cond);
+ e := bc.compileExpr(bc.block, false, s.Cond)
switch {
case e == nil:
// Error reported by compileExpr
case !e.t.isBoolean():
a.diag("'for' condition must be boolean\n\t%v", e.t)
default:
- eval := e.asBool();
- a.flow.put1(true, &bodyPC);
+ eval := e.asBool()
+ a.flow.put1(true, &bodyPC)
a.push(func(t *Thread) {
if eval(t) {
t.pc = bodyPC
}
- });
+ })
}
}
- endPC = a.nextPC();
+ endPC = a.nextPC()
}
/*
@@ -1201,8 +1201,8 @@ func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
*/
func (a *blockCompiler) compileStmt(s ast.Stmt) {
- sc := &stmtCompiler{a, s.Pos(), nil};
- sc.compile(s);
+ sc := &stmtCompiler{a, s.Pos(), nil}
+ sc.compile(s)
}
func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
@@ -1212,15 +1212,15 @@ func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
}
func (a *blockCompiler) enterChild() *blockCompiler {
- block := a.block.enterChild();
+ block := a.block.enterChild()
return &blockCompiler{
funcCompiler: a.funcCompiler,
block: block,
parent: a,
- };
+ }
}
-func (a *blockCompiler) exit() { a.block.exit() }
+func (a *blockCompiler) exit() { a.block.exit() }
/*
* Function compiler
@@ -1231,8 +1231,8 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
//
// The scope of a parameter or result is the body of the
// corresponding function.
- bodyScope := b.ChildScope();
- defer bodyScope.exit();
+ bodyScope := b.ChildScope()
+ defer bodyScope.exit()
for i, t := range decl.Type.In {
if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, decl.InNames[i].Pos(), t)
@@ -1249,7 +1249,7 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
}
// Create block context
- cb := newCodeBuf();
+ cb := newCodeBuf()
fc := &funcCompiler{
compiler: a,
fnType: decl.Type,
@@ -1257,16 +1257,16 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
codeBuf: cb,
flow: newFlowBuf(cb),
labels: make(map[string]*label),
- };
+ }
bc := &blockCompiler{
funcCompiler: fc,
block: bodyScope.block,
- };
+ }
// Compile body
- nerr := a.numError();
- bc.compileStmts(body);
- fc.checkLabels();
+ nerr := a.numError()
+ bc.compileStmts(body)
+ fc.checkLabels()
if nerr != a.numError() {
return nil
}
@@ -1275,19 +1275,19 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
// this if there were no errors compiling the body.
if len(decl.Type.Out) > 0 && fc.flow.reachesEnd(0) {
// XXX(Spec) Not specified.
- a.diagAt(&body.Rbrace, "function ends without a return statement");
- return nil;
+ a.diagAt(&body.Rbrace, "function ends without a return statement")
+ return nil
}
- code := fc.get();
- maxVars := bodyScope.maxVars;
- return func(t *Thread) Func { return &evalFunc{t.f, maxVars, code} };
+ code := fc.get()
+ maxVars := bodyScope.maxVars
+ return func(t *Thread) Func { return &evalFunc{t.f, maxVars, code} }
}
// Checks that labels were resolved and that all jumps obey scoping
// rules. Reports an error and set fc.err if any check fails.
func (a *funcCompiler) checkLabels() {
- nerr := a.numError();
+ nerr := a.numError()
for _, l := range a.labels {
if !l.resolved.IsValid() {
a.diagAt(&l.used, "label %s not defined", l.name)
@@ -1301,5 +1301,5 @@ func (a *funcCompiler) checkLabels() {
// Executing the "goto" statement must not cause any variables
// to come into scope that were not already in scope at the
// point of the goto.
- a.flow.gotosObeyScopes(a.compiler);
+ a.flow.gotosObeyScopes(a.compiler)
}