go/usr/austin/eval/decls.go
Austin Clements 8f694f6661 Flatten the Frame tree. Now each function call produces a
single frame and non-overlapping variables reuse frame slots.
As a result, entering and exiting blocks no longer requires
code execution, which means jumps across block boundaries
should be doable now.  Frame slot initialization happens at
definition time now, instead of at frame creation time.  As an
added bonus, Scope's are now exclusively compile-time objects
and we no longer need to specially track the function
activation frame for access to out vars.

R=rsc
APPROVED=rsc
DELTA=313  (102 added, 90 deleted, 121 changed)
OCL=32416
CL=32420
2009-07-29 11:57:46 -07:00

219 lines
4.6 KiB
Go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package eval
import (
"bignum";
)
/*
* Types
*/
type Value interface
type Type interface {
// literal returns this type with all names recursively
// stripped. This should only be used when determining
// assignment compatibility. To strip a named type for use in
// a type switch, use .rep().
literal() Type;
// rep returns the representative type. If this is a named
// type, this is the unnamed underlying type. Otherwise, this
// is an identity operation.
rep() 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;
// ZeroVal returns a new zero value of this type.
Zero() Value;
// String returns the string representation of this type.
String() string;
}
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;
}
/*
* Values
*/
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(o Value);
}
type BoolValue interface {
Value;
Get() bool;
Set(bool);
}
type UintValue interface {
Value;
Get() uint64;
Set(uint64);
}
type IntValue interface {
Value;
Get() int64;
Set(int64);
}
type IdealIntValue interface {
Value;
Get() *bignum.Integer;
}
type FloatValue interface {
Value;
Get() float64;
Set(float64);
}
type IdealFloatValue interface {
Value;
Get() *bignum.Rational;
}
type StringValue interface {
Value;
Get() string;
Set(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() ArrayValue;
Elem(i int64) Value;
}
type PtrValue interface {
Value;
Get() Value;
Set(Value);
}
type Func interface
type FuncValue interface {
Value;
Get() Func;
Set(Func);
}
/*
* Scopes
*/
type Variable struct {
// Index of this variable in the Frame structure
Index int;
// Static type of this variable
Type Type;
}
type Constant struct {
Type Type;
Value Value;
}
// A definition can be a *Variable, *Constant, or Type.
type Def interface {}
type Scope struct
// 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;
}
// 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
func (b *block) exit()
func (b *block) ChildScope() *Scope
func (b *block) DefineVar(name string, t Type) *Variable
func (b *block) DefineTemp(t Type) *Variable
func (b *block) DefineConst(name string, t Type, v Value) *Constant
func (b *block) DefineType(name string, t Type) Type
func (b *block) Lookup(name string) (level int, def Def)
// The universal scope
func newUniverse() *Scope {
sc := &Scope{nil, 0};
sc.block = &block{
scope: sc,
defs: make(map[string] Def)
};
return sc;
}
var universe *Scope = newUniverse();
/*
* Frames
*/
type Frame struct {
Outer *Frame;
Vars []Value;
}
func (f *Frame) Get(level int, index int) Value
func (f *Frame) child(numVars int) *Frame
func (s *Scope) NewFrame(outer *Frame) *Frame
/*
* Functions
*/
type Func interface {
NewFrame() *Frame;
Call(*Frame);
}