lvm.js

changeset 0
2fcdf7f16d71
child 1
f32a9c1be7c6
equal deleted inserted replaced
-1:000000000000 0:2fcdf7f16d71
1
2 var OP_LOADK = 1;
3 var OP_GETGLOBAL = 5;
4 var OP_CALL = 28;
5
6 function LValue(type, value)
7 {
8 this.type = type||"nil";
9 this.value = value||null;
10 }
11
12 LValue.prototype = {
13 call: function (args)
14 {
15 if(typeof(this.value) == "function")
16 {
17 return this.value.apply(null, args.map(function (a) { return a.value; }));
18 }
19 },
20 index: function (key)
21 {
22 if(this.type == "table")
23 {
24 return this.value[key.value];
25 }
26 },
27 setIndex: function (key, value)
28 {
29 if(this.type == "table")
30 {
31 this.value[key.value] = value;
32 }
33 }
34 };
35
36 function LValueFromString(string)
37 {
38 return new LValue("string", string);
39 }
40
41 function LValueFromFunction(func)
42 {
43 return new LValue("function", func);
44 }
45
46 var default_environment = new LValue("table", {});
47
48 var print;
49 if(typeof(document) == "object")
50 print = function (a) { document.write(a+"<br/>") };
51 else
52 {
53 // Assume running under Nodejs
54 print = require("sys").puts;
55 }
56 default_environment.setIndex(LValueFromString("print"), LValueFromFunction(print));
57
58 function LFunction()
59 {
60 this.constants = [];
61 this.instructions = [];
62 this.environment = default_environment;
63 return this;
64 }
65
66 LFunction.prototype = {
67 addInstruction: function (instruction)
68 {
69 this.instructions.push(instruction);
70 },
71 addConstant: function (constant)
72 {
73 this.constants.push(constant);
74 }
75 };
76
77 function LVM()
78 {
79 this.callstack = [];
80 this.stack = [];
81 return this;
82 }
83
84 LVM.prototype = {
85 run: function (lfFunction)
86 {
87 this.currentFrame = {f:lfFunction,pc:0};
88 this.callstack.push(this.currentFrame);
89 var instruction;
90 while(this.callstack.length>0)
91 {
92 instruction = this.currentFrame.f.instructions[this.currentFrame.pc++];
93 if(!instruction)
94 break;
95 switch(instruction[0])
96 {
97 case OP_GETGLOBAL:
98 var name = this.currentFrame.f.constants[instruction[2]];
99 this.stack[instruction[1]] = this.currentFrame.f.environment.index(name);
100 break;
101 case OP_LOADK:
102 var value = this.currentFrame.f.constants[instruction[2]];
103 this.stack[instruction[1]] = value;
104 break;
105 case OP_CALL:
106 var f = this.stack[instruction[1]];
107 f.call(this.stack.splice(instruction[1]+1, instruction[1]+(instruction[2]-1)));
108 break;
109 case OP_RETURN:
110 this.callstack.pop();
111 break;
112 default:
113 }
114 }
115 }
116 };
117
118 var testvm = new LVM();
119 var mycode = new LFunction();
120 mycode.addConstant(LValueFromString("print"));
121 mycode.addConstant(LValueFromString("Hello world"));
122 mycode.addInstruction([OP_GETGLOBAL, 0, 0]);
123 mycode.addInstruction([OP_LOADK, 1, 1]);
124 mycode.addInstruction([OP_CALL, 0, 2, 1]);
125 testvm.run(mycode);

mercurial