// 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);
}
