# HG changeset patch # User Matthew Wild # Date 1270483386 -3600 # Node ID 253863ece36f5dda3597ba0c585037bb1a0817b5 # Parent f32a9c1be7c68163116cc187af41f8bdc127875b 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. diff -r f32a9c1be7c6 -r 253863ece36f lvm.js --- 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);