lvm.js

Sun, 04 Apr 2010 21:02:16 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Sun, 04 Apr 2010 21:02:16 +0100
changeset 0
2fcdf7f16d71
child 1
f32a9c1be7c6
permissions
-rw-r--r--

Initial commit


var OP_LOADK = 1;
var OP_GETGLOBAL = 5;
var OP_CALL = 28;

function LValue(type, value)
{
	this.type = type||"nil";
	this.value = value||null;
}

LValue.prototype = {
	call: function (args)
	{
		if(typeof(this.value) == "function")
		{
			return this.value.apply(null, args.map(function (a) { return a.value; }));
		}
	},
	index: function (key)
	{
		if(this.type == "table")
		{
			return this.value[key.value];
		}
	},
	setIndex: function (key, value)
	{
		if(this.type == "table")
		{
			this.value[key.value] = value;
		}
	}
};

function LValueFromString(string)
{
	return new LValue("string", string);
}

function LValueFromFunction(func)
{
	return new LValue("function", func);
}

var default_environment = new LValue("table", {});

var print;
if(typeof(document) == "object")
	print = function (a) { document.write(a+"<br/>") };
else
{
	// Assume running under Nodejs
	print = require("sys").puts;
}
default_environment.setIndex(LValueFromString("print"), LValueFromFunction(print));

function LFunction()
{
	this.constants = [];
	this.instructions = [];
	this.environment = default_environment;
	return this;
}

LFunction.prototype = {
	addInstruction: function (instruction)
	{
		this.instructions.push(instruction);
	},
	addConstant: function (constant)
	{
		this.constants.push(constant);
	}
};

function LVM()
{
	this.callstack = [];
	this.stack = [];
	return this;
}

LVM.prototype = {
	run: function (lfFunction)
	{
		this.currentFrame = {f:lfFunction,pc:0};
		this.callstack.push(this.currentFrame);
		var instruction;
		while(this.callstack.length>0)
		{
			instruction = this.currentFrame.f.instructions[this.currentFrame.pc++];
			if(!instruction)
				break;
			switch(instruction[0])
			{
			case OP_GETGLOBAL:
				var name = this.currentFrame.f.constants[instruction[2]];
				this.stack[instruction[1]] = this.currentFrame.f.environment.index(name);
				break;
			case OP_LOADK:
				var value = this.currentFrame.f.constants[instruction[2]];
				this.stack[instruction[1]] = value;
				break;
			case OP_CALL:
				var f = this.stack[instruction[1]];
				f.call(this.stack.splice(instruction[1]+1, instruction[1]+(instruction[2]-1)));
				break;
			case OP_RETURN:
				this.callstack.pop();
				break;
			default:
			}
		}
	}
};

var testvm = new LVM();
var mycode = new LFunction();
mycode.addConstant(LValueFromString("print"));
mycode.addConstant(LValueFromString("Hello world"));
mycode.addInstruction([OP_GETGLOBAL, 0, 0]);
mycode.addInstruction([OP_LOADK, 1, 1]);
mycode.addInstruction([OP_CALL, 0, 2, 1]);
testvm.run(mycode);

mercurial