1
0
mirror of https://github.com/golang/go synced 2024-10-04 22:21:22 -06:00
go/src/pkg/exp/eval/world.go
Robert Griesemer 1c72959999 1) Change default gofmt default settings for
parsing and printing to new syntax.

                  Use -oldparser to parse the old syntax,
                  use -oldprinter to print the old syntax.

               2) Change default gofmt formatting settings
                  to use tabs for indentation only and to use
                  spaces for alignment. This will make the code
                  alignment insensitive to an editor's tabwidth.

                  Use -spaces=false to use tabs for alignment.

               3) Manually changed src/exp/parser/parser_test.go
                  so that it doesn't try to parse the parser's
                  source files using the old syntax (they have
                  new syntax now).

               4) gofmt -w src misc test/bench

	       2nd set of files.

R=rsc
CC=golang-dev
https://golang.org/cl/179067
2009-12-15 15:27:16 -08:00

186 lines
4.1 KiB
Go

// 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"
parser "exp/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 := new(scanner.ErrorVector)
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 := new(scanner.ErrorVector)
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
}