| // 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. |
| |
| // This package is the beginning of an interpreter for Go. |
| // It can run simple Go programs but does not implement |
| // interface values or packages. |
| package eval |
| |
| import ( |
| "go/ast"; |
| "go/parser"; |
| "go/scanner"; |
| "go/token"; |
| "os"; |
| ) |
| |
| type World struct { |
| scope *Scope; |
| frame *Frame; |
| } |
| |
| func NewWorld() *World { |
| w := new(World); |
| w.scope = universe.ChildScope(); |
| w.scope.global = true; // this block's vars allocate directly |
| return w; |
| } |
| |
| type Code interface { |
| // The type of the value Run returns, or nil if Run returns nil. |
| Type() Type; |
| |
| // 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; |
| code code; |
| } |
| |
| func (w *World) CompileStmtList(stmts []ast.Stmt) (Code, os.Error) { |
| if len(stmts) == 1 { |
| if s, ok := stmts[0].(*ast.ExprStmt); ok { |
| return w.CompileExpr(s.X) |
| } |
| } |
| 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: w.scope.block, |
| }; |
| nerr := cc.numError(); |
| for _, 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) CompileDeclList(decls []ast.Decl) (Code, os.Error) { |
| stmts := make([]ast.Stmt, len(decls)); |
| for i, d := range decls { |
| stmts[i] = &ast.DeclStmt{d} |
| } |
| return w.CompileStmtList(stmts); |
| } |
| |
| func (s *stmtCode) Type() Type { return nil } |
| |
| 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) |
| } |
| var eval func(Value, *Thread); |
| switch t := ec.t.(type) { |
| case *idealIntType: |
| // nothing |
| case *idealFloatType: |
| // nothing |
| default: |
| if tm, ok := t.(*MultiType); ok && len(tm.Elems) == 0 { |
| return &stmtCode{w, code{ec.exec}}, nil |
| } |
| 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.CompileStmtList(stmts) |
| } |
| |
| // Otherwise try as DeclList. |
| decls, err1 := parser.ParseDeclList("input", text); |
| if err1 == nil { |
| return w.CompileDeclList(decls) |
| } |
| |
| // Have to pick an error. |
| // Parsing as statement list admits more forms, |
| // its error is more likely to be useful. |
| return nil, err; |
| } |
| |
| type RedefinitionError struct { |
| Name string; |
| Prev Def; |
| } |
| |
| func (e *RedefinitionError) String() string { |
| res := "identifier " + e.Name + " redeclared"; |
| pos := e.Prev.Pos(); |
| if pos.IsValid() { |
| res += "; previous declaration at " + pos.String() |
| } |
| return res; |
| } |
| |
| func (w *World) DefineConst(name string, t Type, val Value) os.Error { |
| _, prev := w.scope.DefineConst(name, token.Position{}, t, val); |
| if prev != nil { |
| return &RedefinitionError{name, prev} |
| } |
| return nil; |
| } |
| |
| func (w *World) DefineVar(name string, t Type, val Value) os.Error { |
| v, prev := w.scope.DefineVar(name, token.Position{}, t); |
| if prev != nil { |
| return &RedefinitionError{name, prev} |
| } |
| v.Init = val; |
| return nil; |
| } |