summaryrefslogtreecommitdiff
path: root/usr/austin/eval
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-10-14 18:10:43 -0700
committerRuss Cox <rsc@golang.org>2009-10-14 18:10:43 -0700
commit8f49b30671161bc5425c4f2f56cee96ad11befeb (patch)
treea545d9b275fbbc2346c40d8ea51b2c741ba9faa2 /usr/austin/eval
parent9615b0b1cfb8bbfc2b963b471bf9ac2afb7c8662 (diff)
downloadgolang-8f49b30671161bc5425c4f2f56cee96ad11befeb.tar.gz
move austin/eval and austin/ogle to exp/eval and exp/ogle
R=r OCL=35736 CL=35746
Diffstat (limited to 'usr/austin/eval')
-rw-r--r--usr/austin/eval/Makefile23
-rw-r--r--usr/austin/eval/abort.go91
-rw-r--r--usr/austin/eval/bridge.go170
-rw-r--r--usr/austin/eval/compiler.go97
-rw-r--r--usr/austin/eval/eval_test.go270
-rw-r--r--usr/austin/eval/expr.go2007
-rw-r--r--usr/austin/eval/expr1.go1836
-rw-r--r--usr/austin/eval/expr_test.go345
-rw-r--r--usr/austin/eval/func.go89
-rw-r--r--usr/austin/eval/gen.go375
-rw-r--r--usr/austin/eval/main.go92
-rw-r--r--usr/austin/eval/scope.go203
-rw-r--r--usr/austin/eval/stmt.go1313
-rw-r--r--usr/austin/eval/stmt_test.go343
-rwxr-xr-xusr/austin/eval/test.bash34
-rw-r--r--usr/austin/eval/type.go1174
-rw-r--r--usr/austin/eval/typec.go366
-rw-r--r--usr/austin/eval/util.go39
-rw-r--r--usr/austin/eval/value.go731
-rw-r--r--usr/austin/eval/world.go189
20 files changed, 0 insertions, 9787 deletions
diff --git a/usr/austin/eval/Makefile b/usr/austin/eval/Makefile
deleted file mode 100644
index 37f7c02a7..000000000
--- a/usr/austin/eval/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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.
-
-include $(GOROOT)/src/Make.$(GOARCH)
-
-TARG=eval
-GOFILES=\
- abort.go\
- bridge.go\
- compiler.go\
- expr.go\
- expr1.go\
- func.go\
- scope.go\
- stmt.go\
- type.go\
- typec.go\
- util.go\
- value.go\
- world.go\
-
-include $(GOROOT)/src/Make.pkg
diff --git a/usr/austin/eval/abort.go b/usr/austin/eval/abort.go
deleted file mode 100644
index 38ad2bf62..000000000
--- a/usr/austin/eval/abort.go
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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 (
- "fmt";
- "os";
- "runtime";
-)
-
-// Abort aborts the thread's current computation,
-// causing the innermost Try to return err.
-func (t *Thread) Abort(err os.Error) {
- if t.abort == nil {
- panicln("abort:", err.String());
- }
- t.abort <- err;
- runtime.Goexit();
-}
-
-// Try executes a computation; if the computation
-// Aborts, Try returns the error passed to abort.
-func (t *Thread) Try(f func(t *Thread)) os.Error {
- oc := t.abort;
- c := make(chan os.Error);
- t.abort = c;
- go func() {
- f(t);
- c <- nil;
- }();
- err := <-c;
- t.abort = oc;
- return err;
-}
-
-type DivByZeroError struct {}
-
-func (DivByZeroError) String() string {
- return "divide by zero";
-}
-
-type NilPointerError struct {}
-
-func (NilPointerError) String() string {
- return "nil pointer dereference";
-}
-
-type IndexError struct {
- Idx, Len int64;
-}
-
-func (e IndexError) String() string {
- if e.Idx < 0 {
- return fmt.Sprintf("negative index: %d", e.Idx);
- }
- return fmt.Sprintf("index %d exceeds length %d", e.Idx, e.Len);
-}
-
-type SliceError struct {
- Lo, Hi, Cap int64;
-}
-
-func (e SliceError) String() string {
- return fmt.Sprintf("slice [%d:%d]; cap %d", e.Lo, e.Hi, e.Cap);
-}
-
-type KeyError struct {
- Key interface {};
-}
-
-func (e KeyError) String() string {
- return fmt.Sprintf("key '%v' not found in map", e.Key);
-}
-
-type NegativeLengthError struct {
- Len int64;
-}
-
-func (e NegativeLengthError) String() string {
- return fmt.Sprintf("negative length: %d", e.Len);
-}
-
-type NegativeCapacityError struct {
- Len int64;
-}
-
-func (e NegativeCapacityError) String() string {
- return fmt.Sprintf("negative capacity: %d", e.Len);
-}
diff --git a/usr/austin/eval/bridge.go b/usr/austin/eval/bridge.go
deleted file mode 100644
index da2dd52a9..000000000
--- a/usr/austin/eval/bridge.go
+++ /dev/null
@@ -1,170 +0,0 @@
-// 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 (
- "log";
- "go/token";
- "reflect";
-)
-
-/*
- * Type bridging
- */
-
-var (
- evalTypes = make(map[reflect.Type] Type);
- nativeTypes = make(map[Type] reflect.Type);
-)
-
-// TypeFromNative converts a regular Go type into a the corresponding
-// interpreter Type.
-func TypeFromNative(t reflect.Type) Type {
- if et, ok := evalTypes[t]; ok {
- return et;
- }
-
- var nt *NamedType;
- if t.Name() != "" {
- name := t.PkgPath() + "ยท" + t.Name();
- nt = &NamedType{token.Position{}, name, nil, true, make(map[string] Method)};
- evalTypes[t] = nt;
- }
-
- var et Type;
- switch t := t.(type) {
- case *reflect.BoolType:
- et = BoolType;
- case *reflect.Float32Type:
- et = Float32Type;
- case *reflect.Float64Type:
- et = Float64Type;
- case *reflect.FloatType:
- et = FloatType;
- case *reflect.Int16Type:
- et = Int16Type;
- case *reflect.Int32Type:
- et = Int32Type;
- case *reflect.Int64Type:
- et = Int64Type;
- case *reflect.Int8Type:
- et = Int8Type;
- case *reflect.IntType:
- et = IntType;
- case *reflect.StringType:
- et = StringType;
- case *reflect.Uint16Type:
- et = Uint16Type;
- case *reflect.Uint32Type:
- et = Uint32Type;
- case *reflect.Uint64Type:
- et = Uint64Type;
- case *reflect.Uint8Type:
- et = Uint8Type;
- case *reflect.UintType:
- et = UintType;
- case *reflect.UintptrType:
- et = UintptrType;
-
- case *reflect.ArrayType:
- et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem()));
- case *reflect.ChanType:
- log.Crashf("%T not implemented", t);
- case *reflect.FuncType:
- nin := t.NumIn();
- // Variadic functions have DotDotDotType at the end
- varidic := false;
- if nin > 0 {
- if _, ok := t.In(nin - 1).(*reflect.DotDotDotType); ok {
- varidic = true;
- nin--;
- }
- }
- in := make([]Type, nin);
- for i := range in {
- in[i] = TypeFromNative(t.In(i));
- }
- out := make([]Type, t.NumOut());
- for i := range out {
- out[i] = TypeFromNative(t.Out(i));
- }
- et = NewFuncType(in, varidic, out);
- case *reflect.InterfaceType:
- log.Crashf("%T not implemented", t);
- case *reflect.MapType:
- log.Crashf("%T not implemented", t);
- case *reflect.PtrType:
- et = NewPtrType(TypeFromNative(t.Elem()));
- case *reflect.SliceType:
- et = NewSliceType(TypeFromNative(t.Elem()));
- case *reflect.StructType:
- n := t.NumField();
- fields := make([]StructField, n);
- for i := 0; i < n; i++ {
- sf := t.Field(i);
- // TODO(austin) What to do about private fields?
- fields[i].Name = sf.Name;
- fields[i].Type = TypeFromNative(sf.Type);
- fields[i].Anonymous = sf.Anonymous;
- }
- et = NewStructType(fields);
- case *reflect.UnsafePointerType:
- log.Crashf("%T not implemented", t);
- default:
- log.Crashf("unexpected reflect.Type: %T", t);
- }
-
- if nt != nil {
- if _, ok := et.(*NamedType); !ok {
- nt.Complete(et);
- et = nt;
- }
- }
-
- nativeTypes[et] = t;
- evalTypes[t] = et;
-
- return et;
-}
-
-// TypeOfNative returns the interpreter Type of a regular Go value.
-func TypeOfNative(v interface {}) Type {
- return TypeFromNative(reflect.Typeof(v));
-}
-
-/*
- * Function bridging
- */
-
-type nativeFunc struct {
- fn func(*Thread, []Value, []Value);
- in, out int;
-}
-
-func (f *nativeFunc) NewFrame() *Frame {
- vars := make([]Value, f.in + f.out);
- return &Frame{nil, vars};
-}
-
-func (f *nativeFunc) Call(t *Thread) {
- f.fn(t, t.f.Vars[0:f.in], t.f.Vars[f.in:f.in+f.out]);
-}
-
-// FuncFromNative creates an interpreter function from a native
-// function that takes its in and out arguments as slices of
-// interpreter Value's. While somewhat inconvenient, this avoids
-// value marshalling.
-func FuncFromNative(fn func(*Thread, []Value, []Value), t *FuncType) FuncValue {
- return &funcV{&nativeFunc{fn, len(t.In), len(t.Out)}};
-}
-
-// FuncFromNativeTyped is like FuncFromNative, but constructs the
-// function type from a function pointer using reflection. Typically,
-// the type will be given as a nil pointer to a function with the
-// desired signature.
-func FuncFromNativeTyped(fn func(*Thread, []Value, []Value), t interface{}) (*FuncType, FuncValue) {
- ft := TypeOfNative(t).(*FuncType);
- return ft, FuncFromNative(fn, ft);
-}
diff --git a/usr/austin/eval/compiler.go b/usr/austin/eval/compiler.go
deleted file mode 100644
index f3c962c2b..000000000
--- a/usr/austin/eval/compiler.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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 (
- "fmt";
- "go/scanner";
- "go/token";
-)
-
-
-type positioned interface {
- Pos() token.Position;
-}
-
-
-// A compiler captures information used throughout an entire
-// compilation. Currently it includes only the error handler.
-//
-// TODO(austin) This might actually represent package level, in which
-// case it should be package compiler.
-type compiler struct {
- errors scanner.ErrorHandler;
- numErrors int;
- silentErrors int;
-}
-
-func (a *compiler) diagAt(pos positioned, format string, args ...) {
- a.errors.Error(pos.Pos(), fmt.Sprintf(format, args));
- a.numErrors++;
-}
-
-func (a *compiler) numError() int {
- return a.numErrors + a.silentErrors;
-}
-
-// The universal scope
-func newUniverse() *Scope {
- sc := &Scope{nil, 0};
- sc.block = &block{
- offset: 0,
- scope: sc,
- global: true,
- defs: make(map[string] Def)
- };
- return sc;
-}
-var universe *Scope = newUniverse();
-
-
-// TODO(austin) These can all go in stmt.go now
-type label struct {
- name string;
- desc string;
- // The PC goto statements should jump to, or nil if this label
- // cannot be goto'd (such as an anonymous for loop label).
- gotoPC *uint;
- // The PC break statements should jump to, or nil if a break
- // statement is invalid.
- breakPC *uint;
- // The PC continue statements should jump to, or nil if a
- // continue statement is invalid.
- continuePC *uint;
- // The position where this label was resolved. If it has not
- // been resolved yet, an invalid position.
- resolved token.Position;
- // The position where this label was first jumped to.
- used token.Position;
-}
-
-// A funcCompiler captures information used throughout the compilation
-// of a single function body.
-type funcCompiler struct {
- *compiler;
- fnType *FuncType;
- // Whether the out variables are named. This affects what
- // kinds of return statements are legal.
- outVarsNamed bool;
- *codeBuf;
- flow *flowBuf;
- labels map[string] *label;
-}
-
-// A blockCompiler captures information used throughout the compilation
-// of a single block within a function.
-type blockCompiler struct {
- *funcCompiler;
- block *block;
- // The label of this block, used for finding break and
- // continue labels.
- label *label;
- // The blockCompiler for the block enclosing this one, or nil
- // for a function-level block.
- parent *blockCompiler;
-}
diff --git a/usr/austin/eval/eval_test.go b/usr/austin/eval/eval_test.go
deleted file mode 100644
index 192a2e782..000000000
--- a/usr/austin/eval/eval_test.go
+++ /dev/null
@@ -1,270 +0,0 @@
-// 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 (
- "bignum";
- "flag";
- "fmt";
- "log";
- "os";
- "reflect";
- "testing";
-)
-
-// Print each statement or expression before parsing it
-var noisy = false
-func init() {
- flag.BoolVar(&noisy, "noisy", false, "chatter during eval tests");
-}
-
-/*
- * Generic statement/expression test framework
- */
-
-type test []job
-
-type job struct {
- code string;
- cerr string;
- rterr string;
- val Value;
- noval bool;
-}
-
-func runTests(t *testing.T, baseName string, tests []test) {
- for i, test := range tests {
- name := fmt.Sprintf("%s[%d]", baseName, i);
- test.run(t, name);
- }
-}
-
-func (a test) run(t *testing.T, name string) {
- w := newTestWorld();
- for _, j := range a {
- src := j.code;
- if noisy {
- println("code:", src);
- }
-
- code, err := w.Compile(src);
- if err != nil {
- if j.cerr == "" {
- t.Errorf("%s: Compile %s: %v", name, src, err);
- break;
- }
- 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);
- break;
- }
-
- val, err := code.Run();
- if err != nil {
- if j.rterr == "" {
- t.Errorf("%s: Run %s: %v", name, src, err);
- break;
- }
- if !match(t, err, j.rterr) {
- t.Errorf("%s: Run %s = error %s; want %v", name, src, err, j.rterr);
- break;
- }
- continue;
- }
- if j.rterr != "" {
- t.Errorf("%s: Run %s succeeded; want %s", name, src, j.rterr);
- break;
- }
-
- if !j.noval && !reflect.DeepEqual(val, j.val) {
- t.Errorf("%s: Run %s = %T(%v) want %T(%v)", name, src, val, val, j.val, j.val);
- }
- }
-}
-
-func match(t *testing.T, err os.Error, pat string) bool {
- ok, errstr := testing.MatchString(pat, err.String());
- if errstr != "" {
- t.Fatalf("compile regexp %s: %v", pat, errstr);
- }
- return ok;
-}
-
-
-/*
- * Test constructors
- */
-
-// Expression compile error
-func CErr(expr string, cerr string) test {
- return test([]job{job{code: expr, cerr: cerr}})
-}
-
-// Expression runtime error
-func RErr(expr string, rterr string) test {
- return test([]job{job{code: expr, rterr: rterr}})
-}
-
-// Expression value
-func Val(expr string, val interface{}) test {
- return test([]job{job{code: expr, val: toValue(val)}})
-}
-
-// Statement runs without error
-func Run(stmts string) test {
- return test([]job{job{code: stmts, noval: true}})
-}
-
-// Two statements without error.
-// TODO(rsc): Should be possible with Run but the parser
-// won't let us do both top-level and non-top-level statements.
-func Run2(stmt1, stmt2 string) test {
- return test([]job{job{code: stmt1, noval: true}, job{code: stmt2, noval: true}})
-}
-
-// Statement runs and test one expression's value
-func Val1(stmts string, expr1 string, val1 interface{}) test {
- return test([]job{
- job{code: stmts, noval: true},
- job{code: expr1, val: toValue(val1)}
- })
-}
-
-// Statement runs and test two expressions' values
-func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test {
- return test([]job{
- job{code: stmts, noval: true},
- job{code: expr1, val: toValue(val1)},
- job{code: expr2, val: toValue(val2)}
- })
-}
-
-/*
- * Value constructors
- */
-
-type vstruct []interface{}
-
-type varray []interface{}
-
-type vslice struct {
- arr varray;
- len, cap int;
-}
-
-func toValue(val interface{}) Value {
- switch val := val.(type) {
- case bool:
- r := boolV(val);
- return &r;
- case uint8:
- r := uint8V(val);
- return &r;
- case uint:
- r := uintV(val);
- return &r;
- case int:
- r := intV(val);
- return &r;
- case *bignum.Integer:
- return &idealIntV{val};
- case float:
- r := floatV(val);
- return &r;
- case *bignum.Rational:
- return &idealFloatV{val};
- case string:
- r := stringV(val);
- return &r;
- case vstruct:
- elems := make([]Value, len(val));
- for i, e := range val {
- elems[i] = toValue(e);
- }
- r := structV(elems);
- return &r;
- case varray:
- elems := make([]Value, len(val));
- for i, e := range val {
- elems[i] = toValue(e);
- }
- r := arrayV(elems);
- return &r;
- case vslice:
- return &sliceV{Slice{toValue(val.arr).(ArrayValue), int64(val.len), int64(val.cap)}};
- case Func:
- return &funcV{val};
- }
- log.Crashf("toValue(%T) not implemented", val);
- panic();
-}
-
-/*
- * Default test scope
- */
-
-type testFunc struct {};
-
-func (*testFunc) NewFrame() *Frame {
- return &Frame{nil, &[2]Value {}};
-}
-
-func (*testFunc) Call(t *Thread) {
- n := t.f.Vars[0].(IntValue).Get(t);
-
- res := n + 1;
-
- t.f.Vars[1].(IntValue).Set(t, res);
-}
-
-type oneTwoFunc struct {};
-
-func (*oneTwoFunc) NewFrame() *Frame {
- return &Frame{nil, &[2]Value {}};
-}
-
-func (*oneTwoFunc) Call(t *Thread) {
- t.f.Vars[0].(IntValue).Set(t, 1);
- t.f.Vars[1].(IntValue).Set(t, 2);
-}
-
-type voidFunc struct {};
-
-func (*voidFunc) NewFrame() *Frame {
- return &Frame{nil, []Value {}};
-}
-
-func (*voidFunc) Call(t *Thread) {
-}
-
-func newTestWorld() *World {
- w := NewWorld();
-
- def := func(name string, t Type, val interface{}) {
- w.DefineVar(name, t, toValue(val));
- };
-
- w.DefineConst("c", IdealIntType, toValue(bignum.Int(1)));
- def("i", IntType, 1);
- def("i2", IntType, 2);
- def("u", UintType, uint(1));
- def("f", FloatType, 1.0);
- def("s", StringType, "abc");
- def("t", NewStructType([]StructField {StructField{"a", IntType, false}}), vstruct{1});
- def("ai", NewArrayType(2, IntType), varray{1, 2});
- def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1,2}, varray{3,4}});
- def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5,6}, varray{7,8}});
- def("fn", NewFuncType([]Type{IntType}, false, []Type {IntType}), &testFunc{});
- def("oneTwo", NewFuncType([]Type{}, false, []Type {IntType, IntType}), &oneTwoFunc{});
- def("void", NewFuncType([]Type{}, false, []Type {}), &voidFunc{});
- def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3});
-
- return w;
-}
diff --git a/usr/austin/eval/expr.go b/usr/austin/eval/expr.go
deleted file mode 100644
index ea4fc082b..000000000
--- a/usr/austin/eval/expr.go
+++ /dev/null
@@ -1,2007 +0,0 @@
-// 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 (
- "bignum";
- "go/ast";
- "go/token";
- "log";
- "strconv";
- "strings";
- "os";
-)
-
-// 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.
- eval interface{};
-
- // Map index expressions permit special forms of assignment,
- // for which we need to know the Map and key.
- evalMapValue func(t *Thread) (Map, interface{});
-
- // Evaluate to the "address of" this value; that is, the
- // settable Value object. nil for expressions whose address
- // cannot be taken.
- evalAddr func(t *Thread) Value;
-
- // Execute this expression as a statement. Only expressions
- // that are valid expression statements should set this.
- exec func(t *Thread);
-
- // If this expression is a type, this is its compiled type.
- // This is only permitted in the function position of a call
- // expression. In this case, t should be nil.
- valType Type;
-
- // A short string describing this expression for error
- // messages.
- desc string;
-}
-
-// 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 *exprInfo) newExpr(t Type, desc string) *expr {
- return &expr{exprInfo: a, t: t, desc: desc};
-}
-
-func (a *exprInfo) diag(format string, args ...) {
- a.diagAt(&a.pos, format, args);
-}
-
-func (a *exprInfo) diagOpType(op token.Token, vt Type) {
- a.diag("illegal operand type for '%v' operator\n\t%v", op, vt);
-}
-
-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);
-}
-
-/*
- * Common expression manipulations
- */
-
-// a.convertTo(t) converts the value of the analyzed expression a,
-// which must be a constant, ideal number, to a new analyzed
-// expression with a constant value of type t.
-//
-// TODO(austin) Rename to resolveIdeal or something?
-func (a *expr) convertTo(t Type) *expr {
- if !a.t.isIdeal() {
- log.Crashf("attempted to convert from %v, expected ideal", a.t);
- }
-
- var rat *bignum.Rational;
-
- // XXX(Spec) The spec says "It is erroneous".
- //
- // It is an error to assign a value with a non-zero fractional
- // part to an integer, or if the assignment would overflow or
- // underflow, or in general if the value cannot be represented
- // by the type of the variable.
- switch a.t {
- case IdealFloatType:
- rat = a.asIdealFloat()();
- if t.isInteger() && !rat.IsInt() {
- a.diag("constant %v truncated to integer", ratToString(rat));
- return nil;
- }
- case IdealIntType:
- i := a.asIdealInt()();
- rat = bignum.MakeRat(i, bignum.Nat(1));
- default:
- log.Crashf("unexpected ideal type %v", a.t);
- }
-
- // Check bounds
- if t, ok := t.lit().(BoundedType); ok {
- if rat.Cmp(t.minVal()) < 0 {
- a.diag("constant %v underflows %v", ratToString(rat), t);
- return nil;
- }
- if rat.Cmp(t.maxVal()) > 0 {
- a.diag("constant %v overflows %v", ratToString(rat), t);
- return nil;
- }
- }
-
- // Convert rat to type t.
- res := a.newExpr(t, a.desc);
- switch t := t.lit().(type) {
- case *uintType:
- n, d := rat.Value();
- f := n.Quo(bignum.MakeInt(false, d));
- v := f.Abs().Value();
- res.eval = func(*Thread) uint64 { return v };
- case *intType:
- n, d := rat.Value();
- f := n.Quo(bignum.MakeInt(false, d));
- v := f.Value();
- res.eval = func(*Thread) int64 { return v };
- case *idealIntType:
- n, d := rat.Value();
- f := n.Quo(bignum.MakeInt(false, d));
- res.eval = func() *bignum.Integer { return f };
- case *floatType:
- n, d := rat.Value();
- v := float64(n.Value())/float64(d.Value());
- res.eval = func(*Thread) float64 { return v };
- case *idealFloatType:
- res.eval = func() *bignum.Rational { return rat };
- default:
- log.Crashf("cannot convert to type %T", t);
- }
-
- return res;
-}
-
-// convertToInt converts this expression to an integer, if possible,
-// or produces an error if not. This accepts ideal ints, uints, and
-// ints. If max is not -1, produces an error if possible if the value
-// exceeds max. If negErr is not "", produces an error if possible if
-// the value is negative.
-func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr {
- switch a.t.lit().(type) {
- case *idealIntType:
- val := a.asIdealInt()();
- if negErr != "" && val.IsNeg() {
- a.diag("negative %s: %s", negErr, val);
- return nil;
- }
- bound := max;
- if negErr == "slice" {
- bound++;
- }
- if max != -1 && val.Cmp(bignum.Int(bound)) >= 0 {
- a.diag("index %s exceeds length %d", val, max);
- return nil;
- }
- return a.convertTo(IntType);
-
- case *uintType:
- // Convert to int
- na := a.newExpr(IntType, a.desc);
- af := a.asUint();
- na.eval = func(t *Thread) int64 {
- return int64(af(t));
- };
- return na;
-
- case *intType:
- // Good as is
- return a;
- }
-
- a.diag("illegal operand type for %s\n\t%v", errOp, a.t);
- return nil;
-}
-
-// derefArray returns an expression of array type if the given
-// expression is a *array type. Otherwise, returns the given
-// expression.
-func (a *expr) derefArray() *expr {
- if pt, ok := a.t.lit().(*PtrType); ok {
- if _, ok := pt.Elem.lit().(*ArrayType); ok {
- deref := a.compileStarExpr(a);
- if deref == nil {
- log.Crashf("failed to dereference *array");
- }
- return deref;
- }
- }
- return a;
-}
-
-/*
- * Assignments
- */
-
-// An assignCompiler compiles assignment operations. Anything other
-// than short declarations should use the compileAssign wrapper.
-//
-// There are three valid types of assignment:
-// 1) T = T
-// Assigning a single expression with single-valued type to a
-// single-valued type.
-// 2) MT = T, T, ...
-// Assigning multiple expressions with single-valued types to a
-// multi-valued type.
-// 3) MT = MT
-// Assigning a single expression with multi-valued type to a
-// multi-valued type.
-type assignCompiler struct {
- *compiler;
- pos token.Position;
- // The RHS expressions. This may include nil's for
- // expressions that failed to compile.
- rs []*expr;
- // The (possibly unary) MultiType of the RHS.
- rmt *MultiType;
- // Whether this is an unpack assignment (case 3).
- isUnpack bool;
- // Whether map special assignment forms are allowed.
- allowMap bool;
- // Whether this is a "r, ok = a[x]" assignment.
- isMapUnpack bool;
- // The operation name to use in error messages, such as
- // "assignment" or "function call".
- errOp string;
- // The name to use for positions in error messages, such as
- // "argument".
- errPosName string;
-}
-
-// Type check the RHS of an assignment, returning a new assignCompiler
-// and indicating if the type check succeeded. This always returns an
-// 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 []*expr, errOp, errPosName string) (*assignCompiler, bool) {
- c := &assignCompiler{
- compiler: a,
- pos: pos,
- rs: rs,
- errOp: errOp,
- errPosName: errPosName,
- };
-
- // Is this an unpack?
- if len(rs) == 1 && rs[0] != nil {
- if rmt, isUnpack := rs[0].t.(*MultiType); isUnpack {
- c.rmt = rmt;
- c.isUnpack = true;
- return c, true;
- }
- }
-
- // Create MultiType for RHS and check that all RHS expressions
- // are single-valued.
- rts := make([]Type, len(rs));
- ok := true;
- for i, r := range rs {
- if r == nil {
- ok = false;
- continue;
- }
-
- if _, isMT := r.t.(*MultiType); isMT {
- r.diag("multi-valued expression not allowed in %s", errOp);
- ok = false;
- continue;
- }
-
- rts[i] = r.t;
- }
-
- c.rmt = NewMultiType(rts);
- return c, ok;
-}
-
-func (a *assignCompiler) allowMapForms(nls int) {
- a.allowMap = true;
-
- // Update unpacking info if this is r, ok = a[x]
- if nls == 2 && len(a.rs) == 1 && a.rs[0] != nil && a.rs[0].evalMapValue != nil {
- a.isUnpack = true;
- a.rmt = NewMultiType([]Type {a.rs[0].t, BoolType});
- a.isMapUnpack = true;
- }
-}
-
-// compile type checks and compiles an assignment operation, returning
-// 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(b *block, lt Type) (func(Value, *Thread)) {
- lmt, isMT := lt.(*MultiType);
- rmt, isUnpack := a.rmt, a.isUnpack;
-
- // Create unary MultiType for single LHS
- if !isMT {
- lmt = NewMultiType([]Type{lt});
- }
-
- // Check that the assignment count matches
- lcount := len(lmt.Elems);
- rcount := len(rmt.Elems);
- if lcount != rcount {
- msg := "not enough";
- pos := a.pos;
- if rcount > lcount {
- msg = "too many";
- if lcount > 0 {
- pos = a.rs[lcount-1].pos;
- }
- }
- a.diagAt(&pos, "%s %ss for %s\n\t%s\n\t%s", msg, a.errPosName, a.errOp, lt, rmt);
- return nil;
- }
-
- bad := false;
-
- // If this is an unpack, create a temporary to store the
- // multi-value and replace the RHS with expressions to pull
- // out values from the temporary. Technically, this is only
- // necessary when we need to perform assignment conversions.
- var effect func(*Thread);
- if isUnpack {
- // This leaks a slot, but is definitely safe.
- temp := b.DefineTemp(a.rmt);
- tempIdx := temp.Index;
- if tempIdx < 0 {
- panicln("tempidx", tempIdx);
- }
- if a.isMapUnpack {
- rf := a.rs[0].evalMapValue;
- vt := a.rmt.Elems[0];
- effect = func(t *Thread) {
- m, k := rf(t);
- v := m.Elem(t, k);
- found := boolV(true);
- if v == nil {
- found = boolV(false);
- v = vt.Zero();
- }
- t.f.Vars[tempIdx] = multiV([]Value {v, &found});
- };
- } else {
- rf := a.rs[0].asMulti();
- effect = func(t *Thread) {
- t.f.Vars[tempIdx] = multiV(rf(t));
- };
- }
- orig := a.rs[0];
- 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.newExpr(t, orig.desc);
- index := i;
- a.rs[i].genValue(func(t *Thread) Value { return t.f.Vars[tempIdx].(multiV)[index] });
- }
- }
- // Now len(a.rs) == len(a.rmt) and we've reduced any unpacking
- // to multi-assignment.
-
- // TODO(austin) Deal with assignment special cases.
-
- // Values of any type may always be assigned to variables of
- // compatible static type.
- for i, lt := range lmt.Elems {
- rt := rmt.Elems[i];
-
- // When [an ideal is] (used in an expression) assigned
- // to a variable or typed constant, the destination
- // must be able to represent the assigned value.
- if rt.isIdeal() {
- a.rs[i] = a.rs[i].convertTo(lmt.Elems[i]);
- if a.rs[i] == nil {
- bad = true;
- continue;
- }
- rt = a.rs[i].t;
- }
-
- // A pointer p to an array can be assigned to a slice
- // variable v with compatible element type if the type
- // of p or v is unnamed.
- if rpt, ok := rt.lit().(*PtrType); ok {
- if at, ok := rpt.Elem.lit().(*ArrayType); ok {
- 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].newExpr(lt, a.rs[i].desc);
- len := at.Len;
- a.rs[i].eval = func(t *Thread) Slice {
- return Slice{rf(t).(ArrayValue), len, len};
- };
- rt = a.rs[i].t;
- }
- }
- }
- }
-
- if !lt.compat(rt, false) {
- if len(a.rs) == 1 {
- a.rs[0].diag("illegal operand types for %s\n\t%v\n\t%v", a.errOp, lt, rt);
- } else {
- a.rs[i].diag("illegal operand types in %s %d of %s\n\t%v\n\t%v", a.errPosName, i+1, a.errOp, lt, rt);
- }
- bad = true;
- }
- }
- if bad {
- return nil;
- }
-
- // Compile
- if !isMT {
- // Case 1
- return genAssign(lt, a.rs[0]);
- }
- // Case 2 or 3
- as := make([]func(lv Value, t *Thread), len(a.rs));
- for i, r := range a.rs {
- as[i] = genAssign(lmt.Elems[i], r);
- }
- return func(lv Value, t *Thread) {
- if effect != nil {
- effect(t);
- }
- lmv := lv.(multiV);
- for i, a := range as {
- a(lmv[i], t);
- }
- };
-}
-
-// 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, b *block, lt Type, rs []*expr, errOp, errPosName string) (func(Value, *Thread)) {
- ac, ok := a.checkAssign(pos, rs, errOp, errPosName);
- if !ok {
- return nil;
- }
- return ac.compile(b, lt);
-}
-
-/*
- * Expression compiler
- */
-
-// 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;
-}
-
-// compile compiles an expression AST. callCtx should be true if this
-// AST is in the function position of a function call node; it allows
-// the returned expression to be a type or a built-in function (which
-// otherwise result in errors).
-func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
- ei := &exprInfo{a.compiler, x.Pos()};
-
- switch x := x.(type) {
- // Literals
- case *ast.BasicLit:
- switch x.Kind {
- case token.INT:
- return ei.compileIntLit(string(x.Value));
- case token.FLOAT:
- return ei.compileFloatLit(string(x.Value));
- case token.CHAR:
- return ei.compileCharLit(string(x.Value));
- case token.STRING:
- return ei.compileStringLit(string(x.Value));
- default:
- log.Crashf("unexpected basic literal type %v", x.Kind);
- }
-
- case *ast.CompositeLit:
- goto notimpl;
-
- 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);
-
- // Types
- case *ast.ArrayType:
- // TODO(austin) Use a multi-type case
- goto typeexpr;
-
- case *ast.ChanType:
- goto typeexpr;
-
- case *ast.Ellipsis:
- goto typeexpr;
-
- case *ast.FuncType:
- goto typeexpr;
-
- case *ast.InterfaceType:
- goto typeexpr;
-
- case *ast.MapType:
- goto typeexpr;
-
- // Remaining expressions
- case *ast.BadExpr:
- // Error already reported by parser
- a.silentErrors++;
- return nil;
-
- case *ast.BinaryExpr:
- l, r := a.compile(x.X, false), a.compile(x.Y, false);
- if l == nil || r == nil {
- return nil;
- }
- return ei.compileBinaryExpr(x.Op, l, r);
-
- case *ast.CallExpr:
- l := a.compile(x.Fun, true);
- args := make([]*expr, len(x.Args));
- bad := false;
- for i, arg := range x.Args {
- if i == 0 && l != nil && (l.t == Type(makeType) || l.t == Type(newType)) {
- argei := &exprInfo{a.compiler, arg.Pos()};
- args[i] = argei.exprFromType(a.compileType(a.block, arg));
- } else {
- args[i] = a.compile(arg, false);
- }
- if args[i] == nil {
- bad = true;
- }
- }
- if bad || l == nil {
- return nil;
- }
- if a.constant {
- a.diagAt(x, "function call in constant context");
- return nil;
- }
-
- if l.valType != nil {
- a.diagAt(x, "type conversions not implemented");
- return nil;
- } else if ft, ok := l.t.(*FuncType); ok && ft.builtin != "" {
- return ei.compileBuiltinCallExpr(a.block, ft, args);
- } else {
- return ei.compileCallExpr(a.block, l, args);
- }
-
- case *ast.Ident:
- return ei.compileIdent(a.block, a.constant, callCtx, x.Value);
-
- case *ast.IndexExpr:
- if x.End != nil {
- arr := a.compile(x.X, false);
- lo := a.compile(x.Index, false);
- hi := a.compile(x.End, false);
- if arr == nil || lo == nil || hi == nil {
- return nil;
- }
- return ei.compileSliceExpr(arr, lo, hi);
- }
- l, r := a.compile(x.X, false), a.compile(x.Index, false);
- 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, callCtx);
-
- case *ast.SelectorExpr:
- v := a.compile(x.X, false);
- if v == nil {
- return nil;
- }
- return ei.compileSelectorExpr(v, x.Sel.Value);
-
- case *ast.StarExpr:
- // We pass down our call context because this could be
- // a pointer type (and thus a type conversion)
- v := a.compile(x.X, callCtx);
- if v == nil {
- return nil;
- }
- if v.valType != nil {
- // Turns out this was a pointer type, not a dereference
- return ei.exprFromType(NewPtrType(v.valType));
- }
- 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, false);
- 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, false);
- if v == nil {
- return nil;
- }
- return ei.compileUnaryExpr(x.Op, v);
- }
- log.Crashf("unexpected ast node type %T", x);
- panic();
-
-typeexpr:
- if !callCtx {
- a.diagAt(x, "type used as expression");
- return nil;
- }
- return ei.exprFromType(a.compileType(a.block, x));
-
-notimpl:
- a.diagAt(x, "%T expression node not implemented", x);
- return nil;
-}
-
-func (a *exprInfo) exprFromType(t Type) *expr {
- if t == nil {
- return nil;
- }
- expr := a.newExpr(nil, "type");
- expr.valType = t;
- return expr;
-}
-
-func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name string) *expr {
- bl, level, def := b.Lookup(name);
- if def == nil {
- a.diag("%s: undefined", name);
- return nil;
- }
- switch def := def.(type) {
- case *Constant:
- expr := a.newExpr(def.Type, "constant");
- if ft, ok := def.Type.(*FuncType); ok && ft.builtin != "" {
- // XXX(Spec) I don't think anything says that
- // built-in functions can't be used as values.
- if !callCtx {
- a.diag("built-in function %s cannot be used as a value", ft.builtin);
- return nil;
- }
- // Otherwise, we leave the evaluators empty
- // because this is handled specially
- } else {
- expr.genConstant(def.Value);
- }
- return expr;
- case *Variable:
- if constant {
- a.diag("variable %s used in constant expression", name);
- return nil;
- }
- if bl.global {
- return a.compileGlobalVariable(def);
- }
- return a.compileVariable(level, def);
- case Type:
- if callCtx {
- return a.exprFromType(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
- a.silentErrors++;
- return nil;
- }
- expr := a.newExpr(v.Type, "variable");
- expr.genIdentOp(level, v.Index);
- 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 };
- return expr;
-}
-
-func (a *exprInfo) compileIntLit(lit string) *expr {
- i, _, _ := bignum.IntFromString(lit, 0);
- return a.compileIdealInt(i, "integer literal");
-}
-
-func (a *exprInfo) compileCharLit(lit string) *expr {
- if lit[0] != '\'' {
- // Caught by parser
- a.silentErrors++;
- return nil;
- }
- v, _, tail, err := strconv.UnquoteChar(lit[1:len(lit)], '\'');
- if err != nil || tail != "'" {
- // Caught by parser
- a.silentErrors++;
- return nil;
- }
- return a.compileIdealInt(bignum.Int(int64(v)), "character literal");
-}
-
-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);
- }
- expr := a.newExpr(IdealFloatType, "float literal");
- expr.eval = func() *bignum.Rational { return f };
- return expr;
-}
-
-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.
- expr := a.newExpr(StringType, "string literal");
- expr.eval = func(*Thread) string { return s };
- return expr;
-}
-
-func (a *exprInfo) compileStringLit(lit string) *expr {
- s, err := strconv.Unquote(lit);
- if err != nil {
- a.diag("illegal string literal, %v", err);
- return nil;
- }
- return a.compileString(s);
-}
-
-func (a *exprInfo) compileStringList(list []*expr) *expr {
- ss := make([]string, len(list));
- for i, s := range list {
- ss[i] = s.asString()(nil);
- }
- return a.compileString(strings.Join(ss, ""));
-}
-
-func (a *exprInfo) compileFuncLit(decl *FuncDecl, fn func(*Thread) Func) *expr {
- expr := a.newExpr(decl.Type, "function literal");
- expr.eval = fn;
- return expr;
-}
-
-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.
- bestDepth := -1;
- ambig := false;
- amberr := "";
- mark := func(depth int, pathName string) {
- switch {
- case bestDepth == -1 || depth < bestDepth:
- bestDepth = depth;
- ambig = false;
- amberr = "";
-
- case depth == bestDepth:
- ambig = true;
-
- default:
- log.Crashf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth);
- }
- amberr += "\n\t" + pathName[1:len(pathName)];
- };
-
- 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 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;
- }
-
- // Don't check the same type twice and avoid loops
- if _, ok := visited[t]; ok {
- return nil;
- }
- visited[t] = true;
-
- // Implicit dereference
- deref := false;
- if ti, ok := t.(*PtrType); ok {
- deref = true;
- t = ti.Elem;
- }
-
- // If it's a named type, look for methods
- if ti, ok := t.(*NamedType); ok {
- _, ok := ti.methods[name];
- if ok {
- mark(depth, pathName + "." + name);
- log.Crash("Methods not implemented");
- }
- t = ti.Def;
- }
-
- // If it's a struct type, check fields and embedded types
- var builder func(*expr) *expr;
- if t, ok := t.(*StructType); ok {
- for i, f := range t.Elems {
- var sub func(*expr) *expr;
- switch {
- case f.Name == name:
- mark(depth, pathName + "." + name);
- sub = func(e *expr) *expr { return e };
-
- case f.Anonymous:
- sub = find(f.Type, depth+1, pathName + "." + f.Name);
- if sub == nil {
- continue;
- }
-
- default:
- continue;
- }
-
- // We found something. Create a
- // builder for accessing this field.
- ft := f.Type;
- index := i;
- builder = func(parent *expr) *expr {
- if deref {
- parent = a.compileStarExpr(parent);
- }
- expr := a.newExpr(ft, "selector expression");
- pf := parent.asStruct();
- evalAddr := func(t *Thread) Value {
- return pf(t).Field(t, index);
- };
- expr.genValue(evalAddr);
- return sub(expr);
- };
- }
- }
-
- return builder;
- };
-
- builder := find(v.t, 0, "");
- if builder == nil {
- a.diag("type %v has no field or method %s", v.t, name);
- return nil;
- }
- if ambig {
- a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr);
- return nil;
- }
-
- return builder(v);
-}
-
-func (a *exprInfo) compileSliceExpr(arr, lo, hi *expr) *expr {
- // Type check object
- arr = arr.derefArray();
-
- var at Type;
- var maxIndex int64 = -1;
-
- switch lt := arr.t.lit().(type) {
- case *ArrayType:
- at = NewSliceType(lt.Elem);
- maxIndex = lt.Len;
-
- case *SliceType:
- at = lt;
-
- case *stringType:
- at = lt;
-
- default:
- a.diag("cannot slice %v", arr.t);
- return nil;
- }
-
- // Type check index and convert to int
- // XXX(Spec) It's unclear if ideal floats with no
- // fractional part are allowed here. 6g allows it. I
- // believe that's wrong.
- lo = lo.convertToInt(maxIndex, "slice", "slice");
- hi = hi.convertToInt(maxIndex, "slice", "slice");
- if lo == nil || hi == nil {
- return nil;
- }
-
- expr := a.newExpr(at, "slice expression");
-
- // Compile
- lof := lo.asInt();
- hif := hi.asInt();
- switch lt := arr.t.lit().(type) {
- case *ArrayType:
- arrf := arr.asArray();
- bound := lt.Len;
- expr.eval = func(t *Thread) Slice {
- arr, lo, hi := arrf(t), lof(t), hif(t);
- if lo > hi || hi > bound || lo < 0 {
- t.Abort(SliceError{lo, hi, bound});
- }
- return Slice{arr.Sub(lo, bound - lo), hi - lo, bound - lo}
- };
-
- case *SliceType:
- arrf := arr.asSlice();
- expr.eval = func(t *Thread) Slice {
- arr, lo, hi := arrf(t), lof(t), hif(t);
- if lo > hi || hi > arr.Cap || lo < 0 {
- t.Abort(SliceError{lo, hi, arr.Cap});
- }
- return Slice{arr.Base.Sub(lo, arr.Cap - lo), hi - lo, arr.Cap - lo}
- };
-
- case *stringType:
- arrf := arr.asString();
- // TODO(austin) This pulls over the whole string in a
- // remote setting, instead of creating a substring backed
- // by remote memory.
- expr.eval = func(t *Thread) string {
- arr, lo, hi := arrf(t), lof(t), hif(t);
- if lo > hi || hi > int64(len(arr)) || lo < 0 {
- t.Abort(SliceError{lo, hi, int64(len(arr))});
- }
- return arr[lo:hi];
- }
-
- default:
- log.Crashf("unexpected left operand type %T", arr.t.lit());
- }
-
- return expr;
-}
-
-func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
- // Type check object
- l = l.derefArray();
-
- var at Type;
- intIndex := false;
- var maxIndex int64 = -1;
-
- switch lt := l.t.lit().(type) {
- case *ArrayType:
- at = lt.Elem;
- intIndex = true;
- maxIndex = lt.Len;
-
- case *SliceType:
- at = lt.Elem;
- intIndex = true;
-
- case *stringType:
- at = Uint8Type;
- intIndex = true;
-
- case *MapType:
- at = lt.Elem;
- if r.t.isIdeal() {
- r = r.convertTo(lt.Key);
- if r == nil {
- return nil;
- }
- }
- if !lt.Key.compat(r.t, false) {
- a.diag("cannot use %s as index into %s", r.t, lt);
- return nil;
- }
-
- default:
- a.diag("cannot index into %v", l.t);
- return nil;
- }
-
- // Type check index and convert to int if necessary
- if intIndex {
- // XXX(Spec) It's unclear if ideal floats with no
- // fractional part are allowed here. 6g allows it. I
- // believe that's wrong.
- r = r.convertToInt(maxIndex, "index", "index");
- if r == nil {
- return nil;
- }
- }
-
- expr := a.newExpr(at, "index expression");
-
- // Compile
- switch lt := l.t.lit().(type) {
- case *ArrayType:
- lf := l.asArray();
- rf := r.asInt();
- bound := lt.Len;
- expr.genValue(func(t *Thread) Value {
- l, r := lf(t), rf(t);
- if r < 0 || r >= bound {
- t.Abort(IndexError{r, bound});
- }
- return l.Elem(t, r);
- });
-
- case *SliceType:
- lf := l.asSlice();
- rf := r.asInt();
- expr.genValue(func(t *Thread) Value {
- l, r := lf(t), rf(t);
- if l.Base == nil {
- t.Abort(NilPointerError{});
- }
- if r < 0 || r >= l.Len {
- t.Abort(IndexError{r, l.Len});
- }
- return l.Base.Elem(t, r);
- });
-
- case *stringType:
- lf := l.asString();
- rf := r.asInt();
- // TODO(austin) This pulls over the whole string in a
- // remote setting, instead of just the one character.
- expr.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- if r < 0 || r >= int64(len(l)) {
- t.Abort(IndexError{r, int64(len(l))});
- }
- return uint64(l[r]);
- }
-
- case *MapType:
- lf := l.asMap();
- rf := r.asInterface();
- expr.genValue(func(t *Thread) Value {
- m := lf(t);
- k := rf(t);
- if m == nil {
- t.Abort(NilPointerError{});
- }
- e := m.Elem(t, k);
- if e == nil {
- t.Abort(KeyError{k});
- }
- return e;
- });
- // genValue makes things addressable, but map values
- // aren't addressable.
- expr.evalAddr = nil;
- expr.evalMapValue = func(t *Thread) (Map, interface{}) {
- // TODO(austin) Key check? nil check?
- return lf(t), rf(t);
- };
-
- default:
- log.Crashf("unexpected left operand type %T", l.t.lit());
- }
-
- return expr;
-}
-
-func (a *exprInfo) compileCallExpr(b *block, l *expr, as []*expr) *expr {
- // TODO(austin) Variadic functions.
-
- // Type check
-
- // XXX(Spec) Calling a named function type is okay. I really
- // think there needs to be a general discussion of named
- // types. A named type creates a new, distinct type, but the
- // type of that type is still whatever it's defined to. Thus,
- // in "type Foo int", Foo is still an integer type and in
- // "type Foo func()", Foo is a function type.
- lt, ok := l.t.lit().(*FuncType);
- if !ok {
- a.diag("cannot call non-function type %v", l.t);
- return nil;
- }
-
- // The arguments must be single-valued expressions assignment
- // compatible with the parameters of F.
- //
- // XXX(Spec) The spec is wrong. It can also be a single
- // multi-valued expression.
- nin := len(lt.In);
- assign := a.compileAssign(a.pos, b, NewMultiType(lt.In), as, "function call", "argument");
- if assign == nil {
- return nil;
- }
-
- var t Type;
- nout := len(lt.Out);
- switch nout {
- case 0:
- t = EmptyType;
- case 1:
- t = lt.Out[0];
- default:
- t = NewMultiType(lt.Out);
- }
- expr := a.newExpr(t, "function call");
-
- // Gather argument and out types to initialize frame variables
- vts := make([]Type, nin + nout);
- for i, t := range lt.In {
- vts[i] = t;
- }
- for i, t := range lt.Out {
- vts[i+nin] = t;
- }
-
- // Compile
- lf := l.asFunc();
- call := func(t *Thread) []Value {
- fun := lf(t);
- fr := fun.NewFrame();
- for i, t := range vts {
- fr.Vars[i] = t.Zero();
- }
- assign(multiV(fr.Vars[0:nin]), t);
- oldf := t.f;
- t.f = fr;
- fun.Call(t);
- t.f = oldf;
- return fr.Vars[nin:nin+nout];
- };
- expr.genFuncCall(call);
-
- return expr;
-}
-
-func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *expr {
- checkCount := func(min, max int) bool {
- if len(as) < min {
- a.diag("not enough arguments to %s", ft.builtin);
- return false;
- } else if len(as) > max {
- a.diag("too many arguments to %s", ft.builtin);
- return false;
- }
- return true;
- };
-
- switch ft {
- case capType:
- if !checkCount(1, 1) {
- return nil;
- }
- arg := as[0].derefArray();
- expr := a.newExpr(IntType, "function call");
- switch t := arg.t.lit().(type) {
- case *ArrayType:
- // TODO(austin) It would be nice if this could
- // be a constant int.
- v := t.Len;
- expr.eval = func(t *Thread) int64 {
- return v;
- };
-
- case *SliceType:
- vf := arg.asSlice();
- expr.eval = func(t *Thread) int64 {
- return vf(t).Cap;
- };
-
- //case *ChanType:
-
- default:
- a.diag("illegal argument type for cap function\n\t%v", arg.t);
- return nil;
- }
- return expr;
-
- case lenType:
- if !checkCount(1, 1) {
- return nil;
- }
- arg := as[0].derefArray();
- expr := a.newExpr(IntType, "function call");
- switch t := arg.t.lit().(type) {
- case *stringType:
- vf := arg.asString();
- expr.eval = func(t *Thread) int64 {
- return int64(len(vf(t)));
- };
-
- case *ArrayType:
- // TODO(austin) It would be nice if this could
- // be a constant int.
- v := t.Len;
- expr.eval = func(t *Thread) int64 {
- return v;
- };
-
- case *SliceType:
- vf := arg.asSlice();
- expr.eval = func(t *Thread) int64 {
- return vf(t).Len;
- };
-
- case *MapType:
- vf := arg.asMap();
- expr.eval = func(t *Thread) int64 {
- // XXX(Spec) What's the len of an
- // uninitialized map?
- m := vf(t);
- if m == nil {
- return 0;
- }
- return m.Len(t);
- };
-
- //case *ChanType:
-
- default:
- a.diag("illegal argument type for len function\n\t%v", arg.t);
- return nil;
- }
- return expr;
-
- case makeType:
- if !checkCount(1, 3) {
- return nil;
- }
- // XXX(Spec) What are the types of the
- // arguments? Do they have to be ints? 6g
- // accepts any integral type.
- var lenexpr, capexpr *expr;
- var lenf, capf func(*Thread) int64;
- if len(as) > 1 {
- lenexpr = as[1].convertToInt(-1, "length", "make function");
- if lenexpr == nil {
- return nil;
- }
- lenf = lenexpr.asInt();
- }
- if len(as) > 2 {
- capexpr = as[2].convertToInt(-1, "capacity", "make function");
- if capexpr == nil {
- return nil;
- }
- capf = capexpr.asInt();
- }
-
- switch t := as[0].valType.lit().(type) {
- case *SliceType:
- // A new, initialized slice value for a given
- // element type T is made using the built-in
- // function make, which takes a slice type and
- // parameters specifying the length and
- // optionally the capacity.
- if !checkCount(2, 3) {
- return nil;
- }
- et := t.Elem;
- expr := a.newExpr(t, "function call");
- expr.eval = func(t *Thread) Slice {
- l := lenf(t);
- // XXX(Spec) What if len or cap is
- // negative? The runtime panics.
- if l < 0 {
- t.Abort(NegativeLengthError{l});
- }
- c := l;
- if capf != nil {
- c = capf(t);
- if c < 0 {
- t.Abort(NegativeCapacityError{c});
- }
- // XXX(Spec) What happens if
- // len > cap? The runtime
- // sets cap to len.
- if l > c {
- c = l;
- }
- }
- base := arrayV(make([]Value, c));
- for i := int64(0); i < c; i++ {
- base[i] = et.Zero();
- }
- return Slice{&base, l, c};
- };
- return expr;
-
- case *MapType:
- // A new, empty map value is made using the
- // built-in function make, which takes the map
- // type and an optional capacity hint as
- // arguments.
- if !checkCount(1, 2) {
- return nil;
- }
- expr := a.newExpr(t, "function call");
- expr.eval = func(t *Thread) Map {
- if lenf == nil {
- return make(evalMap);
- }
- l := lenf(t);
- return make(evalMap, l);
- };
- return expr;
-
- //case *ChanType:
-
- default:
- a.diag("illegal argument type for make function\n\t%v", as[0].valType);
- return nil;
- }
-
- case closeType, closedType:
- a.diag("built-in function %s not implemented", ft.builtin);
- return nil;
-
- case newType:
- if !checkCount(1, 1) {
- return nil;
- }
-
- t := as[0].valType;
- expr := a.newExpr(NewPtrType(t), "new");
- expr.eval = func(*Thread) Value {
- return t.Zero();
- };
- return expr;
-
- case panicType, paniclnType, printType, printlnType:
- evals := make([]func(*Thread)interface{}, len(as));
- for i, x := range as {
- evals[i] = x.asInterface();
- }
- spaces := ft == paniclnType || ft == printlnType;
- newline := ft != printType;
- printer := func(t *Thread) {
- for i, eval := range evals {
- if i > 0 && spaces {
- print(" ");
- }
- v := eval(t);
- type stringer interface { String() string }
- switch v1 := v.(type) {
- case bool:
- print(v1);
- case uint64:
- print(v1);
- case int64:
- print(v1);
- case float64:
- print(v1);
- case string:
- print(v1);
- case stringer:
- print(v1.String());
- default:
- print("???");
- }
- }
- if newline {
- print("\n");
- }
- };
- expr := a.newExpr(EmptyType, "print");
- expr.exec = printer;
- if ft == panicType || ft == paniclnType {
- expr.exec = func(t *Thread) {
- printer(t);
- t.Abort(os.NewError("panic"));
- }
- }
- return expr;
- }
-
- log.Crashf("unexpected built-in function '%s'", ft.builtin);
- panic();
-}
-
-func (a *exprInfo) compileStarExpr(v *expr) *expr {
- switch vt := v.t.lit().(type) {
- case *PtrType:
- expr := a.newExpr(vt.Elem, "indirect expression");
- vf := v.asPtr();
- expr.genValue(func(t *Thread) Value {
- v := vf(t);
- if v == nil {
- t.Abort(NilPointerError{});
- }
- return v;
- });
- return expr;
- }
-
- a.diagOpType(token.MUL, v.t);
- return nil;
-}
-
-var unaryOpDescs = make(map[token.Token] string)
-
-func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr {
- // Type check
- var t Type;
- switch op {
- case token.ADD, token.SUB:
- if !v.t.isInteger() && !v.t.isFloat() {
- a.diagOpType(op, v.t);
- return nil;
- }
- t = v.t;
-
- case token.NOT:
- if !v.t.isBoolean() {
- a.diagOpType(op, v.t);
- return nil;
- }
- t = BoolType;
-
- case token.XOR:
- if !v.t.isInteger() {
- a.diagOpType(op, v.t);
- return nil;
- }
- t = v.t;
-
- case token.AND:
- // The unary prefix address-of operator & generates
- // the address of its operand, which must be a
- // variable, pointer indirection, field selector, or
- // array or slice indexing operation.
- if v.evalAddr == nil {
- a.diag("cannot take the address of %s", v.desc);
- return nil;
- }
-
- // TODO(austin) Implement "It is illegal to take the
- // address of a function result variable" once I have
- // function result variables.
-
- t = NewPtrType(v.t);
-
- case token.ARROW:
- log.Crashf("Unary op %v not implemented", op);
-
- default:
- log.Crashf("unknown unary operator %v", op);
- }
-
- desc, ok := unaryOpDescs[op];
- if !ok {
- desc = "unary " + op.String() + " expression";
- unaryOpDescs[op] = desc;
- }
-
- // Compile
- expr := a.newExpr(t, desc);
- switch op {
- case token.ADD:
- // Just compile it out
- expr = v;
- expr.desc = desc;
-
- case token.SUB:
- expr.genUnaryOpNeg(v);
-
- case token.NOT:
- expr.genUnaryOpNot(v);
-
- case token.XOR:
- expr.genUnaryOpXor(v);
-
- case token.AND:
- vf := v.evalAddr;
- expr.eval = func(t *Thread) Value { return vf(t) };
-
- default:
- log.Crashf("Compilation of unary op %v not implemented", op);
- }
-
- return expr;
-}
-
-var binOpDescs = make(map[token.Token] string)
-
-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;
-
- // XXX(Spec) What is the exact definition of a "named type"?
-
- // XXX(Spec) Arithmetic operators: "Integer types" apparently
- // means all types compatible with basic integer types, though
- // this is never explained. Likewise for float types, etc.
- // This relates to the missing explanation of named types.
-
- // XXX(Spec) Operators: "If both operands are ideal numbers,
- // the conversion is to ideal floats if one of the operands is
- // an ideal float (relevant for / and %)." How is that
- // relevant only for / and %? If I add an ideal int and an
- // ideal float, I get an ideal float.
-
- if op != token.SHL && op != token.SHR {
- // Except in shift expressions, if one operand has
- // numeric type and the other operand is an ideal
- // number, the ideal number is converted to match the
- // type of the other operand.
- if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() {
- r = r.convertTo(l.t);
- } else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() {
- l = l.convertTo(r.t);
- }
- if l == nil || r == nil {
- return nil;
- }
-
- // Except in shift expressions, if both operands are
- // ideal numbers and one is an ideal float, the other
- // is converted to ideal float.
- if l.t.isIdeal() && r.t.isIdeal() {
- if l.t.isInteger() && r.t.isFloat() {
- l = l.convertTo(r.t);
- } else if l.t.isFloat() && r.t.isInteger() {
- r = r.convertTo(l.t);
- }
- if l == nil || r == nil {
- return nil;
- }
- }
- }
-
- // Useful type predicates
- // TODO(austin) CL 33668 mandates identical types except for comparisons.
- compat := func() bool {
- return l.t.compat(r.t, false);
- };
- integers := func() bool {
- return l.t.isInteger() && r.t.isInteger();
- };
- floats := func() bool {
- return l.t.isFloat() && r.t.isFloat();
- };
- strings := func() bool {
- // TODO(austin) Deal with named types
- return l.t == StringType && r.t == StringType;
- };
- booleans := func() bool {
- return l.t.isBoolean() && r.t.isBoolean();
- };
-
- // Type check
- var t Type;
- switch op {
- case token.ADD:
- if !compat() || (!integers() && !floats() && !strings()) {
- a.diagOpTypes(op, origlt, origrt);
- return nil;
- }
- t = l.t;
-
- case token.SUB, token.MUL, token.QUO:
- if !compat() || (!integers() && !floats()) {
- a.diagOpTypes(op, origlt, origrt);
- return nil;
- }
- t = l.t;
-
- case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
- if !compat() || !integers() {
- a.diagOpTypes(op, origlt, origrt);
- return nil;
- }
- t = l.t;
-
- case token.SHL, token.SHR:
- // XXX(Spec) Is it okay for the right operand to be an
- // ideal float with no fractional part? "The right
- // operand in a shift operation must be always be of
- // unsigned integer type or an ideal number that can
- // be safely converted into an unsigned integer type
- // (ยงArithmetic operators)" suggests so and 6g agrees.
-
- if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) {
- a.diagOpTypes(op, origlt, origrt);
- return nil;
- }
-
- // The right operand in a shift operation must be
- // always be of unsigned integer type or an ideal
- // number that can be safely converted into an
- // unsigned integer type.
- if r.t.isIdeal() {
- r2 := r.convertTo(UintType);
- if r2 == nil {
- return nil;
- }
-
- // If the left operand is not ideal, convert
- // the right to not ideal.
- if !l.t.isIdeal() {
- r = r2;
- }
-
- // If both are ideal, but the right side isn't
- // an ideal int, convert it to simplify things.
- if l.t.isIdeal() && !r.t.isInteger() {
- r = r.convertTo(IdealIntType);
- if r == nil {
- log.Crashf("conversion to uintType succeeded, but conversion to idealIntType failed");
- }
- }
- } else if _, ok := r.t.lit().(*uintType); !ok {
- a.diag("right operand of shift must be unsigned");
- return nil;
- }
-
- if l.t.isIdeal() && !r.t.isIdeal() {
- // XXX(Spec) What is the meaning of "ideal >>
- // non-ideal"? Russ says the ideal should be
- // converted to an int. 6g propagates the
- // type down from assignments as a hint.
-
- l = l.convertTo(IntType);
- if l == nil {
- return nil;
- }
- }
-
- // At this point, we should have one of three cases:
- // 1) uint SHIFT uint
- // 2) int SHIFT uint
- // 3) ideal int SHIFT ideal int
-
- t = l.t;
-
- case token.LOR, token.LAND:
- if !booleans() {
- return nil;
- }
- // XXX(Spec) There's no mention of *which* boolean
- // type the logical operators return. From poking at
- // 6g, it appears to be the named boolean type, NOT
- // the type of the left operand, and NOT an unnamed
- // boolean type.
-
- 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");
- t = BoolType;
-
- case token.LSS, token.GTR, token.LEQ, token.GEQ:
- // XXX(Spec) It's really unclear what types which
- // comparison operators apply to. I feel like the
- // text is trying to paint a Venn diagram for me,
- // which it's really pretty simple: <, <=, >, >= apply
- // only to numeric types and strings. == and != apply
- // to everything except arrays and structs, and there
- // are some restrictions on when it applies to slices.
-
- if !compat() || (!integers() && !floats() && !strings()) {
- a.diagOpTypes(op, origlt, origrt);
- return nil;
- }
- t = BoolType;
-
- case token.EQL, token.NEQ:
- // XXX(Spec) The rules for type checking comparison
- // operators are spread across three places that all
- // partially overlap with each other: the Comparison
- // Compatibility section, the Operators section, and
- // the Comparison Operators section. The Operators
- // section should just say that operators require
- // identical types (as it does currently) except that
- // there a few special cases for comparison, which are
- // described in section X. Currently it includes just
- // one of the four special cases. The Comparison
- // Compatibility section and the Comparison Operators
- // section should either be merged, or at least the
- // Comparison Compatibility section should be
- // exclusively about type checking and the Comparison
- // Operators section should be exclusively about
- // semantics.
-
- // XXX(Spec) Comparison operators: "All comparison
- // operators apply to basic types except bools." This
- // is very difficult to parse. It's explained much
- // better in the Comparison Compatibility section.
-
- // XXX(Spec) Comparison compatibility: "Function
- // values are equal if they refer to the same
- // function." is rather vague. It should probably be
- // similar to the way the rule for map values is
- // written: Function values are equal if they were
- // created by the same execution of a function literal
- // or refer to the same function declaration. This is
- // *almost* but not quite waht 6g implements. If a
- // function literals does not capture any variables,
- // then multiple executions of it will result in the
- // same closure. Russ says he'll change that.
-
- // TODO(austin) Deal with remaining special cases
-
- if !compat() {
- a.diagOpTypes(op, origlt, origrt);
- return nil;
- }
- // Arrays and structs may not be compared to anything.
- switch l.t.(type) {
- case *ArrayType, *StructType:
- a.diagOpTypes(op, origlt, origrt);
- return nil;
- }
- t = BoolType;
-
- default:
- log.Crashf("unknown binary operator %v", op);
- }
-
- desc, ok := binOpDescs[op];
- if !ok {
- desc = op.String() + " expression";
- binOpDescs[op] = desc;
- }
-
- // Check for ideal divide by zero
- switch op {
- case token.QUO, token.REM:
- if r.t.isIdeal() {
- if (r.t.isInteger() && r.asIdealInt()().IsZero()) ||
- (r.t.isFloat() && r.asIdealFloat()().IsZero()) {
- a.diag("divide by zero");
- return nil;
- }
- }
- }
-
- // Compile
- expr := a.newExpr(t, desc);
- switch op {
- case token.ADD:
- expr.genBinOpAdd(l, r);
-
- case token.SUB:
- expr.genBinOpSub(l, r);
-
- case token.MUL:
- expr.genBinOpMul(l, r);
-
- case token.QUO:
- expr.genBinOpQuo(l, r);
-
- case token.REM:
- expr.genBinOpRem(l, r);
-
- case token.AND:
- expr.genBinOpAnd(l, r);
-
- case token.OR:
- expr.genBinOpOr(l, r);
-
- case token.XOR:
- expr.genBinOpXor(l, r);
-
- case token.AND_NOT:
- expr.genBinOpAndNot(l, r);
-
- case token.SHL:
- if l.t.isIdeal() {
- lv := l.asIdealInt()();
- rv := r.asIdealInt()();
- const maxShift = 99999;
- if rv.Cmp(bignum.Int(maxShift)) > 0 {
- a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift);
- expr.t = nil;
- return nil;
- }
- val := lv.Shl(uint(rv.Value()));
- expr.eval = func() *bignum.Integer { return val };
- } else {
- expr.genBinOpShl(l, r);
- }
-
- case token.SHR:
- if l.t.isIdeal() {
- lv := l.asIdealInt()();
- rv := r.asIdealInt()();
- val := lv.Shr(uint(rv.Value()));
- expr.eval = func() *bignum.Integer { return val };
- } else {
- expr.genBinOpShr(l, r);
- }
-
- case token.LSS:
- expr.genBinOpLss(l, r);
-
- case token.GTR:
- expr.genBinOpGtr(l, r);
-
- case token.LEQ:
- expr.genBinOpLeq(l, r);
-
- case token.GEQ:
- expr.genBinOpGeq(l, r);
-
- case token.EQL:
- expr.genBinOpEql(l, r);
-
- case token.NEQ:
- expr.genBinOpNeq(l, r);
-
- case token.LAND:
- expr.genBinOpLogAnd(l, r);
-
- case token.LOR:
- expr.genBinOpLogOr(l, r);
-
- default:
- log.Crashf("Compilation of binary op %v not implemented", op);
- }
-
- 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, true, expr);
- if lenExpr == nil {
- return 0, false;
- }
-
- // XXX(Spec) Are ideal floats with no fractional part okay?
- if lenExpr.t.isIdeal() {
- lenExpr = lenExpr.convertTo(IntType);
- if lenExpr == nil {
- return 0, false;
- }
- }
-
- if !lenExpr.t.isInteger() {
- a.diagAt(expr, "array size must be an integer");
- return 0, false;
- }
-
- switch lenExpr.t.lit().(type) {
- case *intType:
- return lenExpr.asInt()(nil), true;
- case *uintType:
- return int64(lenExpr.asUint()(nil)), true;
- }
- log.Crashf("unexpected integer type %T", lenExpr.t);
- return 0, false;
-}
-
-func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
- ec := &exprCompiler{a, b, constant};
- nerr := a.numError();
- e := ec.compile(expr, false);
- if e == nil && nerr == a.numError() {
- log.Crashf("expression compilation failed without reporting errors");
- }
- return e;
-}
-
-// extractEffect separates out any effects that the expression may
-// have, returning a function that will perform those effects and a
-// new exprCompiler that is guaranteed to be side-effect free. These
-// are the moral equivalents of "temp := expr" and "temp" (or "temp :=
-// &expr" and "*temp" for addressable exprs). Because this creates a
-// temporary variable, the caller should create a temporary block for
-// the compilation of this expression and the evaluation of the
-// results.
-func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
- // Create "&a" if a is addressable
- rhs := a;
- if a.evalAddr != nil {
- rhs = a.compileUnaryExpr(token.AND, rhs);
- }
-
- // Create temp
- ac, ok := a.checkAssign(a.pos, []*expr{rhs}, errOp, "");
- if !ok {
- return nil, nil;
- }
- if len(ac.rmt.Elems) != 1 {
- a.diag("multi-valued expression not allowed in %s", errOp);
- return nil, nil;
- }
- tempType := ac.rmt.Elems[0];
- if tempType.isIdeal() {
- // It's too bad we have to duplicate this rule.
- switch {
- case tempType.isInteger():
- tempType = IntType;
- case tempType.isFloat():
- tempType = FloatType;
- default:
- log.Crashf("unexpected ideal type %v", tempType);
- }
- }
- temp := b.DefineTemp(tempType);
- tempIdx := temp.Index;
-
- // Create "temp := rhs"
- assign := ac.compile(b, tempType);
- if assign == nil {
- log.Crashf("compileAssign type check failed");
- }
-
- effect := func(t *Thread) {
- tempVal := tempType.Zero();
- t.f.Vars[tempIdx] = tempVal;
- assign(tempVal, t);
- };
-
- // Generate "temp" or "*temp"
- getTemp := a.compileVariable(0, temp);
- if a.evalAddr == nil {
- return effect, getTemp;
- }
-
- deref := a.compileStarExpr(getTemp);
- if deref == nil {
- return nil, nil;
- }
- return effect, deref;
-}
diff --git a/usr/austin/eval/expr1.go b/usr/austin/eval/expr1.go
deleted file mode 100644
index 7787a2112..000000000
--- a/usr/austin/eval/expr1.go
+++ /dev/null
@@ -1,1836 +0,0 @@
-// This file is machine generated by gen.go.
-// 6g gen.go && 6l gen.6 && ./6.out >expr1.go
-
-package eval
-
-import (
- "bignum";
- "log";
-)
-
-/*
- * "As" functions. These retrieve evaluator functions from an
- * expr, panicking if the requested evaluator has the wrong type.
- */
-func (a *expr) asBool() (func(*Thread) bool) {
- return a.eval.(func(*Thread)(bool))
-}
-func (a *expr) asUint() (func(*Thread) uint64) {
- return a.eval.(func(*Thread)(uint64))
-}
-func (a *expr) asInt() (func(*Thread) int64) {
- return a.eval.(func(*Thread)(int64))
-}
-func (a *expr) asIdealInt() (func() *bignum.Integer) {
- return a.eval.(func()(*bignum.Integer))
-}
-func (a *expr) asFloat() (func(*Thread) float64) {
- return a.eval.(func(*Thread)(float64))
-}
-func (a *expr) asIdealFloat() (func() *bignum.Rational) {
- return a.eval.(func()(*bignum.Rational))
-}
-func (a *expr) asString() (func(*Thread) string) {
- return a.eval.(func(*Thread)(string))
-}
-func (a *expr) asArray() (func(*Thread) ArrayValue) {
- return a.eval.(func(*Thread)(ArrayValue))
-}
-func (a *expr) asStruct() (func(*Thread) StructValue) {
- return a.eval.(func(*Thread)(StructValue))
-}
-func (a *expr) asPtr() (func(*Thread) Value) {
- return a.eval.(func(*Thread)(Value))
-}
-func (a *expr) asFunc() (func(*Thread) Func) {
- return a.eval.(func(*Thread)(Func))
-}
-func (a *expr) asSlice() (func(*Thread) Slice) {
- return a.eval.(func(*Thread)(Slice))
-}
-func (a *expr) asMap() (func(*Thread) Map) {
- return a.eval.(func(*Thread)(Map))
-}
-func (a *expr) asMulti() (func(*Thread) []Value) {
- return a.eval.(func(*Thread)[]Value)
-}
-
-func (a *expr) asInterface() (func(*Thread) interface{}) {
- switch sf := a.eval.(type) {
- case func(t *Thread)bool:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)uint64:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)int64:
- return func(t *Thread) interface{} { return sf(t) }
- case func()*bignum.Integer:
- return func(*Thread) interface{} { return sf() }
- case func(t *Thread)float64:
- return func(t *Thread) interface{} { return sf(t) }
- case func()*bignum.Rational:
- return func(*Thread) interface{} { return sf() }
- case func(t *Thread)string:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)ArrayValue:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)StructValue:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)Value:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)Func:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)Slice:
- return func(t *Thread) interface{} { return sf(t) }
- case func(t *Thread)Map:
- return func(t *Thread) interface{} { return sf(t) }
- default:
- log.Crashf("unexpected expression node type %T at %v", a.eval, a.pos);
- }
- panic();
-}
-
-/*
- * Operator generators.
- */
-
-func (a *expr) genConstant(v Value) {
- switch a.t.lit().(type) {
- case *boolType:
- a.eval = func(t *Thread) bool { return v.(BoolValue).Get(t) }
- case *uintType:
- a.eval = func(t *Thread) uint64 { return v.(UintValue).Get(t) }
- case *intType:
- a.eval = func(t *Thread) int64 { return v.(IntValue).Get(t) }
- case *idealIntType:
- val := v.(IdealIntValue).Get();
- a.eval = func() *bignum.Integer { return val }
- case *floatType:
- a.eval = func(t *Thread) float64 { return v.(FloatValue).Get(t) }
- case *idealFloatType:
- val := v.(IdealFloatValue).Get();
- a.eval = func() *bignum.Rational { return val }
- case *stringType:
- a.eval = func(t *Thread) string { return v.(StringValue).Get(t) }
- case *ArrayType:
- a.eval = func(t *Thread) ArrayValue { return v.(ArrayValue).Get(t) }
- case *StructType:
- a.eval = func(t *Thread) StructValue { return v.(StructValue).Get(t) }
- case *PtrType:
- a.eval = func(t *Thread) Value { return v.(PtrValue).Get(t) }
- case *FuncType:
- a.eval = func(t *Thread) Func { return v.(FuncValue).Get(t) }
- case *SliceType:
- a.eval = func(t *Thread) Slice { return v.(SliceValue).Get(t) }
- case *MapType:
- a.eval = func(t *Thread) Map { return v.(MapValue).Get(t) }
- default:
- log.Crashf("unexpected constant type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genIdentOp(level, index int) {
- a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) };
- switch a.t.lit().(type) {
- case *boolType:
- a.eval = func(t *Thread) bool { return t.f.Get(level, index).(BoolValue).Get(t) }
- case *uintType:
- a.eval = func(t *Thread) uint64 { return t.f.Get(level, index).(UintValue).Get(t) }
- case *intType:
- a.eval = func(t *Thread) int64 { return t.f.Get(level, index).(IntValue).Get(t) }
- case *floatType:
- a.eval = func(t *Thread) float64 { return t.f.Get(level, index).(FloatValue).Get(t) }
- case *stringType:
- a.eval = func(t *Thread) string { return t.f.Get(level, index).(StringValue).Get(t) }
- case *ArrayType:
- a.eval = func(t *Thread) ArrayValue { return t.f.Get(level, index).(ArrayValue).Get(t) }
- case *StructType:
- a.eval = func(t *Thread) StructValue { return t.f.Get(level, index).(StructValue).Get(t) }
- case *PtrType:
- a.eval = func(t *Thread) Value { return t.f.Get(level, index).(PtrValue).Get(t) }
- case *FuncType:
- a.eval = func(t *Thread) Func { return t.f.Get(level, index).(FuncValue).Get(t) }
- case *SliceType:
- a.eval = func(t *Thread) Slice { return t.f.Get(level, index).(SliceValue).Get(t) }
- case *MapType:
- a.eval = func(t *Thread) Map { return t.f.Get(level, index).(MapValue).Get(t) }
- default:
- log.Crashf("unexpected identifier type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genFuncCall(call func(t *Thread) []Value) {
- a.exec = func(t *Thread) { call(t)};
- switch a.t.lit().(type) {
- case *boolType:
- a.eval = func(t *Thread) bool { return call(t)[0].(BoolValue).Get(t) }
- case *uintType:
- a.eval = func(t *Thread) uint64 { return call(t)[0].(UintValue).Get(t) }
- case *intType:
- a.eval = func(t *Thread) int64 { return call(t)[0].(IntValue).Get(t) }
- case *floatType:
- a.eval = func(t *Thread) float64 { return call(t)[0].(FloatValue).Get(t) }
- case *stringType:
- a.eval = func(t *Thread) string { return call(t)[0].(StringValue).Get(t) }
- case *ArrayType:
- a.eval = func(t *Thread) ArrayValue { return call(t)[0].(ArrayValue).Get(t) }
- case *StructType:
- a.eval = func(t *Thread) StructValue { return call(t)[0].(StructValue).Get(t) }
- case *PtrType:
- a.eval = func(t *Thread) Value { return call(t)[0].(PtrValue).Get(t) }
- case *FuncType:
- a.eval = func(t *Thread) Func { return call(t)[0].(FuncValue).Get(t) }
- case *SliceType:
- a.eval = func(t *Thread) Slice { return call(t)[0].(SliceValue).Get(t) }
- case *MapType:
- a.eval = func(t *Thread) Map { return call(t)[0].(MapValue).Get(t) }
- case *MultiType:
- a.eval = func(t *Thread) []Value { return call(t) }
- default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genValue(vf func(*Thread) Value) {
- a.evalAddr = vf;
- switch a.t.lit().(type) {
- case *boolType:
- a.eval = func(t *Thread) bool { return vf(t).(BoolValue).Get(t) }
- case *uintType:
- a.eval = func(t *Thread) uint64 { return vf(t).(UintValue).Get(t) }
- case *intType:
- a.eval = func(t *Thread) int64 { return vf(t).(IntValue).Get(t) }
- case *floatType:
- a.eval = func(t *Thread) float64 { return vf(t).(FloatValue).Get(t) }
- case *stringType:
- a.eval = func(t *Thread) string { return vf(t).(StringValue).Get(t) }
- case *ArrayType:
- a.eval = func(t *Thread) ArrayValue { return vf(t).(ArrayValue).Get(t) }
- case *StructType:
- a.eval = func(t *Thread) StructValue { return vf(t).(StructValue).Get(t) }
- case *PtrType:
- a.eval = func(t *Thread) Value { return vf(t).(PtrValue).Get(t) }
- case *FuncType:
- a.eval = func(t *Thread) Func { return vf(t).(FuncValue).Get(t) }
- case *SliceType:
- a.eval = func(t *Thread) Slice { return vf(t).(SliceValue).Get(t) }
- case *MapType:
- a.eval = func(t *Thread) Map { return vf(t).(MapValue).Get(t) }
- default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genUnaryOpNeg(v *expr) {
- switch a.t.lit().(type) {
- case *uintType:
- vf := v.asUint();
- a.eval = func(t *Thread) uint64 { v := vf(t); return -v }
- case *intType:
- vf := v.asInt();
- a.eval = func(t *Thread) int64 { v := vf(t); return -v }
- case *idealIntType:
- v := v.asIdealInt()();
- val := v.Neg();
- a.eval = func() *bignum.Integer { return val }
- case *floatType:
- vf := v.asFloat();
- a.eval = func(t *Thread) float64 { v := vf(t); return -v }
- case *idealFloatType:
- v := v.asIdealFloat()();
- val := v.Neg();
- a.eval = func() *bignum.Rational { return val }
- default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genUnaryOpNot(v *expr) {
- switch a.t.lit().(type) {
- case *boolType:
- vf := v.asBool();
- a.eval = func(t *Thread) bool { v := vf(t); return !v }
- default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genUnaryOpXor(v *expr) {
- switch a.t.lit().(type) {
- case *uintType:
- vf := v.asUint();
- a.eval = func(t *Thread) uint64 { v := vf(t); return ^v }
- case *intType:
- vf := v.asInt();
- a.eval = func(t *Thread) int64 { v := vf(t); return ^v }
- case *idealIntType:
- v := v.asIdealInt()();
- val := v.Neg().Sub(bignum.Int(1));
- a.eval = func() *bignum.Integer { return val }
- default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpLogAnd(l, r *expr) {
- lf := l.asBool();
- rf := r.asBool();
- a.eval = func(t *Thread) bool { return lf(t) && rf(t) }
-}
-
-func (a *expr) genBinOpLogOr(l, r *expr) {
- lf := l.asBool();
- rf := r.asBool();
- a.eval = func(t *Thread) bool { return lf(t) || rf(t) }
-}
-
-func (a *expr) genBinOpAdd(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l + r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l + r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l + r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l + r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l + r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l + r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l + r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l + r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l + r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l + r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Add(r);
- a.eval = func() *bignum.Integer { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- switch t.Bits {
- case 32:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l + r;
- return float64(float32(ret))
- }
- case 64:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l + r;
- return float64(float64(ret))
- }
- case 0:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l + r;
- return float64(float(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Add(r);
- a.eval = func() *bignum.Rational { return val }
- case *stringType:
- lf := l.asString();
- rf := r.asString();
- a.eval = func(t *Thread) string {
- l, r := lf(t), rf(t);
- return l + r
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpSub(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l - r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l - r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l - r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l - r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l - r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l - r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l - r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l - r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l - r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l - r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Sub(r);
- a.eval = func() *bignum.Integer { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- switch t.Bits {
- case 32:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l - r;
- return float64(float32(ret))
- }
- case 64:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l - r;
- return float64(float64(ret))
- }
- case 0:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l - r;
- return float64(float(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Sub(r);
- a.eval = func() *bignum.Rational { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpMul(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l * r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l * r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l * r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l * r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l * r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l * r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l * r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l * r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l * r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l * r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Mul(r);
- a.eval = func() *bignum.Integer { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- switch t.Bits {
- case 32:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l * r;
- return float64(float32(ret))
- }
- case 64:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l * r;
- return float64(float64(ret))
- }
- case 0:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- ret = l * r;
- return float64(float(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Mul(r);
- a.eval = func() *bignum.Rational { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpQuo(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Quo(r);
- a.eval = func() *bignum.Integer { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- switch t.Bits {
- case 32:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return float64(float32(ret))
- }
- case 64:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return float64(float64(ret))
- }
- case 0:
- a.eval = func(t *Thread) float64 {
- l, r := lf(t), rf(t);
- var ret float64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r;
- return float64(float(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Quo(r);
- a.eval = func() *bignum.Rational { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpRem(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Rem(r);
- a.eval = func() *bignum.Integer { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpAnd(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l & r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l & r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l & r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l & r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l & r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l & r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l & r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l & r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l & r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l & r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.And(r);
- a.eval = func() *bignum.Integer { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpOr(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l | r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l | r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l | r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l | r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l | r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l | r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l | r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l | r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l | r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l | r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Or(r);
- a.eval = func() *bignum.Integer { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpXor(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l ^ r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l ^ r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l ^ r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l ^ r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l ^ r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l ^ r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l ^ r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l ^ r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l ^ r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l ^ r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Xor(r);
- a.eval = func() *bignum.Integer { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpAndNot(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l &^ r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l &^ r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l &^ r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l &^ r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l &^ r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l &^ r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l &^ r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l &^ r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l &^ r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l &^ r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.AndNot(r);
- a.eval = func() *bignum.Integer { return val }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpShl(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l << r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l << r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l << r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l << r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l << r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l << r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l << r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l << r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l << r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l << r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpShr(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l >> r;
- return uint64(uint8(ret))
- }
- case 16:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l >> r;
- return uint64(uint16(ret))
- }
- case 32:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l >> r;
- return uint64(uint32(ret))
- }
- case 64:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l >> r;
- return uint64(uint64(ret))
- }
- case 0:
- a.eval = func(t *Thread) uint64 {
- l, r := lf(t), rf(t);
- var ret uint64;
- ret = l >> r;
- return uint64(uint(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- case *intType:
- lf := l.asInt();
- rf := r.asUint();
- switch t.Bits {
- case 8:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l >> r;
- return int64(int8(ret))
- }
- case 16:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l >> r;
- return int64(int16(ret))
- }
- case 32:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l >> r;
- return int64(int32(ret))
- }
- case 64:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l >> r;
- return int64(int64(ret))
- }
- case 0:
- a.eval = func(t *Thread) int64 {
- l, r := lf(t), rf(t);
- var ret int64;
- ret = l >> r;
- return int64(int(ret))
- }
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpLss(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l < r
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l < r
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Cmp(r) < 0;
- a.eval = func(t *Thread) bool { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l < r
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Cmp(r) < 0;
- a.eval = func(t *Thread) bool { return val }
- case *stringType:
- lf := l.asString();
- rf := r.asString();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l < r
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpGtr(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l > r
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l > r
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Cmp(r) > 0;
- a.eval = func(t *Thread) bool { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l > r
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Cmp(r) > 0;
- a.eval = func(t *Thread) bool { return val }
- case *stringType:
- lf := l.asString();
- rf := r.asString();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l > r
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpLeq(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l <= r
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l <= r
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Cmp(r) <= 0;
- a.eval = func(t *Thread) bool { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l <= r
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Cmp(r) <= 0;
- a.eval = func(t *Thread) bool { return val }
- case *stringType:
- lf := l.asString();
- rf := r.asString();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l <= r
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpGeq(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l >= r
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l >= r
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Cmp(r) >= 0;
- a.eval = func(t *Thread) bool { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l >= r
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Cmp(r) >= 0;
- a.eval = func(t *Thread) bool { return val }
- case *stringType:
- lf := l.asString();
- rf := r.asString();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l >= r
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpEql(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *boolType:
- lf := l.asBool();
- rf := r.asBool();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Cmp(r) == 0;
- a.eval = func(t *Thread) bool { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Cmp(r) == 0;
- a.eval = func(t *Thread) bool { return val }
- case *stringType:
- lf := l.asString();
- rf := r.asString();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- case *PtrType:
- lf := l.asPtr();
- rf := r.asPtr();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- case *FuncType:
- lf := l.asFunc();
- rf := r.asFunc();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- case *MapType:
- lf := l.asMap();
- rf := r.asMap();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l == r
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func (a *expr) genBinOpNeq(l, r *expr) {
- switch t := l.t.lit().(type) {
- case *boolType:
- lf := l.asBool();
- rf := r.asBool();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- case *uintType:
- lf := l.asUint();
- rf := r.asUint();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- case *intType:
- lf := l.asInt();
- rf := r.asInt();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- case *idealIntType:
- l := l.asIdealInt()();
- r := r.asIdealInt()();
- val := l.Cmp(r) != 0;
- a.eval = func(t *Thread) bool { return val }
- case *floatType:
- lf := l.asFloat();
- rf := r.asFloat();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- case *idealFloatType:
- l := l.asIdealFloat()();
- r := r.asIdealFloat()();
- val := l.Cmp(r) != 0;
- a.eval = func(t *Thread) bool { return val }
- case *stringType:
- lf := l.asString();
- rf := r.asString();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- case *PtrType:
- lf := l.asPtr();
- rf := r.asPtr();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- case *FuncType:
- lf := l.asFunc();
- rf := r.asFunc();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- case *MapType:
- lf := l.asMap();
- rf := r.asMap();
- a.eval = func(t *Thread) bool {
- l, r := lf(t), rf(t);
- return l != r
- }
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-func genAssign(lt Type, r *expr) (func(lv Value, t *Thread)) {
- switch lt.lit().(type) {
- case *boolType:
- rf := r.asBool();
- return func(lv Value, t *Thread) { lv.(BoolValue).Set(t, rf(t)) }
- case *uintType:
- rf := r.asUint();
- return func(lv Value, t *Thread) { lv.(UintValue).Set(t, rf(t)) }
- case *intType:
- rf := r.asInt();
- return func(lv Value, t *Thread) { lv.(IntValue).Set(t, rf(t)) }
- case *floatType:
- rf := r.asFloat();
- return func(lv Value, t *Thread) { lv.(FloatValue).Set(t, rf(t)) }
- case *stringType:
- rf := r.asString();
- return func(lv Value, t *Thread) { lv.(StringValue).Set(t, rf(t)) }
- case *ArrayType:
- rf := r.asArray();
- return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
- case *StructType:
- rf := r.asStruct();
- return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
- case *PtrType:
- rf := r.asPtr();
- return func(lv Value, t *Thread) { lv.(PtrValue).Set(t, rf(t)) }
- case *FuncType:
- rf := r.asFunc();
- return func(lv Value, t *Thread) { lv.(FuncValue).Set(t, rf(t)) }
- case *SliceType:
- rf := r.asSlice();
- return func(lv Value, t *Thread) { lv.(SliceValue).Set(t, rf(t)) }
- case *MapType:
- rf := r.asMap();
- return func(lv Value, t *Thread) { lv.(MapValue).Set(t, rf(t)) }
- default:
- log.Crashf("unexpected left operand type %v at %v", lt, r.pos);
- }
- panic();
-}
diff --git a/usr/austin/eval/expr_test.go b/usr/austin/eval/expr_test.go
deleted file mode 100644
index ea11cf69d..000000000
--- a/usr/austin/eval/expr_test.go
+++ /dev/null
@@ -1,345 +0,0 @@
-// 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 (
- "bignum";
- "testing";
-)
-
-var undefined = "undefined"
-var typeAsExpr = "type .* used as expression"
-var badCharLit = "character literal"
-var illegalEscape = "illegal char escape"
-var opTypes = "illegal (operand|argument) type|cannot index into"
-var badAddrOf = "cannot take the address"
-var constantTruncated = "constant [^ ]* truncated"
-var constantUnderflows = "constant [^ ]* underflows"
-var constantOverflows = "constant [^ ]* overflows"
-var implLimit = "implementation limit"
-var mustBeUnsigned = "must be unsigned"
-var divByZero = "divide by zero"
-
-var hugeInteger = bignum.Int(1).Shl(64);
-
-var exprTests = []test {
- Val("i", 1),
- CErr("zzz", undefined),
- // TODO(austin) Test variable in constant context
- //CErr("t", typeAsExpr),
-
- Val("'a'", bignum.Int('a')),
- Val("'\\uffff'", bignum.Int('\uffff')),
- Val("'\\n'", bignum.Int('\n')),
- CErr("''+x", badCharLit),
- // Produces two parse errors
- //CErr("'''", ""),
- CErr("'\n'", badCharLit),
- CErr("'\\z'", illegalEscape),
- CErr("'ab'", badCharLit),
-
- Val("1.0", bignum.Rat(1, 1)),
- Val("1.", bignum.Rat(1, 1)),
- Val(".1", bignum.Rat(1, 10)),
- Val("1e2", bignum.Rat(100, 1)),
-
- Val("\"abc\"", "abc"),
- Val("\"\"", ""),
- Val("\"\\n\\\"\"", "\n\""),
- CErr("\"\\z\"", illegalEscape),
- CErr("\"abc", "string not terminated"),
-
- Val("\"abc\" \"def\"", "abcdef"),
- CErr("\"abc\" \"\\z\"", illegalEscape),
-
- Val("(i)", 1),
-
- Val("ai[0]", 1),
- Val("(&ai)[0]", 1),
- Val("ai[1]", 2),
- Val("ai[i]", 2),
- Val("ai[u]", 2),
- CErr("ai[f]", opTypes),
- CErr("ai[0][0]", opTypes),
- CErr("ai[2]", "index 2 exceeds"),
- CErr("ai[1+1]", "index 2 exceeds"),
- CErr("ai[-1]", "negative index"),
- RErr("ai[i+i]", "index 2 exceeds"),
- RErr("ai[-i]", "negative index"),
- CErr("i[0]", opTypes),
- CErr("f[0]", opTypes),
-
- Val("aai[0][0]", 1),
- Val("aai[1][1]", 4),
- CErr("aai[2][0]", "index 2 exceeds"),
- CErr("aai[0][2]", "index 2 exceeds"),
-
- Val("sli[0]", 1),
- Val("sli[1]", 2),
- CErr("sli[-1]", "negative index"),
- RErr("sli[-i]", "negative index"),
- RErr("sli[2]", "index 2 exceeds"),
-
- Val("s[0]", uint8('a')),
- Val("s[1]", uint8('b')),
- CErr("s[-1]", "negative index"),
- RErr("s[-i]", "negative index"),
- RErr("s[3]", "index 3 exceeds"),
-
- CErr("1(2)", "cannot call"),
- CErr("fn(1,2)", "too many"),
- CErr("fn()", "not enough"),
- CErr("fn(true)", opTypes),
- CErr("fn(true)", "function call"),
- // Single argument functions don't say which argument.
- //CErr("fn(true)", "argument 1"),
- Val("fn(1)", 2),
- Val("fn(1.0)", 2),
- CErr("fn(1.5)", constantTruncated),
- Val("fn(i)", 2),
- CErr("fn(u)", opTypes),
-
- CErr("void()+2", opTypes),
- CErr("oneTwo()+2", opTypes),
-
- Val("cap(ai)", 2),
- Val("cap(&ai)", 2),
- Val("cap(aai)", 2),
- Val("cap(sli)", 3),
- CErr("cap(0)", opTypes),
- CErr("cap(i)", opTypes),
- CErr("cap(s)", opTypes),
-
- Val("len(s)", 3),
- Val("len(ai)", 2),
- Val("len(&ai)", 2),
- Val("len(aai)", 2),
- Val("len(sli)", 2),
- // TODO(austin) Test len of map
- CErr("len(0)", opTypes),
- CErr("len(i)", opTypes),
-
- CErr("*i", opTypes),
- Val("*&i", 1),
- Val("*&(i)", 1),
- CErr("&1", badAddrOf),
- CErr("&c", badAddrOf),
- Val("*(&ai[0])", 1),
-
- Val("+1", bignum.Int(+1)),
- Val("+1.0", bignum.Rat(1, 1)),
- CErr("+\"x\"", opTypes),
-
- Val("-42", bignum.Int(-42)),
- Val("-i", -1),
- Val("-f", -1.0),
- // 6g bug?
- //Val("-(f-1)", -0.0),
- CErr("-\"x\"", opTypes),
-
- // TODO(austin) Test unary !
-
- Val("^2", bignum.Int(^2)),
- Val("^(-2)", bignum.Int(^(-2))),
- CErr("^2.0", opTypes),
- CErr("^2.5", opTypes),
- Val("^i", ^1),
- Val("^u", ^uint(1)),
- CErr("^f", opTypes),
-
- Val("1+i", 2),
- Val("1+u", uint(2)),
- Val("3.0+i", 4),
- Val("1+1", bignum.Int(2)),
- Val("f+f", 2.0),
- Val("1+f", 2.0),
- Val("1.0+1", bignum.Rat(2, 1)),
- Val("\"abc\" + \"def\"", "abcdef"),
- CErr("i+u", opTypes),
- CErr("-1+u", constantUnderflows),
- // TODO(austin) Test named types
-
- Val("2-1", bignum.Int(1)),
- Val("2.0-1", bignum.Rat(1, 1)),
- Val("f-2", -1.0),
- // TOOD(austin) bignum can't do negative 0?
- //Val("-0.0", XXX),
- Val("2*2", bignum.Int(4)),
- Val("2*i", 2),
- Val("3/2", bignum.Int(1)),
- Val("3/i", 3),
- CErr("1/0", divByZero),
- CErr("1.0/0", divByZero),
- RErr("i/0", divByZero),
- Val("3%2", bignum.Int(1)),
- Val("i%2", 1),
- CErr("3%0", divByZero),
- CErr("3.0%0", opTypes),
- RErr("i%0", divByZero),
-
- // Examples from "Arithmetic operators"
- Val("5/3", bignum.Int(1)),
- Val("(i+4)/(i+2)", 1),
- Val("5%3", bignum.Int(2)),
- Val("(i+4)%(i+2)", 2),
- Val("-5/3", bignum.Int(-1)),
- Val("(i-6)/(i+2)", -1),
- Val("-5%3", bignum.Int(-2)),
- Val("(i-6)%(i+2)", -2),
- Val("5/-3", bignum.Int(-1)),
- Val("(i+4)/(i-4)", -1),
- Val("5%-3", bignum.Int(2)),
- Val("(i+4)%(i-4)", 2),
- Val("-5/-3", bignum.Int(1)),
- Val("(i-6)/(i-4)", 1),
- Val("-5%-3", bignum.Int(-2)),
- Val("(i-6)%(i-4)", -2),
-
- // Examples from "Arithmetic operators"
- Val("11/4", bignum.Int(2)),
- Val("(i+10)/4", 2),
- Val("11%4", bignum.Int(3)),
- Val("(i+10)%4", 3),
- Val("11>>2", bignum.Int(2)),
- Val("(i+10)>>2", 2),
- Val("11&3", bignum.Int(3)),
- Val("(i+10)&3", 3),
- Val("-11/4", bignum.Int(-2)),
- Val("(i-12)/4", -2),
- Val("-11%4", bignum.Int(-3)),
- Val("(i-12)%4", -3),
- Val("-11>>2", bignum.Int(-3)),
- Val("(i-12)>>2", -3),
- Val("-11&3", bignum.Int(1)),
- Val("(i-12)&3", 1),
-
- // TODO(austin) Test bit ops
-
- // For shift, we try nearly every combination of positive
- // ideal int, negative ideal int, big ideal int, ideal
- // fractional float, ideal non-fractional float, int, uint,
- // and float.
- Val("2<<2", bignum.Int(2<<2)),
- CErr("2<<(-1)", constantUnderflows),
- CErr("2<<0x10000000000000000", constantOverflows),
- CErr("2<<2.5", constantTruncated),
- Val("2<<2.0", bignum.Int(2<<2.0)),
- CErr("2<<i", mustBeUnsigned),
- Val("2<<u", 2<<1),
- CErr("2<<f", opTypes),
-
- Val("-2<<2", bignum.Int(-2<<2)),
- CErr("-2<<(-1)", constantUnderflows),
- CErr("-2<<0x10000000000000000", constantOverflows),
- CErr("-2<<2.5", constantTruncated),
- Val("-2<<2.0", bignum.Int(-2<<2.0)),
- CErr("-2<<i", mustBeUnsigned),
- Val("-2<<u", -2<<1),
- CErr("-2<<f", opTypes),
-
- Val("0x10000000000000000<<2", hugeInteger.Shl(2)),
- CErr("0x10000000000000000<<(-1)", constantUnderflows),
- CErr("0x10000000000000000<<0x10000000000000000", constantOverflows),
- CErr("0x10000000000000000<<2.5", constantTruncated),
- Val("0x10000000000000000<<2.0", hugeInteger.Shl(2)),
- CErr("0x10000000000000000<<i", mustBeUnsigned),
- CErr("0x10000000000000000<<u", constantOverflows),
- CErr("0x10000000000000000<<f", opTypes),
-
- CErr("2.5<<2", opTypes),
- CErr("2.0<<2", opTypes),
-
- Val("i<<2", 1<<2),
- CErr("i<<(-1)", constantUnderflows),
- CErr("i<<0x10000000000000000", constantOverflows),
- CErr("i<<2.5", constantTruncated),
- Val("i<<2.0", 1<<2),
- CErr("i<<i", mustBeUnsigned),
- Val("i<<u", 1<<1),
- CErr("i<<f", opTypes),
- Val("i<<u", 1<<1),
-
- Val("u<<2", uint(1<<2)),
- CErr("u<<(-1)", constantUnderflows),
- CErr("u<<0x10000000000000000", constantOverflows),
- CErr("u<<2.5", constantTruncated),
- Val("u<<2.0", uint(1<<2)),
- CErr("u<<i", mustBeUnsigned),
- Val("u<<u", uint(1<<1)),
- CErr("u<<f", opTypes),
- Val("u<<u", uint(1<<1)),
-
- CErr("f<<2", opTypes),
-
- // <, <=, >, >=
- Val("1<2", 1<2),
- Val("1<=2", 1<=2),
- Val("2<=2", 2<=2),
- Val("1>2", 1>2),
- Val("1>=2", 1>=2),
- Val("2>=2", 2>=2),
-
- Val("i<2", 1<2),
- Val("i<=2", 1<=2),
- Val("i+1<=2", 2<=2),
- Val("i>2", 1>2),
- Val("i>=2", 1>=2),
- Val("i+1>=2", 2>=2),
-
- Val("u<2", 1<2),
- Val("f<2", 1<2),
-
- Val("s<\"b\"", true),
- Val("s<\"a\"", false),
- Val("s<=\"abc\"", true),
- Val("s>\"aa\"", true),
- Val("s>\"ac\"", false),
- Val("s>=\"abc\"", true),
-
- CErr("i<u", opTypes),
- CErr("i<f", opTypes),
- CErr("i<s", opTypes),
- CErr("&i<&i", opTypes),
- CErr("ai<ai", opTypes),
-
- // ==, !=
- Val("1==1", true),
- Val("1!=1", false),
- Val("1==2", false),
- Val("1!=2", true),
-
- Val("1.0==1", true),
- Val("1.5==1", false),
-
- Val("i==1", true),
- Val("i!=1", false),
- Val("i==2", false),
- Val("i!=2", true),
-
- Val("u==1", true),
- Val("f==1", true),
-
- Val("s==\"abc\"", true),
- Val("s!=\"abc\"", false),
- Val("s==\"abcd\"", false),
- Val("s!=\"abcd\"", true),
-
- Val("&i==&i", true),
- Val("&i==&i2", false),
-
- Val("fn==fn", true),
- Val("fn==func(int)int{return 0}", false),
-
- CErr("i==u", opTypes),
- CErr("i==f", opTypes),
- CErr("&i==&f", opTypes),
- CErr("ai==ai", opTypes),
- CErr("t==t", opTypes),
- CErr("fn==oneTwo", opTypes),
-}
-
-func TestExpr(t *testing.T) {
- runTests(t, "exprTests", exprTests);
-}
diff --git a/usr/austin/eval/func.go b/usr/austin/eval/func.go
deleted file mode 100644
index 3bf52871d..000000000
--- a/usr/austin/eval/func.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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"
-
-/*
- * Virtual machine
- */
-
-type Thread struct {
- abort chan os.Error;
- pc uint;
- // The execution frame of this function. This remains the
- // same throughout a function invocation.
- f *Frame;
-}
-
-type code []func(*Thread)
-
-func (i code) exec(t *Thread) {
- opc := t.pc;
- t.pc = 0;
- l := uint(len(i));
- for t.pc < l {
- pc := t.pc;
- t.pc++;
- i[pc](t);
- }
- t.pc = opc;
-}
-
-/*
- * Code buffer
- */
-
-type codeBuf struct {
- instrs code;
-}
-
-func newCodeBuf() *codeBuf {
- return &codeBuf{make(code, 0, 16)};
-}
-
-func (b *codeBuf) push(instr func(*Thread)) {
- n := len(b.instrs);
- if n >= cap(b.instrs) {
- a := make(code, n, n*2);
- for i := range b.instrs {
- a[i] = b.instrs[i];
- }
- b.instrs = a;
- }
- b.instrs = b.instrs[0:n+1];
- b.instrs[n] = instr;
-}
-
-func (b *codeBuf) nextPC() uint {
- return uint(len(b.instrs));
-}
-
-func (b *codeBuf) get() code {
- // Freeze this buffer into an array of exactly the right size
- a := make(code, len(b.instrs));
- for i := range b.instrs {
- a[i] = b.instrs[i];
- }
- return code(a);
-}
-
-/*
- * User-defined functions
- */
-
-type evalFunc struct {
- outer *Frame;
- frameSize int;
- code code;
-}
-
-func (f *evalFunc) NewFrame() *Frame {
- return f.outer.child(f.frameSize);
-}
-
-func (f *evalFunc) Call(t *Thread) {
- f.code.exec(t);
-}
diff --git a/usr/austin/eval/gen.go b/usr/austin/eval/gen.go
deleted file mode 100644
index 06939e58c..000000000
--- a/usr/austin/eval/gen.go
+++ /dev/null
@@ -1,375 +0,0 @@
-// 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
-
-// generate operator implementations
-
-import (
- "log";
- "os";
- "template";
-)
-
-type Op struct {
- Name string;
- Expr string;
- Body string; // overrides Expr
- ConstExpr string;
- AsRightName string;
- ReturnType string;
- Types []*Type;
-}
-
-type Size struct {
- Bits int;
- Sized string;
-}
-
-type Type struct {
- Repr string;
- Value string;
- Native string;
- As string;
- IsIdeal bool;
- HasAssign bool;
- Sizes []Size;
-}
-
-var (
- boolType = &Type{ Repr: "*boolType", Value: "BoolValue", Native: "bool", As: "asBool" };
- uintType = &Type{ Repr: "*uintType", Value: "UintValue", Native: "uint64", As: "asUint",
- Sizes: []Size{ Size{8, "uint8"}, Size{16, "uint16"}, Size{32, "uint32"}, Size{64, "uint64"}, Size{0, "uint"}}
- };
- intType = &Type{ Repr: "*intType", Value: "IntValue", Native: "int64", As: "asInt",
- Sizes: []Size{Size{8, "int8"}, Size{16, "int16"}, Size{32, "int32"}, Size{64, "int64"}, Size{0, "int"}}
- };
- idealIntType = &Type{ Repr: "*idealIntType", Value: "IdealIntValue", Native: "*bignum.Integer", As: "asIdealInt", IsIdeal: true };
- floatType = &Type{ Repr: "*floatType", Value: "FloatValue", Native: "float64", As: "asFloat",
- Sizes: []Size{Size{32, "float32"}, Size{64, "float64"}, Size{0, "float"}}
- };
- idealFloatType = &Type{ Repr: "*idealFloatType", Value: "IdealFloatValue", Native: "*bignum.Rational", As: "asIdealFloat", IsIdeal: true };
- stringType = &Type{ Repr: "*stringType", Value: "StringValue", Native: "string", As: "asString" };
- arrayType = &Type{ Repr: "*ArrayType", Value: "ArrayValue", Native: "ArrayValue", As: "asArray", HasAssign: true };
- structType = &Type{ Repr: "*StructType", Value: "StructValue", Native: "StructValue", As: "asStruct", HasAssign: true };
- ptrType = &Type{ Repr: "*PtrType", Value: "PtrValue", Native: "Value", As: "asPtr" };
- funcType = &Type{ Repr: "*FuncType", Value: "FuncValue", Native: "Func", As: "asFunc" };
- sliceType = &Type{ Repr: "*SliceType", Value: "SliceValue", Native: "Slice", As: "asSlice" };
- mapType = &Type{ Repr: "*MapType", Value: "MapValue", Native: "Map", As: "asMap" };
-
- all = []*Type{
- boolType,
- uintType,
- intType,
- idealIntType,
- floatType,
- idealFloatType,
- stringType,
- arrayType,
- structType,
- ptrType,
- funcType,
- sliceType,
- mapType,
- };
- bools = all[0:1];
- integers = all[1:4];
- shiftable = all[1:3];
- numbers = all[1:6];
- addable = all[1:7];
- cmpable = []*Type{
- boolType,
- uintType,
- intType,
- idealIntType,
- floatType,
- idealFloatType,
- stringType,
- ptrType,
- funcType,
- mapType,
- };
-)
-
-var unOps = []Op{
- Op{ Name: "Neg", Expr: "-v", ConstExpr: "v.Neg()", Types: numbers },
- Op{ Name: "Not", Expr: "!v", Types: bools },
- Op{ Name: "Xor", Expr: "^v", ConstExpr: "v.Neg().Sub(bignum.Int(1))", Types: integers },
-}
-
-var binOps = []Op{
- Op{ Name: "Add", Expr: "l + r", ConstExpr: "l.Add(r)", Types: addable },
- Op{ Name: "Sub", Expr: "l - r", ConstExpr: "l.Sub(r)", Types: numbers },
- Op{ Name: "Mul", Expr: "l * r", ConstExpr: "l.Mul(r)", Types: numbers },
- Op{ Name: "Quo",
- Body: "if r == 0 { t.Abort(DivByZeroError{}) } ret = l / r",
- ConstExpr: "l.Quo(r)",
- Types: numbers,
- },
- Op{ Name: "Rem",
- Body: "if r == 0 { t.Abort(DivByZeroError{}) } ret = l % r",
- ConstExpr: "l.Rem(r)",
- Types: integers,
- },
- Op{ Name: "And", Expr: "l & r", ConstExpr: "l.And(r)", Types: integers },
- Op{ Name: "Or", Expr: "l | r", ConstExpr: "l.Or(r)", Types: integers },
- Op{ Name: "Xor", Expr: "l ^ r", ConstExpr: "l.Xor(r)", Types: integers },
- Op{ Name: "AndNot", Expr: "l &^ r", ConstExpr: "l.AndNot(r)", Types: integers },
- Op{ Name: "Shl", Expr: "l << r", ConstExpr: "l.Shl(uint(r.Value()))",
- AsRightName: "asUint", Types: shiftable
- },
- Op{ Name: "Shr", Expr: "l >> r", ConstExpr: "l.Shr(uint(r.Value()))",
- AsRightName: "asUint", Types: shiftable
- },
- Op{ Name: "Lss", Expr: "l < r", ConstExpr: "l.Cmp(r) < 0", ReturnType: "bool", Types: addable },
- Op{ Name: "Gtr", Expr: "l > r", ConstExpr: "l.Cmp(r) > 0", ReturnType: "bool", Types: addable },
- Op{ Name: "Leq", Expr: "l <= r", ConstExpr: "l.Cmp(r) <= 0", ReturnType: "bool", Types: addable },
- Op{ Name: "Geq", Expr: "l >= r", ConstExpr: "l.Cmp(r) >= 0", ReturnType: "bool", Types: addable },
- Op{ Name: "Eql", Expr: "l == r", ConstExpr: "l.Cmp(r) == 0", ReturnType: "bool", Types: cmpable },
- Op{ Name: "Neq", Expr: "l != r", ConstExpr: "l.Cmp(r) != 0", ReturnType: "bool", Types: cmpable },
-}
-
-type Data struct {
- UnaryOps []Op;
- BinaryOps []Op;
- Types []*Type;
-}
-
-var data = Data {
- unOps,
- binOps,
- all,
-}
-
-const templateStr = `
-// This file is machine generated by gen.go.
-// 6g gen.go && 6l gen.6 && ./6.out >expr1.go
-
-package eval
-
-import (
- "bignum";
- "log";
-)
-
-/*
- * "As" functions. These retrieve evaluator functions from an
- * expr, panicking if the requested evaluator has the wrong type.
- */
-ยซ.repeated section Typesยป
-ยซ.section IsIdealยป
-func (a *expr) ยซAsยป() (func() ยซNativeยป) {
- return a.eval.(func()(ยซNativeยป))
-}
-ยซ.orยป
-func (a *expr) ยซAsยป() (func(*Thread) ยซNativeยป) {
- return a.eval.(func(*Thread)(ยซNativeยป))
-}
-ยซ.endยป
-ยซ.endยป
-func (a *expr) asMulti() (func(*Thread) []Value) {
- return a.eval.(func(*Thread)[]Value)
-}
-
-func (a *expr) asInterface() (func(*Thread) interface{}) {
- switch sf := a.eval.(type) {
-ยซ.repeated section Typesยป
-ยซ.section IsIdealยป
- case func()ยซNativeยป:
- return func(*Thread) interface{} { return sf() }
-ยซ.orยป
- case func(t *Thread)ยซNativeยป:
- return func(t *Thread) interface{} { return sf(t) }
-ยซ.endยป
-ยซ.endยป
- default:
- log.Crashf("unexpected expression node type %T at %v", a.eval, a.pos);
- }
- panic();
-}
-
-/*
- * Operator generators.
- */
-
-func (a *expr) genConstant(v Value) {
- switch a.t.lit().(type) {
-ยซ.repeated section Typesยป
- case ยซReprยป:
-ยซ.section IsIdealยป
- val := v.(ยซValueยป).Get();
- a.eval = func() ยซNativeยป { return val }
-ยซ.orยป
- a.eval = func(t *Thread) ยซNativeยป { return v.(ยซValueยป).Get(t) }
-ยซ.endยป
-ยซ.endยป
- default:
- log.Crashf("unexpected constant type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genIdentOp(level, index int) {
- a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) };
- switch a.t.lit().(type) {
-ยซ.repeated section Typesยป
-ยซ.section IsIdealยป
-ยซ.orยป
- case ยซReprยป:
- a.eval = func(t *Thread) ยซNativeยป { return t.f.Get(level, index).(ยซValueยป).Get(t) }
-ยซ.endยป
-ยซ.endยป
- default:
- log.Crashf("unexpected identifier type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genFuncCall(call func(t *Thread) []Value) {
- a.exec = func(t *Thread) { call(t)};
- switch a.t.lit().(type) {
-ยซ.repeated section Typesยป
-ยซ.section IsIdealยป
-ยซ.orยป
- case ยซReprยป:
- a.eval = func(t *Thread) ยซNativeยป { return call(t)[0].(ยซValueยป).Get(t) }
-ยซ.endยป
-ยซ.endยป
- case *MultiType:
- a.eval = func(t *Thread) []Value { return call(t) }
- default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos);
- }
-}
-
-func (a *expr) genValue(vf func(*Thread) Value) {
- a.evalAddr = vf;
- switch a.t.lit().(type) {
-ยซ.repeated section Typesยป
-ยซ.section IsIdealยป
-ยซ.orยป
- case ยซReprยป:
- a.eval = func(t *Thread) ยซNativeยป { return vf(t).(ยซValueยป).Get(t) }
-ยซ.endยป
-ยซ.endยป
- default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos);
- }
-}
-
-ยซ.repeated section UnaryOpsยป
-func (a *expr) genUnaryOpยซNameยป(v *expr) {
- switch a.t.lit().(type) {
-ยซ.repeated section Typesยป
- case ยซReprยป:
-ยซ.section IsIdealยป
- v := v.ยซAsยป()();
- val := ยซConstExprยป;
- a.eval = func() ยซNativeยป { return val }
-ยซ.orยป
- vf := v.ยซAsยป();
- a.eval = func(t *Thread) ยซNativeยป { v := vf(t); return ยซExprยป }
-ยซ.endยป
-ยซ.endยป
- default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos);
- }
-}
-
-ยซ.endยป
-func (a *expr) genBinOpLogAnd(l, r *expr) {
- lf := l.asBool();
- rf := r.asBool();
- a.eval = func(t *Thread) bool { return lf(t) && rf(t) }
-}
-
-func (a *expr) genBinOpLogOr(l, r *expr) {
- lf := l.asBool();
- rf := r.asBool();
- a.eval = func(t *Thread) bool { return lf(t) || rf(t) }
-}
-
-ยซ.repeated section BinaryOpsยป
-func (a *expr) genBinOpยซNameยป(l, r *expr) {
- switch t := l.t.lit().(type) {
-ยซ.repeated section Typesยป
- case ยซReprยป:
- ยซ.section IsIdealยป
- l := l.ยซAsยป()();
- r := r.ยซAsยป()();
- val := ยซConstExprยป;
- ยซ.section ReturnTypeยป
- a.eval = func(t *Thread) ยซReturnTypeยป { return val }
- ยซ.orยป
- a.eval = func() ยซNativeยป { return val }
- ยซ.endยป
- ยซ.orยป
- lf := l.ยซAsยป();
- rf := r.ยซ.section AsRightNameยปยซ@ยปยซ.orยปยซAsยปยซ.endยป();
- ยซ.section ReturnTypeยป
- a.eval = func(t *Thread) ยซ@ยป {
- l, r := lf(t), rf(t);
- return ยซExprยป
- }
- ยซ.orยป
- ยซ.section Sizesยป
- switch t.Bits {
- ยซ.repeated section @ยป
- case ยซBitsยป:
- a.eval = func(t *Thread) ยซNativeยป {
- l, r := lf(t), rf(t);
- var ret ยซNativeยป;
- ยซ.section Bodyยป
- ยซBodyยป;
- ยซ.orยป
- ret = ยซExprยป;
- ยซ.endยป
- return ยซNativeยป(ยซSizedยป(ret))
- }
- ยซ.endยป
- default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
- }
- ยซ.orยป
- a.eval = func(t *Thread) ยซNativeยป {
- l, r := lf(t), rf(t);
- return ยซExprยป
- }
- ยซ.endยป
- ยซ.endยป
- ยซ.endยป
- ยซ.endยป
- default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
- }
-}
-
-ยซ.endยป
-func genAssign(lt Type, r *expr) (func(lv Value, t *Thread)) {
- switch lt.lit().(type) {
-ยซ.repeated section Typesยป
-ยซ.section IsIdealยป
-ยซ.orยป
- case ยซReprยป:
- rf := r.ยซAsยป();
- return func(lv Value, t *Thread) { ยซ.section HasAssignยปlv.Assign(t, rf(t))ยซ.orยปlv.(ยซValueยป).Set(t, rf(t))ยซ.endยป }
-ยซ.endยป
-ยซ.endยป
- default:
- log.Crashf("unexpected left operand type %v at %v", lt, r.pos);
- }
- panic();
-}
-`
-
-func main() {
- t := template.New(nil);
- t.SetDelims("ยซ", "ยป");
- err := t.Parse(templateStr);
- if err != nil {
- log.Exit(err);
- }
- err = t.Execute(data, os.Stdout);
- if err != nil {
- log.Exit(err);
- }
-}
diff --git a/usr/austin/eval/main.go b/usr/austin/eval/main.go
deleted file mode 100644
index 2a6d94845..000000000
--- a/usr/austin/eval/main.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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";
- "flag";
- "go/parser";
- "go/scanner";
- "io";
- "os";
-)
-
-var filename = flag.String("f", "", "file to run");
-
-func main() {
- flag.Parse();
- w := eval.NewWorld();
- if *filename != "" {
- data, err := io.ReadFile(*filename);
- if err != nil {
- println(err.String());
- os.Exit(1);
- }
- file, err := parser.ParseFile(*filename, data, 0);
- if err != nil {
- println(err.String());
- os.Exit(1);
- }
- code, err := w.CompileDeclList(file.Decls);
- if err != nil {
- if list, ok := err.(scanner.ErrorList); ok {
- for _, e := range list {
- println(e.String());
- }
- } else {
- println(err.String());
- }
- os.Exit(1);
- }
- _, err := code.Run();
- if err != nil {
- println(err.String());
- os.Exit(1);
- }
- code, err = w.Compile("init()");
- if code != nil {
- _, err := code.Run();
- if err != nil {
- println(err.String());
- os.Exit(1);
- }
- }
- code, err = w.Compile("main()");
- if err != nil {
- println(err.String());
- os.Exit(1);
- }
- _, err = code.Run();
- if err != nil {
- println(err.String());
- os.Exit(1);
- }
- os.Exit(0);
- }
-
- 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());
- }
- }
-}
-
diff --git a/usr/austin/eval/scope.go b/usr/austin/eval/scope.go
deleted file mode 100644
index 7ee4a8915..000000000
--- a/usr/austin/eval/scope.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// 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 (
- "go/token";
- "log";
-)
-
-/*
- * Blocks and scopes
- */
-
-// A definition can be a *Variable, *Constant, or Type.
-type Def interface {
- Pos() token.Position;
-}
-
-type Variable struct {
- token.Position;
- // Index of this variable in the Frame structure
- Index int;
- // Static type of this variable
- Type Type;
- // Value of this variable. This is only used by Scope.NewFrame;
- // therefore, it is useful for global scopes but cannot be used
- // in function scopes.
- Init Value;
-}
-
-type Constant struct {
- token.Position;
- Type Type;
- Value Value;
-}
-
-// A block represents a definition block in which a name may not be
-// defined more than once.
-type block struct {
- // The block enclosing this one, including blocks in other
- // scopes.
- outer *block;
- // The nested block currently being compiled, or nil.
- inner *block;
- // The Scope containing this block.
- scope *Scope;
- // The Variables, Constants, and Types defined in this block.
- defs map[string] Def;
- // The index of the first variable defined in this block.
- // This must be greater than the index of any variable defined
- // in any parent of this block within the same Scope at the
- // time this block is entered.
- offset int;
- // The number of Variables defined in this block.
- 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
-// some subtree of blocks.
-type Scope struct {
- // The root block of this scope.
- *block;
- // The maximum number of variables required at any point in
- // this Scope. This determines the number of slots needed in
- // Frame's created from this Scope at run-time.
- maxVars int;
-}
-
-func (b *block) enterChild() *block {
- if b.inner != nil && b.inner.scope == b.scope {
- log.Crash("Failed to exit child block before entering another child");
- }
- sub := &block{
- outer: b,
- scope: b.scope,
- defs: make(map[string] Def),
- offset: b.offset+b.numVars,
- };
- b.inner = sub;
- return sub;
-}
-
-func (b *block) exit() {
- if b.outer == nil {
- log.Crash("Cannot exit top-level block");
- }
- if b.outer.scope == b.scope {
- if b.outer.inner != b {
- log.Crash("Already exited block");
- }
- if b.inner != nil && b.inner.scope == b.scope {
- log.Crash("Exit of parent block without exit of child block");
- }
- }
- b.outer.inner = nil;
-}
-
-func (b *block) ChildScope() *Scope {
- if b.inner != nil && b.inner.scope == b.scope {
- log.Crash("Failed to exit child block before entering a child scope");
- }
- sub := b.enterChild();
- sub.offset = 0;
- sub.scope = &Scope{sub, 0};
- return sub.scope;
-}
-
-func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, Def) {
- if prev, ok := b.defs[name]; ok {
- return nil, prev;
- }
- v := b.defineSlot(t, false);
- v.Position = pos;
- b.defs[name] = v;
- return v, nil;
-}
-
-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 {
- log.Crash("Failed to exit child block before defining variable");
- }
- index := -1;
- if !b.global || temp {
- index = b.offset+b.numVars;
- b.numVars++;
- if index >= b.scope.maxVars {
- b.scope.maxVars = index+1;
- }
- }
- v := &Variable{token.Position{}, index, t, nil};
- return v;
-}
-
-func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) (*Constant, Def) {
- if prev, ok := b.defs[name]; ok {
- return nil, prev;
- }
- c := &Constant{pos, t, v};
- b.defs[name] = c;
- return c, nil;
-}
-
-func (b *block) DefineType(name string, pos token.Position, t Type) Type {
- if _, ok := b.defs[name]; ok {
- return nil;
- }
- nt := &NamedType{pos, name, nil, true, make(map[string] Method)};
- if t != nil {
- nt.Complete(t);
- }
- b.defs[name] = nt;
- return nt;
-}
-
-func (b *block) Lookup(name string) (bl *block, level int, def Def) {
- for b != nil {
- if d, ok := b.defs[name]; ok {
- return b, level, d;
- }
- if b.outer != nil && b.scope != b.outer.scope {
- level++;
- }
- b = b.outer;
- }
- return nil, 0, nil;
-}
-
-func (s *Scope) NewFrame(outer *Frame) *Frame {
- return outer.child(s.maxVars);
-}
-
-/*
- * Frames
- */
-
-type Frame struct {
- Outer *Frame;
- Vars []Value;
-}
-
-func (f *Frame) Get(level int, index int) Value {
- for ; level > 0; level-- {
- f = f.Outer;
- }
- return f.Vars[index];
-}
-
-func (f *Frame) child(numVars int) *Frame {
- // TODO(austin) This is probably rather expensive. All values
- // require heap allocation and zeroing them when we execute a
- // definition typically requires some computation.
- return &Frame{f, make([]Value, numVars)};
-}
diff --git a/usr/austin/eval/stmt.go b/usr/austin/eval/stmt.go
deleted file mode 100644
index 9ec6fb83d..000000000
--- a/usr/austin/eval/stmt.go
+++ /dev/null
@@ -1,1313 +0,0 @@
-// 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 (
- "bignum";
- "log";
- "go/ast";
- "go/token";
-)
-
-const (
- returnPC = ^uint(0);
- badPC = ^uint(1);
-)
-
-/*
- * Statement compiler
- */
-
-type stmtCompiler struct {
- *blockCompiler;
- pos token.Position;
- // This statement's label, or nil if it is not labeled.
- stmtLabel *label;
-}
-
-func (a *stmtCompiler) diag(format string, args ...) {
- a.diagAt(&a.pos, format, args);
-}
-
-/*
- * Flow checker
- */
-
-type flowEnt struct {
- // Whether this flow entry is conditional. If true, flow can
- // continue to the next PC.
- cond bool;
- // True if this will terminate flow (e.g., a return statement).
- // cond must be false and jumps must be nil if this is true.
- term bool;
- // PC's that can be reached from this flow entry.
- jumps []*uint;
- // Whether this flow entry has been visited by reachesEnd.
- visited bool;
-}
-
-type flowBlock struct {
- // If this is a goto, the target label.
- target string;
- // The inner-most block containing definitions.
- block *block;
- // The numVars from each block leading to the root of the
- // scope, starting at block.
- numVars []int;
-}
-
-type flowBuf struct {
- cb *codeBuf;
- // ents is a map from PC's to flow entries. Any PC missing
- // from this map is assumed to reach only PC+1.
- ents map[uint] *flowEnt;
- // gotos is a map from goto positions to information on the
- // block at the point of the goto.
- gotos map[*token.Position] *flowBlock;
- // labels is a map from label name to information on the block
- // at the point of the label. labels are tracked by name,
- // since mutliple labels at the same PC can have different
- // blocks.
- labels map[string] *flowBlock;
-}
-
-func newFlowBuf(cb *codeBuf) *flowBuf {
- return &flowBuf{cb, make(map[uint] *flowEnt), make(map[*token.Position] *flowBlock), make(map[string] *flowBlock)};
-}
-
-// put creates a flow control point for the next PC in the code buffer.
-// This should be done before pushing the instruction into the code buffer.
-func (f *flowBuf) put(cond bool, term bool, jumps []*uint) {
- pc := f.cb.nextPC();
- if ent, ok := f.ents[pc]; ok {
- log.Crashf("Flow entry already exists at PC %d: %+v", pc, ent);
- }
- f.ents[pc] = &flowEnt{cond, term, jumps, false};
-}
-
-// putTerm creates a flow control point at the next PC that
-// unconditionally terminates execution.
-func (f *flowBuf) putTerm() {
- f.put(false, true, nil);
-}
-
-// put1 creates a flow control point at the next PC that jumps to one
-// PC and, if cond is true, can also continue to the PC following the
-// next PC.
-func (f *flowBuf) put1(cond bool, jumpPC *uint) {
- f.put(cond, false, []*uint {jumpPC});
-}
-
-func newFlowBlock(target string, b *block) *flowBlock {
- // Find the inner-most block containing definitions
- for b.numVars == 0 && b.outer != nil && b.outer.scope == b.scope {
- b = b.outer;
- }
-
- // Count parents leading to the root of the scope
- n := 0;
- for bp := b; bp.scope == b.scope; bp = bp.outer {
- n++;
- }
-
- // Capture numVars from each block to the root of the scope
- numVars := make([]int, n);
- i := 0;
- for bp := b; i < n; bp = bp.outer {
- numVars[i] = bp.numVars;
- i++;
- }
-
- return &flowBlock{target, b, numVars};
-}
-
-// putGoto captures the block at a goto statement. This should be
-// called in addition to putting a flow control point.
-func (f *flowBuf) putGoto(pos token.Position, target string, b *block) {
- f.gotos[&pos] = newFlowBlock(target, b);
-}
-
-// putLabel captures the block at a label.
-func (f *flowBuf) putLabel(name string, b *block) {
- f.labels[name] = newFlowBlock("", b);
-}
-
-// reachesEnd returns true if the end of f's code buffer can be
-// reached from the given program counter. Error reporting is the
-// caller's responsibility.
-func (f *flowBuf) reachesEnd(pc uint) bool {
- endPC := f.cb.nextPC();
- if pc > endPC {
- log.Crashf("Reached bad PC %d past end PC %d", pc, endPC);
- }
-
- for ; pc < endPC; pc++ {
- ent, ok := f.ents[pc];
- if !ok {
- continue;
- }
-
- if ent.visited {
- return false;
- }
- ent.visited = true;
-
- if ent.term {
- return false;
- }
-
- // If anything can reach the end, we can reach the end
- // from pc.
- for _, j := range ent.jumps {
- if f.reachesEnd(*j) {
- return true;
- }
- }
- // If the jump was conditional, we can reach the next
- // PC, so try reaching the end from it.
- if ent.cond {
- continue;
- }
- return false;
- }
- return true;
-}
-
-// gotosObeyScopes returns true if no goto statement causes any
-// variables to come into scope that were not in scope at the point of
-// the goto. Reports any errors using the given compiler.
-func (f *flowBuf) gotosObeyScopes(a *compiler) {
- for pos, src := range f.gotos {
- tgt := f.labels[src.target];
-
- // The target block must be a parent of this block
- numVars := src.numVars;
- b := src.block;
- for len(numVars) > 0 && b != tgt.block {
- b = b.outer;
- numVars = numVars[1:len(numVars)];
- }
- if b != tgt.block {
- // We jumped into a deeper block
- a.diagAt(pos, "goto causes variables to come into scope");
- return;
- }
-
- // There must be no variables in the target block that
- // did not exist at the jump
- tgtNumVars := tgt.numVars;
- for i := range numVars {
- if tgtNumVars[i] > numVars[i] {
- a.diagAt(pos, "goto causes variables to come into scope");
- return;
- }
- }
- }
-}
-
-/*
- * Statement generation helpers
- */
-
-func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
- v, prev := a.block.DefineVar(ident.Value, ident.Pos(), t);
- if prev != nil {
- // TODO(austin) It's silly that we have to capture
- // Pos() in a variable.
- pos := prev.Pos();
- if pos.IsValid() {
- a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Value, &pos);
- } else {
- a.diagAt(ident, "variable %s redeclared in this block", ident.Value);
- }
- return nil;
- }
-
- // Initialize the variable
- index := v.Index;
- if v.Index >= 0 {
- a.push(func(v *Thread) {
- v.f.Vars[index] = t.Zero();
- });
- }
- return v;
-}
-
-// TODO(austin) Move doAssign to here
-
-/*
- * Statement compiler
- */
-
-func (a *stmtCompiler) compile(s ast.Stmt) {
- if a.block.inner != nil {
- log.Crash("Child scope still entered");
- }
-
- notimpl := false;
- switch s := s.(type) {
- case *ast.BadStmt:
- // Error already reported by parser.
- a.silentErrors++;
-
- case *ast.DeclStmt:
- a.compileDeclStmt(s);
-
- case *ast.EmptyStmt:
- // Do nothing.
-
- case *ast.LabeledStmt:
- a.compileLabeledStmt(s);
-
- case *ast.ExprStmt:
- a.compileExprStmt(s);
-
- case *ast.IncDecStmt:
- a.compileIncDecStmt(s);
-
- case *ast.AssignStmt:
- a.compileAssignStmt(s);
-
- case *ast.GoStmt:
- notimpl = true;
-
- case *ast.DeferStmt:
- notimpl = true;
-
- case *ast.ReturnStmt:
- a.compileReturnStmt(s);
-
- case *ast.BranchStmt:
- a.compileBranchStmt(s);
-
- case *ast.BlockStmt:
- a.compileBlockStmt(s);
-
- case *ast.IfStmt:
- a.compileIfStmt(s);
-
- case *ast.CaseClause:
- a.diag("case clause outside switch");
-
- case *ast.SwitchStmt:
- a.compileSwitchStmt(s);
-
- case *ast.TypeCaseClause:
- notimpl = true;
-
- case *ast.TypeSwitchStmt:
- notimpl = true;
-
- case *ast.CommClause:
- notimpl = true;
-
- case *ast.SelectStmt:
- notimpl = true;
-
- case *ast.ForStmt:
- a.compileForStmt(s);
-
- case *ast.RangeStmt:
- notimpl = true;
-
- default:
- log.Crashf("unexpected ast node type %T", s);
- }
-
- if notimpl {
- a.diag("%T statment node not implemented", s);
- }
-
- if a.block.inner != nil {
- log.Crash("Forgot to exit child scope");
- }
-}
-
-func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
- switch decl := s.Decl.(type) {
- case *ast.BadDecl:
- // Do nothing. Already reported by parser.
- a.silentErrors++;
-
- case *ast.FuncDecl:
- if !a.block.global {
- log.Crash("FuncDecl at statement level");
- }
-
- case *ast.GenDecl:
- if decl.Tok == token.IMPORT && !a.block.global {
- log.Crash("import at statement level");
- }
-
- default:
- log.Crashf("Unexpected Decl type %T", s.Decl);
- }
- a.compileDecl(s.Decl);
-}
-
-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 {
- // Declaration 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);
- }
- }
-}
-
-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, prev := a.block.DefineConst(d.Name.Value, a.pos, decl.Type, decl.Type.Zero());
- if prev != nil {
- pos := prev.Pos();
- if pos.IsValid() {
- a.diagAt(d.Name, "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Value, &pos);
- } else {
- a.diagAt(d.Name, "identifier %s redeclared in this block", d.Name.Value);
- }
- }
- fn := a.compileFunc(a.block, decl, d.Body);
- if c == nil || fn == nil {
- return;
- }
- var zeroThread Thread;
- c.Value.(FuncValue).Set(nil, 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) {
- // Define label
- l, ok := a.labels[s.Label.Value];
- if ok {
- if l.resolved.IsValid() {
- a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Value, &l.resolved);
- }
- } else {
- pc := badPC;
- l = &label{name: s.Label.Value, gotoPC: &pc};
- a.labels[l.name] = l;
- }
- l.desc = "regular label";
- l.resolved = s.Pos();
-
- // Set goto PC
- *l.gotoPC = a.nextPC();
-
- // Define flow entry so we can check for jumps over declarations.
- a.flow.putLabel(l.name, a.block);
-
- // Compile the statement. Reuse our stmtCompiler for simplicity.
- sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l};
- sc.compile(s.Stmt);
-}
-
-func (a *stmtCompiler) compileExprStmt(s *ast.ExprStmt) {
- bc := a.enterChild();
- defer bc.exit();
-
- e := a.compileExpr(bc.block, false, s.X);
- if e == nil {
- return;
- }
-
- if e.exec == nil {
- a.diag("%s cannot be used as expression statement", e.desc);
- return;
- }
-
- a.push(e.exec);
-}
-
-func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
- // Create temporary block for extractEffect
- bc := a.enterChild();
- defer bc.exit();
-
- l := a.compileExpr(bc.block, false, s.X);
- if l == nil {
- return;
- }
-
- if l.evalAddr == nil {
- l.diag("cannot assign to %s", l.desc);
- return;
- }
- if !(l.t.isInteger() || l.t.isFloat()) {
- l.diagOpType(s.Tok, l.t);
- return;
- }
-
- var op token.Token;
- var desc string;
- switch s.Tok {
- case token.INC:
- op = token.ADD;
- desc = "increment statement";
- case token.DEC:
- op = token.SUB;
- desc = "decrement statement";
- default:
- log.Crashf("Unexpected IncDec token %v", s.Tok);
- }
-
- effect, l := l.extractEffect(bc.block, desc);
-
- one := l.newExpr(IdealIntType, "constant");
- one.pos = s.Pos();
- one.eval = func() *bignum.Integer { return bignum.Int(1) };
-
- binop := l.compileBinaryExpr(op, l, one);
- if binop == nil {
- return;
- }
-
- assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "");
- if assign == nil {
- log.Crashf("compileAssign type check failed");
- }
-
- lf := l.evalAddr;
- a.push(func(v *Thread) {
- effect(v);
- assign(lf(v), v);
- });
-}
-
-func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
- nerr := a.numError();
-
- // 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([]*expr, len(rhs));
- for i, re := range rhs {
- rs[i] = a.compileExpr(a.block, false, re);
- }
-
- errOp := "assignment";
- if tok == token.DEFINE || tok == token.VAR {
- errOp = "declaration";
- }
- ac, ok := a.checkAssign(a.pos, rs, errOp, "value");
- ac.allowMapForms(len(lhs));
-
- // If this is a definition and the LHS is too big, we won't be
- // able to produce the usual error message because we can't
- // begin to infer the types of the LHS.
- if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) {
- a.diag("not enough values for definition");
- }
-
- // Compile left type if there is one
- var declType Type;
- if declTypeExpr != nil {
- declType = a.compileType(a.block, declTypeExpr);
- }
-
- // Compile left side
- ls := make([]*expr, len(lhs));
- nDefs := 0;
- for i, le := range lhs {
- // If this is a definition, get the identifier and its type
- var ident *ast.Ident;
- var lt Type;
- switch tok {
- case token.DEFINE:
- // Check that it's an identifier
- ident, ok = le.(*ast.Ident);
- if !ok {
- a.diagAt(le, "left side of := must be a name");
- // Suppress new defitions errors
- nDefs++;
- continue;
- }
-
- // Is this simply an assignment?
- if _, ok := a.block.defs[ident.Value]; ok {
- ident = nil;
- break;
- }
- nDefs++;
-
- case token.VAR:
- ident = le.(*ast.Ident);
- }
-
- // If it's a definition, get or infer its type.
- if ident != nil {
- // Compute the identifier's type from the RHS
- // type. We use the computed MultiType so we
- // don't have to worry about unpacking.
- switch {
- case declTypeExpr != nil:
- // We have a declaration type, use it.
- // If declType is nil, we gave an
- // error when we compiled it.
- lt = declType;
-
- case i >= len(ac.rmt.Elems):
- // Define a placeholder. We already
- // gave the "not enough" error above.
- lt = nil;
-
- case ac.rmt.Elems[i] == nil:
- // We gave the error when we compiled
- // the RHS.
- lt = nil;
-
- case ac.rmt.Elems[i].isIdeal():
- // If the type is absent and the
- // corresponding expression is a
- // constant expression of ideal
- // integer or ideal float type, the
- // type of the declared variable is
- // int or float respectively.
- switch {
- case ac.rmt.Elems[i].isInteger():
- lt = IntType;
- case ac.rmt.Elems[i].isFloat():
- lt = FloatType;
- default:
- log.Crashf("unexpected ideal type %v", rs[i].t);
- }
-
- default:
- lt = ac.rmt.Elems[i];
- }
- }
-
- // If it's a definition, define the identifier
- if ident != nil {
- if a.defineVar(ident, lt) == nil {
- continue;
- }
- }
-
- // Compile LHS
- ls[i] = a.compileExpr(a.block, false, le);
- if ls[i] == nil {
- continue;
- }
-
- if ls[i].evalMapValue != nil {
- // Map indexes are not generally addressable,
- // 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] = ls[i].newExpr(sub.t, sub.desc);
- ls[i].evalMapValue = sub.evalMapValue;
- mvf := sub.evalMapValue;
- et := sub.t;
- ls[i].evalAddr = func(t *Thread) Value {
- m, k := mvf(t);
- e := m.Elem(t, k);
- if e == nil {
- e = et.Zero();
- m.SetElem(t, k, e);
- }
- return e;
- };
- } else if ls[i].evalAddr == nil {
- ls[i].diag("cannot assign to %s", ls[i].desc);
- continue;
- }
- }
-
- // A short variable declaration may redeclare variables
- // provided they were originally declared in the same block
- // with the same type, and at least one of the variables is
- // new.
- if tok == token.DEFINE && nDefs == 0 {
- a.diag("at least one new variable must be declared");
- return;
- }
-
- // If there have been errors, our arrays are full of nil's so
- // get out of here now.
- if nerr != a.numError() {
- return;
- }
-
- // Check for 'a[x] = r, ok'
- if len(ls) == 1 && len(rs) == 2 && ls[0].evalMapValue != nil {
- a.diag("a[x] = r, ok form not implemented");
- return;
- }
-
- // Create assigner
- var lt Type;
- n := len(lhs);
- if n == 1 {
- lt = ls[0].t;
- } else {
- lts := make([]Type, len(ls));
- for i, l := range ls {
- if l != nil {
- lts[i] = l.t;
- }
- }
- lt = NewMultiType(lts);
- }
- bc := a.enterChild();
- defer bc.exit();
- assign := ac.compile(bc.block, lt);
- if assign == nil {
- return;
- }
-
- // Compile
- if n == 1 {
- // Don't need temporaries and can avoid []Value.
- lf := ls[0].evalAddr;
- a.push(func(t *Thread) { assign(lf(t), t) });
- } else if tok == token.VAR || (tok == token.DEFINE && nDefs == n) {
- // Don't need temporaries
- lfs := make([]func(*Thread) Value, n);
- for i, l := range ls {
- lfs[i] = l.evalAddr;
- }
- a.push(func(t *Thread) {
- dest := make([]Value, n);
- for i, lf := range lfs {
- dest[i] = lf(t);
- }
- assign(multiV(dest), t);
- });
- } else {
- // Need temporaries
- lmt := lt.(*MultiType);
- lfs := make([]func(*Thread) Value, n);
- for i, l := range ls {
- lfs[i] = l.evalAddr;
- }
- a.push(func(t *Thread) {
- temp := lmt.Zero().(multiV);
- assign(temp, t);
- // Copy to destination
- for i := 0; i < n; i ++ {
- // TODO(austin) Need to evaluate LHS
- // before RHS
- lfs[i](t).Assign(t, temp[i]);
- }
- });
- }
-}
-
-var assignOpToOp = map[token.Token] token.Token {
- token.ADD_ASSIGN : token.ADD,
- token.SUB_ASSIGN : token.SUB,
- token.MUL_ASSIGN : token.MUL,
- token.QUO_ASSIGN : token.QUO,
- token.REM_ASSIGN : token.REM,
-
- token.AND_ASSIGN : token.AND,
- token.OR_ASSIGN : token.OR,
- token.XOR_ASSIGN : token.XOR,
- token.SHL_ASSIGN : token.SHL,
- token.SHR_ASSIGN : token.SHR,
- token.AND_NOT_ASSIGN : token.AND_NOT,
-}
-
-func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
- if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
- a.diag("tuple assignment cannot be combined with an arithmetic operation");
- return;
- }
-
- // Create temporary block for extractEffect
- bc := a.enterChild();
- defer bc.exit();
-
- l := a.compileExpr(bc.block, false, s.Lhs[0]);
- r := a.compileExpr(bc.block, false, s.Rhs[0]);
- if l == nil || r == nil {
- return;
- }
-
- if l.evalAddr == nil {
- l.diag("cannot assign to %s", l.desc);
- return;
- }
-
- effect, l := l.extractEffect(bc.block, "operator-assignment");
-
- binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r);
- if binop == nil {
- return;
- }
-
- assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value");
- if assign == nil {
- log.Crashf("compileAssign type check failed");
- }
-
- lf := l.evalAddr;
- a.push(func(t *Thread) {
- effect(t);
- assign(lf(t), t);
- });
-}
-
-func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) {
- switch s.Tok {
- case token.ASSIGN, token.DEFINE:
- a.doAssign(s.Lhs, s.Rhs, s.Tok, nil);
-
- default:
- a.doAssignOp(s);
- }
-}
-
-func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) {
- if a.fnType == nil {
- a.diag("cannot return at the top level");
- return;
- }
-
- if len(s.Results) == 0 && (len(a.fnType.Out) == 0 || a.outVarsNamed) {
- // Simple case. Simply exit from the function.
- a.flow.putTerm();
- a.push(func(v *Thread) { v.pc = returnPC });
- return;
- }
-
- bc := a.enterChild();
- defer bc.exit();
-
- // Compile expressions
- bad := false;
- rs := make([]*expr, len(s.Results));
- for i, re := range s.Results {
- rs[i] = a.compileExpr(bc.block, false, re);
- if rs[i] == nil {
- bad = true;
- }
- }
- if bad {
- return;
- }
-
- // Create assigner
-
- // However, if the expression list in the "return" statement
- // 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(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value");
-
- // XXX(Spec) "The result types of the current function and the
- // called function must match." Match is fuzzy. It should
- // say that they must be assignment compatible.
-
- // Compile
- start := len(a.fnType.In);
- nout := len(a.fnType.Out);
- a.flow.putTerm();
- a.push(func(t *Thread) {
- assign(multiV(t.f.Vars[start:start+nout]), t);
- t.pc = returnPC;
- });
-}
-
-func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label {
- bc := a.blockCompiler;
- for ; bc != nil; bc = bc.parent {
- if bc.label == nil {
- continue;
- }
- l := bc.label;
- if name == nil && pred(l) {
- return l;
- }
- if name != nil && l.name == name.Value {
- if !pred(l) {
- a.diag("cannot %s to %s %s", errOp, l.desc, l.name);
- return nil;
- }
- return l;
- }
- }
- if name == nil {
- a.diag("%s outside %s", errOp, errCtx);
- } else {
- a.diag("%s label %s not defined", errOp, name.Value);
- }
- return nil;
-}
-
-func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
- var pc *uint;
-
- switch s.Tok {
- case token.BREAK:
- l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select");
- if l == nil {
- return;
- }
- pc = l.breakPC;
-
- case token.CONTINUE:
- l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop");
- if l == nil {
- return;
- }
- pc = l.continuePC;
-
- case token.GOTO:
- l, ok := a.labels[s.Label.Value];
- if !ok {
- pc := badPC;
- l = &label{name: s.Label.Value, desc: "unresolved label", gotoPC: &pc, used: s.Pos()};
- a.labels[l.name] = l;
- }
-
- pc = l.gotoPC;
- a.flow.putGoto(s.Pos(), l.name, a.block);
-
- case token.FALLTHROUGH:
- a.diag("fallthrough outside switch");
- return;
-
- default:
- log.Crash("Unexpected branch token %v", s.Tok);
- }
-
- a.flow.put1(false, pc);
- a.push(func(v *Thread) { v.pc = *pc });
-}
-
-func (a *stmtCompiler) compileBlockStmt(s *ast.BlockStmt) {
- bc := a.enterChild();
- bc.compileStmts(s);
- bc.exit();
-}
-
-func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) {
- // The scope of any variables declared by [the init] statement
- // extends to the end of the "if" statement and the variables
- // are initialized once before the statement is entered.
- //
- // XXX(Spec) What this really wants to say is that there's an
- // implicit scope wrapping every if, for, and switch
- // statement. This is subtly different from what it actually
- // says when there's a non-block else clause, because that
- // else claus has to execute in a scope that is *not* the
- // surrounding scope.
- bc := a.enterChild();
- defer bc.exit();
-
- // Compile init statement, if any
- if s.Init != nil {
- bc.compileStmt(s.Init);
- }
-
- elsePC := badPC;
- endPC := badPC;
-
- // Compile condition, if any. If there is no condition, we
- // fall through to the body.
- if s.Cond != nil {
- e := bc.compileExpr(bc.block, false, s.Cond);
- switch {
- case e == nil:
- // Error reported by compileExpr
- case !e.t.isBoolean():
- e.diag("'if' condition must be boolean\n\t%v", e.t);
- default:
- eval := e.asBool();
- a.flow.put1(true, &elsePC);
- a.push(func(t *Thread) {
- if !eval(t) {
- t.pc = elsePC;
- }
- });
- }
- }
-
- // Compile body
- body := bc.enterChild();
- body.compileStmts(s.Body);
- body.exit();
-
- // Compile else
- if s.Else != nil {
- // Skip over else if we executed the body
- a.flow.put1(false, &endPC);
- a.push(func(v *Thread) {
- v.pc = endPC;
- });
- elsePC = a.nextPC();
- bc.compileStmt(s.Else);
- } else {
- elsePC = a.nextPC();
- }
- endPC = a.nextPC();
-}
-
-func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
- // Create implicit scope around switch
- bc := a.enterChild();
- defer bc.exit();
-
- // Compile init statement, if any
- if s.Init != nil {
- bc.compileStmt(s.Init);
- }
-
- // Compile condition, if any, and extract its effects
- var cond *expr;
- condbc := bc.enterChild();
- if s.Tag != nil {
- e := condbc.compileExpr(condbc.block, false, s.Tag);
- if e != nil {
- var effect func(*Thread);
- effect, cond = e.extractEffect(condbc.block, "switch");
- a.push(effect);
- }
- }
-
- // Count cases
- ncases := 0;
- hasDefault := false;
- for _, c := range s.Body.List {
- clause, ok := c.(*ast.CaseClause);
- if !ok {
- a.diagAt(clause, "switch statement must contain case clauses");
- continue;
- }
- if clause.Values == nil {
- if hasDefault {
- a.diagAt(clause, "switch statement contains more than one default case");
- }
- hasDefault = true;
- } else {
- ncases += len(clause.Values);
- }
- }
-
- // Compile case expressions
- cases := make([]func(*Thread) bool, ncases);
- i := 0;
- for _, c := range s.Body.List {
- clause, ok := c.(*ast.CaseClause);
- if !ok {
- continue;
- }
- for _, v := range clause.Values {
- e := condbc.compileExpr(condbc.block, false, v);
- switch {
- case e == nil:
- // Error reported by compileExpr
- case cond == nil && !e.t.isBoolean():
- a.diagAt(v, "'case' condition must be boolean");
- case cond == nil:
- cases[i] = e.asBool();
- case cond != nil:
- // Create comparison
- // TOOD(austin) This produces bad error messages
- compare := e.compileBinaryExpr(token.EQL, cond, e);
- if compare != nil {
- cases[i] = compare.asBool();
- }
- }
- i++;
- }
- }
-
- // Emit condition
- casePCs := make([]*uint, ncases+1);
- endPC := badPC;
-
- a.flow.put(false, false, casePCs);
- a.push(func(t *Thread) {
- for i, c := range cases {
- if c(t) {
- t.pc = *casePCs[i];
- return;
- }
- }
- t.pc = *casePCs[ncases];
- });
- condbc.exit();
-
- // Compile cases
- i = 0;
- for _, c := range s.Body.List {
- clause, ok := c.(*ast.CaseClause);
- if !ok {
- continue;
- }
-
- // Save jump PC's
- pc := a.nextPC();
- if clause.Values != nil {
- for _ = range clause.Values {
- casePCs[i] = &pc;
- i++;
- }
- } else {
- // Default clause
- casePCs[ncases] = &pc;
- }
-
- // Compile body
- fall := false;
- for j, s := range clause.Body {
- if br, ok := s.(*ast.BranchStmt); ok && br.Tok == token.FALLTHROUGH {
- // println("Found fallthrough");
- // It may be used only as the final
- // non-empty statement in a case or
- // default clause in an expression
- // "switch" statement.
- for _, s2 := range clause.Body[j+1:len(clause.Body)] {
- // XXX(Spec) 6g also considers
- // empty blocks to be empty
- // statements.
- if _, ok := s2.(*ast.EmptyStmt); !ok {
- a.diagAt(s, "fallthrough statement must be final statement in case");
- break;
- }
- }
- fall = true;
- } else {
- bc.compileStmt(s);
- }
- }
- // Jump out of switch, unless there was a fallthrough
- if !fall {
- a.flow.put1(false, &endPC);
- a.push(func(v *Thread) { v.pc = endPC });
- }
- }
-
- // Get end PC
- endPC = a.nextPC();
- if !hasDefault {
- casePCs[ncases] = &endPC;
- }
-}
-
-func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
- // Wrap the entire for in a block.
- bc := a.enterChild();
- defer bc.exit();
-
- // Compile init statement, if any
- if s.Init != nil {
- bc.compileStmt(s.Init);
- }
-
- bodyPC := badPC;
- postPC := badPC;
- checkPC := badPC;
- endPC := badPC;
-
- // Jump to condition check. We generate slightly less code by
- // placing the condition check after the body.
- a.flow.put1(false, &checkPC);
- a.push(func(v *Thread) { v.pc = checkPC });
-
- // Compile body
- bodyPC = a.nextPC();
- body := bc.enterChild();
- if a.stmtLabel != nil {
- body.label = a.stmtLabel;
- } else {
- body.label = &label{resolved: s.Pos()};
- }
- body.label.desc = "for loop";
- body.label.breakPC = &endPC;
- body.label.continuePC = &postPC;
- body.compileStmts(s.Body);
- body.exit();
-
- // Compile post, if any
- postPC = a.nextPC();
- if s.Post != nil {
- // TODO(austin) Does the parser disallow short
- // declarations in s.Post?
- bc.compileStmt(s.Post);
- }
-
- // Compile condition check, if any
- checkPC = a.nextPC();
- if s.Cond == nil {
- // If the condition is absent, it is equivalent to true.
- a.flow.put1(false, &bodyPC);
- a.push(func(v *Thread) { v.pc = bodyPC });
- } else {
- e := bc.compileExpr(bc.block, false, s.Cond);
- switch {
- case e == nil:
- // Error reported by compileExpr
- case !e.t.isBoolean():
- a.diag("'for' condition must be boolean\n\t%v", e.t);
- default:
- eval := e.asBool();
- a.flow.put1(true, &bodyPC);
- a.push(func(t *Thread) {
- if eval(t) {
- t.pc = bodyPC;
- }
- });
- }
- }
-
- endPC = a.nextPC();
-}
-
-/*
- * Block compiler
- */
-
-func (a *blockCompiler) compileStmt(s ast.Stmt) {
- sc := &stmtCompiler{a, s.Pos(), nil};
- sc.compile(s);
-}
-
-func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
- for _, sub := range block.List {
- a.compileStmt(sub);
- }
-}
-
-func (a *blockCompiler) enterChild() *blockCompiler {
- block := a.block.enterChild();
- return &blockCompiler{
- funcCompiler: a.funcCompiler,
- block: block,
- parent: a,
- };
-}
-
-func (a *blockCompiler) exit() {
- a.block.exit();
-}
-
-/*
- * Function compiler
- */
-
-func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (func (*Thread) Func) {
- // Create body scope
- //
- // The scope of a parameter or result is the body of the
- // corresponding function.
- bodyScope := b.ChildScope();
- defer bodyScope.exit();
- for i, t := range decl.Type.In {
- if decl.InNames[i] != nil {
- bodyScope.DefineVar(decl.InNames[i].Value, decl.InNames[i].Pos(), t);
- } else {
- bodyScope.DefineTemp(t);
- }
- }
- for i, t := range decl.Type.Out {
- if decl.OutNames[i] != nil {
- bodyScope.DefineVar(decl.OutNames[i].Value, decl.OutNames[i].Pos(), t);
- } else {
- bodyScope.DefineTemp(t);
- }
- }
-
- // Create block context
- cb := newCodeBuf();
- fc := &funcCompiler{
- compiler: a,
- fnType: decl.Type,
- outVarsNamed: len(decl.OutNames) > 0 && decl.OutNames[0] != nil,
- codeBuf: cb,
- flow: newFlowBuf(cb),
- labels: make(map[string] *label),
- };
- bc := &blockCompiler{
- funcCompiler: fc,
- block: bodyScope.block,
- };
-
- // Compile body
- nerr := a.numError();
- bc.compileStmts(body);
- fc.checkLabels();
- if nerr != a.numError() {
- return nil;
- }
-
- // Check that the body returned if necessary. We only check
- // this if there were no errors compiling the body.
- if len(decl.Type.Out) > 0 && fc.flow.reachesEnd(0) {
- // XXX(Spec) Not specified.
- a.diagAt(&body.Rbrace, "function ends without a return statement");
- return nil;
- }
-
- code := fc.get();
- maxVars := bodyScope.maxVars;
- return func(t *Thread) Func { return &evalFunc{t.f, maxVars, code} };
-}
-
-// Checks that labels were resolved and that all jumps obey scoping
-// rules. Reports an error and set fc.err if any check fails.
-func (a *funcCompiler) checkLabels() {
- nerr := a.numError();
- for _, l := range a.labels {
- if !l.resolved.IsValid() {
- a.diagAt(&l.used, "label %s not defined", l.name);
- }
- }
- if nerr != a.numError() {
- // Don't check scopes if we have unresolved labels
- return;
- }
-
- // Executing the "goto" statement must not cause any variables
- // to come into scope that were not already in scope at the
- // point of the goto.
- a.flow.gotosObeyScopes(a.compiler);
-}
diff --git a/usr/austin/eval/stmt_test.go b/usr/austin/eval/stmt_test.go
deleted file mode 100644
index e94adfb60..000000000
--- a/usr/austin/eval/stmt_test.go
+++ /dev/null
@@ -1,343 +0,0 @@
-// 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 "testing"
-
-var atLeastOneDecl = "at least one new variable must be declared";
-
-var stmtTests = []test {
- // Short declarations
- Val1("x := i", "x", 1),
- Val1("x := f", "x", 1.0),
- // Type defaulting
- Val1("a := 42", "a", 42),
- Val1("a := 1.0", "a", 1.0),
- // Parallel assignment
- Val2("a, b := 1, 2", "a", 1, "b", 2),
- Val2("a, i := 1, 2", "a", 1, "i", 2),
- CErr("a, i := 1, f", opTypes),
- // TODO(austin) The parser produces an error message for this
- // one that's inconsistent with the errors I give for other
- // things
- //CErr("a, b := 1, 2, 3", "too many"),
- CErr("a, b := 1, 2, 3", "arity"),
- CErr("a := 1, 2", "too many"),
- CErr("a, b := 1", "not enough"),
- // Mixed declarations
- CErr("i := 1", atLeastOneDecl),
- CErr("i, u := 1, 2", atLeastOneDecl),
- Val2("i, x := 2, f", "i", 2, "x", 1.0),
- // Various errors
- CErr("1 := 2", "left side of := must be a name"),
- CErr("c, a := 1, 1", "cannot assign"),
- // Unpacking
- Val2("x, y := oneTwo()", "x", 1, "y", 2),
- CErr("x := oneTwo()", "too many"),
- CErr("x, y, z := oneTwo()", "not enough"),
- CErr("x, y := oneTwo(), 2", "multi-valued"),
- CErr("x := oneTwo()+2", opTypes),
- // TOOD(austin) This error message is weird
- CErr("x := void()", "not enough"),
- // Placeholders
- CErr("x := 1+\"x\"; i=x+1", opTypes),
-
- // Assignment
- Val1("i = 2", "i", 2),
- Val1("(i) = 2", "i", 2),
- CErr("1 = 2", "cannot assign"),
- CErr("1-1 = 2", "- expression"),
- Val1("i = 2.0", "i", 2),
- CErr("i = 2.2", constantTruncated),
- CErr("u = -2", constantUnderflows),
- CErr("i = f", opTypes),
- CErr("i, u = 0, f", opTypes),
- CErr("i, u = 0, f", "value 2"),
- Val2("i, i2 = i2, i", "i", 2, "i2", 1),
- CErr("c = 1", "cannot assign"),
-
- Val1("x := &i; *x = 2", "i", 2),
-
- Val1("ai[0] = 42", "ai", varray{ 42, 2 }),
- Val1("aai[1] = ai; ai[0] = 42", "aai", varray{ varray{1, 2}, varray{1, 2} }),
- Val1("aai = aai2", "aai", varray{ varray{5, 6}, varray{7, 8} }),
-
- // Assignment conversions
- Run("var sl []int; sl = &ai"),
- CErr("type ST []int; type AT *[2]int; var x AT = &ai; var y ST = x", opTypes),
- Run("type ST []int; var y ST = &ai"),
- Run("type AT *[2]int; var x AT = &ai; var y []int = x"),
-
- // Op-assignment
- Val1("i += 2", "i", 3),
- Val("i", 1),
- Val1("f += 2", "f", 3.0),
- CErr("2 += 2", "cannot assign"),
- CErr("i, j += 2", "cannot be combined"),
- CErr("i += 2, 3", "cannot be combined"),
- Val2("s2 := s; s += \"def\"", "s2", "abc", "s", "abcdef"),
- CErr("s += 1", opTypes),
- // Single evaluation
- Val2("ai[func()int{i+=1;return 0}()] *= 3; i2 = ai[0]", "i", 2, "i2", 3),
-
- // Type declarations
- // Identifiers
- Run("type T int"),
- CErr("type T x", "undefined"),
- CErr("type T c", "constant"),
- CErr("type T i", "variable"),
- CErr("type T T", "recursive"),
- CErr("type T x; type U T; var v U; v = 1", "undefined"),
- // Pointer types
- Run("type T *int"),
- Run("type T *T"),
- // Array types
- Run("type T [5]int"),
- Run("type T [c+42/2]int"),
- Run("type T [2.0]int"),
- CErr("type T [i]int", "constant expression"),
- CErr("type T [2.5]int", constantTruncated),
- CErr("type T [-1]int", "negative"),
- CErr("type T [2]T", "recursive"),
- // Struct types
- Run("type T struct { a int; b int }"),
- Run("type T struct { a int; int }"),
- Run("type T struct { x *T }"),
- Run("type T int; type U struct { T }"),
- CErr("type T *int; type U struct { T }", "embedded.*pointer"),
- CErr("type T *struct { T }", "embedded.*pointer"),
- CErr("type T struct { a int; a int }", " a .*redeclared.*:1:17"),
- CErr("type T struct { int; int }", "int .*redeclared.*:1:17"),
- CErr("type T struct { int int; int }", "int .*redeclared.*:1:17"),
- Run("type T struct { x *struct { T } }"),
- CErr("type T struct { x struct { T } }", "recursive"),
- CErr("type T struct { x }; type U struct { T }", "undefined"),
- // Function types
- Run("type T func()"),
- Run("type T func(a, b int) int"),
- Run("type T func(a, b int) (x int, y int)"),
- Run("type T func(a, a int) (a int, a int)"),
- Run("type T func(a, b int) (x, y int)"),
- Run("type T func(int, int) (int, int)"),
- CErr("type T func(x); type U T", "undefined"),
- CErr("type T func(a T)", "recursive"),
- // Parens
- Run("type T (int)"),
-
- // Variable declarations
- Val2("var x int", "i", 1, "x", 0),
- Val1("var x = 1", "x", 1),
- Val1("var x = 1.0", "x", 1.0),
- Val1("var x int = 1.0", "x", 1),
- // Placeholders
- CErr("var x foo; x = 1", "undefined"),
- CErr("var x foo = 1; x = 1", "undefined"),
- // Redeclaration
- CErr("var i, x int", " i .*redeclared"),
- CErr("var x int; var x int", " x .*redeclared.*:1:5"),
-
- // Expression statements
- CErr("x := func(){ 1-1 }", "expression statement"),
- CErr("x := func(){ 1-1 }", "- expression"),
- Val1("fn(2)", "i", 1),
-
- // IncDec statements
- Val1("i++", "i", 2),
- Val1("i--", "i", 0),
- Val1("u++", "u", uint(2)),
- Val1("u--", "u", uint(0)),
- Val1("f++", "f", 2.0),
- Val1("f--", "f", 0.0),
- // Single evaluation
- Val2("ai[func()int{i+=1;return 0}()]++; i2 = ai[0]", "i", 2, "i2", 2),
- // Operand types
- CErr("s++", opTypes),
- CErr("s++", "'\\+\\+'"),
- CErr("2++", "cannot assign"),
- CErr("c++", "cannot assign"),
-
- // Function scoping
- Val1("fn1 := func() { i=2 }; fn1()", "i", 2),
- Val1("fn1 := func() { i:=2 }; fn1()", "i", 1),
- Val2("fn1 := func() int { i=2; i:=3; i=4; return i }; x := fn1()", "i", 2, "x", 4),
-
- // Basic returns
- CErr("fn1 := func() int {}", "return"),
- Run("fn1 := func() {}"),
- CErr("fn1 := func() (r int) {}", "return"),
- Val1("fn1 := func() (r int) {return}; i = fn1()", "i", 0),
- Val1("fn1 := func() (r int) {r = 2; return}; i = fn1()", "i", 2),
- Val1("fn1 := func() (r int) {return 2}; i = fn1()", "i", 2),
- Val1("fn1 := func(int) int {return 2}; i = fn1(1)", "i", 2),
-
- // Multi-valued returns
- Val2("fn1 := func() (bool, int) {return true, 2}; x, y := fn1()", "x", true, "y", 2),
- CErr("fn1 := func() int {return}", "not enough values"),
- CErr("fn1 := func() int {return 1,2}", "too many values"),
- CErr("fn1 := func() {return 1}", "too many values"),
- CErr("fn1 := func() (int,int,int) {return 1,2}", "not enough values"),
- Val2("fn1 := func() (int, int) {return oneTwo()}; x, y := fn1()", "x", 1, "y", 2),
- CErr("fn1 := func() int {return oneTwo()}", "too many values"),
- CErr("fn1 := func() (int,int,int) {return oneTwo()}", "not enough values"),
- Val1("fn1 := func(x,y int) int {return x+y}; x := fn1(oneTwo())", "x", 3),
-
- // Return control flow
- Val2("fn1 := func(x *int) bool { *x = 2; return true; *x = 3; }; x := fn1(&i)", "i", 2, "x", true),
-
- // Break/continue/goto/fallthrough
- CErr("break", "outside"),
- CErr("break foo", "break.*foo.*not defined"),
- CErr("continue", "outside"),
- CErr("continue foo", "continue.*foo.*not defined"),
- CErr("fallthrough", "outside"),
- CErr("goto foo", "foo.*not defined"),
- CErr(" foo: foo:;", "foo.*redeclared.*:1:2"),
- Val1("i+=2; goto L; i+=4; L: i+=8", "i", 1+2+8),
- // Return checking
- CErr("fn1 := func() int { goto L; return 1; L: }", "return"),
- Run("fn1 := func() int { L: goto L; i = 2 }"),
- Run("fn1 := func() int { return 1; L: goto L }"),
- // Scope checking
- Run("fn1 := func() { { L: x:=1 } goto L }"),
- CErr("fn1 := func() { { x:=1; L: } goto L }", "into scope"),
- CErr("fn1 := func() { goto L; x:=1; L: }", "into scope"),
- Run("fn1 := func() { goto L; { L: x:=1 } }"),
- CErr("fn1 := func() { goto L; { x:=1; L: } }", "into scope"),
-
- // Blocks
- CErr("fn1 := func() int {{}}", "return"),
- Val1("fn1 := func() bool { { return true } }; b := fn1()", "b", true),
-
- // If
- Val2("if true { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
- Val2("if false { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
- Val2("if i == i2 { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
- // Omit optional parts
- Val2("if { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
- Val2("if true { i = 2 }; i2 = 4", "i", 2, "i2", 4),
- Val2("if false { i = 2 }; i2 = 4", "i", 1, "i2", 4),
- // Init
- Val2("if x := true; x { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
- Val2("if x := false; x { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
- // Statement else
- Val2("if true { i = 2 } else i = 3; i2 = 4", "i", 2, "i2", 4),
- Val2("if false { i = 2 } else i = 3; i2 = 4", "i", 3, "i2", 4),
- // Scoping
- Val2("if true { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
- Val2("if false { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
- Val2("if false { i := 2 } else i := 3; i2 = i", "i", 1, "i2", 1),
- CErr("if true { x := 2 }; x = 4", undefined),
- Val2("if i := 2; true { i2 = i; i := 3 }", "i", 1, "i2", 2),
- Val2("if i := 2; false {} else { i2 = i; i := 3 }", "i", 1, "i2", 2),
- // Return checking
- Run("fn1 := func() int { if true { return 1 } else { return 2 } }"),
- Run("fn1 := func() int { if true { return 1 } else return 2 }"),
- CErr("fn1 := func() int { if true { return 1 } else { } }", "return"),
- CErr("fn1 := func() int { if true { } else { return 1 } }", "return"),
- CErr("fn1 := func() int { if true { } else return 1 }", "return"),
- CErr("fn1 := func() int { if true { } else { } }", "return"),
- CErr("fn1 := func() int { if true { return 1 } }", "return"),
- CErr("fn1 := func() int { if true { } }", "return"),
- Run("fn1 := func() int { if true { }; return 1 }"),
- CErr("fn1 := func() int { if { } }", "return"),
- CErr("fn1 := func() int { if { } else { return 2 } }", "return"),
- Run("fn1 := func() int { if { return 1 } }"),
- Run("fn1 := func() int { if { return 1 } else { } }"),
- Run("fn1 := func() int { if { return 1 } else { } }"),
-
- // Switch
- Val1("switch { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+4),
- Val1("switch { default: i += 2; case false: i += 4; case true: i += 8 }", "i", 1+8),
- CErr("switch { default: i += 2; default: i += 4 }", "more than one"),
- Val1("switch false { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+2),
- CErr("switch s { case 1: }", opTypes),
- CErr("switch ai { case ai: i += 2 }", opTypes),
- Val1("switch 1.0 { case 1: i += 2; case 2: i += 4 }", "i", 1+2),
- Val1("switch 1.5 { case 1: i += 2; case 2: i += 4 }", "i", 1),
- CErr("switch oneTwo() {}", "multi-valued expression"),
- Val1("switch 2 { case 1: i += 2; fallthrough; case 2: i += 4; fallthrough; case 3: i += 8; fallthrough }", "i", 1+4+8),
- Val1("switch 5 { case 1: i += 2; fallthrough; default: i += 4; fallthrough; case 2: i += 8; fallthrough; case 3: i += 16; fallthrough }", "i", 1+4+8+16),
- CErr("switch { case true: fallthrough; i += 2 }", "final statement"),
- Val1("switch { case true: i += 2; fallthrough; ; ; case false: i += 4 }", "i", 1+2+4),
- Val1("switch 2 { case 0, 1: i += 2; case 2, 3: i += 4 }", "i", 1+4),
- Val2("switch func()int{i2++;return 5}() { case 1, 2: i += 2; case 4, 5: i += 4 }", "i", 1+4, "i2", 3),
- Run("switch i { case i: }"),
- // TODO(austin) Why doesn't this fail?
- //CErr("case 1:", "XXX"),
-
- // For
- Val2("for x := 1; x < 5; x++ { i+=x }; i2 = 4", "i", 11, "i2", 4),
- Val2("for x := 1; x < 5; x++ { i+=x; break; i++ }; i2 = 4", "i", 2, "i2", 4),
- Val2("for x := 1; x < 5; x++ { i+=x; continue; i++ }; i2 = 4", "i", 11, "i2", 4),
- Val2("for i = 2; false; i = 3 { i = 4 }; i2 = 4", "i", 2, "i2", 4),
- Val2("for i < 5 { i++ }; i2 = 4", "i", 5, "i2", 4),
- Val2("for i < 0 { i++ }; i2 = 4", "i", 1, "i2", 4),
- // Scoping
- Val2("for i := 2; true; { i2 = i; i := 3; break }", "i", 1, "i2", 2),
- // Labeled break/continue
- Val1("L1: for { L2: for { i+=2; break L1; i+=4 } i+=8 }", "i", 1+2),
- Val1("L1: for { L2: for { i+=2; break L2; i+=4 } i+=8; break; i+=16 }", "i", 1+2+8),
- CErr("L1: { for { break L1 } }", "break.*not defined"),
- CErr("L1: for {} for { break L1 }", "break.*not defined"),
- CErr("L1:; for { break L1 }", "break.*not defined"),
- Val2("L1: for i = 0; i < 2; i++ { L2: for { i2++; continue L1; i2++ } }", "i", 2, "i2", 4),
- CErr("L1: { for { continue L1 } }", "continue.*not defined"),
- CErr("L1:; for { continue L1 }", "continue.*not defined"),
- // Return checking
- Run("fn1 := func() int{ for {} }"),
- CErr("fn1 := func() int{ for true {} }", "return"),
- CErr("fn1 := func() int{ for true {return 1} }", "return"),
- CErr("fn1 := func() int{ for {break} }", "return"),
- Run("fn1 := func() int{ for { for {break} } }"),
- CErr("fn1 := func() int{ L1: for { for {break L1} } }", "return"),
- Run("fn1 := func() int{ for true {} return 1 }"),
-
- // Selectors
- Val1("var x struct { a int; b int }; x.a = 42; i = x.a", "i", 42),
- Val1("type T struct { x int }; var y struct { T }; y.x = 42; i = y.x", "i", 42),
- Val2("type T struct { x int }; var y struct { T; x int }; y.x = 42; i = y.x; i2 = y.T.x", "i", 42, "i2", 0),
- Run("type T struct { x int }; var y struct { *T }; a := func(){i=y.x}"),
- CErr("type T struct { x int }; var x T; x.y = 42", "no field"),
- CErr("type T struct { x int }; type U struct { x int }; var y struct { T; U }; y.x = 42", "ambiguous.*\tT\\.x\n\tU\\.x"),
- CErr("type T struct { *T }; var x T; x.foo", "no field"),
-
- Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 } return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946),
-
- // Make slice
- Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0),
- Val2("x := make([]int, 2); x[1] = 42; i, i2 = x[0], x[1]", "i", 0, "i2", 42),
- RErr("x := make([]int, 2); x[-i] = 42", "negative index"),
- RErr("x := make([]int, 2); x[2] = 42", "index 2 exceeds"),
- Val2("x := make([]int, 2, 3); i, i2 = len(x), cap(x)", "i", 2, "i2", 3),
- Val2("x := make([]int, 3, 2); i, i2 = len(x), cap(x)", "i", 3, "i2", 3),
- RErr("x := make([]int, -i)", "negative length"),
- RErr("x := make([]int, 2, -i)", "negative capacity"),
- RErr("x := make([]int, 2, 3); x[2] = 42", "index 2 exceeds"),
- CErr("x := make([]int, 2, 3, 4)", "too many"),
- CErr("x := make([]int)", "not enough"),
-
- // TODO(austin) Test make map
-
- // Maps
- Val1("x := make(map[int] int); x[1] = 42; i = x[1]", "i", 42),
- Val2("x := make(map[int] int); x[1] = 42; i, y := x[1]", "i", 42, "y", true),
- Val2("x := make(map[int] int); x[1] = 42; i, y := x[2]", "i", 0, "y", false),
- // Not implemented
- //Val1("x := make(map[int] int); x[1] = 42, true; i = x[1]", "i", 42),
- //Val2("x := make(map[int] int); x[1] = 42; x[1] = 42, false; i, y := x[1]", "i", 0, "y", false),
- Run("var x int; a := make(map[int] int); a[0], x = 1, 2"),
- CErr("x := make(map[int] int); (func(a,b int){})(x[0])", "not enough"),
- CErr("x := make(map[int] int); x[1] = oneTwo()", "too many"),
- RErr("x := make(map[int] int); i = x[1]", "key '1' not found"),
-
- // Functions
- Val2("func fib(n int) int { if n <= 2 { return n } return fib(n-1) + fib(n-2) }", "fib(4)", 5, "fib(10)", 89),
- Run("func f1(){}"),
- Run2("func f1(){}", "f1()"),
-}
-
-func TestStmt(t *testing.T) {
- runTests(t, "stmtTests", stmtTests);
-}
diff --git a/usr/austin/eval/test.bash b/usr/austin/eval/test.bash
deleted file mode 100755
index 81f4c3dd1..000000000
--- a/usr/austin/eval/test.bash
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-# 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.
-
-# Run the interpreter against all the Go test programs
-# that begin with the magic
-# // $G $D/$F.go && $L $F.$A && ./$A.out
-# line and do not contain imports.
-
-set -e
-make
-6g main.go && 6l main.6
-(
-for i in $(egrep -l '// \$G (\$D/)?\$F\.go \&\& \$L \$F\.\$A && \./\$A\.out' $GOROOT/test/*.go $GOROOT/test/*/*.go)
-do
- if grep '^import' $i >/dev/null 2>&1
- then
- true
- else
- if $GOROOT/usr/austin/eval/6.out -f $i >/tmp/out 2>&1 && ! test -s /tmp/out
- then
- echo PASS $i
- else
- echo FAIL $i
- (
- echo '>>> ' $i
- cat /tmp/out
- echo
- ) 1>&3
- fi
- fi
-done | (tee /dev/fd/2 | awk '{print $1}' | sort | uniq -c) 2>&1
-) 3>test.log
diff --git a/usr/austin/eval/type.go b/usr/austin/eval/type.go
deleted file mode 100644
index b73f92163..000000000
--- a/usr/austin/eval/type.go
+++ /dev/null
@@ -1,1174 +0,0 @@
-// 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 (
- "bignum";
- "go/ast";
- "go/token";
- "log";
- "reflect";
- "unsafe"; // For Sizeof
-)
-
-
-// XXX(Spec) The type compatibility section is very confusing because
-// it makes it seem like there are three distinct types of
-// compatibility: plain compatibility, assignment compatibility, and
-// comparison compatibility. As I understand it, there's really only
-// assignment compatibility and comparison and conversion have some
-// restrictions and have special meaning in some cases where the types
-// are not otherwise assignment compatible. The comparison
-// compatibility section is almost all about the semantics of
-// comparison, not the type checking of it, so it would make much more
-// sense in the comparison operators section. The compatibility and
-// assignment compatibility sections should be rolled into one.
-
-type Type interface {
- // compat returns whether this type is compatible with another
- // type. If conv is false, this is normal compatibility,
- // where two named types are compatible only if they are the
- // same named type. If conv if true, this is conversion
- // compatibility, where two named types are conversion
- // compatible if their definitions are conversion compatible.
- //
- // TODO(austin) Deal with recursive types
- compat(o Type, conv bool) bool;
- // lit returns this type's literal. If this is a named type,
- // this is the unnamed underlying type. Otherwise, this is an
- // identity operation.
- lit() Type;
- // isBoolean returns true if this is a boolean type.
- isBoolean() bool;
- // isInteger returns true if this is an integer type.
- isInteger() bool;
- // isFloat returns true if this is a floating type.
- isFloat() bool;
- // isIdeal returns true if this is an ideal int or float.
- isIdeal() bool;
- // Zero returns a new zero value of this type.
- Zero() Value;
- // String returns the string representation of this type.
- String() string;
- // The position where this type was defined, if any.
- Pos() token.Position;
-}
-
-type BoundedType interface {
- Type;
- // minVal returns the smallest value of this type.
- minVal() *bignum.Rational;
- // maxVal returns the largest value of this type.
- maxVal() *bignum.Rational;
-}
-
-var universePos = token.Position{"<universe>", 0, 0, 0};
-
-/*
- * Type array maps. These are used to memoize composite types.
- */
-
-type typeArrayMapEntry struct {
- key []Type;
- v interface {};
- next *typeArrayMapEntry;
-}
-
-type typeArrayMap map[uintptr] *typeArrayMapEntry
-
-func hashTypeArray(key []Type) uintptr {
- hash := uintptr(0);
- for _, t := range key {
- hash = hash * 33;
- if t == nil {
- continue;
- }
- addr := reflect.NewValue(t).(*reflect.PtrValue).Get();
- hash ^= addr;
- }
- return hash;
-}
-
-func newTypeArrayMap() typeArrayMap {
- return make(map[uintptr] *typeArrayMapEntry);
-}
-
-func (m typeArrayMap) Get(key []Type) (interface{}) {
- ent, ok := m[hashTypeArray(key)];
- if !ok {
- return nil;
- }
-
-nextEnt:
- for ; ent != nil; ent = ent.next {
- if len(key) != len(ent.key) {
- continue;
- }
- for i := 0; i < len(key); i++ {
- if key[i] != ent.key[i] {
- continue nextEnt;
- }
- }
- // Found it
- return ent.v;
- }
-
- return nil;
-}
-
-func (m typeArrayMap) Put(key []Type, v interface{}) interface{} {
- hash := hashTypeArray(key);
- ent, _ := m[hash];
-
- new := &typeArrayMapEntry{key, v, ent};
- m[hash] = new;
- return v;
-}
-
-/*
- * Common type
- */
-
-type commonType struct {
-}
-
-func (commonType) isBoolean() bool {
- return false;
-}
-
-func (commonType) isInteger() bool {
- return false;
-}
-
-func (commonType) isFloat() bool {
- return false;
-}
-
-func (commonType) isIdeal() bool {
- return false;
-}
-
-func (commonType) Pos() token.Position {
- return token.Position{};
-}
-
-/*
- * Bool
- */
-
-type boolType struct {
- commonType;
-}
-
-var BoolType = universe.DefineType("bool", universePos, &boolType{})
-
-func (t *boolType) compat(o Type, conv bool) bool {
- _, ok := o.lit().(*boolType);
- return ok;
-}
-
-func (t *boolType) lit() Type {
- return t;
-}
-
-func (t *boolType) isBoolean() bool {
- return true;
-}
-
-func (boolType) String() string {
- // Use angle brackets as a convention for printing the
- // underlying, unnamed type. This should only show up in
- // debug output.
- return "<bool>";
-}
-
-func (t *boolType) Zero() Value {
- res := boolV(false);
- return &res;
-}
-
-/*
- * Uint
- */
-
-type uintType struct {
- commonType;
-
- // 0 for architecture-dependent types
- Bits uint;
- // true for uintptr, false for all others
- Ptr bool;
- name string;
-}
-
-var (
- Uint8Type = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"});
- Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"});
- Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"});
- Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"});
-
- UintType = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"});
- UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"});
-)
-
-func (t *uintType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*uintType);
- return ok && t == t2;;
-}
-
-func (t *uintType) lit() Type {
- return t;
-}
-
-func (t *uintType) isInteger() bool {
- return true;
-}
-
-func (t *uintType) String() string {
- return "<" + t.name + ">";
-}
-
-func (t *uintType) Zero() Value {
- switch t.Bits {
- case 0:
- if t.Ptr {
- res := uintptrV(0);
- return &res;
- } else {
- res := uintV(0);
- return &res;
- }
- case 8:
- res := uint8V(0);
- return &res;
- case 16:
- res := uint16V(0);
- return &res;
- case 32:
- res := uint32V(0);
- return &res;
- case 64:
- res := uint64V(0);
- return &res;
- }
- panic("unexpected uint bit count: ", t.Bits);
-}
-
-func (t *uintType) minVal() *bignum.Rational {
- return bignum.Rat(0, 1);
-}
-
-func (t *uintType) maxVal() *bignum.Rational {
- bits := t.Bits;
- if bits == 0 {
- if t.Ptr {
- bits = uint(8 * unsafe.Sizeof(uintptr(0)));
- } else {
- bits = uint(8 * unsafe.Sizeof(uint(0)));
- }
- }
- return bignum.MakeRat(bignum.Int(1).Shl(bits).Add(bignum.Int(-1)), bignum.Nat(1));
-}
-
-/*
- * Int
- */
-
-type intType struct {
- commonType;
-
- // XXX(Spec) Numeric types: "There is also a set of
- // architecture-independent basic numeric types whose size
- // depends on the architecture." Should that be
- // architecture-dependent?
-
- // 0 for architecture-dependent types
- Bits uint;
- name string;
-}
-
-var (
- Int8Type = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"});
- Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"});
- Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"});
- Int64Type = universe.DefineType("int64", universePos, &intType{commonType{}, 64, "int64"});
-
- IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"});
-)
-
-func (t *intType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*intType);
- return ok && t == t2;
-}
-
-func (t *intType) lit() Type {
- return t;
-}
-
-func (t *intType) isInteger() bool {
- return true;
-}
-
-func (t *intType) String() string {
- return "<" + t.name + ">";
-}
-
-func (t *intType) Zero() Value {
- switch t.Bits {
- case 8:
- res := int8V(0);
- return &res;
- case 16:
- res := int16V(0);
- return &res;
- case 32:
- res := int32V(0);
- return &res;
- case 64:
- res := int64V(0);
- return &res;
-
- case 0:
- res := intV(0);
- return &res;
- }
- panic("unexpected int bit count: ", t.Bits);
-}
-
-func (t *intType) minVal() *bignum.Rational {
- bits := t.Bits;
- if bits == 0 {
- bits = uint(8 * unsafe.Sizeof(int(0)));
- }
- return bignum.MakeRat(bignum.Int(-1).Shl(bits - 1), bignum.Nat(1));
-}
-
-func (t *intType) maxVal() *bignum.Rational {
- bits := t.Bits;
- if bits == 0 {
- bits = uint(8 * unsafe.Sizeof(int(0)));
- }
- return bignum.MakeRat(bignum.Int(1).Shl(bits - 1).Add(bignum.Int(-1)), bignum.Nat(1));
-}
-
-/*
- * Ideal int
- */
-
-type idealIntType struct {
- commonType;
-}
-
-var IdealIntType Type = &idealIntType{}
-
-func (t *idealIntType) compat(o Type, conv bool) bool {
- _, ok := o.lit().(*idealIntType);
- return ok;
-}
-
-func (t *idealIntType) lit() Type {
- return t;
-}
-
-func (t *idealIntType) isInteger() bool {
- return true;
-}
-
-func (t *idealIntType) isIdeal() bool {
- return true;
-}
-
-func (t *idealIntType) String() string {
- return "ideal integer";
-}
-
-func (t *idealIntType) Zero() Value {
- return &idealIntV{bignum.Int(0)};
-}
-
-/*
- * Float
- */
-
-type floatType struct {
- commonType;
-
- // 0 for architecture-dependent type
- Bits uint;
-
- name string;
-}
-
-var (
- Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"});
- Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"});
- FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"});
-)
-
-func (t *floatType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*floatType);
- return ok && t == t2;
-}
-
-func (t *floatType) lit() Type {
- return t;
-}
-
-func (t *floatType) isFloat() bool {
- return true;
-}
-
-func (t *floatType) String() string {
- return "<" + t.name + ">";
-}
-
-func (t *floatType) Zero() Value {
- switch t.Bits {
- case 32:
- res := float32V(0);
- return &res;
- case 64:
- res := float64V(0);
- return &res;
- case 0:
- res := floatV(0);
- return &res;
- }
- panic("unexpected float bit count: ", t.Bits);
-}
-
-var maxFloat32Val = bignum.MakeRat(bignum.Int(0xffffff).Shl(127-23), bignum.Nat(1))
-var maxFloat64Val = bignum.MakeRat(bignum.Int(0x1fffffffffffff).Shl(1023-52), bignum.Nat(1))
-var minFloat32Val = maxFloat32Val.Neg()
-var minFloat64Val = maxFloat64Val.Neg()
-
-func (t *floatType) minVal() *bignum.Rational {
- bits := t.Bits;
- if bits == 0 {
- bits = uint(8 * unsafe.Sizeof(float(0)));
- }
- switch bits {
- case 32:
- return minFloat32Val;
- case 64:
- return minFloat64Val;
- }
- log.Crashf("unexpected floating point bit count: %d", bits);
- panic();
-}
-
-func (t *floatType) maxVal() *bignum.Rational {
- bits := t.Bits;
- if bits == 0 {
- bits = uint(8 * unsafe.Sizeof(float(0)));
- }
- switch bits {
- case 32:
- return maxFloat32Val;
- case 64:
- return maxFloat64Val;
- }
- log.Crashf("unexpected floating point bit count: %d", bits);
- panic();
-}
-
-/*
- * Ideal float
- */
-
-type idealFloatType struct {
- commonType;
-}
-
-var IdealFloatType Type = &idealFloatType{};
-
-func (t *idealFloatType) compat(o Type, conv bool) bool {
- _, ok := o.lit().(*idealFloatType);
- return ok;
-}
-
-func (t *idealFloatType) lit() Type {
- return t;
-}
-
-func (t *idealFloatType) isFloat() bool {
- return true;
-}
-
-func (t *idealFloatType) isIdeal() bool {
- return true;
-}
-
-func (t *idealFloatType) String() string {
- return "ideal float";
-}
-
-func (t *idealFloatType) Zero() Value {
- return &idealFloatV{bignum.Rat(1, 0)};
-}
-
-/*
- * String
- */
-
-type stringType struct {
- commonType;
-}
-
-var StringType = universe.DefineType("string", universePos, &stringType{})
-
-func (t *stringType) compat(o Type, conv bool) bool {
- _, ok := o.lit().(*stringType);
- return ok;
-}
-
-func (t *stringType) lit() Type {
- return t;
-}
-
-func (t *stringType) String() string {
- return "<string>";
-}
-
-func (t *stringType) Zero() Value {
- res := stringV("");
- return &res;
-}
-
-/*
- * Array
- */
-
-type ArrayType struct {
- commonType;
- Len int64;
- Elem Type;
-}
-
-var arrayTypes = make(map[int64] map[Type] *ArrayType)
-
-// Two array types are identical if they have identical element types
-// and the same array length.
-
-func NewArrayType(len int64, elem Type) *ArrayType {
- ts, ok := arrayTypes[len];
- if !ok {
- ts = make(map[Type] *ArrayType);
- arrayTypes[len] = ts;
- }
- t, ok := ts[elem];
- if !ok {
- t = &ArrayType{commonType{}, len, elem};
- ts[elem] = t;
- }
- return t;
-}
-
-func (t *ArrayType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*ArrayType);
- if !ok {
- return false;
- }
- return t.Len == t2.Len && t.Elem.compat(t2.Elem, conv);
-}
-
-func (t *ArrayType) lit() Type {
- return t;
-}
-
-func (t *ArrayType) String() string {
- return "[]" + t.Elem.String();
-}
-
-func (t *ArrayType) Zero() Value {
- res := arrayV(make([]Value, t.Len));
- // TODO(austin) It's unfortunate that each element is
- // separately heap allocated. We could add ZeroArray to
- // everything, though that doesn't help with multidimensional
- // arrays. Or we could do something unsafe. We'll have this
- // same problem with structs.
- for i := int64(0); i < t.Len; i++ {
- res[i] = t.Elem.Zero();
- }
- return &res;
-}
-
-/*
- * Struct
- */
-
-type StructField struct {
- Name string;
- Type Type;
- Anonymous bool;
-}
-
-type StructType struct {
- commonType;
- Elems []StructField;
-}
-
-var structTypes = newTypeArrayMap()
-
-// Two struct types are identical if they have the same sequence of
-// fields, and if corresponding fields have the same names and
-// identical types. Two anonymous fields are considered to have the
-// same name.
-
-func NewStructType(fields []StructField) *StructType {
- // Start by looking up just the types
- fts := make([]Type, len(fields));
- for i, f := range fields {
- fts[i] = f.Type;
- }
- tMapI := structTypes.Get(fts);
- if tMapI == nil {
- tMapI = structTypes.Put(fts, make(map[string] *StructType));
- }
- tMap := tMapI.(map[string] *StructType);
-
- // Construct key for field names
- key := "";
- for _, f := range fields {
- // XXX(Spec) It's not clear if struct { T } and struct
- // { T T } are either identical or compatible. The
- // "Struct Types" section says that the name of that
- // field is "T", which suggests that they are
- // identical, but it really means that it's the name
- // for the purpose of selector expressions and nothing
- // else. We decided that they should be neither
- // identical or compatible.
- if f.Anonymous {
- key += "!";
- }
- key += f.Name + " ";
- }
-
- // XXX(Spec) Do the tags also have to be identical for the
- // types to be identical? I certainly hope so, because
- // otherwise, this is the only case where two distinct type
- // objects can represent identical types.
-
- t, ok := tMap[key];
- if !ok {
- // Create new struct type
- t = &StructType{commonType{}, fields};
- tMap[key] = t;
- }
- return t;
-}
-
-func (t *StructType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*StructType);
- if !ok {
- return false;
- }
- if len(t.Elems) != len(t2.Elems) {
- return false;
- }
- for i, e := range t.Elems {
- e2 := t2.Elems[i];
- // XXX(Spec) An anonymous and a non-anonymous field
- // are neither identical nor compatible.
- if (e.Anonymous != e2.Anonymous ||
- (!e.Anonymous && e.Name != e2.Name) ||
- !e.Type.compat(e2.Type, conv)) {
- return false;
- }
- }
- return true;
-}
-
-func (t *StructType) lit() Type {
- return t;
-}
-
-func (t *StructType) String() string {
- s := "struct {";
- for i, f := range t.Elems {
- if i > 0 {
- s += "; ";
- }
- if !f.Anonymous {
- s += f.Name + " ";
- }
- s += f.Type.String();
- }
- return s + "}";
-}
-
-func (t *StructType) Zero() Value {
- res := structV(make([]Value, len(t.Elems)));
- for i, f := range t.Elems {
- res[i] = f.Type.Zero();
- }
- return &res;
-}
-
-/*
- * Pointer
- */
-
-type PtrType struct {
- commonType;
- Elem Type;
-}
-
-var ptrTypes = make(map[Type] *PtrType)
-
-// Two pointer types are identical if they have identical base types.
-
-func NewPtrType(elem Type) *PtrType {
- t, ok := ptrTypes[elem];
- if !ok {
- t = &PtrType{commonType{}, elem};
- ptrTypes[elem] = t;
- }
- return t;
-}
-
-func (t *PtrType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*PtrType);
- if !ok {
- return false;
- }
- return t.Elem.compat(t2.Elem, conv);
-}
-
-func (t *PtrType) lit() Type {
- return t;
-}
-
-func (t *PtrType) String() string {
- return "*" + t.Elem.String();
-}
-
-func (t *PtrType) Zero() Value {
- return &ptrV{nil};
-}
-
-/*
- * Function
- */
-
-type FuncType struct {
- commonType;
- // TODO(austin) Separate receiver Type for methods?
- In []Type;
- Variadic bool;
- Out []Type;
- builtin string;
-}
-
-var funcTypes = newTypeArrayMap()
-var variadicFuncTypes = newTypeArrayMap()
-
-// Create singleton function types for magic built-in functions
-var (
- capType = &FuncType{builtin: "cap"};
- closeType = &FuncType{builtin: "close"};
- closedType = &FuncType{builtin: "closed"};
- lenType = &FuncType{builtin: "len"};
- makeType = &FuncType{builtin: "make"};
- newType = &FuncType{builtin: "new"};
- panicType = &FuncType{builtin: "panic"};
- paniclnType = &FuncType{builtin: "panicln"};
- printType = &FuncType{builtin: "print"};
- printlnType = &FuncType{builtin: "println"};
-)
-
-// Two function types are identical if they have the same number of
-// parameters and result values and if corresponding parameter and
-// result types are identical. All "..." parameters have identical
-// type. Parameter and result names are not required to match.
-
-func NewFuncType(in []Type, variadic bool, out []Type) *FuncType {
- inMap := funcTypes;
- if variadic {
- inMap = variadicFuncTypes;
- }
-
- outMapI := inMap.Get(in);
- if outMapI == nil {
- outMapI = inMap.Put(in, newTypeArrayMap());
- }
- outMap := outMapI.(typeArrayMap);
-
- tI := outMap.Get(out);
- if tI != nil {
- return tI.(*FuncType);
- }
-
- t := &FuncType{commonType{}, in, variadic, out, ""};
- outMap.Put(out, t);
- return t;
-}
-
-func (t *FuncType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*FuncType);
- if !ok {
- return false;
- }
- if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) {
- return false;
- }
- for i := range t.In {
- if !t.In[i].compat(t2.In[i], conv) {
- return false;
- }
- }
- for i := range t.Out {
- if !t.Out[i].compat(t2.Out[i], conv) {
- return false;
- }
- }
- return true;
-}
-
-func (t *FuncType) lit() Type {
- return t;
-}
-
-func typeListString(ts []Type, ns []*ast.Ident) string {
- s := "";
- for i, t := range ts {
- if i > 0 {
- s += ", ";
- }
- if ns != nil && ns[i] != nil {
- s += ns[i].Value + " ";
- }
- if t == nil {
- // Some places use nil types to represent errors
- s += "<none>";
- } else {
- s += t.String();
- }
- }
- return s;
-}
-
-func (t *FuncType) String() string {
- if t.builtin != "" {
- return "built-in function " + t.builtin;
- }
- args := typeListString(t.In, nil);
- if t.Variadic {
- if len(args) > 0 {
- args += ", ";
- }
- args += "...";
- }
- s := "func(" + args + ")";
- if len(t.Out) > 0 {
- s += " (" + typeListString(t.Out, nil) + ")";
- }
- return s;
-}
-
-func (t *FuncType) Zero() Value {
- return &funcV{nil};
-}
-
-type FuncDecl struct {
- Type *FuncType;
- Name *ast.Ident; // nil for function literals
- // InNames will be one longer than Type.In if this function is
- // variadic.
- InNames []*ast.Ident;
- OutNames []*ast.Ident;
-}
-
-func (t *FuncDecl) String() string {
- args := typeListString(t.Type.In, t.InNames);
- if t.Type.Variadic {
- if len(args) > 0 {
- args += ", ";
- }
- args += "...";
- }
- s := "func";
- if t.Name != nil {
- s += " " + t.Name.Value;
- }
- s += "(" + args + ")";
- if len(t.Type.Out) > 0 {
- s += " (" + typeListString(t.Type.Out, t.OutNames) + ")";
- }
- return s;
-}
-
-/*
-type InterfaceType struct {
- // TODO(austin)
-}
-*/
-
-type SliceType struct {
- commonType;
- Elem Type;
-}
-
-var sliceTypes = make(map[Type] *SliceType)
-
-// Two slice types are identical if they have identical element types.
-
-func NewSliceType(elem Type) *SliceType {
- t, ok := sliceTypes[elem];
- if !ok {
- t = &SliceType{commonType{}, elem};
- sliceTypes[elem] = t;
- }
- return t;
-}
-
-func (t *SliceType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*SliceType);
- if !ok {
- return false;
- }
- return t.Elem.compat(t2.Elem, conv);
-}
-
-func (t *SliceType) lit() Type {
- return t;
-}
-
-func (t *SliceType) String() string {
- return "[]" + t.Elem.String();
-}
-
-func (t *SliceType) Zero() Value {
- // The value of an uninitialized slice is nil. The length and
- // capacity of a nil slice are 0.
- return &sliceV{Slice{nil, 0, 0}};
-}
-
-/*
- * Map type
- */
-
-type MapType struct {
- commonType;
- Key Type;
- Elem Type;
-}
-
-var mapTypes = make(map[Type] map[Type] *MapType)
-
-func NewMapType(key Type, elem Type) *MapType {
- ts, ok := mapTypes[key];
- if !ok {
- ts = make(map[Type] *MapType);
- mapTypes[key] = ts;
- }
- t, ok := ts[elem];
- if !ok {
- t = &MapType{commonType{}, key, elem};
- ts[elem] = t;
- }
- return t;
-}
-
-func (t *MapType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*MapType);
- if !ok {
- return false;
- }
- return t.Elem.compat(t2.Elem, conv) && t.Key.compat(t2.Key, conv);
-}
-
-func (t *MapType) lit() Type {
- return t;
-}
-
-func (t *MapType) String() string {
- return "map[" + t.Key.String() + "] " + t.Elem.String();
-}
-
-func (t *MapType) Zero() Value {
- // The value of an uninitialized map is nil.
- return &mapV{nil};
-}
-
-/*
-type ChanType struct {
- // TODO(austin)
-}
-*/
-
-/*
- * Named types
- */
-
-type Method struct {
- decl *FuncDecl;
- fn Func;
-}
-
-type NamedType struct {
- token.Position;
- Name string;
- // Underlying type. If incomplete is true, this will be nil.
- // If incomplete is false and this is still nil, then this is
- // a placeholder type representing an error.
- Def Type;
- // True while this type is being defined.
- incomplete bool;
- methods map[string] Method;
-}
-
-// TODO(austin) This is temporarily needed by the debugger's remote
-// type parser. This should only be possible with block.DefineType.
-func NewNamedType(name string) *NamedType {
- return &NamedType{token.Position{}, name, nil, true, make(map[string] Method)};
-}
-
-func (t *NamedType) Complete(def Type) {
- if !t.incomplete {
- log.Crashf("cannot complete already completed NamedType %+v", *t);
- }
- // We strip the name from def because multiple levels of
- // naming are useless.
- if ndef, ok := def.(*NamedType); ok {
- def = ndef.Def;
- }
- t.Def = def;
- t.incomplete = false;
-}
-
-func (t *NamedType) compat(o Type, conv bool) bool {
- t2, ok := o.(*NamedType);
- if ok {
- if conv {
- // Two named types are conversion compatible
- // if their literals are conversion
- // compatible.
- return t.Def.compat(t2.Def, conv);
- } else {
- // Two named types are compatible if their
- // type names originate in the same type
- // declaration.
- return t == t2;
- }
- }
- // A named and an unnamed type are compatible if the
- // respective type literals are compatible.
- return o.compat(t.Def, conv);
-}
-
-func (t *NamedType) lit() Type {
- return t.Def.lit();
-}
-
-func (t *NamedType) isBoolean() bool {
- return t.Def.isBoolean();
-}
-
-func (t *NamedType) isInteger() bool {
- return t.Def.isInteger();
-}
-
-func (t *NamedType) isFloat() bool {
- return t.Def.isFloat();
-}
-
-func (t *NamedType) isIdeal() bool {
- return false;
-}
-
-func (t *NamedType) String() string {
- return t.Name;
-}
-
-func (t *NamedType) Zero() Value {
- return t.Def.Zero();
-}
-
-/*
- * Multi-valued type
- */
-
-// MultiType is a special type used for multi-valued expressions, akin
-// to a tuple type. It's not generally accessible within the
-// language.
-type MultiType struct {
- commonType;
- Elems []Type;
-}
-
-var multiTypes = newTypeArrayMap()
-
-func NewMultiType(elems []Type) *MultiType {
- if t := multiTypes.Get(elems); t != nil {
- return t.(*MultiType);
- }
-
- t := &MultiType{commonType{}, elems};
- multiTypes.Put(elems, t);
- return t;
-}
-
-func (t *MultiType) compat(o Type, conv bool) bool {
- t2, ok := o.lit().(*MultiType);
- if !ok {
- return false;
- }
- if len(t.Elems) != len(t2.Elems) {
- return false;
- }
- for i := range t.Elems {
- if !t.Elems[i].compat(t2.Elems[i], conv) {
- return false;
- }
- }
- return true;
-}
-
-var EmptyType Type = NewMultiType([]Type{})
-
-func (t *MultiType) lit() Type {
- return t;
-}
-
-func (t *MultiType) String() string {
- if len(t.Elems) == 0 {
- return "<none>";
- }
- return typeListString(t.Elems, nil);
-}
-
-func (t *MultiType) Zero() Value {
- res := make([]Value, len(t.Elems));
- for i, t := range t.Elems {
- res[i] = t.Zero();
- }
- return multiV(res);
-}
-
-/*
- * Initialize the universe
- */
-
-func init() {
- // To avoid portability issues all numeric types are distinct
- // except byte, which is an alias for uint8.
-
- // Make byte an alias for the named type uint8. Type aliases
- // are otherwise impossible in Go, so just hack it here.
- universe.defs["byte"] = universe.defs["uint8"];
-
- // Built-in functions
- universe.DefineConst("cap", universePos, capType, nil);
- universe.DefineConst("close", universePos, closeType, nil);
- universe.DefineConst("closed", universePos, closedType, nil);
- universe.DefineConst("len", universePos, lenType, nil);
- universe.DefineConst("make", universePos, makeType, nil);
- universe.DefineConst("new", universePos, newType, nil);
- universe.DefineConst("panic", universePos, panicType, nil);
- universe.DefineConst("panicln", universePos, paniclnType, nil);
- universe.DefineConst("print", universePos, printType, nil);
- universe.DefineConst("println", universePos, printlnType, nil);
-}
diff --git a/usr/austin/eval/typec.go b/usr/austin/eval/typec.go
deleted file mode 100644
index bdbe98c4c..000000000
--- a/usr/austin/eval/typec.go
+++ /dev/null
@@ -1,366 +0,0 @@
-// 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 (
- "go/ast";
- "go/token";
- "log";
-)
-
-
-/*
- * Type compiler
- */
-
-type typeCompiler struct {
- *compiler;
- block *block;
- // Check to be performed after a type declaration is compiled.
- //
- // TODO(austin) This will probably have to change after we
- // eliminate forward declarations.
- lateCheck func() bool
-}
-
-func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
- _, _, def := a.block.Lookup(x.Value);
- if def == nil {
- a.diagAt(x, "%s: undefined", x.Value);
- return nil;
- }
- switch def := def.(type) {
- case *Constant:
- a.diagAt(x, "constant %v used as type", x.Value);
- return nil;
- case *Variable:
- a.diagAt(x, "variable %v used as type", x.Value);
- return nil;
- case *NamedType:
- if !allowRec && def.incomplete {
- a.diagAt(x, "illegal recursive type");
- return nil;
- }
- if !def.incomplete && def.Def == nil {
- // Placeholder type from an earlier error
- return nil;
- }
- return def;
- case Type:
- return def;
- }
- log.Crashf("name %s has unknown type %T", x.Value, def);
- return nil;
-}
-
-func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
- // Compile element type
- elem := a.compileType(x.Elt, allowRec);
-
- // Compile length expression
- if x.Len == nil {
- if elem == nil {
- return nil;
- }
- return NewSliceType(elem);
- }
-
- if _, ok := x.Len.(*ast.Ellipsis); ok {
- a.diagAt(x.Len, "... array initailizers not implemented");
- return nil;
- }
- l, ok := a.compileArrayLen(a.block, x.Len);
- if !ok {
- return nil;
- }
- if l < 0 {
- a.diagAt(x.Len, "array length must be non-negative");
- return nil;
- }
- if elem == nil {
- return nil;
- }
-
- return NewArrayType(l, elem);
-}
-
-func countFields(fs []*ast.Field) int {
- n := 0;
- for _, f := range fs {
- if f.Names == nil {
- n++;
- } else {
- n += len(f.Names);
- }
- }
- return n;
-}
-
-func (a *typeCompiler) compileFields(fs []*ast.Field, allowRec bool) ([]Type, []*ast.Ident, []token.Position, bool) {
- n := countFields(fs);
- ts := make([]Type, n);
- ns := make([]*ast.Ident, n);
- ps := make([]token.Position, n);
-
- bad := false;
- i := 0;
- for _, f := range fs {
- t := a.compileType(f.Type, allowRec);
- if t == nil {
- bad = true;
- }
- if f.Names == nil {
- ns[i] = nil;
- ts[i] = t;
- ps[i] = f.Type.Pos();
- i++;
- continue;
- }
- for _, n := range f.Names {
- ns[i] = n;
- ts[i] = t;
- ps[i] = n.Pos();
- i++;
- }
- }
-
- return ts, ns, ps, bad;
-}
-
-func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type {
- ts, names, poss, bad := a.compileFields(x.Fields, allowRec);
-
- // XXX(Spec) The spec claims that field identifiers must be
- // unique, but 6g only checks this when they are accessed. I
- // think the spec is better in this regard: if I write two
- // fields with the same name in the same struct type, clearly
- // that's a mistake. This definition does *not* descend into
- // anonymous fields, so it doesn't matter if those change.
- // There's separate language in the spec about checking
- // uniqueness of field names inherited from anonymous fields
- // at use time.
- fields := make([]StructField, len(ts));
- nameSet := make(map[string] token.Position, len(ts));
- for i := range fields {
- // Compute field name and check anonymous fields
- var name string;
- if names[i] != nil {
- name = names[i].Value;
- } else {
- if ts[i] == nil {
- continue;
- }
-
- var nt *NamedType;
- // [For anonymous fields,] the unqualified
- // type name acts as the field identifier.
- switch t := ts[i].(type) {
- case *NamedType:
- name = t.Name;
- nt = t;
- case *PtrType:
- switch t := t.Elem.(type) {
- case *NamedType:
- name = t.Name;
- nt = t;
- }
- }
- // [An anonymous field] must be specified as a
- // type name T or as a pointer to a type name
- // *T, and T itself, may not be a pointer or
- // interface type.
- if nt == nil {
- a.diagAt(&poss[i], "embedded type must T or *T, where T is a named type");
- bad = true;
- continue;
- }
- // The check for embedded pointer types must
- // be deferred because of things like
- // type T *struct { T }
- lateCheck := a.lateCheck;
- a.lateCheck = func() bool {
- if _, ok := nt.lit().(*PtrType); ok {
- a.diagAt(&poss[i], "embedded type %v is a pointer type", nt);
- return false;
- }
- return lateCheck();
- };
- }
-
- // Check name uniqueness
- if prev, ok := nameSet[name]; ok {
- a.diagAt(&poss[i], "field %s redeclared\n\tprevious declaration at %s", name, &prev);
- bad = true;
- continue;
- }
- nameSet[name] = poss[i];
-
- // Create field
- fields[i].Name = name;
- fields[i].Type = ts[i];
- fields[i].Anonymous = (names[i] == nil);
- }
-
- if bad {
- return nil;
- }
-
- return NewStructType(fields);
-}
-
-func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type {
- elem := a.compileType(x.X, true);
- if elem == nil {
- return nil;
- }
- return NewPtrType(elem);
-}
-
-func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl {
- // TODO(austin) Variadic function types
-
- // The types of parameters and results must be complete.
- //
- // TODO(austin) It's not clear they actually have to be complete.
- in, inNames, _, inBad := a.compileFields(x.Params, allowRec);
- out, outNames, _, outBad := a.compileFields(x.Results, allowRec);
-
- if inBad || outBad {
- return nil;
- }
- return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames};
-}
-
-func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
- key := a.compileType(x.Key, true);
- val := a.compileType(x.Value, true);
- if key == nil || val == nil {
- return nil;
- }
- // XXX(Spec) The Map types section explicitly lists all types
- // that can be map keys except for function types.
- switch key.lit().(type) {
- case *StructType:
- a.diagAt(x, "map key cannot be a struct type");
- return nil;
- case *ArrayType:
- a.diagAt(x, "map key cannot be an array type");
- return nil;
- case *SliceType:
- a.diagAt(x, "map key cannot be a slice type");
- return nil;
- }
- return NewMapType(key, val);
-}
-
-func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
- switch x := x.(type) {
- case *ast.BadExpr:
- // Error already reported by parser
- a.silentErrors++;
- return nil;
-
- case *ast.Ident:
- return a.compileIdent(x, allowRec);
-
- case *ast.ArrayType:
- return a.compileArrayType(x, allowRec);
-
- case *ast.StructType:
- return a.compileStructType(x, allowRec);
-
- case *ast.StarExpr:
- return a.compilePtrType(x);
-
- case *ast.FuncType:
- fd := a.compileFuncType(x, allowRec);
- if fd == nil {
- return nil;
- }
- return fd.Type;
-
- case *ast.InterfaceType:
- goto notimpl;
-
- case *ast.MapType:
- return a.compileMapType(x);
-
- case *ast.ChanType:
- goto notimpl;
-
- case *ast.ParenExpr:
- return a.compileType(x.X, allowRec);
-
- case *ast.Ellipsis:
- a.diagAt(x, "illegal use of ellipsis");
- return nil;
- }
- a.diagAt(x, "expression used as type");
- return nil;
-
-notimpl:
- a.diagAt(x, "compileType: %T not implemented", x);
- return nil;
-}
-
-/*
- * Type compiler interface
- */
-
-func noLateCheck() bool {
- return true;
-}
-
-func (a *compiler) compileType(b *block, typ ast.Expr) Type {
- tc := &typeCompiler{a, b, noLateCheck};
- t := tc.compileType(typ, false);
- if !tc.lateCheck() {
- t = nil;
- }
- return t;
-}
-
-func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
- ok := true;
- for _, spec := range decl.Specs {
- spec := spec.(*ast.TypeSpec);
- // Create incomplete type for this type
- nt := b.DefineType(spec.Name.Value, spec.Name.Pos(), nil);
- if nt != nil {
- nt.(*NamedType).incomplete = true;
- }
- // Compile type
- tc := &typeCompiler{a, b, noLateCheck};
- t := tc.compileType(spec.Type, false);
- if t == nil {
- // Create a placeholder type
- ok = false;
- }
- // Fill incomplete type
- if nt != nil {
- nt.(*NamedType).Complete(t);
- }
- // Perform late type checking with complete type
- if !tc.lateCheck() {
- ok = false;
- if nt != nil {
- // Make the type a placeholder
- nt.(*NamedType).Def = nil;
- }
- }
- }
- return ok;
-}
-
-func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
- tc := &typeCompiler{a, b, noLateCheck};
- res := tc.compileFuncType(typ, false);
- if res != nil {
- if !tc.lateCheck() {
- res = nil;
- }
- }
- return res;
-}
diff --git a/usr/austin/eval/util.go b/usr/austin/eval/util.go
deleted file mode 100644
index 9cdf23722..000000000
--- a/usr/austin/eval/util.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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 (
- "bignum";
-)
-
-// TODO(austin): Maybe add to bignum in more general form
-func ratToString(rat *bignum.Rational) string {
- n, dnat := rat.Value();
- d := bignum.MakeInt(false, dnat);
- w, frac := n.QuoRem(d);
- out := w.String();
- if frac.IsZero() {
- return out;
- }
-
- r := frac.Abs();
- r = r.Mul(bignum.Nat(1e6));
- dec, tail := r.DivMod(dnat);
- // Round last digit
- if tail.Cmp(dnat.Div(bignum.Nat(2))) >= 0 {
- dec = dec.Add(bignum.Nat(1));
- }
- // Strip zeros
- ten := bignum.Nat(10);
- for !dec.IsZero() {
- dec2, r2 := dec.DivMod(ten);
- if !r2.IsZero() {
- break;
- }
- dec = dec2;
- }
- out += "." + dec.String();
- return out;
-}
diff --git a/usr/austin/eval/value.go b/usr/austin/eval/value.go
deleted file mode 100644
index 1a64a6d96..000000000
--- a/usr/austin/eval/value.go
+++ /dev/null
@@ -1,731 +0,0 @@
-// 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 (
- "bignum";
- "fmt";
-)
-
-type Value interface {
- String() string;
- // Assign copies another value into this one. It should
- // assume that the other value satisfies the same specific
- // value interface (BoolValue, etc.), but must not assume
- // anything about its specific type.
- Assign(t *Thread, o Value);
-}
-
-type BoolValue interface {
- Value;
- Get(*Thread) bool;
- Set(*Thread, bool);
-}
-
-type UintValue interface {
- Value;
- Get(*Thread) uint64;
- Set(*Thread, uint64);
-}
-
-type IntValue interface {
- Value;
- Get(*Thread) int64;
- Set(*Thread, int64);
-}
-
-// TODO(austin) IdealIntValue and IdealFloatValue should not exist
-// because ideals are not l-values.
-type IdealIntValue interface {
- Value;
- Get() *bignum.Integer;
-}
-
-type FloatValue interface {
- Value;
- Get(*Thread) float64;
- Set(*Thread, float64);
-}
-
-type IdealFloatValue interface {
- Value;
- Get() *bignum.Rational;
-}
-
-type StringValue interface {
- Value;
- Get(*Thread) string;
- Set(*Thread, string);
-}
-
-type ArrayValue interface {
- Value;
- // TODO(austin) Get() is here for uniformity, but is
- // completely useless. If a lot of other types have similarly
- // useless Get methods, just special-case these uses.
- Get(*Thread) ArrayValue;
- Elem(*Thread, int64) Value;
- // Sub returns an ArrayValue backed by the same array that
- // starts from element i and has length len.
- Sub(i int64, len int64) ArrayValue;
-}
-
-type StructValue interface {
- Value;
- // TODO(austin) This is another useless Get()
- Get(*Thread) StructValue;
- Field(*Thread, int) Value;
-}
-
-type PtrValue interface {
- Value;
- Get(*Thread) Value;
- Set(*Thread, Value);
-}
-
-type Func interface {
- NewFrame() *Frame;
- Call(*Thread);
-}
-
-type FuncValue interface {
- Value;
- Get(*Thread) Func;
- Set(*Thread, Func);
-}
-
-type Slice struct {
- Base ArrayValue;
- Len, Cap int64;
-}
-
-type SliceValue interface {
- Value;
- Get(*Thread) Slice;
- Set(*Thread, Slice);
-}
-
-type Map interface {
- Len(*Thread) int64;
- // Retrieve an element from the map, returning nil if it does
- // not exist.
- Elem(t *Thread, key interface{}) Value;
- // Set an entry in the map. If val is nil, delete the entry.
- SetElem(t *Thread, key interface{}, val Value);
- // TODO(austin) Perhaps there should be an iterator interface instead.
- Iter(func(key interface{}, val Value) bool);
-}
-
-type MapValue interface {
- Value;
- Get(*Thread) Map;
- Set(*Thread, Map);
-}
-
-/*
- * Bool
- */
-
-type boolV bool
-
-func (v *boolV) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *boolV) Assign(t *Thread, o Value) {
- *v = boolV(o.(BoolValue).Get(t));
-}
-
-func (v *boolV) Get(*Thread) bool {
- return bool(*v);
-}
-
-func (v *boolV) Set(t *Thread, x bool) {
- *v = boolV(x);
-}
-
-/*
- * Uint
- */
-
-type uint8V uint8
-
-func (v *uint8V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *uint8V) Assign(t *Thread, o Value) {
- *v = uint8V(o.(UintValue).Get(t));
-}
-
-func (v *uint8V) Get(*Thread) uint64 {
- return uint64(*v);
-}
-
-func (v *uint8V) Set(t *Thread, x uint64) {
- *v = uint8V(x);
-}
-
-type uint16V uint16
-
-func (v *uint16V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *uint16V) Assign(t *Thread, o Value) {
- *v = uint16V(o.(UintValue).Get(t));
-}
-
-func (v *uint16V) Get(*Thread) uint64 {
- return uint64(*v);
-}
-
-func (v *uint16V) Set(t *Thread, x uint64) {
- *v = uint16V(x);
-}
-
-type uint32V uint32
-
-func (v *uint32V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *uint32V) Assign(t *Thread, o Value) {
- *v = uint32V(o.(UintValue).Get(t));
-}
-
-func (v *uint32V) Get(*Thread) uint64 {
- return uint64(*v);
-}
-
-func (v *uint32V) Set(t *Thread, x uint64) {
- *v = uint32V(x);
-}
-
-type uint64V uint64
-
-func (v *uint64V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *uint64V) Assign(t *Thread, o Value) {
- *v = uint64V(o.(UintValue).Get(t));
-}
-
-func (v *uint64V) Get(*Thread) uint64 {
- return uint64(*v);
-}
-
-func (v *uint64V) Set(t *Thread, x uint64) {
- *v = uint64V(x);
-}
-
-type uintV uint
-
-func (v *uintV) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *uintV) Assign(t *Thread, o Value) {
- *v = uintV(o.(UintValue).Get(t));
-}
-
-func (v *uintV) Get(*Thread) uint64 {
- return uint64(*v);
-}
-
-func (v *uintV) Set(t *Thread, x uint64) {
- *v = uintV(x);
-}
-
-type uintptrV uintptr
-
-func (v *uintptrV) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *uintptrV) Assign(t *Thread, o Value) {
- *v = uintptrV(o.(UintValue).Get(t));
-}
-
-func (v *uintptrV) Get(*Thread) uint64 {
- return uint64(*v);
-}
-
-func (v *uintptrV) Set(t *Thread, x uint64) {
- *v = uintptrV(x);
-}
-
-/*
- * Int
- */
-
-type int8V int8
-
-func (v *int8V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *int8V) Assign(t *Thread, o Value) {
- *v = int8V(o.(IntValue).Get(t));
-}
-
-func (v *int8V) Get(*Thread) int64 {
- return int64(*v);
-}
-
-func (v *int8V) Set(t *Thread, x int64) {
- *v = int8V(x);
-}
-
-type int16V int16
-
-func (v *int16V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *int16V) Assign(t *Thread, o Value) {
- *v = int16V(o.(IntValue).Get(t));
-}
-
-func (v *int16V) Get(*Thread) int64 {
- return int64(*v);
-}
-
-func (v *int16V) Set(t *Thread, x int64) {
- *v = int16V(x);
-}
-
-type int32V int32
-
-func (v *int32V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *int32V) Assign(t *Thread, o Value) {
- *v = int32V(o.(IntValue).Get(t));
-}
-
-func (v *int32V) Get(*Thread) int64 {
- return int64(*v);
-}
-
-func (v *int32V) Set(t *Thread, x int64) {
- *v = int32V(x);
-}
-
-type int64V int64
-
-func (v *int64V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *int64V) Assign(t *Thread, o Value) {
- *v = int64V(o.(IntValue).Get(t));
-}
-
-func (v *int64V) Get(*Thread) int64 {
- return int64(*v);
-}
-
-func (v *int64V) Set(t *Thread, x int64) {
- *v = int64V(x);
-}
-
-type intV int
-
-func (v *intV) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *intV) Assign(t *Thread, o Value) {
- *v = intV(o.(IntValue).Get(t));
-}
-
-func (v *intV) Get(*Thread) int64 {
- return int64(*v);
-}
-
-func (v *intV) Set(t *Thread, x int64) {
- *v = intV(x);
-}
-
-/*
- * Ideal int
- */
-
-type idealIntV struct {
- V *bignum.Integer;
-}
-
-func (v *idealIntV) String() string {
- return v.V.String();
-}
-
-func (v *idealIntV) Assign(t *Thread, o Value) {
- v.V = o.(IdealIntValue).Get();
-}
-
-func (v *idealIntV) Get() *bignum.Integer {
- return v.V;
-}
-
-/*
- * Float
- */
-
-type float32V float32
-
-func (v *float32V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *float32V) Assign(t *Thread, o Value) {
- *v = float32V(o.(FloatValue).Get(t));
-}
-
-func (v *float32V) Get(*Thread) float64 {
- return float64(*v);
-}
-
-func (v *float32V) Set(t *Thread, x float64) {
- *v = float32V(x);
-}
-
-type float64V float64
-
-func (v *float64V) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *float64V) Assign(t *Thread, o Value) {
- *v = float64V(o.(FloatValue).Get(t));
-}
-
-func (v *float64V) Get(*Thread) float64 {
- return float64(*v);
-}
-
-func (v *float64V) Set(t *Thread, x float64) {
- *v = float64V(x);
-}
-
-type floatV float
-
-func (v *floatV) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *floatV) Assign(t *Thread, o Value) {
- *v = floatV(o.(FloatValue).Get(t));
-}
-
-func (v *floatV) Get(*Thread) float64 {
- return float64(*v);
-}
-
-func (v *floatV) Set(t *Thread, x float64) {
- *v = floatV(x);
-}
-
-/*
- * Ideal float
- */
-
-type idealFloatV struct {
- V *bignum.Rational;
-}
-
-func (v *idealFloatV) String() string {
- return ratToString(v.V);
-}
-
-func (v *idealFloatV) Assign(t *Thread, o Value) {
- v.V = o.(IdealFloatValue).Get();
-}
-
-func (v *idealFloatV) Get() *bignum.Rational {
- return v.V;
-}
-
-/*
- * String
- */
-
-type stringV string
-
-func (v *stringV) String() string {
- return fmt.Sprint(*v);
-}
-
-func (v *stringV) Assign(t *Thread, o Value) {
- *v = stringV(o.(StringValue).Get(t));
-}
-
-func (v *stringV) Get(*Thread) string {
- return string(*v);
-}
-
-func (v *stringV) Set(t *Thread, x string) {
- *v = stringV(x);
-}
-
-/*
- * Array
- */
-
-type arrayV []Value
-
-func (v *arrayV) String() string {
- res := "{";
- for i, e := range *v {
- if i > 0 {
- res += ", ";
- }
- res += e.String();
- }
- return res + "}";
-}
-
-func (v *arrayV) Assign(t *Thread, o Value) {
- oa := o.(ArrayValue);
- l := int64(len(*v));
- for i := int64(0); i < l; i++ {
- (*v)[i].Assign(t, oa.Elem(t, i));
- }
-}
-
-func (v *arrayV) Get(*Thread) ArrayValue {
- return v;
-}
-
-func (v *arrayV) Elem(t *Thread, i int64) Value {
- return (*v)[i];
-}
-
-func (v *arrayV) Sub(i int64, len int64) ArrayValue {
- res := (*v)[i:i+len];
- return &res;
-}
-
-/*
- * Struct
- */
-
-type structV []Value
-
-// TODO(austin) Should these methods (and arrayV's) be on structV
-// instead of *structV?
-func (v *structV) String() string {
- res := "{";
- for i, v := range *v {
- if i > 0 {
- res += ", ";
- }
- res += v.String();
- }
- return res + "}";
-}
-
-func (v *structV) Assign(t *Thread, o Value) {
- oa := o.(StructValue);
- l := len(*v);
- for i := 0; i < l; i++ {
- (*v)[i].Assign(t, oa.Field(t, i));
- }
-}
-
-func (v *structV) Get(*Thread) StructValue {
- return v;
-}
-
-func (v *structV) Field(t *Thread, i int) Value {
- return (*v)[i];
-}
-
-/*
- * Pointer
- */
-
-type ptrV struct {
- // nil if the pointer is nil
- target Value;
-}
-
-func (v *ptrV) String() string {
- if v.target == nil {
- return "<nil>";
- }
- return "&" + v.target.String();
-}
-
-func (v *ptrV) Assign(t *Thread, o Value) {
- v.target = o.(PtrValue).Get(t);
-}
-
-func (v *ptrV) Get(*Thread) Value {
- return v.target;
-}
-
-func (v *ptrV) Set(t *Thread, x Value) {
- v.target = x;
-}
-
-/*
- * Functions
- */
-
-type funcV struct {
- target Func;
-}
-
-func (v *funcV) String() string {
- // TODO(austin) Rob wants to see the definition
- return "func {...}";
-}
-
-func (v *funcV) Assign(t *Thread, o Value) {
- v.target = o.(FuncValue).Get(t);
-}
-
-func (v *funcV) Get(*Thread) Func {
- return v.target;
-}
-
-func (v *funcV) Set(t *Thread, x Func) {
- v.target = x;
-}
-
-/*
- * Slices
- */
-
-type sliceV struct {
- Slice;
-}
-
-func (v *sliceV) String() string {
- if v.Base == nil {
- return "<nil>";
- }
- return v.Base.Sub(0, v.Len).String();
-}
-
-func (v *sliceV) Assign(t *Thread, o Value) {
- v.Slice = o.(SliceValue).Get(t);
-}
-
-func (v *sliceV) Get(*Thread) Slice {
- return v.Slice;
-}
-
-func (v *sliceV) Set(t *Thread, x Slice) {
- v.Slice = x;
-}
-
-/*
- * Maps
- */
-
-type mapV struct {
- target Map;
-}
-
-func (v *mapV) String() string {
- if v.target == nil {
- return "<nil>";
- }
- res := "map[";
- i := 0;
- v.target.Iter(func(key interface{}, val Value) bool {
- if i > 0 {
- res += ", ";
- }
- i++;
- res += fmt.Sprint(key) + ":" + val.String();
- return true;
- });
- return res + "]";
-}
-
-func (v *mapV) Assign(t *Thread, o Value) {
- v.target = o.(MapValue).Get(t);
-}
-
-func (v *mapV) Get(*Thread) Map {
- return v.target;
-}
-
-func (v *mapV) Set(t *Thread, x Map) {
- v.target = x;
-}
-
-type evalMap map[interface{}] Value
-
-func (m evalMap) Len(t *Thread) int64 {
- return int64(len(m));
-}
-
-func (m evalMap) Elem(t *Thread, key interface{}) Value {
- if v, ok := m[key]; ok {
- return v;
- }
- return nil;
-}
-
-func (m evalMap) SetElem(t *Thread, key interface{}, val Value) {
- if val == nil {
- m[key] = nil, false;
- } else {
- m[key] = val;
- }
-}
-
-func (m evalMap) Iter(cb func(key interface{}, val Value) bool) {
- for k, v := range m {
- if !cb(k, v) {
- break;
- }
- }
-}
-
-/*
- * Multi-values
- */
-
-type multiV []Value
-
-func (v multiV) String() string {
- res := "(";
- for i, v := range v {
- if i > 0 {
- res += ", ";
- }
- res += v.String();
- }
- return res + ")";
-}
-
-func (v multiV) Assign(t *Thread, o Value) {
- omv := o.(multiV);
- for i := range v {
- v[i].Assign(t, omv[i]);
- }
-}
-
-/*
- * Universal constants
- */
-
-// TODO(austin) Nothing complains if I accidentally define init with
-// arguments. Is this intentional?
-func init() {
- s := universe;
-
- true := boolV(true);
- s.DefineConst("true", universePos, BoolType, &true);
- false := boolV(false);
- s.DefineConst("false", universePos, BoolType, &false);
-}
diff --git a/usr/austin/eval/world.go b/usr/austin/eval/world.go
deleted file mode 100644
index 6d547f6e8..000000000
--- a/usr/austin/eval/world.go
+++ /dev/null
@@ -1,189 +0,0 @@
-// 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 (
- "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
- case *MultiType:
- if len(t.Elems) == 0 {
- return &stmtCode{w, code{ec.exec}}, nil;
- }
- fallthrough;
- 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.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;
-}
-