| // 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)) { |
| b.instrs = append(b.instrs, 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)) |
| copy(a, b.instrs) |
| 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) } |