Commit dcb1c5f5 authored by Russ Cox's avatar Russ Cox

convert testing to World.

start on Decl, but not working yet

R=austin
DELTA=762  (201 added, 205 deleted, 356 changed)
OCL=34335
CL=34349
parent 620dc595
...@@ -41,8 +41,9 @@ func (a *compiler) numError() int { ...@@ -41,8 +41,9 @@ func (a *compiler) numError() int {
func newUniverse() *Scope { func newUniverse() *Scope {
sc := &Scope{nil, 0}; sc := &Scope{nil, 0};
sc.block = &block{ sc.block = &block{
offset: -1, offset: 0,
scope: sc, scope: sc,
global: true,
defs: make(map[string] Def) defs: make(map[string] Def)
}; };
return sc; return sc;
......
...@@ -6,6 +6,7 @@ package eval ...@@ -6,6 +6,7 @@ package eval
import ( import (
"bignum"; "bignum";
"flag";
"fmt"; "fmt";
"go/parser"; "go/parser";
"go/scanner"; "go/scanner";
...@@ -17,23 +18,23 @@ import ( ...@@ -17,23 +18,23 @@ import (
) )
// Print each statement or expression before parsing it // Print each statement or expression before parsing it
const noisy = false var noisy = false
func init() {
flag.BoolVar(&noisy, "noisy", false, "chatter during eval tests");
}
/* /*
* Generic statement/expression test framework * Generic statement/expression test framework
*/ */
type test struct { type test []job
code string;
rterr string;
exprs []exprTest;
cerr string;
}
type exprTest struct { type job struct {
code string; code string;
val interface{}; cerr string;
rterr string; rterr string;
val Value;
noval bool;
} }
func runTests(t *testing.T, baseName string, tests []test) { func runTests(t *testing.T, baseName string, tests []test) {
...@@ -43,168 +44,102 @@ func runTests(t *testing.T, baseName string, tests []test) { ...@@ -43,168 +44,102 @@ func runTests(t *testing.T, baseName string, tests []test) {
} }
} }
func (a *test) run(t *testing.T, name string) { func (a test) run(t *testing.T, name string) {
sc := newTestScope(); w := newTestWorld();
for _, j := range a {
var fr *Frame; src := j.code;
var cerr os.Error;
if a.code != "" {
if noisy { if noisy {
println(a.code); println("code:", src);
} }
// Compile statements code, err := w.Compile(src);
asts, err := parser.ParseStmtList(name, a.code); if err != nil {
if err != nil && cerr == nil { if j.cerr == "" {
cerr = err; t.Errorf("%s: Compile %s: %v", name, src, err);
} break;
code, err := CompileStmts(sc, asts);
if err != nil && cerr == nil {
cerr = err;
}
// Execute statements
if cerr == nil {
fr = sc.NewFrame(nil);
rterr := code.Exec(fr);
if a.rterr == "" && rterr != nil {
t.Errorf("%s: expected %s to run, got runtime error %v", name, a.code, rterr);
return;
} else if !checkRTError(t, name, a.code, rterr, a.rterr) {
return;
} }
if !match(t, err, j.cerr) {
t.Errorf("%s: Compile %s = error %s; want %v", name, src, err, j.cerr);
break;
}
continue;
} }
} if j.cerr != "" {
t.Errorf("%s: Compile %s succeeded; want %s", name, src, j.cerr);
if fr == nil {
fr = sc.NewFrame(nil);
}
for _, e := range a.exprs {
if cerr != nil {
break; break;
} }
if noisy { val, err := code.Run();
println(e.code); if err != nil {
} if j.rterr == "" {
t.Errorf("%s: Run %s: %v", name, src, err);
// Compile expression break;
ast, err := parser.ParseExpr(name, e.code);
if err != nil && cerr == nil {
cerr = err;
}
code, err := CompileExpr(sc, ast);
if err != nil && cerr == nil {
cerr = err;
}
// Evaluate expression
if cerr == nil {
val, rterr := code.Eval(fr);
if e.rterr == "" && rterr != nil {
t.Errorf("%s: expected %q to have value %T(%v), got runtime error %v", name, e.code, e.val, e.val, rterr);
} else if !checkRTError(t, name, e.code, rterr, e.rterr) {
continue;
} }
if e.val != nil { if !match(t, err, j.rterr) {
wantval := toValue(e.val); t.Errorf("%s: Run %s = error %s; want %v", name, src, err, j.rterr);
if !reflect.DeepEqual(val, wantval) { break;
t.Errorf("%s: expected %q to have value %T(%v), got %T(%v)", name, e.code, wantval, wantval, val, val);
}
} }
continue;
} }
} if j.rterr != "" {
t.Errorf("%s: Run %s succeeded; want %s", name, src, j.rterr);
// Check compile errors
switch {
case cerr == nil && a.cerr == "":
// Good
case cerr == nil && a.cerr != "":
t.Errorf("%s: expected compile error matching %q, got no errors", name, a.cerr);
case cerr != nil && a.cerr == "":
t.Errorf("%s: expected no compile error, got error %v", name, cerr);
case cerr != nil && a.cerr != "":
cerr := cerr.(scanner.ErrorList);
if len(cerr) > 1 {
t.Errorf("%s: expected 1 compile error matching %q, got %v", name, a.cerr, cerr);
break; break;
} }
m, err := testing.MatchString(a.cerr, cerr.String());
if err != "" { if !j.noval && !reflect.DeepEqual(val, j.val) {
t.Fatalf("%s: failed to compile regexp %q: %s", name, a.cerr, err); t.Errorf("%s: Run %s = %T(%v) want %T(%v)", name, src, val, val, j.val, j.val);
}
if !m {
t.Errorf("%s: expected compile error matching %q, got compile error %v", name, a.cerr, cerr);
} }
} }
} }
func checkRTError(t *testing.T, name string, code string, rterr os.Error, pat string) bool { func match(t *testing.T, err os.Error, pat string) bool {
switch { ok, errstr := testing.MatchString(pat, err.String());
case rterr == nil && pat == "": if errstr != "" {
return true; t.Fatalf("compile regexp %s: %v", pat, errstr);
case rterr == nil && pat != "":
t.Errorf("%s: expected %s to fail with runtime error matching %q, got no error", name, code, pat);
return false;
case rterr != nil && pat != "":
m, err := testing.MatchString(pat, rterr.String());
if err != "" {
t.Fatalf("%s: failed to compile regexp %q: %s", name, pat, err);
}
if !m {
t.Errorf("%s: expected runtime error matching %q, got runtime error %v", name, pat, rterr);
return false;
}
return true;
} }
panic("rterr != nil && pat == \"\" should have been handled by the caller"); return ok;
} }
/* /*
* Test constructors * Test constructors
*/ */
// Expression compile error // Expression compile error
func EErr(expr string, cerr string) test { func CErr(expr string, cerr string) test {
return test{"", "", []exprTest{exprTest{expr, nil, ""}}, cerr}; return test([]job{job{code: expr, cerr: cerr}})
} }
// Expression runtime error // Expression runtime error
func ERTErr(expr string, rterr string) test { func RErr(expr string, rterr string) test {
return test{"", "", []exprTest{exprTest{expr, nil, rterr}}, ""}; return test([]job{job{code: expr, rterr: rterr}})
} }
// Expression value // Expression value
func Val(expr string, val interface{}) test { func Val(expr string, val interface{}) test {
return test{"", "", []exprTest{exprTest{expr, val, ""}}, ""}; return test([]job{job{code: expr, val: toValue(val)}})
}
// Statement compile error
func SErr(stmts string, cerr string) test {
return test{stmts, "", nil, cerr};
}
// Statement runtime error
func SRTErr(stmts string, rterr string) test {
return test{stmts, rterr, nil, ""};
} }
// Statement runs without error // Statement runs without error
func SRuns(stmts string) test { func Run(stmts string) test {
return test{stmts, "", nil, ""}; return test([]job{job{code: stmts, noval: true}})
} }
// Statement runs and test one expression's value // Statement runs and test one expression's value
func Val1(stmts string, expr1 string, val1 interface{}) test { func Val1(stmts string, expr1 string, val1 interface{}) test {
return test{stmts, "", []exprTest{exprTest{expr1, val1, ""}}, ""}; return test([]job{
job{code: stmts, noval: true},
job{code: expr1, val: toValue(val1)}
})
} }
// Statement runs and test two expressions' values // Statement runs and test two expressions' values
func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test { func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test {
return test{stmts, "", []exprTest{exprTest{expr1, val1, ""}, exprTest{expr2, val2, ""}}, ""}; return test([]job{
job{code: stmts, noval: true},
job{code: expr1, val: toValue(val1)},
job{code: expr2, val: toValue(val2)}
})
} }
/* /*
...@@ -305,16 +240,14 @@ func (*voidFunc) NewFrame() *Frame { ...@@ -305,16 +240,14 @@ func (*voidFunc) NewFrame() *Frame {
func (*voidFunc) Call(t *Thread) { func (*voidFunc) Call(t *Thread) {
} }
func newTestScope() *Scope { func newTestWorld() *World {
sc := universe.ChildScope(); w := NewWorld();
p := token.Position{"<testScope>", 0, 0, 0};
def := func(name string, t Type, val interface{}) { def := func(name string, t Type, val interface{}) {
v, _ := sc.DefineVar(name, p, t); w.DefineVar(name, t, toValue(val));
v.Init = toValue(val);
}; };
sc.DefineConst("c", p, IdealIntType, toValue(bignum.Int(1))); w.DefineConst("c", IdealIntType, toValue(bignum.Int(1)));
def("i", IntType, 1); def("i", IntType, 1);
def("i2", IntType, 2); def("i2", IntType, 2);
def("u", UintType, uint(1)); def("u", UintType, uint(1));
...@@ -329,5 +262,5 @@ func newTestScope() *Scope { ...@@ -329,5 +262,5 @@ func newTestScope() *Scope {
def("void", NewFuncType([]Type{}, false, []Type {}), &voidFunc{}); def("void", NewFuncType([]Type{}, false, []Type {}), &voidFunc{});
def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3}); def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3});
return sc; return w;
} }
...@@ -336,8 +336,11 @@ func (a *assignCompiler) compile(b *block, lt Type) (func(Value, *Thread)) { ...@@ -336,8 +336,11 @@ func (a *assignCompiler) compile(b *block, lt Type) (func(Value, *Thread)) {
var effect func(*Thread); var effect func(*Thread);
if isUnpack { if isUnpack {
// This leaks a slot, but is definitely safe. // This leaks a slot, but is definitely safe.
temp := b.DefineSlot(a.rmt); temp := b.DefineTemp(a.rmt);
tempIdx := temp.Index; tempIdx := temp.Index;
if tempIdx < 0 {
panicln("tempidx", tempIdx);
}
if a.isMapUnpack { if a.isMapUnpack {
rf := a.rs[0].evalMapValue; rf := a.rs[0].evalMapValue;
vt := a.rmt.Elems[0]; vt := a.rmt.Elems[0];
...@@ -693,7 +696,7 @@ func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name stri ...@@ -693,7 +696,7 @@ func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name stri
a.diag("variable %s used in constant expression", name); a.diag("variable %s used in constant expression", name);
return nil; return nil;
} }
if bl.offset < 0 { if bl.global {
return a.compileGlobalVariable(def); return a.compileGlobalVariable(def);
} }
return a.compileVariable(level, def); return a.compileVariable(level, def);
...@@ -1830,7 +1833,7 @@ func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) { ...@@ -1830,7 +1833,7 @@ func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
log.Crashf("unexpected ideal type %v", tempType); log.Crashf("unexpected ideal type %v", tempType);
} }
} }
temp := b.DefineSlot(tempType); temp := b.DefineTemp(tempType);
tempIdx := temp.Index; tempIdx := temp.Index;
// Create "temp := rhs" // Create "temp := rhs"
...@@ -1857,41 +1860,3 @@ func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) { ...@@ -1857,41 +1860,3 @@ func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
} }
return effect, deref; return effect, deref;
} }
/*
* Public interface
*/
type Expr struct {
e *expr;
}
func (expr *Expr) Type() Type {
return expr.e.t;
}
func (expr *Expr) Eval(f *Frame) (Value, os.Error) {
t := new(Thread);
t.f = f;
switch _ := expr.e.t.(type) {
case *idealIntType:
return &idealIntV{expr.e.asIdealInt()()}, nil;
case *idealFloatType:
return &idealFloatV{expr.e.asIdealFloat()()}, nil;
}
v := expr.e.t.Zero();
eval := genAssign(expr.e.t, expr.e);
err := t.Try(func(t *Thread){eval(v, t)});
return v, err;
}
func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
errors := scanner.NewErrorVector();
cc := &compiler{errors, 0, 0};
ec := cc.compileExpr(scope.block, false, expr);
if ec == nil {
return nil, errors.GetError(scanner.Sorted);
}
return &Expr{ec}, nil;
}
...@@ -26,19 +26,19 @@ var hugeInteger = bignum.Int(1).Shl(64); ...@@ -26,19 +26,19 @@ var hugeInteger = bignum.Int(1).Shl(64);
var exprTests = []test { var exprTests = []test {
Val("i", 1), Val("i", 1),
EErr("zzz", undefined), CErr("zzz", undefined),
// TODO(austin) Test variable in constant context // TODO(austin) Test variable in constant context
//EErr("t", typeAsExpr), //CErr("t", typeAsExpr),
Val("'a'", bignum.Int('a')), Val("'a'", bignum.Int('a')),
Val("'\\uffff'", bignum.Int('\uffff')), Val("'\\uffff'", bignum.Int('\uffff')),
Val("'\\n'", bignum.Int('\n')), Val("'\\n'", bignum.Int('\n')),
EErr("''+x", badCharLit), CErr("''+x", badCharLit),
// Produces two parse errors // Produces two parse errors
//EErr("'''", ""), //CErr("'''", ""),
EErr("'\n'", badCharLit), CErr("'\n'", badCharLit),
EErr("'\\z'", illegalEscape), CErr("'\\z'", illegalEscape),
EErr("'ab'", badCharLit), CErr("'ab'", badCharLit),
Val("1.0", bignum.Rat(1, 1)), Val("1.0", bignum.Rat(1, 1)),
Val("1.", bignum.Rat(1, 1)), Val("1.", bignum.Rat(1, 1)),
...@@ -48,11 +48,11 @@ var exprTests = []test { ...@@ -48,11 +48,11 @@ var exprTests = []test {
Val("\"abc\"", "abc"), Val("\"abc\"", "abc"),
Val("\"\"", ""), Val("\"\"", ""),
Val("\"\\n\\\"\"", "\n\""), Val("\"\\n\\\"\"", "\n\""),
EErr("\"\\z\"", illegalEscape), CErr("\"\\z\"", illegalEscape),
EErr("\"abc", "string not terminated"), CErr("\"abc", "string not terminated"),
Val("\"abc\" \"def\"", "abcdef"), Val("\"abc\" \"def\"", "abcdef"),
EErr("\"abc\" \"\\z\"", illegalEscape), CErr("\"abc\" \"\\z\"", illegalEscape),
Val("(i)", 1), Val("(i)", 1),
...@@ -61,56 +61,56 @@ var exprTests = []test { ...@@ -61,56 +61,56 @@ var exprTests = []test {
Val("ai[1]", 2), Val("ai[1]", 2),
Val("ai[i]", 2), Val("ai[i]", 2),
Val("ai[u]", 2), Val("ai[u]", 2),
EErr("ai[f]", opTypes), CErr("ai[f]", opTypes),
EErr("ai[0][0]", opTypes), CErr("ai[0][0]", opTypes),
EErr("ai[2]", "index 2 exceeds"), CErr("ai[2]", "index 2 exceeds"),
EErr("ai[1+1]", "index 2 exceeds"), CErr("ai[1+1]", "index 2 exceeds"),
EErr("ai[-1]", "negative index"), CErr("ai[-1]", "negative index"),
ERTErr("ai[i+i]", "index 2 exceeds"), RErr("ai[i+i]", "index 2 exceeds"),
ERTErr("ai[-i]", "negative index"), RErr("ai[-i]", "negative index"),
EErr("i[0]", opTypes), CErr("i[0]", opTypes),
EErr("f[0]", opTypes), CErr("f[0]", opTypes),
Val("aai[0][0]", 1), Val("aai[0][0]", 1),
Val("aai[1][1]", 4), Val("aai[1][1]", 4),
EErr("aai[2][0]", "index 2 exceeds"), CErr("aai[2][0]", "index 2 exceeds"),
EErr("aai[0][2]", "index 2 exceeds"), CErr("aai[0][2]", "index 2 exceeds"),
Val("sli[0]", 1), Val("sli[0]", 1),
Val("sli[1]", 2), Val("sli[1]", 2),
EErr("sli[-1]", "negative index"), CErr("sli[-1]", "negative index"),
ERTErr("sli[-i]", "negative index"), RErr("sli[-i]", "negative index"),
ERTErr("sli[2]", "index 2 exceeds"), RErr("sli[2]", "index 2 exceeds"),
Val("s[0]", uint8('a')), Val("s[0]", uint8('a')),
Val("s[1]", uint8('b')), Val("s[1]", uint8('b')),
EErr("s[-1]", "negative index"), CErr("s[-1]", "negative index"),
ERTErr("s[-i]", "negative index"), RErr("s[-i]", "negative index"),
ERTErr("s[3]", "index 3 exceeds"), RErr("s[3]", "index 3 exceeds"),
EErr("1(2)", "cannot call"), CErr("1(2)", "cannot call"),
EErr("fn(1,2)", "too many"), CErr("fn(1,2)", "too many"),
EErr("fn()", "not enough"), CErr("fn()", "not enough"),
EErr("fn(true)", opTypes), CErr("fn(true)", opTypes),
EErr("fn(true)", "function call"), CErr("fn(true)", "function call"),
// Single argument functions don't say which argument. // Single argument functions don't say which argument.
//EErr("fn(true)", "argument 1"), //CErr("fn(true)", "argument 1"),
Val("fn(1)", 2), Val("fn(1)", 2),
Val("fn(1.0)", 2), Val("fn(1.0)", 2),
EErr("fn(1.5)", constantTruncated), CErr("fn(1.5)", constantTruncated),
Val("fn(i)", 2), Val("fn(i)", 2),
EErr("fn(u)", opTypes), CErr("fn(u)", opTypes),
EErr("void()+2", opTypes), CErr("void()+2", opTypes),
EErr("oneTwo()+2", opTypes), CErr("oneTwo()+2", opTypes),
Val("cap(ai)", 2), Val("cap(ai)", 2),
Val("cap(&ai)", 2), Val("cap(&ai)", 2),
Val("cap(aai)", 2), Val("cap(aai)", 2),
Val("cap(sli)", 3), Val("cap(sli)", 3),
EErr("cap(0)", opTypes), CErr("cap(0)", opTypes),
EErr("cap(i)", opTypes), CErr("cap(i)", opTypes),
EErr("cap(s)", opTypes), CErr("cap(s)", opTypes),
Val("len(s)", 3), Val("len(s)", 3),
Val("len(ai)", 2), Val("len(ai)", 2),
...@@ -118,36 +118,36 @@ var exprTests = []test { ...@@ -118,36 +118,36 @@ var exprTests = []test {
Val("len(aai)", 2), Val("len(aai)", 2),
Val("len(sli)", 2), Val("len(sli)", 2),
// TODO(austin) Test len of map // TODO(austin) Test len of map
EErr("len(0)", opTypes), CErr("len(0)", opTypes),
EErr("len(i)", opTypes), CErr("len(i)", opTypes),
EErr("*i", opTypes), CErr("*i", opTypes),
Val("*&i", 1), Val("*&i", 1),
Val("*&(i)", 1), Val("*&(i)", 1),
EErr("&1", badAddrOf), CErr("&1", badAddrOf),
EErr("&c", badAddrOf), CErr("&c", badAddrOf),
Val("*(&ai[0])", 1), Val("*(&ai[0])", 1),
Val("+1", bignum.Int(+1)), Val("+1", bignum.Int(+1)),
Val("+1.0", bignum.Rat(1, 1)), Val("+1.0", bignum.Rat(1, 1)),
EErr("+\"x\"", opTypes), CErr("+\"x\"", opTypes),
Val("-42", bignum.Int(-42)), Val("-42", bignum.Int(-42)),
Val("-i", -1), Val("-i", -1),
Val("-f", -1.0), Val("-f", -1.0),
// 6g bug? // 6g bug?
//Val("-(f-1)", -0.0), //Val("-(f-1)", -0.0),
EErr("-\"x\"", opTypes), CErr("-\"x\"", opTypes),
// TODO(austin) Test unary ! // TODO(austin) Test unary !
Val("^2", bignum.Int(^2)), Val("^2", bignum.Int(^2)),
Val("^(-2)", bignum.Int(^(-2))), Val("^(-2)", bignum.Int(^(-2))),
EErr("^2.0", opTypes), CErr("^2.0", opTypes),
EErr("^2.5", opTypes), CErr("^2.5", opTypes),
Val("^i", ^1), Val("^i", ^1),
Val("^u", ^uint(1)), Val("^u", ^uint(1)),
EErr("^f", opTypes), CErr("^f", opTypes),
Val("1+i", 2), Val("1+i", 2),
Val("1+u", uint(2)), Val("1+u", uint(2)),
...@@ -157,8 +157,8 @@ var exprTests = []test { ...@@ -157,8 +157,8 @@ var exprTests = []test {
Val("1+f", 2.0), Val("1+f", 2.0),
Val("1.0+1", bignum.Rat(2, 1)), Val("1.0+1", bignum.Rat(2, 1)),
Val("\"abc\" + \"def\"", "abcdef"), Val("\"abc\" + \"def\"", "abcdef"),
EErr("i+u", opTypes), CErr("i+u", opTypes),
EErr("-1+u", constantUnderflows), CErr("-1+u", constantUnderflows),
// TODO(austin) Test named types // TODO(austin) Test named types
Val("2-1", bignum.Int(1)), Val("2-1", bignum.Int(1)),
...@@ -170,14 +170,14 @@ var exprTests = []test { ...@@ -170,14 +170,14 @@ var exprTests = []test {
Val("2*i", 2), Val("2*i", 2),
Val("3/2", bignum.Int(1)), Val("3/2", bignum.Int(1)),
Val("3/i", 3), Val("3/i", 3),
EErr("1/0", divByZero), CErr("1/0", divByZero),
EErr("1.0/0", divByZero), CErr("1.0/0", divByZero),
ERTErr("i/0", divByZero), RErr("i/0", divByZero),
Val("3%2", bignum.Int(1)), Val("3%2", bignum.Int(1)),
Val("i%2", 1), Val("i%2", 1),
EErr("3%0", divByZero), CErr("3%0", divByZero),
EErr("3.0%0", opTypes), CErr("3.0%0", opTypes),
ERTErr("i%0", divByZero), RErr("i%0", divByZero),
// Examples from "Arithmetic operators" // Examples from "Arithmetic operators"
Val("5/3", bignum.Int(1)), Val("5/3", bignum.Int(1)),
...@@ -222,56 +222,56 @@ var exprTests = []test { ...@@ -222,56 +222,56 @@ var exprTests = []test {
// fractional float, ideal non-fractional float, int, uint, // fractional float, ideal non-fractional float, int, uint,
// and float. // and float.
Val("2<<2", bignum.Int(2<<2)), Val("2<<2", bignum.Int(2<<2)),
EErr("2<<(-1)", constantUnderflows), CErr("2<<(-1)", constantUnderflows),
EErr("2<<0x10000000000000000", constantOverflows), CErr("2<<0x10000000000000000", constantOverflows),
EErr("2<<2.5", constantTruncated), CErr("2<<2.5", constantTruncated),
Val("2<<2.0", bignum.Int(2<<2.0)), Val("2<<2.0", bignum.Int(2<<2.0)),
EErr("2<<i", mustBeUnsigned), CErr("2<<i", mustBeUnsigned),
Val("2<<u", 2<<1), Val("2<<u", 2<<1),
EErr("2<<f", opTypes), CErr("2<<f", opTypes),
Val("-2<<2", bignum.Int(-2<<2)), Val("-2<<2", bignum.Int(-2<<2)),
EErr("-2<<(-1)", constantUnderflows), CErr("-2<<(-1)", constantUnderflows),
EErr("-2<<0x10000000000000000", constantOverflows), CErr("-2<<0x10000000000000000", constantOverflows),
EErr("-2<<2.5", constantTruncated), CErr("-2<<2.5", constantTruncated),
Val("-2<<2.0", bignum.Int(-2<<2.0)), Val("-2<<2.0", bignum.Int(-2<<2.0)),
EErr("-2<<i", mustBeUnsigned), CErr("-2<<i", mustBeUnsigned),
Val("-2<<u", -2<<1), Val("-2<<u", -2<<1),
EErr("-2<<f", opTypes), CErr("-2<<f", opTypes),
Val("0x10000000000000000<<2", hugeInteger.Shl(2)), Val("0x10000000000000000<<2", hugeInteger.Shl(2)),
EErr("0x10000000000000000<<(-1)", constantUnderflows), CErr("0x10000000000000000<<(-1)", constantUnderflows),
EErr("0x10000000000000000<<0x10000000000000000", constantOverflows), CErr("0x10000000000000000<<0x10000000000000000", constantOverflows),
EErr("0x10000000000000000<<2.5", constantTruncated), CErr("0x10000000000000000<<2.5", constantTruncated),
Val("0x10000000000000000<<2.0", hugeInteger.Shl(2)), Val("0x10000000000000000<<2.0", hugeInteger.Shl(2)),
EErr("0x10000000000000000<<i", mustBeUnsigned), CErr("0x10000000000000000<<i", mustBeUnsigned),
EErr("0x10000000000000000<<u", constantOverflows), CErr("0x10000000000000000<<u", constantOverflows),
EErr("0x10000000000000000<<f", opTypes), CErr("0x10000000000000000<<f", opTypes),
EErr("2.5<<2", opTypes), CErr("2.5<<2", opTypes),
EErr("2.0<<2", opTypes), CErr("2.0<<2", opTypes),
Val("i<<2", 1<<2), Val("i<<2", 1<<2),
EErr("i<<(-1)", constantUnderflows), CErr("i<<(-1)", constantUnderflows),
EErr("i<<0x10000000000000000", constantOverflows), CErr("i<<0x10000000000000000", constantOverflows),
EErr("i<<2.5", constantTruncated), CErr("i<<2.5", constantTruncated),
Val("i<<2.0", 1<<2), Val("i<<2.0", 1<<2),
EErr("i<<i", mustBeUnsigned), CErr("i<<i", mustBeUnsigned),
Val("i<<u", 1<<1), Val("i<<u", 1<<1),
EErr("i<<f", opTypes), CErr("i<<f", opTypes),
Val("i<<u", 1<<1), Val("i<<u", 1<<1),
Val("u<<2", uint(1<<2)), Val("u<<2", uint(1<<2)),
EErr("u<<(-1)", constantUnderflows), CErr("u<<(-1)", constantUnderflows),
EErr("u<<0x10000000000000000", constantOverflows), CErr("u<<0x10000000000000000", constantOverflows),
EErr("u<<2.5", constantTruncated), CErr("u<<2.5", constantTruncated),
Val("u<<2.0", uint(1<<2)), Val("u<<2.0", uint(1<<2)),
EErr("u<<i", mustBeUnsigned), CErr("u<<i", mustBeUnsigned),
Val("u<<u", uint(1<<1)), Val("u<<u", uint(1<<1)),
EErr("u<<f", opTypes), CErr("u<<f", opTypes),
Val("u<<u", uint(1<<1)), Val("u<<u", uint(1<<1)),
EErr("f<<2", opTypes), CErr("f<<2", opTypes),
// <, <=, >, >= // <, <=, >, >=
Val("1<2", 1<2), Val("1<2", 1<2),
...@@ -298,11 +298,11 @@ var exprTests = []test { ...@@ -298,11 +298,11 @@ var exprTests = []test {
Val("s>\"ac\"", false), Val("s>\"ac\"", false),
Val("s>=\"abc\"", true), Val("s>=\"abc\"", true),
EErr("i<u", opTypes), CErr("i<u", opTypes),
EErr("i<f", opTypes), CErr("i<f", opTypes),
EErr("i<s", opTypes), CErr("i<s", opTypes),
EErr("&i<&i", opTypes), CErr("&i<&i", opTypes),
EErr("ai<ai", opTypes), CErr("ai<ai", opTypes),
// ==, != // ==, !=
Val("1==1", true), Val("1==1", true),
...@@ -332,12 +332,12 @@ var exprTests = []test { ...@@ -332,12 +332,12 @@ var exprTests = []test {
Val("fn==fn", true), Val("fn==fn", true),
Val("fn==func(int)int{return 0}", false), Val("fn==func(int)int{return 0}", false),
EErr("i==u", opTypes), CErr("i==u", opTypes),
EErr("i==f", opTypes), CErr("i==f", opTypes),
EErr("&i==&f", opTypes), CErr("&i==&f", opTypes),
EErr("ai==ai", opTypes), CErr("ai==ai", opTypes),
EErr("t==t", opTypes), CErr("t==t", opTypes),
EErr("fn==oneTwo", opTypes), CErr("fn==oneTwo", opTypes),
} }
func TestExpr(t *testing.T) { func TestExpr(t *testing.T) {
......
...@@ -56,6 +56,10 @@ type block struct { ...@@ -56,6 +56,10 @@ type block struct {
offset int; offset int;
// The number of Variables defined in this block. // The number of Variables defined in this block.
numVars int; numVars int;
// If global, do not allocate new vars and consts in
// the frame; assume that the refs will be compiled in
// using defs[name].Init.
global bool;
} }
// A Scope is the compile-time analogue of a Frame, which captures // A Scope is the compile-time analogue of a Frame, which captures
...@@ -112,21 +116,25 @@ func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, D ...@@ -112,21 +116,25 @@ func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, D
if prev, ok := b.defs[name]; ok { if prev, ok := b.defs[name]; ok {
return nil, prev; return nil, prev;
} }
v := b.DefineSlot(t); v := b.defineSlot(t, false);
v.Position = pos; v.Position = pos;
b.defs[name] = v; b.defs[name] = v;
return v, nil; return v, nil;
} }
func (b *block) DefineSlot(t Type) *Variable { func (b *block) DefineTemp(t Type) *Variable {
return b.defineSlot(t, true)
}
func (b *block) defineSlot(t Type, temp bool) *Variable {
if b.inner != nil && b.inner.scope == b.scope { if b.inner != nil && b.inner.scope == b.scope {
log.Crash("Failed to exit child block before defining variable"); log.Crash("Failed to exit child block before defining variable");
} }
index := -1; index := -1;
if b.offset >= 0 { if !b.global || temp {
index = b.offset+b.numVars; index = b.offset+b.numVars;
b.numVars++; b.numVars++;
if index+1 > b.scope.maxVars { if index >= b.scope.maxVars {
b.scope.maxVars = index+1; b.scope.maxVars = index+1;
} }
} }
...@@ -169,18 +177,7 @@ func (b *block) Lookup(name string) (bl *block, level int, def Def) { ...@@ -169,18 +177,7 @@ func (b *block) Lookup(name string) (bl *block, level int, def Def) {
} }
func (s *Scope) NewFrame(outer *Frame) *Frame { func (s *Scope) NewFrame(outer *Frame) *Frame {
fr := outer.child(s.maxVars); return outer.child(s.maxVars);
// TODO(rsc): Take this loop out once eval_test.go
// no longer fiddles with init.
for _, v := range s.defs {
switch v := v.(type) {
case *Variable:
if v.Index >= 0 {
fr.Vars[v.Index] = v.Init;
}
}
}
return fr;
} }
/* /*
......
...@@ -341,36 +341,12 @@ func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) { ...@@ -341,36 +341,12 @@ func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
switch decl.Tok { switch decl.Tok {
case token.IMPORT: case token.IMPORT:
log.Crash("import at statement level"); log.Crash("import at statement level");
case token.CONST: case token.CONST:
log.Crashf("%v not implemented", decl.Tok); log.Crashf("%v not implemented", decl.Tok);
case token.TYPE: case token.TYPE:
a.compileTypeDecl(a.block, decl); a.compileTypeDecl(a.block, decl);
case token.VAR: case token.VAR:
for _, spec := range decl.Specs { a.compileVarDecl(decl);
spec := spec.(*ast.ValueSpec);
if spec.Values == nil {
// Declaration without assignment
if spec.Type == nil {
// Parser should have caught
log.Crash("Type and Values nil");
}
t := a.compileType(a.block, spec.Type);
// Define placeholders even if type compile failed
for _, n := range spec.Names {
a.defineVar(n, t);
}
} else {
// Decalaration with assignment
lhs := make([]ast.Expr, len(spec.Names));
for i, n := range spec.Names {
lhs[i] = n;
}
a.doAssign(lhs, spec.Values, decl.Tok, spec.Type);
}
}
} }
default: default:
...@@ -378,6 +354,73 @@ func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) { ...@@ -378,6 +354,73 @@ func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
} }
} }
// decl might or might not be at top level;
func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) {
for _, spec := range decl.Specs {
spec := spec.(*ast.ValueSpec);
if spec.Values == nil {
// Declaration without assignment
if spec.Type == nil {
// Parser should have caught
log.Crash("Type and Values nil");
}
t := a.compileType(a.block, spec.Type);
// Define placeholders even if type compile failed
for _, n := range spec.Names {
a.defineVar(n, t);
}
} else {
// Decalaration with assignment
lhs := make([]ast.Expr, len(spec.Names));
for i, n := range spec.Names {
lhs[i] = n;
}
a.doAssign(lhs, spec.Values, decl.Tok, spec.Type);
}
}
}
// decl is top level
func (a *stmtCompiler) compileDecl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.BadDecl:
// Do nothing. Already reported by parser.
a.silentErrors++;
case *ast.FuncDecl:
decl := a.compileFuncType(a.block, d.Type);
if decl == nil {
return;
}
// Declare and initialize v before compiling func
// so that body can refer to itself.
c := a.block.DefineConst(d.Name.Value, a.pos, decl.Type, decl.Type.Zero());
// TODO(rsc): How to mark v as constant
// so the type checker rejects assignments to it?
fn := a.compileFunc(a.block, decl, d.Body);
if fn == nil {
return;
}
var zeroThread Thread;
c.Value.(FuncValue).Set(fn(&zeroThread));
case *ast.GenDecl:
switch d.Tok {
case token.IMPORT:
log.Crashf("%v not implemented", d.Tok);
case token.CONST:
log.Crashf("%v not implemented", d.Tok);
case token.TYPE:
a.compileTypeDecl(a.block, d);
case token.VAR:
a.compileVarDecl(d);
}
default:
log.Crashf("Unexpected Decl type %T", decl);
}
}
func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) { func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
// Define label // Define label
l, ok := a.labels[s.Label.Value]; l, ok := a.labels[s.Label.Value];
...@@ -1205,14 +1248,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f ...@@ -1205,14 +1248,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
if decl.InNames[i] != nil { if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, decl.InNames[i].Pos(), t); bodyScope.DefineVar(decl.InNames[i].Value, decl.InNames[i].Pos(), t);
} else { } else {
bodyScope.DefineSlot(t); bodyScope.DefineTemp(t);
} }
} }
for i, t := range decl.Type.Out { for i, t := range decl.Type.Out {
if decl.OutNames[i] != nil { if decl.OutNames[i] != nil {
bodyScope.DefineVar(decl.OutNames[i].Value, decl.OutNames[i].Pos(), t); bodyScope.DefineVar(decl.OutNames[i].Value, decl.OutNames[i].Pos(), t);
} else { } else {
bodyScope.DefineSlot(t); bodyScope.DefineTemp(t);
} }
} }
...@@ -1271,46 +1314,3 @@ func (a *funcCompiler) checkLabels() { ...@@ -1271,46 +1314,3 @@ func (a *funcCompiler) checkLabels() {
// point of the goto. // point of the goto.
a.flow.gotosObeyScopes(a.compiler); a.flow.gotosObeyScopes(a.compiler);
} }
/*
* Public interface
*/
type Stmt struct {
code code;
}
func (s *Stmt) Exec(f *Frame) os.Error {
t := new(Thread);
t.f = f;
return t.Try(func(t *Thread){s.code.exec(t)});
}
func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
errors := scanner.NewErrorVector();
cc := &compiler{errors, 0, 0};
cb := newCodeBuf();
fc := &funcCompiler{
compiler: cc,
fnType: nil,
outVarsNamed: false,
codeBuf: cb,
flow: newFlowBuf(cb),
labels: make(map[string] *label),
};
bc := &blockCompiler{
funcCompiler: fc,
block: scope.block,
};
out := make([]*Stmt, len(stmts));
nerr := cc.numError();
for i, stmt := range stmts {
bc.compileStmt(stmt);
}
fc.checkLabels();
if nerr != cc.numError() {
return nil, errors.GetError(scanner.Sorted);
}
code := fc.get();
return &Stmt{code}, nil;
}
This diff is collapsed.
...@@ -5,12 +5,14 @@ ...@@ -5,12 +5,14 @@
package eval package eval
import ( import (
"os";
"go/ast"; "go/ast";
"go/parser"; "go/parser";
"go/scanner";
"go/token";
"os";
) )
// TODO: Make CompileExpr and CompileStmts // TODO: Make CompileExpr and CompileStmts
// methods on World. // methods on World.
type World struct { type World struct {
...@@ -21,46 +23,143 @@ type World struct { ...@@ -21,46 +23,143 @@ type World struct {
func NewWorld() (*World) { func NewWorld() (*World) {
w := new(World); w := new(World);
w.scope = universe.ChildScope(); w.scope = universe.ChildScope();
w.scope.offset = -1; // this block's vars allocate directly w.scope.global = true; // this block's vars allocate directly
w.scope.numVars = 1; // inner blocks have frames: offset+numVars >= 0
return w; return w;
} }
type Code interface {
// The type of the value Run returns, or nil if Run returns nil.
Type() Type;
type Code struct { // Run runs the code; if the code is a single expression
// with a value, it returns the value; otherwise it returns nil.
Run() (Value, os.Error);
}
type stmtCode struct {
w *World; w *World;
stmt *Stmt; code code;
expr *Expr;
} }
func (w *World) Compile(text string) (*Code, os.Error) { func (w *World) compileStmts(stmts []ast.Stmt) (Code, os.Error) {
asts, err := parser.ParseStmtList("input", text); if len(stmts) == 1 {
if err != nil { if s, ok := stmts[0].(*ast.ExprStmt); ok {
return nil, err; return w.compileExpr(s.X);
}
if len(asts) == 1 {
if s, ok := asts[0].(*ast.ExprStmt); ok {
expr, err := CompileExpr(w.scope, s.X);
if err != nil {
return nil, err;
}
return &Code{w: w, expr: expr}, nil;
} }
} }
stmt, err := CompileStmts(w.scope, asts); errors := scanner.NewErrorVector();
if err != nil { cc := &compiler{errors, 0, 0};
return nil, err; cb := newCodeBuf();
fc := &funcCompiler{
compiler: cc,
fnType: nil,
outVarsNamed: false,
codeBuf: cb,
flow: newFlowBuf(cb),
labels: make(map[string] *label),
};
bc := &blockCompiler{
funcCompiler: fc,
block: w.scope.block,
};
nerr := cc.numError();
for i, stmt := range stmts {
bc.compileStmt(stmt);
}
fc.checkLabels();
if nerr != cc.numError() {
return nil, errors.GetError(scanner.Sorted);
}
return &stmtCode{w, fc.get()}, nil;
}
func (w *World) compileDecls(decls []ast.Decl) (Code, os.Error) {
stmts := make([]ast.Stmt, len(decls));
for i, d := range decls {
stmts[i] = &ast.DeclStmt{d};
} }
return &Code{w: w, stmt: stmt}, nil; return w.compileStmts(stmts);
} }
func (c *Code) Run() (Value, os.Error) { func (s *stmtCode) Type() Type {
w := c.w; return nil;
w.frame = w.scope.NewFrame(nil); }
if c.stmt != nil {
return nil, c.stmt.Exec(w.frame); func (s *stmtCode) Run() (Value, os.Error) {
t := new(Thread);
t.f = s.w.scope.NewFrame(nil);
return nil, t.Try(func(t *Thread){s.code.exec(t)});
}
type exprCode struct {
w *World;
e *expr;
eval func(Value, *Thread);
}
func (w *World) compileExpr(e ast.Expr) (Code, os.Error) {
errors := scanner.NewErrorVector();
cc := &compiler{errors, 0, 0};
ec := cc.compileExpr(w.scope.block, false, e);
if ec == nil {
return nil, errors.GetError(scanner.Sorted);
} }
val, err := c.expr.Eval(w.frame); var eval func(Value, *Thread);
return val, err; switch _ := ec.t.(type) {
case *idealIntType:
// nothing
case *idealFloatType:
// nothing
default:
eval = genAssign(ec.t, ec);
}
return &exprCode{w, ec, eval}, nil;
}
func (e *exprCode) Type() Type {
return e.e.t;
}
func (e *exprCode) Run() (Value, os.Error) {
t := new(Thread);
t.f = e.w.scope.NewFrame(nil);
switch _ := e.e.t.(type) {
case *idealIntType:
return &idealIntV{e.e.asIdealInt()()}, nil;
case *idealFloatType:
return &idealFloatV{e.e.asIdealFloat()()}, nil;
}
v := e.e.t.Zero();
eval := e.eval;
err := t.Try(func(t *Thread){eval(v, t)});
return v, err;
}
func (w *World) Compile(text string) (Code, os.Error) {
stmts, err := parser.ParseStmtList("input", text);
if err == nil {
return w.compileStmts(stmts);
}
// Otherwise try as DeclList.
decls, err1 := parser.ParseDeclList("input", text);
if err == nil {
return w.compileDecls(decls);
}
// Have to pick an error.
// Parsing as statement list admits more forms,
// its error is more likely to be useful.
return nil, err;
}
func (w *World) DefineConst(name string, t Type, val Value) {
w.scope.DefineConst(name, token.Position{}, t, val);
}
func (w *World) DefineVar(name string, t Type, val Value) {
v, _ := w.scope.DefineVar(name, token.Position{}, t);
v.Init = val;
} }
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