// 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.Pos } type Variable struct { VarPos token.Pos // 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 } func (v *Variable) Pos() token.Pos { return v.VarPos } type Constant struct { ConstPos token.Pos Type Type Value Value } func (c *Constant) Pos() token.Pos { return c.ConstPos } // 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.Panic("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.Panic("Cannot exit top-level block") } if b.outer.scope == b.scope { if b.outer.inner != b { log.Panic("Already exited block") } if b.inner != nil && b.inner.scope == b.scope { log.Panic("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.Panic("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.Pos, t Type) (*Variable, Def) { if prev, ok := b.defs[name]; ok { return nil, prev } v := b.defineSlot(t, false) v.VarPos = 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.Panic("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.NoPos, index, t, nil} return v } func (b *block) DefineConst(name string, pos token.Pos, 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.Pos, 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)} }