# HG changeset patch # User Matthew Wild # Date 1270411336 -3600 # Node ID 2fcdf7f16d71fc8ed15a0033c57ed6d7de5687a3 Initial commit diff -r 000000000000 -r 2fcdf7f16d71 demo.html --- /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 @@ + + + + + diff -r 000000000000 -r 2fcdf7f16d71 lvm.js --- /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+"
") }; +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);