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