mirror of
https://github.com/golang/go
synced 2024-11-13 19:20:31 -07:00
Make the statement compiler not use the AST visitor.
In the process, I made error handling in the statement compiler much saner. Instead of separately tracking various error flags with weird relations, I just track if any error messages have been produced. R=rsc APPROVED=rsc DELTA=308 (98 added, 135 deleted, 75 changed) OCL=33870 CL=33961
This commit is contained in:
parent
4b409289f6
commit
c0dd9f526b
@ -24,13 +24,21 @@ type positioned interface {
|
|||||||
// case it should be package compiler.
|
// case it should be package compiler.
|
||||||
type compiler struct {
|
type compiler struct {
|
||||||
errors scanner.ErrorHandler;
|
errors scanner.ErrorHandler;
|
||||||
|
numErrors int;
|
||||||
|
silentErrors int;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *compiler) diagAt(pos positioned, format string, args ...) {
|
func (a *compiler) diagAt(pos positioned, format string, args ...) {
|
||||||
a.errors.Error(pos.Pos(), fmt.Sprintf(format, args));
|
a.errors.Error(pos.Pos(), fmt.Sprintf(format, args));
|
||||||
|
a.numErrors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *compiler) numError() int {
|
||||||
|
return a.numErrors + a.silentErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(austin) These can all go in stmt.go now
|
||||||
type label struct {
|
type label struct {
|
||||||
name string;
|
name string;
|
||||||
desc string;
|
desc string;
|
||||||
@ -61,7 +69,6 @@ type funcCompiler struct {
|
|||||||
*codeBuf;
|
*codeBuf;
|
||||||
flow *flowBuf;
|
flow *flowBuf;
|
||||||
labels map[string] *label;
|
labels map[string] *label;
|
||||||
err bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A blockCompiler captures information used throughout the compilation
|
// A blockCompiler captures information used throughout the compilation
|
||||||
|
@ -615,6 +615,7 @@ func (a *exprCompiler) compile(x ast.Expr) *expr {
|
|||||||
// Remaining expressions
|
// Remaining expressions
|
||||||
case *ast.BadExpr:
|
case *ast.BadExpr:
|
||||||
// Error already reported by parser
|
// Error already reported by parser
|
||||||
|
a.silentErrors++;
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
case *ast.BinaryExpr:
|
case *ast.BinaryExpr:
|
||||||
@ -740,6 +741,7 @@ func (a *exprInfo) compileIdent(b *block, constant bool, name string) *expr {
|
|||||||
func (a *exprInfo) compileVariable(level int, v *Variable) *expr {
|
func (a *exprInfo) compileVariable(level int, v *Variable) *expr {
|
||||||
if v.Type == nil {
|
if v.Type == nil {
|
||||||
// Placeholder definition from an earlier error
|
// Placeholder definition from an earlier error
|
||||||
|
a.silentErrors++;
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
expr := a.newExpr(v.Type, "variable");
|
expr := a.newExpr(v.Type, "variable");
|
||||||
@ -1614,7 +1616,12 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
|
|||||||
|
|
||||||
func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
|
func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
|
||||||
ec := &exprCompiler{a, b, constant};
|
ec := &exprCompiler{a, b, constant};
|
||||||
return ec.compile(expr);
|
nerr := a.numError();
|
||||||
|
e := ec.compile(expr);
|
||||||
|
if e == nil && nerr == a.numError() {
|
||||||
|
log.Crashf("expression compilation failed without reporting errors");
|
||||||
|
}
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractEffect separates out any effects that the expression may
|
// extractEffect separates out any effects that the expression may
|
||||||
@ -1698,7 +1705,7 @@ func (expr *Expr) Eval(f *Frame) Value {
|
|||||||
|
|
||||||
func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
|
func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
|
||||||
errors := scanner.NewErrorVector();
|
errors := scanner.NewErrorVector();
|
||||||
cc := &compiler{errors};
|
cc := &compiler{errors, 0, 0};
|
||||||
|
|
||||||
ec := cc.compileExpr(scope.block, false, expr);
|
ec := cc.compileExpr(scope.block, false, expr);
|
||||||
if ec == nil {
|
if ec == nil {
|
||||||
|
@ -28,12 +28,6 @@ type stmtCompiler struct {
|
|||||||
pos token.Position;
|
pos token.Position;
|
||||||
// This statement's label, or nil if it is not labeled.
|
// This statement's label, or nil if it is not labeled.
|
||||||
stmtLabel *label;
|
stmtLabel *label;
|
||||||
// err should be initialized to true before visiting and set
|
|
||||||
// to false when the statement is compiled successfully. The
|
|
||||||
// function invoking Visit should or this with
|
|
||||||
// blockCompiler.err. This is less error prone than setting
|
|
||||||
// blockCompiler.err on every failure path.
|
|
||||||
err bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) diag(format string, args ...) {
|
func (a *stmtCompiler) diag(format string, args ...) {
|
||||||
@ -187,7 +181,7 @@ func (f *flowBuf) reachesEnd(pc uint) bool {
|
|||||||
// gotosObeyScopes returns true if no goto statement causes any
|
// gotosObeyScopes returns true if no goto statement causes any
|
||||||
// variables to come into scope that were not in scope at the point of
|
// variables to come into scope that were not in scope at the point of
|
||||||
// the goto. Reports any errors using the given compiler.
|
// the goto. Reports any errors using the given compiler.
|
||||||
func (f *flowBuf) gotosObeyScopes(a *compiler) bool {
|
func (f *flowBuf) gotosObeyScopes(a *compiler) {
|
||||||
for pos, src := range f.gotos {
|
for pos, src := range f.gotos {
|
||||||
tgt := f.labels[src.target];
|
tgt := f.labels[src.target];
|
||||||
|
|
||||||
@ -201,7 +195,7 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) bool {
|
|||||||
if b != tgt.block {
|
if b != tgt.block {
|
||||||
// We jumped into a deeper block
|
// We jumped into a deeper block
|
||||||
a.diagAt(pos, "goto causes variables to come into scope");
|
a.diagAt(pos, "goto causes variables to come into scope");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There must be no variables in the target block that
|
// There must be no variables in the target block that
|
||||||
@ -210,11 +204,10 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) bool {
|
|||||||
for i := range numVars {
|
for i := range numVars {
|
||||||
if tgtNumVars[i] > numVars[i] {
|
if tgtNumVars[i] > numVars[i] {
|
||||||
a.diagAt(pos, "goto causes variables to come into scope");
|
a.diagAt(pos, "goto causes variables to come into scope");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -246,20 +239,98 @@ func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
|
|||||||
// TODO(austin) Move doAssign to here
|
// TODO(austin) Move doAssign to here
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Statement visitors
|
* Statement compiler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (a *stmtCompiler) DoBadStmt(s *ast.BadStmt) {
|
func (a *stmtCompiler) compile(s ast.Stmt) {
|
||||||
// Do nothing. Already reported by parser.
|
if a.block.inner != nil {
|
||||||
|
log.Crash("Child scope still entered");
|
||||||
|
}
|
||||||
|
|
||||||
|
notimpl := false;
|
||||||
|
switch s := s.(type) {
|
||||||
|
case *ast.BadStmt:
|
||||||
|
// Error already reported by parser.
|
||||||
|
a.silentErrors++;
|
||||||
|
|
||||||
|
case *ast.DeclStmt:
|
||||||
|
a.compileDeclStmt(s);
|
||||||
|
|
||||||
|
case *ast.EmptyStmt:
|
||||||
|
// Do nothing.
|
||||||
|
|
||||||
|
case *ast.LabeledStmt:
|
||||||
|
a.compileLabeledStmt(s);
|
||||||
|
|
||||||
|
case *ast.ExprStmt:
|
||||||
|
a.compileExprStmt(s);
|
||||||
|
|
||||||
|
case *ast.IncDecStmt:
|
||||||
|
a.compileIncDecStmt(s);
|
||||||
|
|
||||||
|
case *ast.AssignStmt:
|
||||||
|
a.compileAssignStmt(s);
|
||||||
|
|
||||||
|
case *ast.GoStmt:
|
||||||
|
notimpl = true;
|
||||||
|
|
||||||
|
case *ast.DeferStmt:
|
||||||
|
notimpl = true;
|
||||||
|
|
||||||
|
case *ast.ReturnStmt:
|
||||||
|
a.compileReturnStmt(s);
|
||||||
|
|
||||||
|
case *ast.BranchStmt:
|
||||||
|
a.compileBranchStmt(s);
|
||||||
|
|
||||||
|
case *ast.BlockStmt:
|
||||||
|
a.compileBlockStmt(s);
|
||||||
|
|
||||||
|
case *ast.IfStmt:
|
||||||
|
a.compileIfStmt(s);
|
||||||
|
|
||||||
|
case *ast.CaseClause:
|
||||||
|
a.diag("case clause outside switch");
|
||||||
|
|
||||||
|
case *ast.SwitchStmt:
|
||||||
|
a.compileSwitchStmt(s);
|
||||||
|
|
||||||
|
case *ast.TypeCaseClause:
|
||||||
|
notimpl = true;
|
||||||
|
|
||||||
|
case *ast.TypeSwitchStmt:
|
||||||
|
notimpl = true;
|
||||||
|
|
||||||
|
case *ast.CommClause:
|
||||||
|
notimpl = true;
|
||||||
|
|
||||||
|
case *ast.SelectStmt:
|
||||||
|
notimpl = true;
|
||||||
|
|
||||||
|
case *ast.ForStmt:
|
||||||
|
a.compileForStmt(s);
|
||||||
|
|
||||||
|
case *ast.RangeStmt:
|
||||||
|
notimpl = true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Crashf("unexpected ast node type %T", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if notimpl {
|
||||||
|
a.diag("%T statment node not implemented", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.block.inner != nil {
|
||||||
|
log.Crash("Forgot to exit child scope");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
|
func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
|
||||||
ok := true;
|
|
||||||
|
|
||||||
switch decl := s.Decl.(type) {
|
switch decl := s.Decl.(type) {
|
||||||
case *ast.BadDecl:
|
case *ast.BadDecl:
|
||||||
// Do nothing. Already reported by parser.
|
// Do nothing. Already reported by parser.
|
||||||
ok = false;
|
a.silentErrors++;
|
||||||
|
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
log.Crash("FuncDecl at statement level");
|
log.Crash("FuncDecl at statement level");
|
||||||
@ -273,7 +344,7 @@ func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
|
|||||||
log.Crashf("%v not implemented", decl.Tok);
|
log.Crashf("%v not implemented", decl.Tok);
|
||||||
|
|
||||||
case token.TYPE:
|
case token.TYPE:
|
||||||
ok = a.compileTypeDecl(a.block, decl);
|
a.compileTypeDecl(a.block, decl);
|
||||||
|
|
||||||
case token.VAR:
|
case token.VAR:
|
||||||
for _, spec := range decl.Specs {
|
for _, spec := range decl.Specs {
|
||||||
@ -285,14 +356,9 @@ func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
|
|||||||
log.Crash("Type and Values nil");
|
log.Crash("Type and Values nil");
|
||||||
}
|
}
|
||||||
t := a.compileType(a.block, spec.Type);
|
t := a.compileType(a.block, spec.Type);
|
||||||
if t == nil {
|
// Define placeholders even if type compile failed
|
||||||
// Define placeholders
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
for _, n := range spec.Names {
|
for _, n := range spec.Names {
|
||||||
if a.defineVar(n, t) == nil {
|
a.defineVar(n, t);
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Decalaration with assignment
|
// Decalaration with assignment
|
||||||
@ -301,36 +367,21 @@ func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
|
|||||||
lhs[i] = n;
|
lhs[i] = n;
|
||||||
}
|
}
|
||||||
a.doAssign(lhs, spec.Values, decl.Tok, spec.Type);
|
a.doAssign(lhs, spec.Values, decl.Tok, spec.Type);
|
||||||
// TODO(austin) This is ridiculous. doAssign
|
|
||||||
// indicates failure by setting a.err.
|
|
||||||
if a.err {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Crashf("Unexpected Decl type %T", s.Decl);
|
log.Crashf("Unexpected Decl type %T", s.Decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok {
|
|
||||||
a.err = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoEmptyStmt(s *ast.EmptyStmt) {
|
func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
|
||||||
a.err = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
|
|
||||||
bad := false;
|
|
||||||
|
|
||||||
// Define label
|
// Define label
|
||||||
l, ok := a.labels[s.Label.Value];
|
l, ok := a.labels[s.Label.Value];
|
||||||
if ok {
|
if ok {
|
||||||
if l.resolved.IsValid() {
|
if l.resolved.IsValid() {
|
||||||
a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Value, &l.resolved);
|
a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Value, &l.resolved);
|
||||||
bad = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pc := badPC;
|
pc := badPC;
|
||||||
@ -347,15 +398,11 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
|
|||||||
a.flow.putLabel(l.name, a.block);
|
a.flow.putLabel(l.name, a.block);
|
||||||
|
|
||||||
// Compile the statement. Reuse our stmtCompiler for simplicity.
|
// Compile the statement. Reuse our stmtCompiler for simplicity.
|
||||||
a.pos = s.Stmt.Pos();
|
sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l};
|
||||||
a.stmtLabel = l;
|
sc.compile(s.Stmt);
|
||||||
s.Stmt.Visit(a);
|
|
||||||
if bad {
|
|
||||||
a.err = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
|
func (a *stmtCompiler) compileExprStmt(s *ast.ExprStmt) {
|
||||||
bc := a.enterChild();
|
bc := a.enterChild();
|
||||||
defer bc.exit();
|
defer bc.exit();
|
||||||
|
|
||||||
@ -373,10 +420,9 @@ func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
|
|||||||
a.push(func(v *vm) {
|
a.push(func(v *vm) {
|
||||||
exec(v.f);
|
exec(v.f);
|
||||||
});
|
});
|
||||||
a.err = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
|
func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
|
||||||
// Create temporary block for extractEffect
|
// Create temporary block for extractEffect
|
||||||
bc := a.enterChild();
|
bc := a.enterChild();
|
||||||
defer bc.exit();
|
defer bc.exit();
|
||||||
@ -429,11 +475,10 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
|
|||||||
effect(v.f);
|
effect(v.f);
|
||||||
assign(lf(v.f), v.f);
|
assign(lf(v.f), v.f);
|
||||||
});
|
});
|
||||||
a.err = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
|
func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
|
||||||
bad := false;
|
nerr := a.numError();
|
||||||
|
|
||||||
// Compile right side first so we have the types when
|
// Compile right side first so we have the types when
|
||||||
// compiling the left side and so we don't see definitions
|
// compiling the left side and so we don't see definitions
|
||||||
@ -441,9 +486,6 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
rs := make([]*expr, len(rhs));
|
rs := make([]*expr, len(rhs));
|
||||||
for i, re := range rhs {
|
for i, re := range rhs {
|
||||||
rs[i] = a.compileExpr(a.block, false, re);
|
rs[i] = a.compileExpr(a.block, false, re);
|
||||||
if rs[i] == nil {
|
|
||||||
bad = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errOp := "assignment";
|
errOp := "assignment";
|
||||||
@ -451,9 +493,6 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
errOp = "declaration";
|
errOp = "declaration";
|
||||||
}
|
}
|
||||||
ac, ok := a.checkAssign(a.pos, rs, errOp, "value");
|
ac, ok := a.checkAssign(a.pos, rs, errOp, "value");
|
||||||
if !ok {
|
|
||||||
bad = true;
|
|
||||||
}
|
|
||||||
ac.allowMapForms(len(lhs));
|
ac.allowMapForms(len(lhs));
|
||||||
|
|
||||||
// If this is a definition and the LHS is too big, we won't be
|
// If this is a definition and the LHS is too big, we won't be
|
||||||
@ -461,16 +500,12 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
// begin to infer the types of the LHS.
|
// begin to infer the types of the LHS.
|
||||||
if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) {
|
if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) {
|
||||||
a.diag("not enough values for definition");
|
a.diag("not enough values for definition");
|
||||||
bad = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile left type if there is one
|
// Compile left type if there is one
|
||||||
var declType Type;
|
var declType Type;
|
||||||
if declTypeExpr != nil {
|
if declTypeExpr != nil {
|
||||||
declType = a.compileType(a.block, declTypeExpr);
|
declType = a.compileType(a.block, declTypeExpr);
|
||||||
if declType == nil {
|
|
||||||
bad = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile left side
|
// Compile left side
|
||||||
@ -486,7 +521,6 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
ident, ok = le.(*ast.Ident);
|
ident, ok = le.(*ast.Ident);
|
||||||
if !ok {
|
if !ok {
|
||||||
a.diagAt(le, "left side of := must be a name");
|
a.diagAt(le, "left side of := must be a name");
|
||||||
bad = true;
|
|
||||||
// Suppress new defitions errors
|
// Suppress new defitions errors
|
||||||
nDefs++;
|
nDefs++;
|
||||||
continue;
|
continue;
|
||||||
@ -549,7 +583,6 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
// If it's a definition, define the identifier
|
// If it's a definition, define the identifier
|
||||||
if ident != nil {
|
if ident != nil {
|
||||||
if a.defineVar(ident, lt) == nil {
|
if a.defineVar(ident, lt) == nil {
|
||||||
bad = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -557,7 +590,6 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
// Compile LHS
|
// Compile LHS
|
||||||
ls[i] = a.compileExpr(a.block, false, le);
|
ls[i] = a.compileExpr(a.block, false, le);
|
||||||
if ls[i] == nil {
|
if ls[i] == nil {
|
||||||
bad = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,7 +616,6 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
};
|
};
|
||||||
} else if ls[i].evalAddr == nil {
|
} else if ls[i].evalAddr == nil {
|
||||||
ls[i].diag("cannot assign to %s", ls[i].desc);
|
ls[i].diag("cannot assign to %s", ls[i].desc);
|
||||||
bad = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -598,7 +629,9 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if bad {
|
// If there have been errors, our arrays are full of nil's so
|
||||||
|
// get out of here now.
|
||||||
|
if nerr != a.numError() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,7 +698,6 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
a.err = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var assignOpToOp = map[token.Token] token.Token {
|
var assignOpToOp = map[token.Token] token.Token {
|
||||||
@ -721,10 +753,9 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
|
|||||||
effect(v.f);
|
effect(v.f);
|
||||||
assign(lf(v.f), v.f);
|
assign(lf(v.f), v.f);
|
||||||
});
|
});
|
||||||
a.err = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoAssignStmt(s *ast.AssignStmt) {
|
func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) {
|
||||||
switch s.Tok {
|
switch s.Tok {
|
||||||
case token.ASSIGN, token.DEFINE:
|
case token.ASSIGN, token.DEFINE:
|
||||||
a.doAssign(s.Lhs, s.Rhs, s.Tok, nil);
|
a.doAssign(s.Lhs, s.Rhs, s.Tok, nil);
|
||||||
@ -734,15 +765,7 @@ func (a *stmtCompiler) DoAssignStmt(s *ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoGoStmt(s *ast.GoStmt) {
|
func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) {
|
||||||
log.Crash("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoDeferStmt(s *ast.DeferStmt) {
|
|
||||||
log.Crash("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
|
|
||||||
if a.fnType == nil {
|
if a.fnType == nil {
|
||||||
a.diag("cannot return at the top level");
|
a.diag("cannot return at the top level");
|
||||||
return;
|
return;
|
||||||
@ -752,7 +775,6 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
|
|||||||
// Simple case. Simply exit from the function.
|
// Simple case. Simply exit from the function.
|
||||||
a.flow.putTerm();
|
a.flow.putTerm();
|
||||||
a.push(func(v *vm) { v.pc = returnPC });
|
a.push(func(v *vm) { v.pc = returnPC });
|
||||||
a.err = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -779,9 +801,6 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
|
|||||||
// returned from the called function will be returned from
|
// returned from the called function will be returned from
|
||||||
// this one.
|
// 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");
|
||||||
if assign == nil {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX(Spec) "The result types of the current function and the
|
// XXX(Spec) "The result types of the current function and the
|
||||||
// called function must match." Match is fuzzy. It should
|
// called function must match." Match is fuzzy. It should
|
||||||
@ -795,7 +814,6 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
|
|||||||
assign(multiV(v.f.Vars[start:start+nout]), v.f);
|
assign(multiV(v.f.Vars[start:start+nout]), v.f);
|
||||||
v.pc = returnPC;
|
v.pc = returnPC;
|
||||||
});
|
});
|
||||||
a.err = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label {
|
func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label {
|
||||||
@ -824,7 +842,7 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool,
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoBranchStmt(s *ast.BranchStmt) {
|
func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
|
||||||
var pc *uint;
|
var pc *uint;
|
||||||
|
|
||||||
switch s.Tok {
|
switch s.Tok {
|
||||||
@ -863,18 +881,15 @@ func (a *stmtCompiler) DoBranchStmt(s *ast.BranchStmt) {
|
|||||||
|
|
||||||
a.flow.put1(false, pc);
|
a.flow.put1(false, pc);
|
||||||
a.push(func(v *vm) { v.pc = *pc });
|
a.push(func(v *vm) { v.pc = *pc });
|
||||||
a.err = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoBlockStmt(s *ast.BlockStmt) {
|
func (a *stmtCompiler) compileBlockStmt(s *ast.BlockStmt) {
|
||||||
bc := a.enterChild();
|
bc := a.enterChild();
|
||||||
bc.compileStmts(s);
|
bc.compileStmts(s);
|
||||||
bc.exit();
|
bc.exit();
|
||||||
|
|
||||||
a.err = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
|
func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) {
|
||||||
// The scope of any variables declared by [the init] statement
|
// The scope of any variables declared by [the init] statement
|
||||||
// extends to the end of the "if" statement and the variables
|
// extends to the end of the "if" statement and the variables
|
||||||
// are initialized once before the statement is entered.
|
// are initialized once before the statement is entered.
|
||||||
@ -898,15 +913,13 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
|
|||||||
|
|
||||||
// Compile condition, if any. If there is no condition, we
|
// Compile condition, if any. If there is no condition, we
|
||||||
// fall through to the body.
|
// fall through to the body.
|
||||||
bad := false;
|
|
||||||
if s.Cond != nil {
|
if s.Cond != nil {
|
||||||
e := bc.compileExpr(bc.block, false, s.Cond);
|
e := bc.compileExpr(bc.block, false, s.Cond);
|
||||||
switch {
|
switch {
|
||||||
case e == nil:
|
case e == nil:
|
||||||
bad = true;
|
// Error reported by compileExpr
|
||||||
case !e.t.isBoolean():
|
case !e.t.isBoolean():
|
||||||
e.diag("'if' condition must be boolean\n\t%v", e.t);
|
e.diag("'if' condition must be boolean\n\t%v", e.t);
|
||||||
bad = true;
|
|
||||||
default:
|
default:
|
||||||
eval := e.asBool();
|
eval := e.asBool();
|
||||||
a.flow.put1(true, &elsePC);
|
a.flow.put1(true, &elsePC);
|
||||||
@ -936,17 +949,9 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
|
|||||||
elsePC = a.nextPC();
|
elsePC = a.nextPC();
|
||||||
}
|
}
|
||||||
endPC = a.nextPC();
|
endPC = a.nextPC();
|
||||||
|
|
||||||
if !bad {
|
|
||||||
a.err = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoCaseClause(s *ast.CaseClause) {
|
func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
|
||||||
a.diag("case clause outside switch");
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
|
|
||||||
// Create implicit scope around switch
|
// Create implicit scope around switch
|
||||||
bc := a.enterChild();
|
bc := a.enterChild();
|
||||||
defer bc.exit();
|
defer bc.exit();
|
||||||
@ -959,17 +964,11 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
|
|||||||
// Compile condition, if any, and extract its effects
|
// Compile condition, if any, and extract its effects
|
||||||
var cond *expr;
|
var cond *expr;
|
||||||
condbc := bc.enterChild();
|
condbc := bc.enterChild();
|
||||||
bad := false;
|
|
||||||
if s.Tag != nil {
|
if s.Tag != nil {
|
||||||
e := condbc.compileExpr(condbc.block, false, s.Tag);
|
e := condbc.compileExpr(condbc.block, false, s.Tag);
|
||||||
if e == nil {
|
if e != nil {
|
||||||
bad = true;
|
|
||||||
} else {
|
|
||||||
var effect func(f *Frame);
|
var effect func(f *Frame);
|
||||||
effect, cond = e.extractEffect(condbc.block, "switch");
|
effect, cond = e.extractEffect(condbc.block, "switch");
|
||||||
if effect == nil {
|
|
||||||
bad = true;
|
|
||||||
}
|
|
||||||
a.push(func(v *vm) { effect(v.f) });
|
a.push(func(v *vm) { effect(v.f) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -981,13 +980,11 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
|
|||||||
clause, ok := c.(*ast.CaseClause);
|
clause, ok := c.(*ast.CaseClause);
|
||||||
if !ok {
|
if !ok {
|
||||||
a.diagAt(clause, "switch statement must contain case clauses");
|
a.diagAt(clause, "switch statement must contain case clauses");
|
||||||
bad = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if clause.Values == nil {
|
if clause.Values == nil {
|
||||||
if hasDefault {
|
if hasDefault {
|
||||||
a.diagAt(clause, "switch statement contains more than one default case");
|
a.diagAt(clause, "switch statement contains more than one default case");
|
||||||
bad = true;
|
|
||||||
}
|
}
|
||||||
hasDefault = true;
|
hasDefault = true;
|
||||||
} else {
|
} else {
|
||||||
@ -1007,19 +1004,16 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
|
|||||||
e := condbc.compileExpr(condbc.block, false, v);
|
e := condbc.compileExpr(condbc.block, false, v);
|
||||||
switch {
|
switch {
|
||||||
case e == nil:
|
case e == nil:
|
||||||
bad = true;
|
// Error reported by compileExpr
|
||||||
case cond == nil && !e.t.isBoolean():
|
case cond == nil && !e.t.isBoolean():
|
||||||
a.diagAt(v, "'case' condition must be boolean");
|
a.diagAt(v, "'case' condition must be boolean");
|
||||||
bad = true;
|
|
||||||
case cond == nil:
|
case cond == nil:
|
||||||
cases[i] = e.asBool();
|
cases[i] = e.asBool();
|
||||||
case cond != nil:
|
case cond != nil:
|
||||||
// Create comparison
|
// Create comparison
|
||||||
// TOOD(austin) This produces bad error messages
|
// TOOD(austin) This produces bad error messages
|
||||||
compare := e.compileBinaryExpr(token.EQL, cond, e);
|
compare := e.compileBinaryExpr(token.EQL, cond, e);
|
||||||
if compare == nil {
|
if compare != nil {
|
||||||
bad = true;
|
|
||||||
} else {
|
|
||||||
cases[i] = compare.asBool();
|
cases[i] = compare.asBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1031,18 +1025,16 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
|
|||||||
casePCs := make([]*uint, ncases+1);
|
casePCs := make([]*uint, ncases+1);
|
||||||
endPC := badPC;
|
endPC := badPC;
|
||||||
|
|
||||||
if !bad {
|
a.flow.put(false, false, casePCs);
|
||||||
a.flow.put(false, false, casePCs);
|
a.push(func(v *vm) {
|
||||||
a.push(func(v *vm) {
|
for i, c := range cases {
|
||||||
for i, c := range cases {
|
if c(v.f) {
|
||||||
if c(v.f) {
|
v.pc = *casePCs[i];
|
||||||
v.pc = *casePCs[i];
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
v.pc = *casePCs[ncases];
|
}
|
||||||
});
|
v.pc = *casePCs[ncases];
|
||||||
}
|
});
|
||||||
condbc.exit();
|
condbc.exit();
|
||||||
|
|
||||||
// Compile cases
|
// Compile cases
|
||||||
@ -1080,7 +1072,6 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
|
|||||||
// statements.
|
// statements.
|
||||||
if _, ok := s2.(*ast.EmptyStmt); !ok {
|
if _, ok := s2.(*ast.EmptyStmt); !ok {
|
||||||
a.diagAt(s, "fallthrough statement must be final statement in case");
|
a.diagAt(s, "fallthrough statement must be final statement in case");
|
||||||
bad = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1101,29 +1092,9 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
|
|||||||
if !hasDefault {
|
if !hasDefault {
|
||||||
casePCs[ncases] = &endPC;
|
casePCs[ncases] = &endPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bad {
|
|
||||||
a.err = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *stmtCompiler) DoTypeCaseClause(s *ast.TypeCaseClause) {
|
func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
|
||||||
log.Crash("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoTypeSwitchStmt(s *ast.TypeSwitchStmt) {
|
|
||||||
log.Crash("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoCommClause(s *ast.CommClause) {
|
|
||||||
log.Crash("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoSelectStmt(s *ast.SelectStmt) {
|
|
||||||
log.Crash("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
|
|
||||||
// Wrap the entire for in a block.
|
// Wrap the entire for in a block.
|
||||||
bc := a.enterChild();
|
bc := a.enterChild();
|
||||||
defer bc.exit();
|
defer bc.exit();
|
||||||
@ -1166,7 +1137,6 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compile condition check, if any
|
// Compile condition check, if any
|
||||||
bad := false;
|
|
||||||
checkPC = a.nextPC();
|
checkPC = a.nextPC();
|
||||||
if s.Cond == nil {
|
if s.Cond == nil {
|
||||||
// If the condition is absent, it is equivalent to true.
|
// If the condition is absent, it is equivalent to true.
|
||||||
@ -1176,10 +1146,9 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
|
|||||||
e := bc.compileExpr(bc.block, false, s.Cond);
|
e := bc.compileExpr(bc.block, false, s.Cond);
|
||||||
switch {
|
switch {
|
||||||
case e == nil:
|
case e == nil:
|
||||||
bad = true;
|
// Error reported by compileExpr
|
||||||
case !e.t.isBoolean():
|
case !e.t.isBoolean():
|
||||||
a.diag("'for' condition must be boolean\n\t%v", e.t);
|
a.diag("'for' condition must be boolean\n\t%v", e.t);
|
||||||
bad = true;
|
|
||||||
default:
|
default:
|
||||||
eval := e.asBool();
|
eval := e.asBool();
|
||||||
a.flow.put1(true, &bodyPC);
|
a.flow.put1(true, &bodyPC);
|
||||||
@ -1192,14 +1161,6 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
endPC = a.nextPC();
|
endPC = a.nextPC();
|
||||||
|
|
||||||
if !bad {
|
|
||||||
a.err = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *stmtCompiler) DoRangeStmt(s *ast.RangeStmt) {
|
|
||||||
log.Crash("Not implemented");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1207,15 +1168,8 @@ func (a *stmtCompiler) DoRangeStmt(s *ast.RangeStmt) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
func (a *blockCompiler) compileStmt(s ast.Stmt) {
|
func (a *blockCompiler) compileStmt(s ast.Stmt) {
|
||||||
if a.block.inner != nil {
|
sc := &stmtCompiler{a, s.Pos(), nil};
|
||||||
log.Crash("Child scope still entered");
|
sc.compile(s);
|
||||||
}
|
|
||||||
sc := &stmtCompiler{a, s.Pos(), nil, true};
|
|
||||||
s.Visit(sc);
|
|
||||||
if a.block.inner != nil {
|
|
||||||
log.Crash("Forgot to exit child scope");
|
|
||||||
}
|
|
||||||
a.err = a.err || sc.err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
|
func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
|
||||||
@ -1272,7 +1226,6 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
|
|||||||
codeBuf: cb,
|
codeBuf: cb,
|
||||||
flow: newFlowBuf(cb),
|
flow: newFlowBuf(cb),
|
||||||
labels: make(map[string] *label),
|
labels: make(map[string] *label),
|
||||||
err: false,
|
|
||||||
};
|
};
|
||||||
bc := &blockCompiler{
|
bc := &blockCompiler{
|
||||||
funcCompiler: fc,
|
funcCompiler: fc,
|
||||||
@ -1280,10 +1233,10 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Compile body
|
// Compile body
|
||||||
|
nerr := a.numError();
|
||||||
bc.compileStmts(body);
|
bc.compileStmts(body);
|
||||||
fc.checkLabels();
|
fc.checkLabels();
|
||||||
|
if nerr != a.numError() {
|
||||||
if fc.err {
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1303,15 +1256,13 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
|
|||||||
// Checks that labels were resolved and that all jumps obey scoping
|
// Checks that labels were resolved and that all jumps obey scoping
|
||||||
// rules. Reports an error and set fc.err if any check fails.
|
// rules. Reports an error and set fc.err if any check fails.
|
||||||
func (a *funcCompiler) checkLabels() {
|
func (a *funcCompiler) checkLabels() {
|
||||||
bad := false;
|
nerr := a.numError();
|
||||||
for _, l := range a.labels {
|
for _, l := range a.labels {
|
||||||
if !l.resolved.IsValid() {
|
if !l.resolved.IsValid() {
|
||||||
a.diagAt(&l.used, "label %s not defined", l.name);
|
a.diagAt(&l.used, "label %s not defined", l.name);
|
||||||
bad = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if bad {
|
if nerr != a.numError() {
|
||||||
a.err = true;
|
|
||||||
// Don't check scopes if we have unresolved labels
|
// Don't check scopes if we have unresolved labels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1319,9 +1270,7 @@ func (a *funcCompiler) checkLabels() {
|
|||||||
// Executing the "goto" statement must not cause any variables
|
// Executing the "goto" statement must not cause any variables
|
||||||
// to come into scope that were not already in scope at the
|
// to come into scope that were not already in scope at the
|
||||||
// point of the goto.
|
// point of the goto.
|
||||||
if !a.flow.gotosObeyScopes(a.compiler) {
|
a.flow.gotosObeyScopes(a.compiler);
|
||||||
a.err = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1338,7 +1287,7 @@ func (s *Stmt) Exec(f *Frame) {
|
|||||||
|
|
||||||
func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
|
func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
|
||||||
errors := scanner.NewErrorVector();
|
errors := scanner.NewErrorVector();
|
||||||
cc := &compiler{errors};
|
cc := &compiler{errors, 0, 0};
|
||||||
cb := newCodeBuf();
|
cb := newCodeBuf();
|
||||||
fc := &funcCompiler{
|
fc := &funcCompiler{
|
||||||
compiler: cc,
|
compiler: cc,
|
||||||
@ -1347,18 +1296,18 @@ func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
|
|||||||
codeBuf: cb,
|
codeBuf: cb,
|
||||||
flow: newFlowBuf(cb),
|
flow: newFlowBuf(cb),
|
||||||
labels: make(map[string] *label),
|
labels: make(map[string] *label),
|
||||||
err: false,
|
|
||||||
};
|
};
|
||||||
bc := &blockCompiler{
|
bc := &blockCompiler{
|
||||||
funcCompiler: fc,
|
funcCompiler: fc,
|
||||||
block: scope.block,
|
block: scope.block,
|
||||||
};
|
};
|
||||||
out := make([]*Stmt, len(stmts));
|
out := make([]*Stmt, len(stmts));
|
||||||
|
nerr := cc.numError();
|
||||||
for i, stmt := range stmts {
|
for i, stmt := range stmts {
|
||||||
bc.compileStmt(stmt);
|
bc.compileStmt(stmt);
|
||||||
}
|
}
|
||||||
fc.checkLabels();
|
fc.checkLabels();
|
||||||
if fc.err {
|
if nerr != cc.numError() {
|
||||||
return nil, errors.GetError(scanner.Sorted);
|
return nil, errors.GetError(scanner.Sorted);
|
||||||
}
|
}
|
||||||
code := fc.get();
|
code := fc.get();
|
||||||
|
Loading…
Reference in New Issue
Block a user