Initial commit

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

Initial commit

demo.html file | annotate | diff | comparison | revisions
lvm.js file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demo.html	Sun Apr 04 21:02:16 2010 +0100
@@ -0,0 +1,5 @@
+<html>
+<body>
+<script type="text/javascript" src="lvm.js"></script>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lvm.js	Sun Apr 04 21:02:16 2010 +0100
@@ -0,0 +1,125 @@
+
+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