Implement OP_MOVE, OP_LOADNIL and OP_RETURN. Also change the way OP_CALL is implemented, and update the test code with a more complicated (kind of) sample.

Mon, 05 Apr 2010 17:03:06 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Mon, 05 Apr 2010 17:03:06 +0100
changeset 2
253863ece36f
parent 1
f32a9c1be7c6
child 3
6f338fbf0abc

Implement OP_MOVE, OP_LOADNIL and OP_RETURN. Also change the way OP_CALL is implemented, and update the test code with a more complicated (kind of) sample.

lvm.js file | annotate | diff | comparison | revisions
--- a/lvm.js	Sun Apr 04 21:08:23 2010 +0100
+++ b/lvm.js	Mon Apr 05 17:03:06 2010 +0100
@@ -1,7 +1,10 @@
 
+var OP_MOVE = 0;
 var OP_LOADK = 1;
+var OP_LOADNIL = 3;
 var OP_GETGLOBAL = 5;
 var OP_CALL = 28;
+var OP_RETURN = 30;
 
 function LValue(type, value)
 {
@@ -12,10 +15,7 @@
 LValue.prototype = {
 	call: function (args)
 	{
-		if(typeof(this.value) == "function")
-		{
-			return this.value.apply(null, args.map(function (a) { return a.value; }));
-		}
+		return this.value;
 	},
 	index: function (key)
 	{
@@ -82,27 +82,41 @@
 LVM.prototype = {
 	run: function (lfFunction)
 	{
-		this.currentFrame = {f:lfFunction,pc:0};
-		this.callstack.push(this.currentFrame);
+		this.frame = {f:lfFunction,pc:0,reg:[]};
+		this.callstack.push(this.frame);
 		var instruction;
 		while(this.callstack.length>0)
 		{
-			instruction = this.currentFrame.f.instructions[this.currentFrame.pc++];
-			if(!instruction)
-				break;
+			instruction = this.frame.f.instructions[this.frame.pc++];
 			switch(instruction[0])
 			{
+			case OP_MOVE:
+				this.frame.reg[instruction[1]] = this.frame.reg[instruction[2]];
+				break;
+			case OP_LOADNIL:
+				for(var i = instruction[1];i<=instruction[2];i++)
+					this.frame.reg[i] = new LValue("nil", null);
+				break;
 			case OP_GETGLOBAL:
-				var name = this.currentFrame.f.constants[instruction[2]];
-				this.stack[instruction[1]] = this.currentFrame.f.environment.index(name);
+				var name = this.frame.f.constants[instruction[2]];
+				this.frame.reg[instruction[1]] = this.frame.f.environment.index(name);
 				break;
 			case OP_LOADK:
-				var value = this.currentFrame.f.constants[instruction[2]];
-				this.stack[instruction[1]] = value;
+				var value = this.frame.f.constants[instruction[2]];
+				this.frame.reg[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)));
+				var f = this.frame.reg[instruction[1]].call(); // return JS or LValue
+				var args = this.frame.reg.splice(instruction[1]+1, instruction[1]+(instruction[2]-1));
+				if(typeof(f) == "function")
+				{
+					// JS native function
+					var ret = f.apply(null, args.map(function (a) { return a.value; }));
+				}
+				else
+				{
+					// Lua function
+				}
 				break;
 			case OP_RETURN:
 				this.callstack.pop();
@@ -115,9 +129,18 @@
 
 var testvm = new LVM();
 var mycode = new LFunction();
+
+mycode.addConstant(LValueFromString("hello"));
 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]);
+
+mycode.addInstruction([OP_LOADK, 0, 0]);
+mycode.addInstruction([OP_LOADNIL, 1, 1]);
+mycode.addInstruction([OP_MOVE, 1, 0]);
+mycode.addInstruction([OP_GETGLOBAL, 2, 1]);
+mycode.addInstruction([OP_MOVE, 3, 1]);
+mycode.addInstruction([OP_CALL, 2, 2, 1]);
+mycode.addInstruction([OP_RETURN, 0, 1]);
+
+
+
 testvm.run(mycode);

mercurial