Mon, 05 Apr 2010 17:14:36 +0100
Return nil for non-existent table keys
0 | 1 | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
2 | var OP_MOVE = 0; |
0 | 3 | var OP_LOADK = 1; |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
4 | var OP_LOADNIL = 3; |
0 | 5 | var OP_GETGLOBAL = 5; |
6 | var OP_CALL = 28; | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
7 | var OP_RETURN = 30; |
0 | 8 | |
9 | function LValue(type, value) | |
10 | { | |
11 | this.type = type||"nil"; | |
12 | this.value = value||null; | |
13 | } | |
14 | ||
15 | LValue.prototype = { | |
16 | call: function (args) | |
17 | { | |
3
6f338fbf0abc
Throw an error if trying to call a non-function
Matthew Wild <mwild1@gmail.com>
parents:
2
diff
changeset
|
18 | if(this.type == "function") |
6f338fbf0abc
Throw an error if trying to call a non-function
Matthew Wild <mwild1@gmail.com>
parents:
2
diff
changeset
|
19 | return this.value; |
6f338fbf0abc
Throw an error if trying to call a non-function
Matthew Wild <mwild1@gmail.com>
parents:
2
diff
changeset
|
20 | else |
6f338fbf0abc
Throw an error if trying to call a non-function
Matthew Wild <mwild1@gmail.com>
parents:
2
diff
changeset
|
21 | throw "Attempt to call a " + this.type + " value"; |
0 | 22 | }, |
23 | index: function (key) | |
24 | { | |
25 | if(this.type == "table") | |
26 | { | |
4
0eda73eda4ae
Return nil for non-existent table keys
Matthew Wild <mwild1@gmail.com>
parents:
3
diff
changeset
|
27 | var val = this.value[key.value]; |
0eda73eda4ae
Return nil for non-existent table keys
Matthew Wild <mwild1@gmail.com>
parents:
3
diff
changeset
|
28 | if(typeof(val) == "undefined") |
0eda73eda4ae
Return nil for non-existent table keys
Matthew Wild <mwild1@gmail.com>
parents:
3
diff
changeset
|
29 | return new LValue("nil", null); |
0eda73eda4ae
Return nil for non-existent table keys
Matthew Wild <mwild1@gmail.com>
parents:
3
diff
changeset
|
30 | return val; |
0 | 31 | } |
32 | }, | |
33 | setIndex: function (key, value) | |
34 | { | |
35 | if(this.type == "table") | |
36 | { | |
37 | this.value[key.value] = value; | |
38 | } | |
39 | } | |
40 | }; | |
41 | ||
42 | function LValueFromString(string) | |
43 | { | |
44 | return new LValue("string", string); | |
45 | } | |
46 | ||
47 | function LValueFromFunction(func) | |
48 | { | |
49 | return new LValue("function", func); | |
50 | } | |
51 | ||
52 | var default_environment = new LValue("table", {}); | |
53 | ||
54 | var print; | |
55 | if(typeof(document) == "object") | |
1 | 56 | print = function (a) { document.write(a+"<br/>") }; // Browser |
0 | 57 | else |
1 | 58 | print = require("sys").puts; // Nodejs |
59 | ||
0 | 60 | default_environment.setIndex(LValueFromString("print"), LValueFromFunction(print)); |
61 | ||
62 | function LFunction() | |
63 | { | |
64 | this.constants = []; | |
65 | this.instructions = []; | |
66 | this.environment = default_environment; | |
67 | return this; | |
68 | } | |
69 | ||
70 | LFunction.prototype = { | |
71 | addInstruction: function (instruction) | |
72 | { | |
73 | this.instructions.push(instruction); | |
74 | }, | |
75 | addConstant: function (constant) | |
76 | { | |
77 | this.constants.push(constant); | |
78 | } | |
79 | }; | |
80 | ||
81 | function LVM() | |
82 | { | |
83 | this.callstack = []; | |
84 | this.stack = []; | |
85 | return this; | |
86 | } | |
87 | ||
88 | LVM.prototype = { | |
89 | run: function (lfFunction) | |
90 | { | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
91 | this.frame = {f:lfFunction,pc:0,reg:[]}; |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
92 | this.callstack.push(this.frame); |
0 | 93 | var instruction; |
94 | while(this.callstack.length>0) | |
95 | { | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
96 | instruction = this.frame.f.instructions[this.frame.pc++]; |
0 | 97 | switch(instruction[0]) |
98 | { | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
99 | case OP_MOVE: |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
100 | this.frame.reg[instruction[1]] = this.frame.reg[instruction[2]]; |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
101 | break; |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
102 | case OP_LOADNIL: |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
103 | for(var i = instruction[1];i<=instruction[2];i++) |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
104 | this.frame.reg[i] = new LValue("nil", null); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
105 | break; |
0 | 106 | case OP_GETGLOBAL: |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
107 | var name = this.frame.f.constants[instruction[2]]; |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
108 | this.frame.reg[instruction[1]] = this.frame.f.environment.index(name); |
0 | 109 | break; |
110 | case OP_LOADK: | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
111 | var value = this.frame.f.constants[instruction[2]]; |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
112 | this.frame.reg[instruction[1]] = value; |
0 | 113 | break; |
114 | case OP_CALL: | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
115 | var f = this.frame.reg[instruction[1]].call(); // return JS or LValue |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
116 | var args = this.frame.reg.splice(instruction[1]+1, instruction[1]+(instruction[2]-1)); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
117 | if(typeof(f) == "function") |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
118 | { |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
119 | // JS native function |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
120 | var ret = f.apply(null, args.map(function (a) { return a.value; })); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
121 | } |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
122 | else |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
123 | { |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
124 | // Lua function |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
125 | } |
0 | 126 | break; |
127 | case OP_RETURN: | |
128 | this.callstack.pop(); | |
129 | break; | |
130 | default: | |
131 | } | |
132 | } | |
133 | } | |
134 | }; | |
135 | ||
136 | var testvm = new LVM(); | |
137 | var mycode = new LFunction(); | |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
138 | |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
139 | mycode.addConstant(LValueFromString("hello")); |
0 | 140 | mycode.addConstant(LValueFromString("print")); |
2
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
141 | |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
142 | mycode.addInstruction([OP_LOADK, 0, 0]); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
143 | mycode.addInstruction([OP_LOADNIL, 1, 1]); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
144 | mycode.addInstruction([OP_MOVE, 1, 0]); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
145 | mycode.addInstruction([OP_GETGLOBAL, 2, 1]); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
146 | mycode.addInstruction([OP_MOVE, 3, 1]); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
147 | mycode.addInstruction([OP_CALL, 2, 2, 1]); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
148 | mycode.addInstruction([OP_RETURN, 0, 1]); |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
149 | |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
150 | |
253863ece36f
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.
Matthew Wild <mwild1@gmail.com>
parents:
1
diff
changeset
|
151 | |
0 | 152 | testvm.run(mycode); |