typec.go\
util.go\
value.go\
+ world.go\
include $(GOROOT)/src/Make.pkg
func newUniverse() *Scope {
sc := &Scope{nil, 0};
sc.block = &block{
+ offset: -1,
scope: sc,
defs: make(map[string] Def)
};
}
func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name string) *expr {
- level, def := b.Lookup(name);
+ bl, level, def := b.Lookup(name);
if def == nil {
a.diag("%s: undefined", name);
return nil;
a.diag("variable %s used in constant expression", name);
return nil;
}
+ if bl.offset < 0 {
+ return a.compileGlobalVariable(def);
+ }
return a.compileVariable(level, def);
case Type:
if callCtx {
return expr;
}
+func (a *exprInfo) compileGlobalVariable(v *Variable) *expr {
+ if v.Type == nil {
+ // Placeholder definition from an earlier error
+ a.silentErrors++;
+ return nil;
+ }
+ if v.Init == nil {
+ v.Init = v.Type.Zero();
+ }
+ expr := a.newExpr(v.Type, "variable");
+ val := v.Init;
+ expr.genValue(func(t *Thread) Value { return val });
+ return expr;
+}
+
func (a *exprInfo) compileIdealInt(i *bignum.Integer, desc string) *expr {
expr := a.newExpr(IdealIntType, desc);
expr.eval = func() *bignum.Integer { return i };
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./_obj/eval";
+ "bufio";
+ "os";
+)
+
+func main() {
+ w := eval.NewWorld();
+ r := bufio.NewReader(os.Stdin);
+ for {
+ print("; ");
+ line, err := r.ReadString('\n');
+ if err != nil {
+ break;
+ }
+ code, err := w.Compile(line);
+ if err != nil {
+ println(err.String());
+ continue;
+ }
+ v, err := code.Run();
+ if err != nil {
+ println(err.String());
+ continue;
+ }
+ if v != nil {
+ println(v.String());
+ }
+ }
+}
+
if b.inner != nil && b.inner.scope == b.scope {
log.Crash("Failed to exit child block before defining variable");
}
- index := b.offset+b.numVars;
- v := &Variable{token.Position{}, index, t, nil};
- b.numVars++;
- if index+1 > b.scope.maxVars {
- b.scope.maxVars = index+1;
+ index := -1;
+ if b.offset >= 0 {
+ index = b.offset+b.numVars;
+ b.numVars++;
+ if index+1 > b.scope.maxVars {
+ b.scope.maxVars = index+1;
+ }
}
+ v := &Variable{token.Position{}, index, t, nil};
return v;
}
return nt;
}
-func (b *block) Lookup(name string) (level int, def Def) {
+func (b *block) Lookup(name string) (bl *block, level int, def Def) {
for b != nil {
if d, ok := b.defs[name]; ok {
- return level, d;
+ return b, level, d;
}
if b.outer != nil && b.scope != b.outer.scope {
level++;
}
b = b.outer;
}
- return 0, nil;
+ return nil, 0, nil;
}
func (s *Scope) NewFrame(outer *Frame) *Frame {
fr := 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:
- fr.Vars[v.Index] = v.Init;
+ if v.Index >= 0 {
+ fr.Vars[v.Index] = v.Init;
+ }
}
}
return fr;
// Initialize the variable
index := v.Index;
- a.push(func(v *Thread) {
- v.f.Vars[index] = t.Zero();
- });
+ if v.Index >= 0 {
+ a.push(func(v *Thread) {
+ v.f.Vars[index] = t.Zero();
+ });
+ }
return v;
}
}
func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
- _, def := a.block.Lookup(x.Value);
+ _bl, _index, def := a.block.Lookup(x.Value);
if def == nil {
a.diagAt(x, "%s: undefined", x.Value);
return nil;
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+ "os";
+ "go/ast";
+ "go/parser";
+)
+
+// TODO: Make CompileExpr and CompileStmts
+// methods on World.
+
+type World struct {
+ scope *Scope;
+ frame *Frame;
+}
+
+func NewWorld() (*World) {
+ w := new(World);
+ w.scope = universe.ChildScope();
+ w.scope.offset = -1; // this block's vars allocate directly
+ w.scope.numVars = 1; // inner blocks have frames: offset+numVars >= 0
+ return w;
+}
+
+
+type Code struct {
+ w *World;
+ stmt *Stmt;
+ expr *Expr;
+}
+
+func (w *World) Compile(text string) (*Code, os.Error) {
+ asts, err := parser.ParseStmtList("input", text);
+ if err != nil {
+ return nil, err;
+ }
+ 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);
+ if err != nil {
+ return nil, err;
+ }
+ return &Code{w: w, stmt: stmt}, nil;
+}
+
+func (c *Code) Run() (Value, os.Error) {
+ w := c.w;
+ w.frame = w.scope.NewFrame(nil);
+ if c.stmt != nil {
+ return nil, c.stmt.Exec(w.frame);
+ }
+ val, err := c.expr.Eval(w.frame);
+ return val, err;
+}
+