Commit 36eee6d1 authored by Austin Clements's avatar Austin Clements

Make the expression compiler not use the AST visitor. The

statement compiler will be fixed in a later CL.

The input and output of the expression compiler are now
clearly distinguished.  In the process, I made the individual
expression compilers operate on the compiled form of their
children instead of AST nodes.  As a result, there are now
fewer places where I hand-craft intermediate expression nodes.

The diff looks scarier than it is, mostly because exprCompiler
has been split into the input and output types, resulting in
lots of little renames.

R=rsc
APPROVED=rsc
DELTA=774  (204 added, 199 deleted, 371 changed)
OCL=33851
CL=33851
parent 87f2208b
...@@ -76,15 +76,3 @@ type blockCompiler struct { ...@@ -76,15 +76,3 @@ type blockCompiler struct {
// for a function-level block. // for a function-level block.
parent *blockCompiler; parent *blockCompiler;
} }
// An exprContext stores information used throughout the compilation
// of a single expression. It does not embed funcCompiler because
// expressions can appear at top level.
//
// TODO(austin) Rename exprCompiler to exprNodeCompiler and rename
// this to exprCompiler.
type exprContext struct {
*compiler;
block *block;
constant bool;
}
...@@ -15,13 +15,10 @@ import ( ...@@ -15,13 +15,10 @@ import (
"strings"; "strings";
) )
// An exprCompiler compiles a single node in an expression. It stores // An expr is the result of compiling an expression. It stores the
// the whole expression's context plus information specific to this node. // type of the expression and its evaluator function.
// After compilation, it stores the type of the expression and its type expr struct {
// evaluator function. *exprInfo;
type exprCompiler struct {
*exprContext;
pos token.Position;
t Type; t Type;
// Evaluate this node as the given type. // Evaluate this node as the given type.
evalBool func(f *Frame) bool; evalBool func(f *Frame) bool;
...@@ -51,146 +48,138 @@ type exprCompiler struct { ...@@ -51,146 +48,138 @@ type exprCompiler struct {
// that are valid expression statements should set this. // that are valid expression statements should set this.
exec func(f *Frame); exec func(f *Frame);
// A short string describing this expression for error // A short string describing this expression for error
// messages. Only necessary if t != nil. // messages.
desc string; desc string;
} }
func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler { // exprInfo stores information needed to compile any expression node.
return &exprCompiler{ // Each expr also stores its exprInfo so further expressions can be
exprContext: c, // compiled from it.
pos: pos, type exprInfo struct {
desc: "<missing description>" *compiler;
}; pos token.Position;
}
func (a *exprCompiler) copy() *exprCompiler {
ec := newExprCompiler(a.exprContext, a.pos);
ec.desc = a.desc;
return ec;
} }
func (a *exprCompiler) copyVisit(x ast.Expr) *exprCompiler { func (a *exprInfo) newExpr(t Type, desc string) *expr {
ec := newExprCompiler(a.exprContext, x.Pos()); return &expr{exprInfo: a, t: t, desc: desc};
x.Visit(ec);
return ec;
} }
func (a *exprCompiler) diag(format string, args ...) { func (a *exprInfo) diag(format string, args ...) {
a.diagAt(&a.pos, format, args); a.diagAt(&a.pos, format, args);
} }
func (a *exprCompiler) diagOpType(op token.Token, vt Type) { func (a *exprInfo) diagOpType(op token.Token, vt Type) {
a.diag("illegal operand type for '%v' operator\n\t%v", op, vt); a.diag("illegal operand type for '%v' operator\n\t%v", op, vt);
} }
func (a *exprCompiler) diagOpTypes(op token.Token, lt Type, rt Type) { func (a *exprInfo) diagOpTypes(op token.Token, lt Type, rt Type) {
a.diag("illegal operand types for '%v' operator\n\t%v\n\t%v", op, lt, rt); a.diag("illegal operand types for '%v' operator\n\t%v\n\t%v", op, lt, rt);
} }
/* /*
* "As" functions. These retrieve evaluator functions from an * "As" functions. These retrieve evaluator functions from an
* exprCompiler, panicking if the requested evaluator is nil. * expr, panicking if the requested evaluator is nil.
*/ */
func (a *exprCompiler) asBool() (func(f *Frame) bool) { func (a *expr) asBool() (func(f *Frame) bool) {
if a.evalBool == nil { if a.evalBool == nil {
log.Crashf("tried to get %v node as boolType", a.t); log.Crashf("tried to get %v node as boolType", a.t);
} }
return a.evalBool; return a.evalBool;
} }
func (a *exprCompiler) asUint() (func(f *Frame) uint64) { func (a *expr) asUint() (func(f *Frame) uint64) {
if a.evalUint == nil { if a.evalUint == nil {
log.Crashf("tried to get %v node as uintType", a.t); log.Crashf("tried to get %v node as uintType", a.t);
} }
return a.evalUint; return a.evalUint;
} }
func (a *exprCompiler) asInt() (func(f *Frame) int64) { func (a *expr) asInt() (func(f *Frame) int64) {
if a.evalInt == nil { if a.evalInt == nil {
log.Crashf("tried to get %v node as intType", a.t); log.Crashf("tried to get %v node as intType", a.t);
} }
return a.evalInt; return a.evalInt;
} }
func (a *exprCompiler) asIdealInt() (func() *bignum.Integer) { func (a *expr) asIdealInt() (func() *bignum.Integer) {
if a.evalIdealInt == nil { if a.evalIdealInt == nil {
log.Crashf("tried to get %v node as idealIntType", a.t); log.Crashf("tried to get %v node as idealIntType", a.t);
} }
return a.evalIdealInt; return a.evalIdealInt;
} }
func (a *exprCompiler) asFloat() (func(f *Frame) float64) { func (a *expr) asFloat() (func(f *Frame) float64) {
if a.evalFloat == nil { if a.evalFloat == nil {
log.Crashf("tried to get %v node as floatType", a.t); log.Crashf("tried to get %v node as floatType", a.t);
} }
return a.evalFloat; return a.evalFloat;
} }
func (a *exprCompiler) asIdealFloat() (func() *bignum.Rational) { func (a *expr) asIdealFloat() (func() *bignum.Rational) {
if a.evalIdealFloat == nil { if a.evalIdealFloat == nil {
log.Crashf("tried to get %v node as idealFloatType", a.t); log.Crashf("tried to get %v node as idealFloatType", a.t);
} }
return a.evalIdealFloat; return a.evalIdealFloat;
} }
func (a *exprCompiler) asString() (func(f *Frame) string) { func (a *expr) asString() (func(f *Frame) string) {
if a.evalString == nil { if a.evalString == nil {
log.Crashf("tried to get %v node as stringType", a.t); log.Crashf("tried to get %v node as stringType", a.t);
} }
return a.evalString; return a.evalString;
} }
func (a *exprCompiler) asArray() (func(f *Frame) ArrayValue) { func (a *expr) asArray() (func(f *Frame) ArrayValue) {
if a.evalArray == nil { if a.evalArray == nil {
log.Crashf("tried to get %v node as ArrayType", a.t); log.Crashf("tried to get %v node as ArrayType", a.t);
} }
return a.evalArray; return a.evalArray;
} }
func (a *exprCompiler) asStruct() (func(f *Frame) StructValue) { func (a *expr) asStruct() (func(f *Frame) StructValue) {
if a.evalStruct == nil { if a.evalStruct == nil {
log.Crashf("tried to get %v node as StructType", a.t); log.Crashf("tried to get %v node as StructType", a.t);
} }
return a.evalStruct; return a.evalStruct;
} }
func (a *exprCompiler) asPtr() (func(f *Frame) Value) { func (a *expr) asPtr() (func(f *Frame) Value) {
if a.evalPtr == nil { if a.evalPtr == nil {
log.Crashf("tried to get %v node as PtrType", a.t); log.Crashf("tried to get %v node as PtrType", a.t);
} }
return a.evalPtr; return a.evalPtr;
} }
func (a *exprCompiler) asFunc() (func(f *Frame) Func) { func (a *expr) asFunc() (func(f *Frame) Func) {
if a.evalFunc == nil { if a.evalFunc == nil {
log.Crashf("tried to get %v node as FuncType", a.t); log.Crashf("tried to get %v node as FuncType", a.t);
} }
return a.evalFunc; return a.evalFunc;
} }
func (a *exprCompiler) asSlice() (func(f *Frame) Slice) { func (a *expr) asSlice() (func(f *Frame) Slice) {
if a.evalSlice == nil { if a.evalSlice == nil {
log.Crashf("tried to get %v node as SliceType", a.t); log.Crashf("tried to get %v node as SliceType", a.t);
} }
return a.evalSlice; return a.evalSlice;
} }
func (a *exprCompiler) asMap() (func(f *Frame) Map) { func (a *expr) asMap() (func(f *Frame) Map) {
if a.evalMap == nil { if a.evalMap == nil {
log.Crashf("tried to get %v node as MapType", a.t); log.Crashf("tried to get %v node as MapType", a.t);
} }
return a.evalMap; return a.evalMap;
} }
func (a *exprCompiler) asMulti() (func(f *Frame) []Value) { func (a *expr) asMulti() (func(f *Frame) []Value) {
if a.evalMulti == nil { if a.evalMulti == nil {
log.Crashf("tried to get %v node as MultiType", a.t); log.Crashf("tried to get %v node as MultiType", a.t);
} }
return a.evalMulti; return a.evalMulti;
} }
func (a *exprCompiler) asInterface() (func(f *Frame) interface {}) { func (a *expr) asInterface() (func(f *Frame) interface {}) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *boolType: case *boolType:
sf := a.asBool(); sf := a.asBool();
...@@ -231,7 +220,7 @@ func (a *exprCompiler) asInterface() (func(f *Frame) interface {}) { ...@@ -231,7 +220,7 @@ func (a *exprCompiler) asInterface() (func(f *Frame) interface {}) {
// expression with a constant value of type t. // expression with a constant value of type t.
// //
// TODO(austin) Rename to resolveIdeal or something? // TODO(austin) Rename to resolveIdeal or something?
func (a *exprCompiler) convertTo(t Type) *exprCompiler { func (a *expr) convertTo(t Type) *expr {
if !a.t.isIdeal() { if !a.t.isIdeal() {
log.Crashf("attempted to convert from %v, expected ideal", a.t); log.Crashf("attempted to convert from %v, expected ideal", a.t);
} }
...@@ -271,8 +260,7 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler { ...@@ -271,8 +260,7 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
} }
// Convert rat to type t. // Convert rat to type t.
res := a.copy(); res := a.newExpr(t, a.desc);
res.t = t;
switch t := t.lit().(type) { switch t := t.lit().(type) {
case *uintType: case *uintType:
n, d := rat.Value(); n, d := rat.Value();
...@@ -301,10 +289,6 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler { ...@@ -301,10 +289,6 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
return res; return res;
} }
func (a *exprCompiler) genStarOp(v *exprCompiler) {
a.genValue(v.asPtr());
}
/* /*
* Assignments * Assignments
*/ */
...@@ -327,7 +311,7 @@ type assignCompiler struct { ...@@ -327,7 +311,7 @@ type assignCompiler struct {
pos token.Position; pos token.Position;
// The RHS expressions. This may include nil's for // The RHS expressions. This may include nil's for
// expressions that failed to compile. // expressions that failed to compile.
rs []*exprCompiler; rs []*expr;
// The (possibly unary) MultiType of the RHS. // The (possibly unary) MultiType of the RHS.
rmt *MultiType; rmt *MultiType;
// Whether this is an unpack assignment (case 3). // Whether this is an unpack assignment (case 3).
...@@ -349,7 +333,7 @@ type assignCompiler struct { ...@@ -349,7 +333,7 @@ type assignCompiler struct {
// assignCompiler with rmt set, but if type checking fails, slots in // assignCompiler with rmt set, but if type checking fails, slots in
// the MultiType may be nil. If rs contains nil's, type checking will // the MultiType may be nil. If rs contains nil's, type checking will
// fail and these expressions given a nil type. // fail and these expressions given a nil type.
func (a *compiler) checkAssign(pos token.Position, rs []*exprCompiler, errOp, errPosName string) (*assignCompiler, bool) { func (a *compiler) checkAssign(pos token.Position, rs []*expr, errOp, errPosName string) (*assignCompiler, bool) {
c := &assignCompiler{ c := &assignCompiler{
compiler: a, compiler: a,
pos: pos, pos: pos,
...@@ -405,7 +389,7 @@ func (a *assignCompiler) allowMapForms(nls int) { ...@@ -405,7 +389,7 @@ func (a *assignCompiler) allowMapForms(nls int) {
// a function that expects an l-value and the frame in which to // a function that expects an l-value and the frame in which to
// evaluate the RHS expressions. The l-value must have exactly the // evaluate the RHS expressions. The l-value must have exactly the
// type given by lt. Returns nil if type checking fails. // type given by lt. Returns nil if type checking fails.
func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) { func (a *assignCompiler) compile(b *block, lt Type) (func(lv Value, f *Frame)) {
lmt, isMT := lt.(*MultiType); lmt, isMT := lt.(*MultiType);
rmt, isUnpack := a.rmt, a.isUnpack; rmt, isUnpack := a.rmt, a.isUnpack;
...@@ -438,15 +422,8 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) { ...@@ -438,15 +422,8 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) {
// necessary when we need to perform assignment conversions. // necessary when we need to perform assignment conversions.
var effect func(f *Frame); var effect func(f *Frame);
if isUnpack { if isUnpack {
// TODO(austin) Is it safe to exit the block? What if
// there are multiple unpacks in one statement, such
// as for function calls?
//bc := a.rs[0].block.enterChild();
//defer bc.exit();
// This leaks a slot, but is definitely safe. // This leaks a slot, but is definitely safe.
bc := a.rs[0].block; temp := b.DefineSlot(a.rmt);
temp := bc.DefineSlot(a.rmt);
tempIdx := temp.Index; tempIdx := temp.Index;
if a.isMapUnpack { if a.isMapUnpack {
rf := a.rs[0].evalMapValue; rf := a.rs[0].evalMapValue;
...@@ -468,13 +445,12 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) { ...@@ -468,13 +445,12 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) {
}; };
} }
orig := a.rs[0]; orig := a.rs[0];
a.rs = make([]*exprCompiler, len(a.rmt.Elems)); a.rs = make([]*expr, len(a.rmt.Elems));
for i, t := range a.rmt.Elems { for i, t := range a.rmt.Elems {
if t.isIdeal() { if t.isIdeal() {
log.Crashf("Right side of unpack contains ideal: %s", rmt); log.Crashf("Right side of unpack contains ideal: %s", rmt);
} }
a.rs[i] = orig.copy(); a.rs[i] = orig.newExpr(t, orig.desc);
a.rs[i].t = t;
index := i; index := i;
a.rs[i].genValue(func(f *Frame) Value { return f.Vars[tempIdx].(multiV)[index] }); a.rs[i].genValue(func(f *Frame) Value { return f.Vars[tempIdx].(multiV)[index] });
} }
...@@ -509,8 +485,7 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) { ...@@ -509,8 +485,7 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) {
if lst, ok := lt.lit().(*SliceType); ok { if lst, ok := lt.lit().(*SliceType); ok {
if lst.Elem.compat(at.Elem, false) && (rt.lit() == Type(rt) || lt.lit() == Type(lt)) { if lst.Elem.compat(at.Elem, false) && (rt.lit() == Type(rt) || lt.lit() == Type(lt)) {
rf := a.rs[i].asPtr(); rf := a.rs[i].asPtr();
a.rs[i] = a.rs[i].copy(); a.rs[i] = a.rs[i].newExpr(lt, a.rs[i].desc);
a.rs[i].t = lt;
len := at.Len; len := at.Len;
a.rs[i].evalSlice = func(f *Frame) Slice { a.rs[i].evalSlice = func(f *Frame) Slice {
return Slice{rf(f).(ArrayValue), len, len}; return Slice{rf(f).(ArrayValue), len, len};
...@@ -558,158 +533,286 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) { ...@@ -558,158 +533,286 @@ func (a *assignCompiler) compile(lt Type) (func(lv Value, f *Frame)) {
// compileAssign compiles an assignment operation without the full // compileAssign compiles an assignment operation without the full
// generality of an assignCompiler. See assignCompiler for a // generality of an assignCompiler. See assignCompiler for a
// description of the arguments. // description of the arguments.
func (a *compiler) compileAssign(pos token.Position, lt Type, rs []*exprCompiler, errOp, errPosName string) (func(lv Value, f *Frame)) { func (a *compiler) compileAssign(pos token.Position, b *block, lt Type, rs []*expr, errOp, errPosName string) (func(lv Value, f *Frame)) {
ac, ok := a.checkAssign(pos, rs, errOp, errPosName); ac, ok := a.checkAssign(pos, rs, errOp, errPosName);
if !ok { if !ok {
return nil; return nil;
} }
return ac.compile(lt); return ac.compile(b, lt);
} }
/* /*
* Expression visitors * Expression compiler
*/ */
func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) { // An exprCompiler stores information used throughout the compilation
// Do nothing. Already reported by parser. // of a single expression. It does not embed funcCompiler because
// expressions can appear at top level.
type exprCompiler struct {
*compiler;
// The block this expression is being compiled in.
block *block;
// Whether this expression is used in a constant context.
constant bool;
} }
func (a *exprCompiler) DoIdent(x *ast.Ident) { func (a *exprCompiler) compile(x ast.Expr) *expr {
level, def := a.block.Lookup(x.Value); ei := &exprInfo{a.compiler, x.Pos()};
switch x := x.(type) {
// Literals
case *ast.CharLit:
return ei.compileCharLit(string(x.Value));
case *ast.CompositeLit:
goto notimpl;
case *ast.FloatLit:
return ei.compileFloatLit(string(x.Value));
case *ast.FuncLit:
decl := ei.compileFuncType(a.block, x.Type);
if decl == nil {
// TODO(austin) Try compiling the body,
// perhaps with dummy argument definitions
return nil;
}
fn := ei.compileFunc(a.block, decl, x.Body);
if fn == nil {
return nil;
}
if a.constant {
a.diagAt(x, "function literal used in constant expression");
return nil;
}
return ei.compileFuncLit(decl, fn);
case *ast.IntLit:
return ei.compileIntLit(string(x.Value));
case *ast.StringLit:
return ei.compileStringLit(string(x.Value));
// Types
case *ast.ArrayType:
goto notimpl;
case *ast.ChanType:
goto notimpl;
case *ast.Ellipsis:
goto notimpl;
case *ast.FuncType:
goto notimpl;
case *ast.InterfaceType:
goto notimpl;
case *ast.MapType:
goto notimpl;
// Remaining expressions
case *ast.BadExpr:
// Error already reported by parser
return nil;
case *ast.BinaryExpr:
l, r := a.compile(x.X), a.compile(x.Y);
if l == nil || r == nil {
return nil;
}
return ei.compileBinaryExpr(x.Op, l, r);
case *ast.CallExpr:
l := a.compile(x.Fun);
args := make([]*expr, len(x.Args));
bad := false;
for i, arg := range x.Args {
args[i] = a.compile(arg);
if args[i] == nil {
bad = true;
}
}
if l == nil || bad {
return nil;
}
if a.constant {
a.diagAt(x, "function call in constant context");
return nil;
}
return ei.compileCallExpr(a.block, l, args);
case *ast.Ident:
return ei.compileIdent(a.block, a.constant, x.Value);
case *ast.IndexExpr:
if x.End != nil {
a.diagAt(x, "slice expression not implemented");
return nil;
}
l, r := a.compile(x.X), a.compile(x.Index);
if l == nil || r == nil {
return nil;
}
return ei.compileIndexExpr(l, r);
case *ast.KeyValueExpr:
goto notimpl;
case *ast.ParenExpr:
return a.compile(x.X);
case *ast.SelectorExpr:
v := a.compile(x.X);
if v == nil {
return nil;
}
return ei.compileSelectorExpr(v, x.Sel.Value);
case *ast.StarExpr:
v := a.compile(x.X);
if v == nil {
return nil;
}
return ei.compileStarExpr(v);
case *ast.StringList:
strings := make([]*expr, len(x.Strings));
bad := false;
for i, s := range x.Strings {
strings[i] = a.compile(s);
if strings[i] == nil {
bad = true;
}
}
if bad {
return nil;
}
return ei.compileStringList(strings);
case *ast.StructType:
goto notimpl;
case *ast.TypeAssertExpr:
goto notimpl;
case *ast.UnaryExpr:
v := a.compile(x.X);
if v == nil {
return nil;
}
return ei.compileUnaryExpr(x.Op, v);
}
log.Crashf("unexpected ast node type %T", x);
panic();
notimpl:
a.diagAt(x, "%T expression node not implemented", x);
return nil;
}
func (a *exprInfo) compileIdent(b *block, constant bool, name string) *expr {
level, def := b.Lookup(name);
if def == nil { if def == nil {
a.diag("%s: undefined", x.Value); a.diag("%s: undefined", name);
return; return nil;
} }
switch def := def.(type) { switch def := def.(type) {
case *Constant: case *Constant:
a.t = def.Type; expr := a.newExpr(def.Type, "constant");
a.genConstant(def.Value); expr.genConstant(def.Value);
a.desc = "constant"; return expr;
case *Variable: case *Variable:
if a.constant { if constant {
a.diag("variable %s used in constant expression", x.Value); a.diag("variable %s used in constant expression", name);
return; return nil;
}
if def.Type == nil {
// Placeholder definition from an earlier error
return;
} }
a.t = def.Type; return a.compileVariable(level, def);
defidx := def.Index;
a.genIdentOp(level, defidx);
a.desc = "variable";
case Type: case Type:
a.diag("type %v used as expression", x.Value); a.diag("type %v used as expression", name);
default: return nil;
log.Crashf("name %s has unknown type %T", x.Value, def); }
log.Crashf("name %s has unknown type %T", name, def);
panic();
}
func (a *exprInfo) compileVariable(level int, v *Variable) *expr {
if v.Type == nil {
// Placeholder definition from an earlier error
return nil;
} }
expr := a.newExpr(v.Type, "variable");
expr.genIdentOp(level, v.Index);
return expr;
} }
func (a *exprCompiler) doIdealInt(i *bignum.Integer) { func (a *exprInfo) compileIdealInt(i *bignum.Integer, desc string) *expr {
a.t = IdealIntType; expr := a.newExpr(IdealIntType, desc);
a.evalIdealInt = func() *bignum.Integer { return i }; expr.evalIdealInt = func() *bignum.Integer { return i };
return expr;
} }
func (a *exprCompiler) DoIntLit(x *ast.IntLit) { func (a *exprInfo) compileIntLit(lit string) *expr {
i, _, _2 := bignum.IntFromString(string(x.Value), 0); i, _, _2 := bignum.IntFromString(lit, 0);
a.doIdealInt(i); return a.compileIdealInt(i, "integer literal");
a.desc = "integer literal";
} }
func (a *exprCompiler) DoCharLit(x *ast.CharLit) { func (a *exprInfo) compileCharLit(lit string) *expr {
if x.Value[0] != '\'' { if lit[0] != '\'' {
log.Crashf("malformed character literal %s at %v passed parser", x.Value, x.Pos()); log.Crashf("malformed character literal %s at %v passed parser", lit, a.pos);
} }
v, mb, tail, err := strconv.UnquoteChar(string(x.Value[1:len(x.Value)]), '\''); v, mb, tail, err := strconv.UnquoteChar(lit[1:len(lit)], '\'');
if err != nil || tail != "'" { if err != nil || tail != "'" {
log.Crashf("malformed character literal %s at %v passed parser", x.Value, x.Pos()); log.Crashf("malformed character literal %s at %v passed parser", lit, a.pos);
} }
a.doIdealInt(bignum.Int(int64(v))); return a.compileIdealInt(bignum.Int(int64(v)), "character literal");
a.desc = "character literal";
} }
func (a *exprCompiler) DoFloatLit(x *ast.FloatLit) { func (a *exprInfo) compileFloatLit(lit string) *expr {
f, _, n := bignum.RatFromString(string(x.Value), 0); f, _, n := bignum.RatFromString(lit, 0);
if n != len(x.Value) { if n != len(lit) {
log.Crashf("malformed float literal %s at %v passed parser", x.Value, x.Pos()); log.Crashf("malformed float literal %s at %v passed parser", lit, a.pos);
} }
a.t = IdealFloatType; expr := a.newExpr(IdealFloatType, "float literal");
a.evalIdealFloat = func() *bignum.Rational { return f }; expr.evalIdealFloat = func() *bignum.Rational { return f };
a.desc = "float literal"; return expr;
} }
func (a *exprCompiler) doString(s string) { func (a *exprInfo) compileString(s string) *expr {
// Ideal strings don't have a named type but they are // Ideal strings don't have a named type but they are
// compatible with type string. // compatible with type string.
// TODO(austin) Use unnamed string type. // TODO(austin) Use unnamed string type.
a.t = StringType; expr := a.newExpr(StringType, "string literal");
a.evalString = func(*Frame) string { return s }; expr.evalString = func(*Frame) string { return s };
return expr;
} }
func (a *exprCompiler) DoStringLit(x *ast.StringLit) { func (a *exprInfo) compileStringLit(lit string) *expr {
s, err := strconv.Unquote(string(x.Value)); s, err := strconv.Unquote(lit);
if err != nil { if err != nil {
a.diag("illegal string literal, %v", err); a.diag("illegal string literal, %v", err);
return; return nil;
}
a.doString(s);
a.desc = "string literal";
}
func (a *exprCompiler) DoStringList(x *ast.StringList) {
ss := make([]string, len(x.Strings));
for i := 0; i < len(x.Strings); i++ {
s, err := strconv.Unquote(string(x.Strings[i].Value));
if err != nil {
a.diag("illegal string literal, %v", err);
return;
}
ss[i] = s;
} }
a.doString(strings.Join(ss, "")); return a.compileString(s);
a.desc = "string literal";
} }
func (a *exprCompiler) DoFuncLit(x *ast.FuncLit) { func (a *exprInfo) compileStringList(list []*expr) *expr {
// TODO(austin) Closures capture their entire defining frame ss := make([]string, len(list));
// instead of just the variables they use. for i, s := range list {
ss[i] = s.asString()(nil);
decl := a.compileFuncType(a.block, x.Type);
if decl == nil {
// TODO(austin) Try compiling the body, perhaps with
// dummy definitions for the arguments
return;
} }
return a.compileString(strings.Join(ss, ""));
evalFunc := a.compileFunc(a.block, decl, x.Body);
if evalFunc == nil {
return;
}
if a.constant {
a.diag("function literal used in constant expression");
return;
}
a.t = decl.Type;
a.evalFunc = evalFunc;
} }
func (a *exprCompiler) DoCompositeLit(x *ast.CompositeLit) { func (a *exprInfo) compileFuncLit(decl *FuncDecl, fn func(f *Frame) Func) *expr {
log.Crash("Not implemented"); expr := a.newExpr(decl.Type, "function literal");
expr.evalFunc = fn;
return expr;
} }
func (a *exprCompiler) DoParenExpr(x *ast.ParenExpr) { func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr {
x.X.Visit(a);
}
func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) {
v := a.copyVisit(x.X);
if v.t == nil {
return;
}
// mark marks a field that matches the selector name. It // mark marks a field that matches the selector name. It
// tracks the best depth found so far and whether more than // tracks the best depth found so far and whether more than
// one field has been found at that depth. // one field has been found at that depth.
...@@ -732,18 +835,20 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) { ...@@ -732,18 +835,20 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) {
amberr += "\n\t" + pathName[1:len(pathName)]; amberr += "\n\t" + pathName[1:len(pathName)];
}; };
name := x.Sel.Value;
visited := make(map[Type] bool); visited := make(map[Type] bool);
// find recursively searches for the named field, starting at // find recursively searches for the named field, starting at
// type t. If it finds the named field, it returns a function // type t. If it finds the named field, it returns a function
// which takes an exprCompiler that retrieves a value of type // which takes an expr that represents a value of type 't' and
// 't' and fills 'a' to retrieve the named field. We delay // returns an expr that retrieves the named field. We delay
// exprCompiler construction to avoid filling in anything // expr construction to avoid producing lots of useless expr's
// until we're sure we have the right field, and to avoid // as we search.
// producing lots of garbage exprCompilers as we search. //
var find func(Type, int, string) (func (*exprCompiler)); // TODO(austin) Now that the expression compiler works on
find = func(t Type, depth int, pathName string) (func (*exprCompiler)) { // semantic values instead of AST's, there should be a much
// better way of doing this.
var find func(Type, int, string) (func (*expr) *expr);
find = func(t Type, depth int, pathName string) (func (*expr) *expr) {
// Don't bother looking if we've found something shallower // Don't bother looking if we've found something shallower
if bestDepth != -1 && bestDepth < depth { if bestDepth != -1 && bestDepth < depth {
return nil; return nil;
...@@ -773,23 +878,20 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) { ...@@ -773,23 +878,20 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) {
} }
// If it's a struct type, check fields and embedded types // If it's a struct type, check fields and embedded types
var builder func(*exprCompiler); var builder func(*expr) *expr;
if t, ok := t.(*StructType); ok { if t, ok := t.(*StructType); ok {
for i, f := range t.Elems { for i, f := range t.Elems {
var this *exprCompiler; var sub func(*expr) *expr;
var sub func(*exprCompiler);
switch { switch {
case f.Name == name: case f.Name == name:
mark(depth, pathName + "." + name); mark(depth, pathName + "." + name);
this = a; sub = func(e *expr) *expr { return e };
sub = func(*exprCompiler) {};
case f.Anonymous: case f.Anonymous:
sub = find(f.Type, depth+1, pathName + "." + f.Name); sub = find(f.Type, depth+1, pathName + "." + f.Name);
if sub == nil { if sub == nil {
continue; continue;
} }
this = a.copy();
default: default:
continue; continue;
...@@ -799,22 +901,17 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) { ...@@ -799,22 +901,17 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) {
// builder for accessing this field. // builder for accessing this field.
ft := f.Type; ft := f.Type;
index := i; index := i;
builder = func(parent *exprCompiler) { builder = func(parent *expr) *expr {
this.t = ft;
var evalAddr func(f *Frame) Value;
if deref { if deref {
pf := parent.asPtr(); parent = a.compileStarExpr(parent);
evalAddr = func(f *Frame) Value {
return pf(f).(StructValue).Field(index);
};
} else {
pf := parent.asStruct();
evalAddr = func(f *Frame) Value {
return pf(f).Field(index);
};
} }
this.genValue(evalAddr); expr := a.newExpr(ft, "selector expression");
sub(this); pf := parent.asStruct();
evalAddr := func(f *Frame) Value {
return pf(f).Field(index);
};
expr.genValue(evalAddr);
return sub(expr);
}; };
} }
} }
...@@ -825,31 +922,25 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) { ...@@ -825,31 +922,25 @@ func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) {
builder := find(v.t, 0, ""); builder := find(v.t, 0, "");
if builder == nil { if builder == nil {
a.diag("type %v has no field or method %s", v.t, name); a.diag("type %v has no field or method %s", v.t, name);
return; return nil;
} }
if ambig { if ambig {
a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr); a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr);
return; return nil;
} }
a.desc = "selector expression"; return builder(v);
builder(v);
} }
func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
l, r := a.copyVisit(x.X), a.copyVisit(x.Index);
if l.t == nil || r.t == nil {
return;
}
// Type check object // Type check object
if lt, ok := l.t.lit().(*PtrType); ok { if lt, ok := l.t.lit().(*PtrType); ok {
if et, ok := lt.Elem.lit().(*ArrayType); ok { if et, ok := lt.Elem.lit().(*ArrayType); ok {
// Automatic dereference // Automatic dereference
nl := l.copy(); l = a.compileStarExpr(l);
nl.t = et; if l == nil {
nl.genStarOp(l); return nil;
l = nl; }
} }
} }
...@@ -876,17 +967,17 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { ...@@ -876,17 +967,17 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) {
if r.t.isIdeal() { if r.t.isIdeal() {
r = r.convertTo(lt.Key); r = r.convertTo(lt.Key);
if r == nil { if r == nil {
return; return nil;
} }
} }
if !lt.Key.compat(r.t, false) { if !lt.Key.compat(r.t, false) {
a.diag("cannot use %s as index into %s", r.t, lt); a.diag("cannot use %s as index into %s", r.t, lt);
return; return nil;
} }
default: default:
a.diag("cannot index into %v", l.t); a.diag("cannot index into %v", l.t);
return; return nil;
} }
// Type check index and convert to int if necessary // Type check index and convert to int if necessary
...@@ -899,17 +990,16 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { ...@@ -899,17 +990,16 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) {
val := r.asIdealInt()(); val := r.asIdealInt()();
if val.IsNeg() || (maxIndex != -1 && val.Cmp(bignum.Int(maxIndex)) >= 0) { if val.IsNeg() || (maxIndex != -1 && val.Cmp(bignum.Int(maxIndex)) >= 0) {
a.diag("array index out of bounds"); a.diag("array index out of bounds");
return; return nil;
} }
r = r.convertTo(IntType); r = r.convertTo(IntType);
if r == nil { if r == nil {
return; return nil;
} }
case *uintType: case *uintType:
// Convert to int // Convert to int
nr := r.copy(); nr := a.newExpr(IntType, r.desc);
nr.t = IntType;
rf := r.asUint(); rf := r.asUint();
nr.evalInt = func(f *Frame) int64 { nr.evalInt = func(f *Frame) int64 {
return int64(rf(f)); return int64(rf(f));
...@@ -921,31 +1011,30 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { ...@@ -921,31 +1011,30 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) {
default: default:
a.diag("illegal operand type for index\n\t%v", r.t); a.diag("illegal operand type for index\n\t%v", r.t);
return; return nil;
} }
} }
a.t = at; expr := a.newExpr(at, "index expression");
a.desc = "index expression";
// Compile // Compile
switch lt := l.t.lit().(type) { switch lt := l.t.lit().(type) {
case *ArrayType: case *ArrayType:
// TODO(austin) Bounds check // TODO(austin) Bounds check
a.genIndexArray(l, r); expr.genIndexArray(l, r);
lf := l.asArray(); lf := l.asArray();
rf := r.asInt(); rf := r.asInt();
a.evalAddr = func(f *Frame) Value { expr.evalAddr = func(f *Frame) Value {
return lf(f).Elem(rf(f)); return lf(f).Elem(rf(f));
}; };
case *SliceType: case *SliceType:
// TODO(austin) Bounds check // TODO(austin) Bounds check
// TODO(austin) Can this be done with genValue? // TODO(austin) Can this be done with genValue?
a.genIndexSlice(l, r); expr.genIndexSlice(l, r);
lf := l.asSlice(); lf := l.asSlice();
rf := r.asInt(); rf := r.asInt();
a.evalAddr = func(f *Frame) Value { expr.evalAddr = func(f *Frame) Value {
return lf(f).Base.Elem(rf(f)); return lf(f).Base.Elem(rf(f));
}; };
...@@ -955,7 +1044,7 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { ...@@ -955,7 +1044,7 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) {
rf := r.asInt(); rf := r.asInt();
// TODO(austin) This pulls over the whole string in a // TODO(austin) This pulls over the whole string in a
// remote setting, instead of just the one character. // remote setting, instead of just the one character.
a.evalUint = func(f *Frame) uint64 { expr.evalUint = func(f *Frame) uint64 {
return uint64(lf(f)[rf(f)]); return uint64(lf(f)[rf(f)]);
} }
...@@ -963,7 +1052,7 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { ...@@ -963,7 +1052,7 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) {
// TODO(austin) Bounds check // TODO(austin) Bounds check
lf := l.asMap(); lf := l.asMap();
rf := r.asInterface(); rf := r.asInterface();
a.genValue(func(f *Frame) Value { expr.genValue(func(f *Frame) Value {
m := lf(f); m := lf(f);
k := rf(f); k := rf(f);
e := m.Elem(k); e := m.Elem(k);
...@@ -975,21 +1064,19 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { ...@@ -975,21 +1064,19 @@ func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) {
}); });
// genValue makes things addressable, but map values // genValue makes things addressable, but map values
// aren't addressable. // aren't addressable.
a.evalAddr = nil; expr.evalAddr = nil;
a.evalMapValue = func(f *Frame) (Map, interface{}) { expr.evalMapValue = func(f *Frame) (Map, interface{}) {
return lf(f), rf(f); return lf(f), rf(f);
}; };
default: default:
log.Crashf("unexpected left operand type %T", l.t.lit()); log.Crashf("unexpected left operand type %T", l.t.lit());
} }
}
func (a *exprCompiler) DoTypeAssertExpr(x *ast.TypeAssertExpr) { return expr;
log.Crash("Not implemented");
} }
func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { func (a *exprInfo) compileCallExpr(b *block, l *expr, as []*expr) *expr {
// TODO(austin) Type conversions look like calls, but will // TODO(austin) Type conversions look like calls, but will
// fail in DoIdent right now. // fail in DoIdent right now.
// //
...@@ -997,28 +1084,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -997,28 +1084,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
// //
// TODO(austin) Variadic functions. // TODO(austin) Variadic functions.
// Compile children
bad := false;
l := a.copyVisit(x.Fun);
if l.t == nil {
bad = true;
}
as := make([]*exprCompiler, len(x.Args));
for i := 0; i < len(x.Args); i++ {
as[i] = a.copyVisit(x.Args[i]);
if as[i].t == nil {
bad = true;
}
}
if bad {
return;
}
// Type check // Type check
if a.constant {
a.diag("function call in constant context");
return;
}
// XXX(Spec) Calling a named function type is okay. I really // XXX(Spec) Calling a named function type is okay. I really
// think there needs to be a general discussion of named // think there needs to be a general discussion of named
...@@ -1029,7 +1095,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -1029,7 +1095,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
lt, ok := l.t.lit().(*FuncType); lt, ok := l.t.lit().(*FuncType);
if !ok { if !ok {
a.diag("cannot call non-function type %v", l.t); a.diag("cannot call non-function type %v", l.t);
return; return nil;
} }
// The arguments must be single-valued expressions assignment // The arguments must be single-valued expressions assignment
...@@ -1038,20 +1104,22 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -1038,20 +1104,22 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
// XXX(Spec) The spec is wrong. It can also be a single // XXX(Spec) The spec is wrong. It can also be a single
// multi-valued expression. // multi-valued expression.
nin := len(lt.In); nin := len(lt.In);
assign := a.compileAssign(x.Pos(), NewMultiType(lt.In), as, "function call", "argument"); assign := a.compileAssign(a.pos, b, NewMultiType(lt.In), as, "function call", "argument");
if assign == nil { if assign == nil {
return; return nil;
} }
var t Type;
nout := len(lt.Out); nout := len(lt.Out);
switch nout { switch nout {
case 0: case 0:
a.t = EmptyType; t = EmptyType;
case 1: case 1:
a.t = lt.Out[0]; t = lt.Out[0];
default: default:
a.t = NewMultiType(lt.Out); t = NewMultiType(lt.Out);
} }
expr := a.newExpr(t, "function call");
// Gather argument and out types to initialize frame variables // Gather argument and out types to initialize frame variables
vts := make([]Type, nin + nout); vts := make([]Type, nin + nout);
...@@ -1074,62 +1142,50 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -1074,62 +1142,50 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
fun.Call(fr); fun.Call(fr);
return fr.Vars[nin:nin+nout]; return fr.Vars[nin:nin+nout];
}; };
a.genFuncCall(call); expr.genFuncCall(call);
}
func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) { return expr;
v := a.copyVisit(x.X); }
if v.t == nil {
return;
}
func (a *exprInfo) compileStarExpr(v *expr) *expr {
switch vt := v.t.lit().(type) { switch vt := v.t.lit().(type) {
case *PtrType: case *PtrType:
a.t = vt.Elem; expr := a.newExpr(vt.Elem, "indirect expression");
// TODO(austin) Deal with nil pointers // TODO(austin) Deal with nil pointers
a.genStarOp(v); expr.genValue(v.asPtr());
a.desc = "indirect expression"; return expr;
default:
a.diagOpType(token.MUL, v.t);
} }
}
func (a *exprCompiler) genUnaryAddrOf(v *exprCompiler) { a.diagOpType(token.MUL, v.t);
vf := v.evalAddr; return nil;
a.evalPtr = func(f *Frame) Value { return vf(f) };
} }
var unaryOpDescs = make(map[token.Token] string) var unaryOpDescs = make(map[token.Token] string)
func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) { func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr {
v := a.copyVisit(x.X);
if v.t == nil {
return;
}
// Type check // Type check
switch x.Op { var t Type;
switch op {
case token.ADD, token.SUB: case token.ADD, token.SUB:
if !v.t.isInteger() && !v.t.isFloat() { if !v.t.isInteger() && !v.t.isFloat() {
a.diagOpType(x.Op, v.t); a.diagOpType(op, v.t);
return; return nil;
} }
a.t = v.t; t = v.t;
case token.NOT: case token.NOT:
if !v.t.isBoolean() { if !v.t.isBoolean() {
a.diagOpType(x.Op, v.t); a.diagOpType(op, v.t);
return; return nil;
} }
a.t = BoolType; t = BoolType;
case token.XOR: case token.XOR:
if !v.t.isInteger() { if !v.t.isInteger() {
a.diagOpType(x.Op, v.t); a.diagOpType(op, v.t);
return; return nil;
} }
a.t = v.t; t = v.t;
case token.AND: case token.AND:
// The unary prefix address-of operator & generates // The unary prefix address-of operator & generates
...@@ -1138,55 +1194,59 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) { ...@@ -1138,55 +1194,59 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
// array or slice indexing operation. // array or slice indexing operation.
if v.evalAddr == nil { if v.evalAddr == nil {
a.diag("cannot take the address of %s", v.desc); a.diag("cannot take the address of %s", v.desc);
return; return nil;
} }
// TODO(austin) Implement "It is illegal to take the // TODO(austin) Implement "It is illegal to take the
// address of a function result variable" once I have // address of a function result variable" once I have
// function result variables. // function result variables.
a.t = NewPtrType(v.t); t = NewPtrType(v.t);
case token.ARROW: case token.ARROW:
log.Crashf("Unary op %v not implemented", x.Op); log.Crashf("Unary op %v not implemented", op);
default: default:
log.Crashf("unknown unary operator %v", x.Op); log.Crashf("unknown unary operator %v", op);
} }
var ok bool; desc, ok := unaryOpDescs[op];
a.desc, ok = unaryOpDescs[x.Op];
if !ok { if !ok {
a.desc = "unary " + x.Op.String() + " expression"; desc = "unary " + op.String() + " expression";
unaryOpDescs[x.Op] = a.desc; unaryOpDescs[op] = desc;
} }
// Compile // Compile
switch x.Op { expr := a.newExpr(t, desc);
switch op {
case token.ADD: case token.ADD:
// Just compile it out // Just compile it out
*a = *v; expr = v;
expr.desc = desc;
case token.SUB: case token.SUB:
a.genUnaryOpNeg(v); expr.genUnaryOpNeg(v);
case token.NOT: case token.NOT:
a.genUnaryOpNot(v); expr.genUnaryOpNot(v);
case token.XOR: case token.XOR:
a.genUnaryOpXor(v); expr.genUnaryOpXor(v);
case token.AND: case token.AND:
a.genUnaryAddrOf(v); vf := v.evalAddr;
expr.evalPtr = func(f *Frame) Value { return vf(f) };
default: default:
log.Crashf("Compilation of unary op %v not implemented", x.Op); log.Crashf("Compilation of unary op %v not implemented", op);
} }
return expr;
} }
var binOpDescs = make(map[token.Token] string) var binOpDescs = make(map[token.Token] string)
func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
// Save the original types of l.t and r.t for error messages. // Save the original types of l.t and r.t for error messages.
origlt := l.t; origlt := l.t;
origrt := r.t; origrt := r.t;
...@@ -1215,7 +1275,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1215,7 +1275,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
l = l.convertTo(r.t); l = l.convertTo(r.t);
} }
if l == nil || r == nil { if l == nil || r == nil {
return; return nil;
} }
// Except in shift expressions, if both operands are // Except in shift expressions, if both operands are
...@@ -1228,7 +1288,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1228,7 +1288,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
r = r.convertTo(l.t); r = r.convertTo(l.t);
} }
if l == nil || r == nil { if l == nil || r == nil {
return; return nil;
} }
} }
} }
...@@ -1253,27 +1313,28 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1253,27 +1313,28 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
}; };
// Type check // Type check
var t Type;
switch op { switch op {
case token.ADD: case token.ADD:
if !compat() || (!integers() && !floats() && !strings()) { if !compat() || (!integers() && !floats() && !strings()) {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
a.t = l.t; t = l.t;
case token.SUB, token.MUL, token.QUO: case token.SUB, token.MUL, token.QUO:
if !compat() || (!integers() && !floats()) { if !compat() || (!integers() && !floats()) {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
a.t = l.t; t = l.t;
case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT: case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
if !compat() || !integers() { if !compat() || !integers() {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
a.t = l.t; t = l.t;
case token.SHL, token.SHR: case token.SHL, token.SHR:
// XXX(Spec) Is it okay for the right operand to be an // XXX(Spec) Is it okay for the right operand to be an
...@@ -1285,7 +1346,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1285,7 +1346,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) { if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
// The right operand in a shift operation must be // The right operand in a shift operation must be
...@@ -1295,7 +1356,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1295,7 +1356,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
if r.t.isIdeal() { if r.t.isIdeal() {
r2 := r.convertTo(UintType); r2 := r.convertTo(UintType);
if r2 == nil { if r2 == nil {
return; return nil;
} }
// If the left operand is not ideal, convert // If the left operand is not ideal, convert
...@@ -1314,7 +1375,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1314,7 +1375,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
} }
} else if _, ok := r.t.lit().(*uintType); !ok { } else if _, ok := r.t.lit().(*uintType); !ok {
a.diag("right operand of shift must be unsigned"); a.diag("right operand of shift must be unsigned");
return; return nil;
} }
if l.t.isIdeal() && !r.t.isIdeal() { if l.t.isIdeal() && !r.t.isIdeal() {
...@@ -1325,7 +1386,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1325,7 +1386,7 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
l = l.convertTo(IntType); l = l.convertTo(IntType);
if l == nil { if l == nil {
return; return nil;
} }
} }
...@@ -1334,11 +1395,11 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1334,11 +1395,11 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
// 2) int SHIFT uint // 2) int SHIFT uint
// 3) ideal int SHIFT ideal int // 3) ideal int SHIFT ideal int
a.t = l.t; t = l.t;
case token.LOR, token.LAND: case token.LOR, token.LAND:
if !booleans() { if !booleans() {
return; return nil;
} }
// XXX(Spec) There's no mention of *which* boolean // XXX(Spec) There's no mention of *which* boolean
// type the logical operators return. From poking at // type the logical operators return. From poking at
...@@ -1346,14 +1407,14 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1346,14 +1407,14 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
// the type of the left operand, and NOT an unnamed // the type of the left operand, and NOT an unnamed
// boolean type. // boolean type.
a.t = BoolType; t = BoolType;
case token.ARROW: case token.ARROW:
// The operands in channel sends differ in type: one // The operands in channel sends differ in type: one
// is always a channel and the other is a variable or // is always a channel and the other is a variable or
// value of the channel's element type. // value of the channel's element type.
log.Crash("Binary op <- not implemented"); log.Crash("Binary op <- not implemented");
a.t = BoolType; t = BoolType;
case token.LSS, token.GTR, token.LEQ, token.GEQ: case token.LSS, token.GTR, token.LEQ, token.GEQ:
// XXX(Spec) It's really unclear what types which // XXX(Spec) It's really unclear what types which
...@@ -1366,9 +1427,9 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1366,9 +1427,9 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
if !compat() || (!integers() && !floats() && !strings()) { if !compat() || (!integers() && !floats() && !strings()) {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
a.t = BoolType; t = BoolType;
case token.EQL, token.NEQ: case token.EQL, token.NEQ:
// XXX(Spec) The rules for type checking comparison // XXX(Spec) The rules for type checking comparison
...@@ -1409,65 +1470,65 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1409,65 +1470,65 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
if !compat() { if !compat() {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
// Arrays and structs may not be compared to anything. // Arrays and structs may not be compared to anything.
// TODO(austin) Use a multi-type switch // TODO(austin) Use a multi-type switch
if _, ok := l.t.(*ArrayType); ok { if _, ok := l.t.(*ArrayType); ok {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
if _, ok := l.t.(*StructType); ok { if _, ok := l.t.(*StructType); ok {
a.diagOpTypes(op, origlt, origrt); a.diagOpTypes(op, origlt, origrt);
return; return nil;
} }
a.t = BoolType; t = BoolType;
default: default:
log.Crashf("unknown binary operator %v", op); log.Crashf("unknown binary operator %v", op);
} }
var ok bool; desc, ok := binOpDescs[op];
a.desc, ok = binOpDescs[op];
if !ok { if !ok {
a.desc = op.String() + " expression"; desc = op.String() + " expression";
binOpDescs[op] = a.desc; binOpDescs[op] = desc;
} }
// Compile // Compile
expr := a.newExpr(t, desc);
switch op { switch op {
case token.ADD: case token.ADD:
a.genBinOpAdd(l, r); expr.genBinOpAdd(l, r);
case token.SUB: case token.SUB:
a.genBinOpSub(l, r); expr.genBinOpSub(l, r);
case token.MUL: case token.MUL:
a.genBinOpMul(l, r); expr.genBinOpMul(l, r);
case token.QUO: case token.QUO:
// TODO(austin) What if divisor is zero? // TODO(austin) What if divisor is zero?
// TODO(austin) Clear higher bits that may have // TODO(austin) Clear higher bits that may have
// accumulated in our temporary. // accumulated in our temporary.
a.genBinOpQuo(l, r); expr.genBinOpQuo(l, r);
case token.REM: case token.REM:
// TODO(austin) What if divisor is zero? // TODO(austin) What if divisor is zero?
// TODO(austin) Clear higher bits that may have // TODO(austin) Clear higher bits that may have
// accumulated in our temporary. // accumulated in our temporary.
a.genBinOpRem(l, r); expr.genBinOpRem(l, r);
case token.AND: case token.AND:
a.genBinOpAnd(l, r); expr.genBinOpAnd(l, r);
case token.OR: case token.OR:
a.genBinOpOr(l, r); expr.genBinOpOr(l, r);
case token.XOR: case token.XOR:
a.genBinOpXor(l, r); expr.genBinOpXor(l, r);
case token.AND_NOT: case token.AND_NOT:
a.genBinOpAndNot(l, r); expr.genBinOpAndNot(l, r);
case token.SHL: case token.SHL:
if l.t.isIdeal() { if l.t.isIdeal() {
...@@ -1476,13 +1537,13 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1476,13 +1537,13 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
const maxShift = 99999; const maxShift = 99999;
if rv.Cmp(bignum.Int(maxShift)) > 0 { if rv.Cmp(bignum.Int(maxShift)) > 0 {
a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift); a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift);
a.t = nil; expr.t = nil;
return; return nil;
} }
val := lv.Shl(uint(rv.Value())); val := lv.Shl(uint(rv.Value()));
a.evalIdealInt = func() *bignum.Integer { return val }; expr.evalIdealInt = func() *bignum.Integer { return val };
} else { } else {
a.genBinOpShl(l, r); expr.genBinOpShl(l, r);
} }
case token.SHR: case token.SHR:
...@@ -1490,79 +1551,40 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { ...@@ -1490,79 +1551,40 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
lv := l.asIdealInt()(); lv := l.asIdealInt()();
rv := r.asIdealInt()(); rv := r.asIdealInt()();
val := lv.Shr(uint(rv.Value())); val := lv.Shr(uint(rv.Value()));
a.evalIdealInt = func() *bignum.Integer { return val }; expr.evalIdealInt = func() *bignum.Integer { return val };
} else { } else {
a.genBinOpShr(l, r); expr.genBinOpShr(l, r);
} }
case token.LSS: case token.LSS:
a.genBinOpLss(l, r); expr.genBinOpLss(l, r);
case token.GTR: case token.GTR:
a.genBinOpGtr(l, r); expr.genBinOpGtr(l, r);
case token.LEQ: case token.LEQ:
a.genBinOpLeq(l, r); expr.genBinOpLeq(l, r);
case token.GEQ: case token.GEQ:
a.genBinOpGeq(l, r); expr.genBinOpGeq(l, r);
case token.EQL: case token.EQL:
a.genBinOpEql(l, r); expr.genBinOpEql(l, r);
case token.NEQ: case token.NEQ:
a.genBinOpNeq(l, r); expr.genBinOpNeq(l, r);
default: default:
log.Crashf("Compilation of binary op %v not implemented", op); log.Crashf("Compilation of binary op %v not implemented", op);
} }
}
func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) { return expr;
l, r := a.copyVisit(x.X), a.copyVisit(x.Y);
if l.t == nil || r.t == nil {
return;
}
a.doBinaryExpr(x.Op, l, r);
}
func (a *exprCompiler) DoKeyValueExpr(x *ast.KeyValueExpr) {
log.Crash("Not implemented");
}
func (a *exprCompiler) DoEllipsis(x *ast.Ellipsis) {
log.Crash("Not implemented");
}
func (a *exprCompiler) DoArrayType(x *ast.ArrayType) {
log.Crash("Not implemented");
}
func (a *exprCompiler) DoStructType(x *ast.StructType) {
log.Crash("Not implemented");
}
func (a *exprCompiler) DoFuncType(x *ast.FuncType) {
log.Crash("Not implemented");
}
func (a *exprCompiler) DoInterfaceType(x *ast.InterfaceType) {
log.Crash("Not implemented");
}
func (a *exprCompiler) DoMapType(x *ast.MapType) {
log.Crash("Not implemented");
}
func (a *exprCompiler) DoChanType(x *ast.ChanType) {
log.Crash("Not implemented");
} }
// TODO(austin) This is a hack to eliminate a circular dependency // TODO(austin) This is a hack to eliminate a circular dependency
// between type.go and expr.go // between type.go and expr.go
func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) { func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
lenExpr := a.compileExpr(b, expr, true); lenExpr := a.compileExpr(b, true, expr);
if lenExpr == nil { if lenExpr == nil {
return 0, false; return 0, false;
} }
...@@ -1590,13 +1612,9 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) { ...@@ -1590,13 +1612,9 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
return 0, false; return 0, false;
} }
func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprCompiler { func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
ec := newExprCompiler(&exprContext{a, b, constant}, expr.Pos()); ec := &exprCompiler{a, b, constant};
expr.Visit(ec); return ec.compile(expr);
if ec.t == nil {
return nil;
}
return ec;
} }
// extractEffect separates out any effects that the expression may // extractEffect separates out any effects that the expression may
...@@ -1607,18 +1625,15 @@ func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprComp ...@@ -1607,18 +1625,15 @@ func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprComp
// temporary variable, the caller should create a temporary block for // temporary variable, the caller should create a temporary block for
// the compilation of this expression and the evaluation of the // the compilation of this expression and the evaluation of the
// results. // results.
func (a *exprCompiler) extractEffect(errOp string) (func(f *Frame), *exprCompiler) { func (a *expr) extractEffect(b *block, errOp string) (func(f *Frame), *expr) {
// Create "&a" if a is addressable // Create "&a" if a is addressable
rhs := a; rhs := a;
if a.evalAddr != nil { if a.evalAddr != nil {
rhs = a.copy(); rhs = a.compileUnaryExpr(token.AND, rhs);
rhs.t = NewPtrType(a.t);
rhs.genUnaryAddrOf(a);
} }
// Create temp // Create temp
tempBlock := a.block; ac, ok := a.checkAssign(a.pos, []*expr{rhs}, errOp, "");
ac, ok := a.checkAssign(a.pos, []*exprCompiler{rhs}, errOp, "");
if !ok { if !ok {
return nil, nil; return nil, nil;
} }
...@@ -1638,11 +1653,11 @@ func (a *exprCompiler) extractEffect(errOp string) (func(f *Frame), *exprCompile ...@@ -1638,11 +1653,11 @@ func (a *exprCompiler) extractEffect(errOp string) (func(f *Frame), *exprCompile
log.Crashf("unexpected ideal type %v", tempType); log.Crashf("unexpected ideal type %v", tempType);
} }
} }
temp := tempBlock.DefineSlot(tempType); temp := b.DefineSlot(tempType);
tempIdx := temp.Index; tempIdx := temp.Index;
// Create "temp := rhs" // Create "temp := rhs"
assign := ac.compile(tempType); assign := ac.compile(b, tempType);
if assign == nil { if assign == nil {
log.Crashf("compileAssign type check failed"); log.Crashf("compileAssign type check failed");
} }
...@@ -1654,16 +1669,15 @@ func (a *exprCompiler) extractEffect(errOp string) (func(f *Frame), *exprCompile ...@@ -1654,16 +1669,15 @@ func (a *exprCompiler) extractEffect(errOp string) (func(f *Frame), *exprCompile
}; };
// Generate "temp" or "*temp" // Generate "temp" or "*temp"
getTemp := a.copy(); getTemp := a.compileVariable(0, temp);
getTemp.t = tempType;
getTemp.genIdentOp(0, tempIdx);
if a.evalAddr == nil { if a.evalAddr == nil {
return effect, getTemp; return effect, getTemp;
} }
deref := a.copy(); deref := a.compileStarExpr(getTemp);
deref.t = a.t; if deref == nil {
deref.genStarOp(getTemp); return nil, nil;
}
return effect, deref; return effect, deref;
} }
...@@ -1686,7 +1700,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) { ...@@ -1686,7 +1700,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
errors := scanner.NewErrorVector(); errors := scanner.NewErrorVector();
cc := &compiler{errors}; cc := &compiler{errors};
ec := cc.compileExpr(scope.block, expr, false); ec := cc.compileExpr(scope.block, false, expr);
if ec == nil { if ec == nil {
return nil, errors.GetError(scanner.Sorted); return nil, errors.GetError(scanner.Sorted);
} }
...@@ -1723,7 +1737,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) { ...@@ -1723,7 +1737,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
* Everything below here is MACHINE GENERATED by gen.py genOps * Everything below here is MACHINE GENERATED by gen.py genOps
*/ */
func (a *exprCompiler) genConstant(v Value) { func (a *expr) genConstant(v Value) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *boolType: case *boolType:
val := v.(BoolValue).Get(); val := v.(BoolValue).Get();
...@@ -1769,7 +1783,7 @@ func (a *exprCompiler) genConstant(v Value) { ...@@ -1769,7 +1783,7 @@ func (a *exprCompiler) genConstant(v Value) {
} }
} }
func (a *exprCompiler) genIdentOp(level int, index int) { func (a *expr) genIdentOp(level int, index int) {
a.evalAddr = func(f *Frame) Value { return f.Get(level, index) }; a.evalAddr = func(f *Frame) Value { return f.Get(level, index) };
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *boolType: case *boolType:
...@@ -1799,7 +1813,7 @@ func (a *exprCompiler) genIdentOp(level int, index int) { ...@@ -1799,7 +1813,7 @@ func (a *exprCompiler) genIdentOp(level int, index int) {
} }
} }
func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) { func (a *expr) genIndexArray(l, r *expr) {
lf := l.asArray(); lf := l.asArray();
rf := r.asInt(); rf := r.asInt();
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
...@@ -1830,7 +1844,7 @@ func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) { ...@@ -1830,7 +1844,7 @@ func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genIndexSlice(l *exprCompiler, r *exprCompiler) { func (a *expr) genIndexSlice(l, r *expr) {
lf := l.asSlice(); lf := l.asSlice();
rf := r.asInt(); rf := r.asInt();
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
...@@ -1861,7 +1875,7 @@ func (a *exprCompiler) genIndexSlice(l *exprCompiler, r *exprCompiler) { ...@@ -1861,7 +1875,7 @@ func (a *exprCompiler) genIndexSlice(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) { func (a *expr) genFuncCall(call func(f *Frame) []Value) {
a.exec = func(f *Frame) { call(f) }; a.exec = func(f *Frame) { call(f) };
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *boolType: case *boolType:
...@@ -1893,7 +1907,7 @@ func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) { ...@@ -1893,7 +1907,7 @@ func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) {
} }
} }
func (a *exprCompiler) genValue(vf func(*Frame) Value) { func (a *expr) genValue(vf func(*Frame) Value) {
a.evalAddr = vf; a.evalAddr = vf;
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *boolType: case *boolType:
...@@ -1923,7 +1937,7 @@ func (a *exprCompiler) genValue(vf func(*Frame) Value) { ...@@ -1923,7 +1937,7 @@ func (a *exprCompiler) genValue(vf func(*Frame) Value) {
} }
} }
func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler) { func (a *expr) genUnaryOpNeg(v *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
vf := v.asUint(); vf := v.asUint();
...@@ -1947,7 +1961,7 @@ func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler) { ...@@ -1947,7 +1961,7 @@ func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler) {
} }
} }
func (a *exprCompiler) genUnaryOpNot(v *exprCompiler) { func (a *expr) genUnaryOpNot(v *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *boolType: case *boolType:
vf := v.asBool(); vf := v.asBool();
...@@ -1957,7 +1971,7 @@ func (a *exprCompiler) genUnaryOpNot(v *exprCompiler) { ...@@ -1957,7 +1971,7 @@ func (a *exprCompiler) genUnaryOpNot(v *exprCompiler) {
} }
} }
func (a *exprCompiler) genUnaryOpXor(v *exprCompiler) { func (a *expr) genUnaryOpXor(v *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
vf := v.asUint(); vf := v.asUint();
...@@ -1974,7 +1988,7 @@ func (a *exprCompiler) genUnaryOpXor(v *exprCompiler) { ...@@ -1974,7 +1988,7 @@ func (a *exprCompiler) genUnaryOpXor(v *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpAdd(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpAdd(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2007,7 +2021,7 @@ func (a *exprCompiler) genBinOpAdd(l *exprCompiler, r *exprCompiler) { ...@@ -2007,7 +2021,7 @@ func (a *exprCompiler) genBinOpAdd(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpSub(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpSub(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2036,7 +2050,7 @@ func (a *exprCompiler) genBinOpSub(l *exprCompiler, r *exprCompiler) { ...@@ -2036,7 +2050,7 @@ func (a *exprCompiler) genBinOpSub(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpMul(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpMul(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2065,7 +2079,7 @@ func (a *exprCompiler) genBinOpMul(l *exprCompiler, r *exprCompiler) { ...@@ -2065,7 +2079,7 @@ func (a *exprCompiler) genBinOpMul(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpQuo(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpQuo(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2094,7 +2108,7 @@ func (a *exprCompiler) genBinOpQuo(l *exprCompiler, r *exprCompiler) { ...@@ -2094,7 +2108,7 @@ func (a *exprCompiler) genBinOpQuo(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpRem(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpRem(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2114,7 +2128,7 @@ func (a *exprCompiler) genBinOpRem(l *exprCompiler, r *exprCompiler) { ...@@ -2114,7 +2128,7 @@ func (a *exprCompiler) genBinOpRem(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpAnd(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpAnd(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2134,7 +2148,7 @@ func (a *exprCompiler) genBinOpAnd(l *exprCompiler, r *exprCompiler) { ...@@ -2134,7 +2148,7 @@ func (a *exprCompiler) genBinOpAnd(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpOr(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpOr(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2154,7 +2168,7 @@ func (a *exprCompiler) genBinOpOr(l *exprCompiler, r *exprCompiler) { ...@@ -2154,7 +2168,7 @@ func (a *exprCompiler) genBinOpOr(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpXor(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpXor(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2174,7 +2188,7 @@ func (a *exprCompiler) genBinOpXor(l *exprCompiler, r *exprCompiler) { ...@@ -2174,7 +2188,7 @@ func (a *exprCompiler) genBinOpXor(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpAndNot(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpAndNot(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2194,7 +2208,7 @@ func (a *exprCompiler) genBinOpAndNot(l *exprCompiler, r *exprCompiler) { ...@@ -2194,7 +2208,7 @@ func (a *exprCompiler) genBinOpAndNot(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpShl(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpShl(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2209,7 +2223,7 @@ func (a *exprCompiler) genBinOpShl(l *exprCompiler, r *exprCompiler) { ...@@ -2209,7 +2223,7 @@ func (a *exprCompiler) genBinOpShl(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpShr(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpShr(l, r *expr) {
switch _ := a.t.lit().(type) { switch _ := a.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2224,7 +2238,7 @@ func (a *exprCompiler) genBinOpShr(l *exprCompiler, r *exprCompiler) { ...@@ -2224,7 +2238,7 @@ func (a *exprCompiler) genBinOpShr(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpLss(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpLss(l, r *expr) {
switch _ := l.t.lit().(type) { switch _ := l.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2257,7 +2271,7 @@ func (a *exprCompiler) genBinOpLss(l *exprCompiler, r *exprCompiler) { ...@@ -2257,7 +2271,7 @@ func (a *exprCompiler) genBinOpLss(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpGtr(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpGtr(l, r *expr) {
switch _ := l.t.lit().(type) { switch _ := l.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2290,7 +2304,7 @@ func (a *exprCompiler) genBinOpGtr(l *exprCompiler, r *exprCompiler) { ...@@ -2290,7 +2304,7 @@ func (a *exprCompiler) genBinOpGtr(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpLeq(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpLeq(l, r *expr) {
switch _ := l.t.lit().(type) { switch _ := l.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2323,7 +2337,7 @@ func (a *exprCompiler) genBinOpLeq(l *exprCompiler, r *exprCompiler) { ...@@ -2323,7 +2337,7 @@ func (a *exprCompiler) genBinOpLeq(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpGeq(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpGeq(l, r *expr) {
switch _ := l.t.lit().(type) { switch _ := l.t.lit().(type) {
case *uintType: case *uintType:
lf := l.asUint(); lf := l.asUint();
...@@ -2356,7 +2370,7 @@ func (a *exprCompiler) genBinOpGeq(l *exprCompiler, r *exprCompiler) { ...@@ -2356,7 +2370,7 @@ func (a *exprCompiler) genBinOpGeq(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpEql(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpEql(l, r *expr) {
switch _ := l.t.lit().(type) { switch _ := l.t.lit().(type) {
case *boolType: case *boolType:
lf := l.asBool(); lf := l.asBool();
...@@ -2405,7 +2419,7 @@ func (a *exprCompiler) genBinOpEql(l *exprCompiler, r *exprCompiler) { ...@@ -2405,7 +2419,7 @@ func (a *exprCompiler) genBinOpEql(l *exprCompiler, r *exprCompiler) {
} }
} }
func (a *exprCompiler) genBinOpNeq(l *exprCompiler, r *exprCompiler) { func (a *expr) genBinOpNeq(l, r *expr) {
switch _ := l.t.lit().(type) { switch _ := l.t.lit().(type) {
case *boolType: case *boolType:
lf := l.asBool(); lf := l.asBool();
...@@ -2454,7 +2468,7 @@ func (a *exprCompiler) genBinOpNeq(l *exprCompiler, r *exprCompiler) { ...@@ -2454,7 +2468,7 @@ func (a *exprCompiler) genBinOpNeq(l *exprCompiler, r *exprCompiler) {
} }
} }
func genAssign(lt Type, r *exprCompiler) (func(lv Value, f *Frame)) { func genAssign(lt Type, r *expr) (func(lv Value, f *Frame)) {
switch _ := lt.lit().(type) { switch _ := lt.lit().(type) {
case *boolType: case *boolType:
rf := r.asBool(); rf := r.asBool();
......
...@@ -356,7 +356,10 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) { ...@@ -356,7 +356,10 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
} }
func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) { func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
e := a.compileExpr(a.block, s.X, false); bc := a.enterChild();
defer bc.exit();
e := a.compileExpr(bc.block, false, s.X);
if e == nil { if e == nil {
return; return;
} }
...@@ -378,7 +381,7 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) { ...@@ -378,7 +381,7 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
bc := a.enterChild(); bc := a.enterChild();
defer bc.exit(); defer bc.exit();
l := a.compileExpr(bc.block, s.X, false); l := a.compileExpr(bc.block, false, s.X);
if l == nil { if l == nil {
return; return;
} }
...@@ -405,21 +408,18 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) { ...@@ -405,21 +408,18 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
log.Crashf("Unexpected IncDec token %v", s.Tok); log.Crashf("Unexpected IncDec token %v", s.Tok);
} }
effect, l := l.extractEffect(desc); effect, l := l.extractEffect(bc.block, desc);
one := l.copy(); one := l.newExpr(IdealIntType, "constant");
one.pos = s.Pos(); one.pos = s.Pos();
one.t = IdealIntType;
one.evalIdealInt = func() *bignum.Integer { return bignum.Int(1) }; one.evalIdealInt = func() *bignum.Integer { return bignum.Int(1) };
binop := l.copy(); binop := l.compileBinaryExpr(op, l, one);
binop.pos = s.Pos(); if binop == nil {
binop.doBinaryExpr(op, l, one);
if binop.t == nil {
return; return;
} }
assign := a.compileAssign(s.Pos(), l.t, []*exprCompiler{binop}, "", ""); assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "");
if assign == nil { if assign == nil {
log.Crashf("compileAssign type check failed"); log.Crashf("compileAssign type check failed");
} }
...@@ -438,9 +438,9 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, ...@@ -438,9 +438,9 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
// 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
// made on the left side. // made on the left side.
rs := make([]*exprCompiler, len(rhs)); rs := make([]*expr, len(rhs));
for i, re := range rhs { for i, re := range rhs {
rs[i] = a.compileExpr(a.block, re, false); rs[i] = a.compileExpr(a.block, false, re);
if rs[i] == nil { if rs[i] == nil {
bad = true; bad = true;
} }
...@@ -474,7 +474,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, ...@@ -474,7 +474,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
} }
// Compile left side // Compile left side
ls := make([]*exprCompiler, len(lhs)); ls := make([]*expr, len(lhs));
nDefs := 0; nDefs := 0;
for i, le := range lhs { for i, le := range lhs {
// If this is a definition, get the identifier and its type // If this is a definition, get the identifier and its type
...@@ -555,7 +555,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, ...@@ -555,7 +555,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
} }
// Compile LHS // Compile LHS
ls[i] = a.compileExpr(a.block, le, false); ls[i] = a.compileExpr(a.block, false, le);
if ls[i] == nil { if ls[i] == nil {
bad = true; bad = true;
continue; continue;
...@@ -563,12 +563,13 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, ...@@ -563,12 +563,13 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
if ls[i].evalMapValue != nil { if ls[i].evalMapValue != nil {
// Map indexes are not generally addressable, // Map indexes are not generally addressable,
// but they are assignable. If function call // but they are assignable.
// compiling took semantic values, this might //
// TODO(austin) Now that the expression
// compiler uses semantic values, this might
// be easier to implement as a function call. // be easier to implement as a function call.
sub := ls[i]; sub := ls[i];
ls[i] = sub.copy(); ls[i] = ls[i].newExpr(sub.t, sub.desc);
ls[i].t, ls[i].desc = sub.t, sub.desc;
ls[i].evalMapValue = sub.evalMapValue; ls[i].evalMapValue = sub.evalMapValue;
mvf := sub.evalMapValue; mvf := sub.evalMapValue;
et := sub.t; et := sub.t;
...@@ -621,7 +622,9 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, ...@@ -621,7 +622,9 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
} }
lt = NewMultiType(lts); lt = NewMultiType(lts);
} }
assign := ac.compile(lt); bc := a.enterChild();
defer bc.exit();
assign := ac.compile(bc.block, lt);
if assign == nil { if assign == nil {
return; return;
} }
...@@ -690,8 +693,8 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) { ...@@ -690,8 +693,8 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
bc := a.enterChild(); bc := a.enterChild();
defer bc.exit(); defer bc.exit();
l := a.compileExpr(bc.block, s.Lhs[0], false); l := a.compileExpr(bc.block, false, s.Lhs[0]);
r := a.compileExpr(bc.block, s.Rhs[0], false); r := a.compileExpr(bc.block, false, s.Rhs[0]);
if l == nil || r == nil { if l == nil || r == nil {
return; return;
} }
...@@ -701,16 +704,14 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) { ...@@ -701,16 +704,14 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
return; return;
} }
effect, l := l.extractEffect("operator-assignment"); effect, l := l.extractEffect(bc.block, "operator-assignment");
binop := r.copy(); binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r);
binop.pos = s.TokPos; if binop == nil {
binop.doBinaryExpr(assignOpToOp[s.Tok], l, r);
if binop.t == nil {
return; return;
} }
assign := a.compileAssign(s.Pos(), l.t, []*exprCompiler{binop}, "assignment", "value"); assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value");
if assign == nil { if assign == nil {
log.Crashf("compileAssign type check failed"); log.Crashf("compileAssign type check failed");
} }
...@@ -755,11 +756,14 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) { ...@@ -755,11 +756,14 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
return; return;
} }
bc := a.enterChild();
defer bc.exit();
// Compile expressions // Compile expressions
bad := false; bad := false;
rs := make([]*exprCompiler, len(s.Results)); rs := make([]*expr, len(s.Results));
for i, re := range s.Results { for i, re := range s.Results {
rs[i] = a.compileExpr(a.block, re, false); rs[i] = a.compileExpr(bc.block, false, re);
if rs[i] == nil { if rs[i] == nil {
bad = true; bad = true;
} }
...@@ -774,7 +778,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) { ...@@ -774,7 +778,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
// is a single call to a multi-valued function, the values // is a single call to a multi-valued function, the values
// 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(), NewMultiType(a.fnType.Out), rs, "return", "value"); assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value");
if assign == nil { if assign == nil {
return; return;
} }
...@@ -896,7 +900,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) { ...@@ -896,7 +900,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
// fall through to the body. // fall through to the body.
bad := false; bad := false;
if s.Cond != nil { if s.Cond != nil {
e := bc.compileExpr(bc.block, s.Cond, false); e := bc.compileExpr(bc.block, false, s.Cond);
switch { switch {
case e == nil: case e == nil:
bad = true; bad = true;
...@@ -953,16 +957,16 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) { ...@@ -953,16 +957,16 @@ 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 *exprCompiler; var cond *expr;
condbc := bc.enterChild(); condbc := bc.enterChild();
bad := false; bad := false;
if s.Tag != nil { if s.Tag != nil {
e := condbc.compileExpr(condbc.block, s.Tag, false); e := condbc.compileExpr(condbc.block, false, s.Tag);
if e == nil { if e == nil {
bad = true; bad = true;
} else { } else {
var effect func(f *Frame); var effect func(f *Frame);
effect, cond = e.extractEffect("switch"); effect, cond = e.extractEffect(condbc.block, "switch");
if effect == nil { if effect == nil {
bad = true; bad = true;
} }
...@@ -1000,7 +1004,7 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) { ...@@ -1000,7 +1004,7 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
continue; continue;
} }
for _, v := range clause.Values { for _, v := range clause.Values {
e := condbc.compileExpr(condbc.block, v, false); e := condbc.compileExpr(condbc.block, false, v);
switch { switch {
case e == nil: case e == nil:
bad = true; bad = true;
...@@ -1011,10 +1015,9 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) { ...@@ -1011,10 +1015,9 @@ func (a *stmtCompiler) DoSwitchStmt(s *ast.SwitchStmt) {
cases[i] = e.asBool(); cases[i] = e.asBool();
case cond != nil: case cond != nil:
// Create comparison // Create comparison
compare := e.copy();
// TOOD(austin) This produces bad error messages // TOOD(austin) This produces bad error messages
compare.doBinaryExpr(token.EQL, cond, e); compare := e.compileBinaryExpr(token.EQL, cond, e);
if compare.t == nil { if compare == nil {
bad = true; bad = true;
} else { } else {
cases[i] = compare.asBool(); cases[i] = compare.asBool();
...@@ -1170,7 +1173,7 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) { ...@@ -1170,7 +1173,7 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
a.flow.put1(false, &bodyPC); a.flow.put1(false, &bodyPC);
a.push(func(v *vm) { v.pc = bodyPC }); a.push(func(v *vm) { v.pc = bodyPC });
} else { } else {
e := bc.compileExpr(bc.block, s.Cond, false); e := bc.compileExpr(bc.block, false, s.Cond);
switch { switch {
case e == nil: case e == nil:
bad = true; bad = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment