diff options
Diffstat (limited to '')
16 files changed, 0 insertions, 5869 deletions
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/README b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/README deleted file mode 100644 index 06fea0a..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/README +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | orig-5.1.3 | ||
2 | |||
3 | This is a straightforward port of the Lua 5.1.3 front end (lexical | ||
4 | analyzer, parser, code generator, binary chunk dumper.) | ||
5 | |||
6 | The front end files are: | ||
7 | |||
8 | lopcodes.lua opcode definition | ||
9 | lzio.lua input streams | ||
10 | llex.lua lexical analyzer | ||
11 | lparser.lua parser | ||
12 | lcode.lua code generator | ||
13 | ldump.lua binary chunk dumper | ||
14 | |||
15 | Status: operational, passes all current tests (non-exhaustive) | ||
16 | |||
17 | Major test scripts are: | ||
18 | |||
19 | test/test_llex.lua exercises test cases | ||
20 | test/test_lparser2.lua exercises test cases | ||
21 | |||
22 | luac.lua is a clone of Lua 5.1.3's luac.lua, except that it generates a | ||
23 | binary chunk using Yueliang's front end implementation. | ||
24 | |||
25 | See the README file in orig-5.0.3 for a discussion. | ||
26 | |||
27 | The following is some performance data. Note that absolutely nothing has | ||
28 | been done to optimize the code; it is meant to mirror the original C as | ||
29 | an educational tool. | ||
30 | |||
31 | lzio llex TOTAL Speed (1) | ||
32 | (bytes) (bytes) (bytes) (KB/s) | ||
33 | ---------------------------------------------- | ||
34 | (in orig-5.0.3:) | ||
35 | ---------------------------------------------- | ||
36 | normal 2219 12639 14585 404.9 | ||
37 | stripped 1292 7618 8910 | ||
38 | ---------------------------------------------- | ||
39 | (in orig-5.0.3:) | ||
40 | ---------------------------------------------- | ||
41 | normal - - - 389.7 | ||
42 | stripped - - - | ||
43 | ---------------------------------------------- | ||
44 | |||
45 | (1) Speed was benchmarked using a Sempron 3000+. Benchmark scripts are | ||
46 | in the test directories. Best of first three figures quoted. This is a | ||
47 | measurement of raw lexer speed, i.e. tokens are read but no processing | ||
48 | is done. All files are read in entirely before running the lexer. | ||
49 | |||
50 | For Lua 5.1.1, see Yueliang 0.2.1, which was the last release of Lua | ||
51 | 5.1.1 material. | ||
52 | |||
53 | For Lua 5.1.2, see Yueliang 0.2.2, which was the last release of Lua | ||
54 | 5.1.2 material. | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua deleted file mode 100644 index 4dc8548..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua +++ /dev/null | |||
@@ -1,1125 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | lcode.lua | ||
4 | Lua 5 code generator in Lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * one function manipulate a pointer argument with a simple data type | ||
18 | -- (can't be emulated by a table, ambiguous), now returns that value: | ||
19 | -- luaK:concat(fs, l1, l2) | ||
20 | -- * luaM_growvector uses the faux luaY:growvector, for limit checking | ||
21 | -- * some function parameters changed to boolean, additional code | ||
22 | -- translates boolean back to 1/0 for instruction fields | ||
23 | -- | ||
24 | -- Not implemented: | ||
25 | -- * NOTE there is a failed assert in luaK:addk, a porting problem | ||
26 | -- | ||
27 | -- Added: | ||
28 | -- * constant MAXSTACK from llimits.h | ||
29 | -- * luaK:ttisnumber(o) (from lobject.h) | ||
30 | -- * luaK:nvalue(o) (from lobject.h) | ||
31 | -- * luaK:setnilvalue(o) (from lobject.h) | ||
32 | -- * luaK:setnvalue(o, x) (from lobject.h) | ||
33 | -- * luaK:setbvalue(o, x) (from lobject.h) | ||
34 | -- * luaK:sethvalue(o, x) (from lobject.h), parameter L deleted | ||
35 | -- * luaK:setsvalue(o, x) (from lobject.h), parameter L deleted | ||
36 | -- * luaK:numadd, luaK:numsub, luaK:nummul, luaK:numdiv, luaK:nummod, | ||
37 | -- luaK:numpow, luaK:numunm, luaK:numisnan (from luaconf.h) | ||
38 | -- * copyexp(e1, e2) added in luaK:posfix to copy expdesc struct | ||
39 | -- | ||
40 | -- Changed in 5.1.x: | ||
41 | -- * enum BinOpr has a new entry, OPR_MOD | ||
42 | -- * enum UnOpr has a new entry, OPR_LEN | ||
43 | -- * binopistest, unused in 5.0.x, has been deleted | ||
44 | -- * macro setmultret is new | ||
45 | -- * functions isnumeral, luaK_ret, boolK are new | ||
46 | -- * funcion nilK was named nil_constant in 5.0.x | ||
47 | -- * function interface changed: need_value, patchtestreg, concat | ||
48 | -- * TObject now a TValue | ||
49 | -- * functions luaK_setreturns, luaK_setoneret are new | ||
50 | -- * function luaK:setcallreturns deleted, to be replaced by: | ||
51 | -- luaK:setmultret, luaK:ret, luaK:setreturns, luaK:setoneret | ||
52 | -- * functions constfolding, codearith, codecomp are new | ||
53 | -- * luaK:codebinop has been deleted | ||
54 | -- * function luaK_setlist is new | ||
55 | -- * OPR_MULT renamed to OPR_MUL | ||
56 | ----------------------------------------------------------------------]] | ||
57 | |||
58 | -- requires luaP, luaX, luaY | ||
59 | luaK = {} | ||
60 | |||
61 | ------------------------------------------------------------------------ | ||
62 | -- constants used by code generator | ||
63 | ------------------------------------------------------------------------ | ||
64 | -- maximum stack for a Lua function | ||
65 | luaK.MAXSTACK = 250 -- (from llimits.h) | ||
66 | |||
67 | --[[-------------------------------------------------------------------- | ||
68 | -- other functions | ||
69 | ----------------------------------------------------------------------]] | ||
70 | |||
71 | ------------------------------------------------------------------------ | ||
72 | -- emulation of TValue macros (these are from lobject.h) | ||
73 | -- * TValue is a table since lcode passes references around | ||
74 | -- * tt member field removed, using Lua's type() instead | ||
75 | -- * for setsvalue, sethvalue, parameter L (deleted here) in lobject.h | ||
76 | -- is used in an assert for testing, see checkliveness(g,obj) | ||
77 | ------------------------------------------------------------------------ | ||
78 | function luaK:ttisnumber(o) | ||
79 | if o then return type(o.value) == "number" else return false end | ||
80 | end | ||
81 | function luaK:nvalue(o) return o.value end | ||
82 | function luaK:setnilvalue(o) o.value = nil end | ||
83 | function luaK:setsvalue(o, x) o.value = x end | ||
84 | luaK.setnvalue = luaK.setsvalue | ||
85 | luaK.sethvalue = luaK.setsvalue | ||
86 | luaK.setbvalue = luaK.setsvalue | ||
87 | |||
88 | ------------------------------------------------------------------------ | ||
89 | -- The luai_num* macros define the primitive operations over numbers. | ||
90 | -- * this is not the entire set of primitive operations from luaconf.h | ||
91 | -- * used in luaK:constfolding() | ||
92 | ------------------------------------------------------------------------ | ||
93 | function luaK:numadd(a, b) return a + b end | ||
94 | function luaK:numsub(a, b) return a - b end | ||
95 | function luaK:nummul(a, b) return a * b end | ||
96 | function luaK:numdiv(a, b) return a / b end | ||
97 | function luaK:nummod(a, b) return a % b end | ||
98 | -- ((a) - floor((a)/(b))*(b)) /* actual, for reference */ | ||
99 | function luaK:numpow(a, b) return a ^ b end | ||
100 | function luaK:numunm(a) return -a end | ||
101 | function luaK:numisnan(a) return not a == a end | ||
102 | -- a NaN cannot equal another NaN | ||
103 | |||
104 | --[[-------------------------------------------------------------------- | ||
105 | -- code generator functions | ||
106 | ----------------------------------------------------------------------]] | ||
107 | |||
108 | ------------------------------------------------------------------------ | ||
109 | -- Marks the end of a patch list. It is an invalid value both as an absolute | ||
110 | -- address, and as a list link (would link an element to itself). | ||
111 | ------------------------------------------------------------------------ | ||
112 | luaK.NO_JUMP = -1 | ||
113 | |||
114 | ------------------------------------------------------------------------ | ||
115 | -- grep "ORDER OPR" if you change these enums | ||
116 | ------------------------------------------------------------------------ | ||
117 | luaK.BinOpr = { | ||
118 | OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5, | ||
119 | OPR_CONCAT = 6, | ||
120 | OPR_NE = 7, OPR_EQ = 8, | ||
121 | OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12, | ||
122 | OPR_AND = 13, OPR_OR = 14, | ||
123 | OPR_NOBINOPR = 15, | ||
124 | } | ||
125 | |||
126 | -- * UnOpr is used by luaK:prefix's op argument, but not directly used | ||
127 | -- because the function receives the symbols as strings, e.g. "OPR_NOT" | ||
128 | luaK.UnOpr = { | ||
129 | OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3 | ||
130 | } | ||
131 | |||
132 | ------------------------------------------------------------------------ | ||
133 | -- returns the instruction object for given e (expdesc), was a macro | ||
134 | ------------------------------------------------------------------------ | ||
135 | function luaK:getcode(fs, e) | ||
136 | return fs.f.code[e.info] | ||
137 | end | ||
138 | |||
139 | ------------------------------------------------------------------------ | ||
140 | -- codes an instruction with a signed Bx (sBx) field, was a macro | ||
141 | -- * used in luaK:jump(), (lparser) luaY:forbody() | ||
142 | ------------------------------------------------------------------------ | ||
143 | function luaK:codeAsBx(fs, o, A, sBx) | ||
144 | return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx) | ||
145 | end | ||
146 | |||
147 | ------------------------------------------------------------------------ | ||
148 | -- set the expdesc e instruction for multiple returns, was a macro | ||
149 | ------------------------------------------------------------------------ | ||
150 | function luaK:setmultret(fs, e) | ||
151 | self:setreturns(fs, e, luaY.LUA_MULTRET) | ||
152 | end | ||
153 | |||
154 | ------------------------------------------------------------------------ | ||
155 | -- there is a jump if patch lists are not identical, was a macro | ||
156 | -- * used in luaK:exp2reg(), luaK:exp2anyreg(), luaK:exp2val() | ||
157 | ------------------------------------------------------------------------ | ||
158 | function luaK:hasjumps(e) | ||
159 | return e.t ~= e.f | ||
160 | end | ||
161 | |||
162 | ------------------------------------------------------------------------ | ||
163 | -- true if the expression is a constant number (for constant folding) | ||
164 | -- * used in constfolding(), infix() | ||
165 | ------------------------------------------------------------------------ | ||
166 | function luaK:isnumeral(e) | ||
167 | return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP | ||
168 | end | ||
169 | |||
170 | ------------------------------------------------------------------------ | ||
171 | -- codes loading of nil, optimization done if consecutive locations | ||
172 | -- * used in luaK:discharge2reg(), (lparser) luaY:adjust_assign() | ||
173 | ------------------------------------------------------------------------ | ||
174 | function luaK:_nil(fs, from, n) | ||
175 | if fs.pc > fs.lasttarget then -- no jumps to current position? | ||
176 | if fs.pc == 0 then -- function start? | ||
177 | if from >= fs.nactvar then | ||
178 | return -- positions are already clean | ||
179 | end | ||
180 | else | ||
181 | local previous = fs.f.code[fs.pc - 1] | ||
182 | if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then | ||
183 | local pfrom = luaP:GETARG_A(previous) | ||
184 | local pto = luaP:GETARG_B(previous) | ||
185 | if pfrom <= from and from <= pto + 1 then -- can connect both? | ||
186 | if from + n - 1 > pto then | ||
187 | luaP:SETARG_B(previous, from + n - 1) | ||
188 | end | ||
189 | return | ||
190 | end | ||
191 | end | ||
192 | end | ||
193 | end | ||
194 | self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) -- else no optimization | ||
195 | end | ||
196 | |||
197 | ------------------------------------------------------------------------ | ||
198 | -- | ||
199 | -- * used in multiple locations | ||
200 | ------------------------------------------------------------------------ | ||
201 | function luaK:jump(fs) | ||
202 | local jpc = fs.jpc -- save list of jumps to here | ||
203 | fs.jpc = self.NO_JUMP | ||
204 | local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP) | ||
205 | j = self:concat(fs, j, jpc) -- keep them on hold | ||
206 | return j | ||
207 | end | ||
208 | |||
209 | ------------------------------------------------------------------------ | ||
210 | -- codes a RETURN instruction | ||
211 | -- * used in luaY:close_func(), luaY:retstat() | ||
212 | ------------------------------------------------------------------------ | ||
213 | function luaK:ret(fs, first, nret) | ||
214 | self:codeABC(fs, "OP_RETURN", first, nret + 1, 0) | ||
215 | end | ||
216 | |||
217 | ------------------------------------------------------------------------ | ||
218 | -- | ||
219 | -- * used in luaK:jumponcond(), luaK:codecomp() | ||
220 | ------------------------------------------------------------------------ | ||
221 | function luaK:condjump(fs, op, A, B, C) | ||
222 | self:codeABC(fs, op, A, B, C) | ||
223 | return self:jump(fs) | ||
224 | end | ||
225 | |||
226 | ------------------------------------------------------------------------ | ||
227 | -- | ||
228 | -- * used in luaK:patchlistaux(), luaK:concat() | ||
229 | ------------------------------------------------------------------------ | ||
230 | function luaK:fixjump(fs, pc, dest) | ||
231 | local jmp = fs.f.code[pc] | ||
232 | local offset = dest - (pc + 1) | ||
233 | lua_assert(dest ~= self.NO_JUMP) | ||
234 | if math.abs(offset) > luaP.MAXARG_sBx then | ||
235 | luaX:syntaxerror(fs.ls, "control structure too long") | ||
236 | end | ||
237 | luaP:SETARG_sBx(jmp, offset) | ||
238 | end | ||
239 | |||
240 | ------------------------------------------------------------------------ | ||
241 | -- returns current 'pc' and marks it as a jump target (to avoid wrong | ||
242 | -- optimizations with consecutive instructions not in the same basic block). | ||
243 | -- * used in multiple locations | ||
244 | -- * fs.lasttarget tested only by luaK:_nil() when optimizing OP_LOADNIL | ||
245 | ------------------------------------------------------------------------ | ||
246 | function luaK:getlabel(fs) | ||
247 | fs.lasttarget = fs.pc | ||
248 | return fs.pc | ||
249 | end | ||
250 | |||
251 | ------------------------------------------------------------------------ | ||
252 | -- | ||
253 | -- * used in luaK:need_value(), luaK:removevalues(), luaK:patchlistaux(), | ||
254 | -- luaK:concat() | ||
255 | ------------------------------------------------------------------------ | ||
256 | function luaK:getjump(fs, pc) | ||
257 | local offset = luaP:GETARG_sBx(fs.f.code[pc]) | ||
258 | if offset == self.NO_JUMP then -- point to itself represents end of list | ||
259 | return self.NO_JUMP -- end of list | ||
260 | else | ||
261 | return (pc + 1) + offset -- turn offset into absolute position | ||
262 | end | ||
263 | end | ||
264 | |||
265 | ------------------------------------------------------------------------ | ||
266 | -- | ||
267 | -- * used in luaK:need_value(), luaK:patchtestreg(), luaK:invertjump() | ||
268 | ------------------------------------------------------------------------ | ||
269 | function luaK:getjumpcontrol(fs, pc) | ||
270 | local pi = fs.f.code[pc] | ||
271 | local ppi = fs.f.code[pc - 1] | ||
272 | if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then | ||
273 | return ppi | ||
274 | else | ||
275 | return pi | ||
276 | end | ||
277 | end | ||
278 | |||
279 | ------------------------------------------------------------------------ | ||
280 | -- check whether list has any jump that do not produce a value | ||
281 | -- (or produce an inverted value) | ||
282 | -- * return value changed to boolean | ||
283 | -- * used only in luaK:exp2reg() | ||
284 | ------------------------------------------------------------------------ | ||
285 | function luaK:need_value(fs, list) | ||
286 | while list ~= self.NO_JUMP do | ||
287 | local i = self:getjumpcontrol(fs, list) | ||
288 | if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then return true end | ||
289 | list = self:getjump(fs, list) | ||
290 | end | ||
291 | return false -- not found | ||
292 | end | ||
293 | |||
294 | ------------------------------------------------------------------------ | ||
295 | -- | ||
296 | -- * used in luaK:removevalues(), luaK:patchlistaux() | ||
297 | ------------------------------------------------------------------------ | ||
298 | function luaK:patchtestreg(fs, node, reg) | ||
299 | local i = self:getjumpcontrol(fs, node) | ||
300 | if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then | ||
301 | return false -- cannot patch other instructions | ||
302 | end | ||
303 | if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then | ||
304 | luaP:SETARG_A(i, reg) | ||
305 | else -- no register to put value or register already has the value | ||
306 | -- due to use of a table as i, i cannot be replaced by another table | ||
307 | -- so the following is required; there is no change to ARG_C | ||
308 | luaP:SET_OPCODE(i, "OP_TEST") | ||
309 | local b = luaP:GETARG_B(i) | ||
310 | luaP:SETARG_A(i, b) | ||
311 | luaP:SETARG_B(i, 0) | ||
312 | -- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); /* C */ | ||
313 | end | ||
314 | return true | ||
315 | end | ||
316 | |||
317 | ------------------------------------------------------------------------ | ||
318 | -- | ||
319 | -- * used only in luaK:codenot() | ||
320 | ------------------------------------------------------------------------ | ||
321 | function luaK:removevalues(fs, list) | ||
322 | while list ~= self.NO_JUMP do | ||
323 | self:patchtestreg(fs, list, luaP.NO_REG) | ||
324 | list = self:getjump(fs, list) | ||
325 | end | ||
326 | end | ||
327 | |||
328 | ------------------------------------------------------------------------ | ||
329 | -- | ||
330 | -- * used in luaK:dischargejpc(), luaK:patchlist(), luaK:exp2reg() | ||
331 | ------------------------------------------------------------------------ | ||
332 | function luaK:patchlistaux(fs, list, vtarget, reg, dtarget) | ||
333 | while list ~= self.NO_JUMP do | ||
334 | local _next = self:getjump(fs, list) | ||
335 | if self:patchtestreg(fs, list, reg) then | ||
336 | self:fixjump(fs, list, vtarget) | ||
337 | else | ||
338 | self:fixjump(fs, list, dtarget) -- jump to default target | ||
339 | end | ||
340 | list = _next | ||
341 | end | ||
342 | end | ||
343 | |||
344 | ------------------------------------------------------------------------ | ||
345 | -- | ||
346 | -- * used only in luaK:code() | ||
347 | ------------------------------------------------------------------------ | ||
348 | function luaK:dischargejpc(fs) | ||
349 | self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc) | ||
350 | fs.jpc = self.NO_JUMP | ||
351 | end | ||
352 | |||
353 | ------------------------------------------------------------------------ | ||
354 | -- | ||
355 | -- * used in (lparser) luaY:whilestat(), luaY:repeatstat(), luaY:forbody() | ||
356 | ------------------------------------------------------------------------ | ||
357 | function luaK:patchlist(fs, list, target) | ||
358 | if target == fs.pc then | ||
359 | self:patchtohere(fs, list) | ||
360 | else | ||
361 | lua_assert(target < fs.pc) | ||
362 | self:patchlistaux(fs, list, target, luaP.NO_REG, target) | ||
363 | end | ||
364 | end | ||
365 | |||
366 | ------------------------------------------------------------------------ | ||
367 | -- | ||
368 | -- * used in multiple locations | ||
369 | ------------------------------------------------------------------------ | ||
370 | function luaK:patchtohere(fs, list) | ||
371 | self:getlabel(fs) | ||
372 | fs.jpc = self:concat(fs, fs.jpc, list) | ||
373 | end | ||
374 | |||
375 | ------------------------------------------------------------------------ | ||
376 | -- * l1 was a pointer, now l1 is returned and callee assigns the value | ||
377 | -- * used in multiple locations | ||
378 | ------------------------------------------------------------------------ | ||
379 | function luaK:concat(fs, l1, l2) | ||
380 | if l2 == self.NO_JUMP then return l1 | ||
381 | elseif l1 == self.NO_JUMP then | ||
382 | return l2 | ||
383 | else | ||
384 | local list = l1 | ||
385 | local _next = self:getjump(fs, list) | ||
386 | while _next ~= self.NO_JUMP do -- find last element | ||
387 | list = _next | ||
388 | _next = self:getjump(fs, list) | ||
389 | end | ||
390 | self:fixjump(fs, list, l2) | ||
391 | end | ||
392 | return l1 | ||
393 | end | ||
394 | |||
395 | ------------------------------------------------------------------------ | ||
396 | -- | ||
397 | -- * used in luaK:reserveregs(), (lparser) luaY:forlist() | ||
398 | ------------------------------------------------------------------------ | ||
399 | function luaK:checkstack(fs, n) | ||
400 | local newstack = fs.freereg + n | ||
401 | if newstack > fs.f.maxstacksize then | ||
402 | if newstack >= self.MAXSTACK then | ||
403 | luaX:syntaxerror(fs.ls, "function or expression too complex") | ||
404 | end | ||
405 | fs.f.maxstacksize = newstack | ||
406 | end | ||
407 | end | ||
408 | |||
409 | ------------------------------------------------------------------------ | ||
410 | -- | ||
411 | -- * used in multiple locations | ||
412 | ------------------------------------------------------------------------ | ||
413 | function luaK:reserveregs(fs, n) | ||
414 | self:checkstack(fs, n) | ||
415 | fs.freereg = fs.freereg + n | ||
416 | end | ||
417 | |||
418 | ------------------------------------------------------------------------ | ||
419 | -- | ||
420 | -- * used in luaK:freeexp(), luaK:dischargevars() | ||
421 | ------------------------------------------------------------------------ | ||
422 | function luaK:freereg(fs, reg) | ||
423 | if not luaP:ISK(reg) and reg >= fs.nactvar then | ||
424 | fs.freereg = fs.freereg - 1 | ||
425 | lua_assert(reg == fs.freereg) | ||
426 | end | ||
427 | end | ||
428 | |||
429 | ------------------------------------------------------------------------ | ||
430 | -- | ||
431 | -- * used in multiple locations | ||
432 | ------------------------------------------------------------------------ | ||
433 | function luaK:freeexp(fs, e) | ||
434 | if e.k == "VNONRELOC" then | ||
435 | self:freereg(fs, e.info) | ||
436 | end | ||
437 | end | ||
438 | |||
439 | ------------------------------------------------------------------------ | ||
440 | -- * TODO NOTE implementation is not 100% correct, since the assert fails | ||
441 | -- * luaH_set, setobj deleted; direct table access used instead | ||
442 | -- * used in luaK:stringK(), luaK:numberK(), luaK:boolK(), luaK:nilK() | ||
443 | ------------------------------------------------------------------------ | ||
444 | function luaK:addk(fs, k, v) | ||
445 | local L = fs.L | ||
446 | local idx = fs.h[k.value] | ||
447 | --TValue *idx = luaH_set(L, fs->h, k); /* C */ | ||
448 | local f = fs.f | ||
449 | if self:ttisnumber(idx) then | ||
450 | --TODO this assert currently FAILS (last tested for 5.0.2) | ||
451 | --lua_assert(fs.f.k[self:nvalue(idx)] == v) | ||
452 | --lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); /* C */ | ||
453 | return self:nvalue(idx) | ||
454 | else -- constant not found; create a new entry | ||
455 | idx = {} | ||
456 | self:setnvalue(idx, fs.nk) | ||
457 | fs.h[k.value] = idx | ||
458 | -- setnvalue(idx, cast_num(fs->nk)); /* C */ | ||
459 | luaY:growvector(L, f.k, fs.nk, f.sizek, nil, | ||
460 | luaP.MAXARG_Bx, "constant table overflow") | ||
461 | -- loop to initialize empty f.k positions not required | ||
462 | f.k[fs.nk] = v | ||
463 | -- setobj(L, &f->k[fs->nk], v); /* C */ | ||
464 | -- luaC_barrier(L, f, v); /* GC */ | ||
465 | local nk = fs.nk | ||
466 | fs.nk = fs.nk + 1 | ||
467 | return nk | ||
468 | end | ||
469 | |||
470 | end | ||
471 | |||
472 | ------------------------------------------------------------------------ | ||
473 | -- creates and sets a string object | ||
474 | -- * used in (lparser) luaY:codestring(), luaY:singlevar() | ||
475 | ------------------------------------------------------------------------ | ||
476 | function luaK:stringK(fs, s) | ||
477 | local o = {} -- TValue | ||
478 | self:setsvalue(o, s) | ||
479 | return self:addk(fs, o, o) | ||
480 | end | ||
481 | |||
482 | ------------------------------------------------------------------------ | ||
483 | -- creates and sets a number object | ||
484 | -- * used in luaK:prefix() for negative (or negation of) numbers | ||
485 | -- * used in (lparser) luaY:simpleexp(), luaY:fornum() | ||
486 | ------------------------------------------------------------------------ | ||
487 | function luaK:numberK(fs, r) | ||
488 | local o = {} -- TValue | ||
489 | self:setnvalue(o, r) | ||
490 | return self:addk(fs, o, o) | ||
491 | end | ||
492 | |||
493 | ------------------------------------------------------------------------ | ||
494 | -- creates and sets a boolean object | ||
495 | -- * used only in luaK:exp2RK() | ||
496 | ------------------------------------------------------------------------ | ||
497 | function luaK:boolK(fs, b) | ||
498 | local o = {} -- TValue | ||
499 | self:setbvalue(o, b) | ||
500 | return self:addk(fs, o, o) | ||
501 | end | ||
502 | |||
503 | ------------------------------------------------------------------------ | ||
504 | -- creates and sets a nil object | ||
505 | -- * used only in luaK:exp2RK() | ||
506 | ------------------------------------------------------------------------ | ||
507 | function luaK:nilK(fs) | ||
508 | local k, v = {}, {} -- TValue | ||
509 | self:setnilvalue(v) | ||
510 | -- cannot use nil as key; instead use table itself to represent nil | ||
511 | self:sethvalue(k, fs.h) | ||
512 | return self:addk(fs, k, v) | ||
513 | end | ||
514 | |||
515 | ------------------------------------------------------------------------ | ||
516 | -- | ||
517 | -- * used in luaK:setmultret(), (lparser) luaY:adjust_assign() | ||
518 | ------------------------------------------------------------------------ | ||
519 | function luaK:setreturns(fs, e, nresults) | ||
520 | if e.k == "VCALL" then -- expression is an open function call? | ||
521 | luaP:SETARG_C(self:getcode(fs, e), nresults + 1) | ||
522 | elseif e.k == "VVARARG" then | ||
523 | luaP:SETARG_B(self:getcode(fs, e), nresults + 1); | ||
524 | luaP:SETARG_A(self:getcode(fs, e), fs.freereg); | ||
525 | luaK:reserveregs(fs, 1) | ||
526 | end | ||
527 | end | ||
528 | |||
529 | ------------------------------------------------------------------------ | ||
530 | -- | ||
531 | -- * used in luaK:dischargevars(), (lparser) luaY:assignment() | ||
532 | ------------------------------------------------------------------------ | ||
533 | function luaK:setoneret(fs, e) | ||
534 | if e.k == "VCALL" then -- expression is an open function call? | ||
535 | e.k = "VNONRELOC" | ||
536 | e.info = luaP:GETARG_A(self:getcode(fs, e)) | ||
537 | elseif e.k == "VVARARG" then | ||
538 | luaP:SETARG_B(self:getcode(fs, e), 2) | ||
539 | e.k = "VRELOCABLE" -- can relocate its simple result | ||
540 | end | ||
541 | end | ||
542 | |||
543 | ------------------------------------------------------------------------ | ||
544 | -- | ||
545 | -- * used in multiple locations | ||
546 | ------------------------------------------------------------------------ | ||
547 | function luaK:dischargevars(fs, e) | ||
548 | local k = e.k | ||
549 | if k == "VLOCAL" then | ||
550 | e.k = "VNONRELOC" | ||
551 | elseif k == "VUPVAL" then | ||
552 | e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0) | ||
553 | e.k = "VRELOCABLE" | ||
554 | elseif k == "VGLOBAL" then | ||
555 | e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info) | ||
556 | e.k = "VRELOCABLE" | ||
557 | elseif k == "VINDEXED" then | ||
558 | self:freereg(fs, e.aux) | ||
559 | self:freereg(fs, e.info) | ||
560 | e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux) | ||
561 | e.k = "VRELOCABLE" | ||
562 | elseif k == "VVARARG" or k == "VCALL" then | ||
563 | self:setoneret(fs, e) | ||
564 | else | ||
565 | -- there is one value available (somewhere) | ||
566 | end | ||
567 | end | ||
568 | |||
569 | ------------------------------------------------------------------------ | ||
570 | -- | ||
571 | -- * used only in luaK:exp2reg() | ||
572 | ------------------------------------------------------------------------ | ||
573 | function luaK:code_label(fs, A, b, jump) | ||
574 | self:getlabel(fs) -- those instructions may be jump targets | ||
575 | return self:codeABC(fs, "OP_LOADBOOL", A, b, jump) | ||
576 | end | ||
577 | |||
578 | ------------------------------------------------------------------------ | ||
579 | -- | ||
580 | -- * used in luaK:discharge2anyreg(), luaK:exp2reg() | ||
581 | ------------------------------------------------------------------------ | ||
582 | function luaK:discharge2reg(fs, e, reg) | ||
583 | self:dischargevars(fs, e) | ||
584 | local k = e.k | ||
585 | if k == "VNIL" then | ||
586 | self:_nil(fs, reg, 1) | ||
587 | elseif k == "VFALSE" or k == "VTRUE" then | ||
588 | self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0) | ||
589 | elseif k == "VK" then | ||
590 | self:codeABx(fs, "OP_LOADK", reg, e.info) | ||
591 | elseif k == "VKNUM" then | ||
592 | self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval)) | ||
593 | elseif k == "VRELOCABLE" then | ||
594 | local pc = self:getcode(fs, e) | ||
595 | luaP:SETARG_A(pc, reg) | ||
596 | elseif k == "VNONRELOC" then | ||
597 | if reg ~= e.info then | ||
598 | self:codeABC(fs, "OP_MOVE", reg, e.info, 0) | ||
599 | end | ||
600 | else | ||
601 | lua_assert(e.k == "VVOID" or e.k == "VJMP") | ||
602 | return -- nothing to do... | ||
603 | end | ||
604 | e.info = reg | ||
605 | e.k = "VNONRELOC" | ||
606 | end | ||
607 | |||
608 | ------------------------------------------------------------------------ | ||
609 | -- | ||
610 | -- * used in luaK:jumponcond(), luaK:codenot() | ||
611 | ------------------------------------------------------------------------ | ||
612 | function luaK:discharge2anyreg(fs, e) | ||
613 | if e.k ~= "VNONRELOC" then | ||
614 | self:reserveregs(fs, 1) | ||
615 | self:discharge2reg(fs, e, fs.freereg - 1) | ||
616 | end | ||
617 | end | ||
618 | |||
619 | ------------------------------------------------------------------------ | ||
620 | -- | ||
621 | -- * used in luaK:exp2nextreg(), luaK:exp2anyreg(), luaK:storevar() | ||
622 | ------------------------------------------------------------------------ | ||
623 | function luaK:exp2reg(fs, e, reg) | ||
624 | self:discharge2reg(fs, e, reg) | ||
625 | if e.k == "VJMP" then | ||
626 | e.t = self:concat(fs, e.t, e.info) -- put this jump in 't' list | ||
627 | end | ||
628 | if self:hasjumps(e) then | ||
629 | local final -- position after whole expression | ||
630 | local p_f = self.NO_JUMP -- position of an eventual LOAD false | ||
631 | local p_t = self.NO_JUMP -- position of an eventual LOAD true | ||
632 | if self:need_value(fs, e.t) or self:need_value(fs, e.f) then | ||
633 | local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs) | ||
634 | p_f = self:code_label(fs, reg, 0, 1) | ||
635 | p_t = self:code_label(fs, reg, 1, 0) | ||
636 | self:patchtohere(fs, fj) | ||
637 | end | ||
638 | final = self:getlabel(fs) | ||
639 | self:patchlistaux(fs, e.f, final, reg, p_f) | ||
640 | self:patchlistaux(fs, e.t, final, reg, p_t) | ||
641 | end | ||
642 | e.f, e.t = self.NO_JUMP, self.NO_JUMP | ||
643 | e.info = reg | ||
644 | e.k = "VNONRELOC" | ||
645 | end | ||
646 | |||
647 | ------------------------------------------------------------------------ | ||
648 | -- | ||
649 | -- * used in multiple locations | ||
650 | ------------------------------------------------------------------------ | ||
651 | function luaK:exp2nextreg(fs, e) | ||
652 | self:dischargevars(fs, e) | ||
653 | self:freeexp(fs, e) | ||
654 | self:reserveregs(fs, 1) | ||
655 | self:exp2reg(fs, e, fs.freereg - 1) | ||
656 | end | ||
657 | |||
658 | ------------------------------------------------------------------------ | ||
659 | -- | ||
660 | -- * used in multiple locations | ||
661 | ------------------------------------------------------------------------ | ||
662 | function luaK:exp2anyreg(fs, e) | ||
663 | self:dischargevars(fs, e) | ||
664 | if e.k == "VNONRELOC" then | ||
665 | if not self:hasjumps(e) then -- exp is already in a register | ||
666 | return e.info | ||
667 | end | ||
668 | if e.info >= fs.nactvar then -- reg. is not a local? | ||
669 | self:exp2reg(fs, e, e.info) -- put value on it | ||
670 | return e.info | ||
671 | end | ||
672 | end | ||
673 | self:exp2nextreg(fs, e) -- default | ||
674 | return e.info | ||
675 | end | ||
676 | |||
677 | ------------------------------------------------------------------------ | ||
678 | -- | ||
679 | -- * used in luaK:exp2RK(), luaK:prefix(), luaK:posfix() | ||
680 | -- * used in (lparser) luaY:yindex() | ||
681 | ------------------------------------------------------------------------ | ||
682 | function luaK:exp2val(fs, e) | ||
683 | if self:hasjumps(e) then | ||
684 | self:exp2anyreg(fs, e) | ||
685 | else | ||
686 | self:dischargevars(fs, e) | ||
687 | end | ||
688 | end | ||
689 | |||
690 | ------------------------------------------------------------------------ | ||
691 | -- | ||
692 | -- * used in multiple locations | ||
693 | ------------------------------------------------------------------------ | ||
694 | function luaK:exp2RK(fs, e) | ||
695 | self:exp2val(fs, e) | ||
696 | local k = e.k | ||
697 | if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then | ||
698 | if fs.nk <= luaP.MAXINDEXRK then -- constant fit in RK operand? | ||
699 | -- converted from a 2-deep ternary operator expression | ||
700 | if e.k == "VNIL" then | ||
701 | e.info = self:nilK(fs) | ||
702 | else | ||
703 | e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval) | ||
704 | or self:boolK(fs, e.k == "VTRUE") | ||
705 | end | ||
706 | e.k = "VK" | ||
707 | return luaP:RKASK(e.info) | ||
708 | end | ||
709 | elseif k == "VK" then | ||
710 | if e.info <= luaP.MAXINDEXRK then -- constant fit in argC? | ||
711 | return luaP:RKASK(e.info) | ||
712 | end | ||
713 | else | ||
714 | -- default | ||
715 | end | ||
716 | -- not a constant in the right range: put it in a register | ||
717 | return self:exp2anyreg(fs, e) | ||
718 | end | ||
719 | |||
720 | ------------------------------------------------------------------------ | ||
721 | -- | ||
722 | -- * used in (lparser) luaY:assignment(), luaY:localfunc(), luaY:funcstat() | ||
723 | ------------------------------------------------------------------------ | ||
724 | function luaK:storevar(fs, var, ex) | ||
725 | local k = var.k | ||
726 | if k == "VLOCAL" then | ||
727 | self:freeexp(fs, ex) | ||
728 | self:exp2reg(fs, ex, var.info) | ||
729 | return | ||
730 | elseif k == "VUPVAL" then | ||
731 | local e = self:exp2anyreg(fs, ex) | ||
732 | self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0) | ||
733 | elseif k == "VGLOBAL" then | ||
734 | local e = self:exp2anyreg(fs, ex) | ||
735 | self:codeABx(fs, "OP_SETGLOBAL", e, var.info) | ||
736 | elseif k == "VINDEXED" then | ||
737 | local e = self:exp2RK(fs, ex) | ||
738 | self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e) | ||
739 | else | ||
740 | lua_assert(0) -- invalid var kind to store | ||
741 | end | ||
742 | self:freeexp(fs, ex) | ||
743 | end | ||
744 | |||
745 | ------------------------------------------------------------------------ | ||
746 | -- | ||
747 | -- * used only in (lparser) luaY:primaryexp() | ||
748 | ------------------------------------------------------------------------ | ||
749 | function luaK:_self(fs, e, key) | ||
750 | self:exp2anyreg(fs, e) | ||
751 | self:freeexp(fs, e) | ||
752 | local func = fs.freereg | ||
753 | self:reserveregs(fs, 2) | ||
754 | self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key)) | ||
755 | self:freeexp(fs, key) | ||
756 | e.info = func | ||
757 | e.k = "VNONRELOC" | ||
758 | end | ||
759 | |||
760 | ------------------------------------------------------------------------ | ||
761 | -- | ||
762 | -- * used in luaK:goiftrue(), luaK:codenot() | ||
763 | ------------------------------------------------------------------------ | ||
764 | function luaK:invertjump(fs, e) | ||
765 | local pc = self:getjumpcontrol(fs, e.info) | ||
766 | lua_assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and | ||
767 | luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and | ||
768 | luaP:GET_OPCODE(pc) ~= "OP_TEST") | ||
769 | luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0) | ||
770 | end | ||
771 | |||
772 | ------------------------------------------------------------------------ | ||
773 | -- | ||
774 | -- * used in luaK:goiftrue(), luaK:goiffalse() | ||
775 | ------------------------------------------------------------------------ | ||
776 | function luaK:jumponcond(fs, e, cond) | ||
777 | if e.k == "VRELOCABLE" then | ||
778 | local ie = self:getcode(fs, e) | ||
779 | if luaP:GET_OPCODE(ie) == "OP_NOT" then | ||
780 | fs.pc = fs.pc - 1 -- remove previous OP_NOT | ||
781 | return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1) | ||
782 | end | ||
783 | -- else go through | ||
784 | end | ||
785 | self:discharge2anyreg(fs, e) | ||
786 | self:freeexp(fs, e) | ||
787 | return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0) | ||
788 | end | ||
789 | |||
790 | ------------------------------------------------------------------------ | ||
791 | -- | ||
792 | -- * used in luaK:infix(), (lparser) luaY:cond() | ||
793 | ------------------------------------------------------------------------ | ||
794 | function luaK:goiftrue(fs, e) | ||
795 | local pc -- pc of last jump | ||
796 | self:dischargevars(fs, e) | ||
797 | local k = e.k | ||
798 | if k == "VK" or k == "VKNUM" or k == "VTRUE" then | ||
799 | pc = self.NO_JUMP -- always true; do nothing | ||
800 | elseif k == "VFALSE" then | ||
801 | pc = self:jump(fs) -- always jump | ||
802 | elseif k == "VJMP" then | ||
803 | self:invertjump(fs, e) | ||
804 | pc = e.info | ||
805 | else | ||
806 | pc = self:jumponcond(fs, e, false) | ||
807 | end | ||
808 | e.f = self:concat(fs, e.f, pc) -- insert last jump in `f' list | ||
809 | self:patchtohere(fs, e.t) | ||
810 | e.t = self.NO_JUMP | ||
811 | end | ||
812 | |||
813 | ------------------------------------------------------------------------ | ||
814 | -- | ||
815 | -- * used in luaK:infix() | ||
816 | ------------------------------------------------------------------------ | ||
817 | function luaK:goiffalse(fs, e) | ||
818 | local pc -- pc of last jump | ||
819 | self:dischargevars(fs, e) | ||
820 | local k = e.k | ||
821 | if k == "VNIL" or k == "VFALSE"then | ||
822 | pc = self.NO_JUMP -- always false; do nothing | ||
823 | elseif k == "VTRUE" then | ||
824 | pc = self:jump(fs) -- always jump | ||
825 | elseif k == "VJMP" then | ||
826 | pc = e.info | ||
827 | else | ||
828 | pc = self:jumponcond(fs, e, true) | ||
829 | end | ||
830 | e.t = self:concat(fs, e.t, pc) -- insert last jump in `t' list | ||
831 | self:patchtohere(fs, e.f) | ||
832 | e.f = self.NO_JUMP | ||
833 | end | ||
834 | |||
835 | ------------------------------------------------------------------------ | ||
836 | -- | ||
837 | -- * used only in luaK:prefix() | ||
838 | ------------------------------------------------------------------------ | ||
839 | function luaK:codenot(fs, e) | ||
840 | self:dischargevars(fs, e) | ||
841 | local k = e.k | ||
842 | if k == "VNIL" or k == "VFALSE" then | ||
843 | e.k = "VTRUE" | ||
844 | elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then | ||
845 | e.k = "VFALSE" | ||
846 | elseif k == "VJMP" then | ||
847 | self:invertjump(fs, e) | ||
848 | elseif k == "VRELOCABLE" or k == "VNONRELOC" then | ||
849 | self:discharge2anyreg(fs, e) | ||
850 | self:freeexp(fs, e) | ||
851 | e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0) | ||
852 | e.k = "VRELOCABLE" | ||
853 | else | ||
854 | lua_assert(0) -- cannot happen | ||
855 | end | ||
856 | -- interchange true and false lists | ||
857 | e.f, e.t = e.t, e.f | ||
858 | self:removevalues(fs, e.f) | ||
859 | self:removevalues(fs, e.t) | ||
860 | end | ||
861 | |||
862 | ------------------------------------------------------------------------ | ||
863 | -- | ||
864 | -- * used in (lparser) luaY:field(), luaY:primaryexp() | ||
865 | ------------------------------------------------------------------------ | ||
866 | function luaK:indexed(fs, t, k) | ||
867 | t.aux = self:exp2RK(fs, k) | ||
868 | t.k = "VINDEXED" | ||
869 | end | ||
870 | |||
871 | ------------------------------------------------------------------------ | ||
872 | -- | ||
873 | -- * used only in luaK:codearith() | ||
874 | ------------------------------------------------------------------------ | ||
875 | function luaK:constfolding(op, e1, e2) | ||
876 | local r | ||
877 | if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end | ||
878 | local v1 = e1.nval | ||
879 | local v2 = e2.nval | ||
880 | if op == "OP_ADD" then | ||
881 | r = self:numadd(v1, v2) | ||
882 | elseif op == "OP_SUB" then | ||
883 | r = self:numsub(v1, v2) | ||
884 | elseif op == "OP_MUL" then | ||
885 | r = self:nummul(v1, v2) | ||
886 | elseif op == "OP_DIV" then | ||
887 | if v2 == 0 then return false end -- do not attempt to divide by 0 | ||
888 | r = self:numdiv(v1, v2) | ||
889 | elseif op == "OP_MOD" then | ||
890 | if v2 == 0 then return false end -- do not attempt to divide by 0 | ||
891 | r = self:nummod(v1, v2) | ||
892 | elseif op == "OP_POW" then | ||
893 | r = self:numpow(v1, v2) | ||
894 | elseif op == "OP_UNM" then | ||
895 | r = self:numunm(v1) | ||
896 | elseif op == "OP_LEN" then | ||
897 | return false -- no constant folding for 'len' | ||
898 | else | ||
899 | lua_assert(0) | ||
900 | r = 0 | ||
901 | end | ||
902 | if self:numisnan(r) then return false end -- do not attempt to produce NaN | ||
903 | e1.nval = r | ||
904 | return true | ||
905 | end | ||
906 | |||
907 | ------------------------------------------------------------------------ | ||
908 | -- | ||
909 | -- * used in luaK:prefix(), luaK:posfix() | ||
910 | ------------------------------------------------------------------------ | ||
911 | function luaK:codearith(fs, op, e1, e2) | ||
912 | if self:constfolding(op, e1, e2) then | ||
913 | return | ||
914 | else | ||
915 | local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0 | ||
916 | local o1 = self:exp2RK(fs, e1) | ||
917 | if o1 > o2 then | ||
918 | self:freeexp(fs, e1) | ||
919 | self:freeexp(fs, e2) | ||
920 | else | ||
921 | self:freeexp(fs, e2) | ||
922 | self:freeexp(fs, e1) | ||
923 | end | ||
924 | e1.info = self:codeABC(fs, op, 0, o1, o2) | ||
925 | e1.k = "VRELOCABLE" | ||
926 | end | ||
927 | end | ||
928 | |||
929 | ------------------------------------------------------------------------ | ||
930 | -- | ||
931 | -- * used only in luaK:posfix() | ||
932 | ------------------------------------------------------------------------ | ||
933 | function luaK:codecomp(fs, op, cond, e1, e2) | ||
934 | local o1 = self:exp2RK(fs, e1) | ||
935 | local o2 = self:exp2RK(fs, e2) | ||
936 | self:freeexp(fs, e2) | ||
937 | self:freeexp(fs, e1) | ||
938 | if cond == 0 and op ~= "OP_EQ" then | ||
939 | -- exchange args to replace by `<' or `<=' | ||
940 | o1, o2 = o2, o1 -- o1 <==> o2 | ||
941 | cond = 1 | ||
942 | end | ||
943 | e1.info = self:condjump(fs, op, cond, o1, o2) | ||
944 | e1.k = "VJMP" | ||
945 | end | ||
946 | |||
947 | ------------------------------------------------------------------------ | ||
948 | -- | ||
949 | -- * used only in (lparser) luaY:subexpr() | ||
950 | ------------------------------------------------------------------------ | ||
951 | function luaK:prefix(fs, op, e) | ||
952 | local e2 = {} -- expdesc | ||
953 | e2.t, e2.f = self.NO_JUMP, self.NO_JUMP | ||
954 | e2.k = "VKNUM" | ||
955 | e2.nval = 0 | ||
956 | if op == "OPR_MINUS" then | ||
957 | if not self:isnumeral(e) then | ||
958 | self:exp2anyreg(fs, e) -- cannot operate on non-numeric constants | ||
959 | end | ||
960 | self:codearith(fs, "OP_UNM", e, e2) | ||
961 | elseif op == "OPR_NOT" then | ||
962 | self:codenot(fs, e) | ||
963 | elseif op == "OPR_LEN" then | ||
964 | self:exp2anyreg(fs, e) -- cannot operate on constants | ||
965 | self:codearith(fs, "OP_LEN", e, e2) | ||
966 | else | ||
967 | lua_assert(0) | ||
968 | end | ||
969 | end | ||
970 | |||
971 | ------------------------------------------------------------------------ | ||
972 | -- | ||
973 | -- * used only in (lparser) luaY:subexpr() | ||
974 | ------------------------------------------------------------------------ | ||
975 | function luaK:infix(fs, op, v) | ||
976 | if op == "OPR_AND" then | ||
977 | self:goiftrue(fs, v) | ||
978 | elseif op == "OPR_OR" then | ||
979 | self:goiffalse(fs, v) | ||
980 | elseif op == "OPR_CONCAT" then | ||
981 | self:exp2nextreg(fs, v) -- operand must be on the 'stack' | ||
982 | elseif op == "OPR_ADD" or op == "OPR_SUB" or | ||
983 | op == "OPR_MUL" or op == "OPR_DIV" or | ||
984 | op == "OPR_MOD" or op == "OPR_POW" then | ||
985 | if not self:isnumeral(v) then self:exp2RK(fs, v) end | ||
986 | else | ||
987 | self:exp2RK(fs, v) | ||
988 | end | ||
989 | end | ||
990 | |||
991 | ------------------------------------------------------------------------ | ||
992 | -- | ||
993 | -- * used only in (lparser) luaY:subexpr() | ||
994 | ------------------------------------------------------------------------ | ||
995 | -- table lookups to simplify testing | ||
996 | luaK.arith_op = { | ||
997 | OPR_ADD = "OP_ADD", OPR_SUB = "OP_SUB", OPR_MUL = "OP_MUL", | ||
998 | OPR_DIV = "OP_DIV", OPR_MOD = "OP_MOD", OPR_POW = "OP_POW", | ||
999 | } | ||
1000 | luaK.comp_op = { | ||
1001 | OPR_EQ = "OP_EQ", OPR_NE = "OP_EQ", OPR_LT = "OP_LT", | ||
1002 | OPR_LE = "OP_LE", OPR_GT = "OP_LT", OPR_GE = "OP_LE", | ||
1003 | } | ||
1004 | luaK.comp_cond = { | ||
1005 | OPR_EQ = 1, OPR_NE = 0, OPR_LT = 1, | ||
1006 | OPR_LE = 1, OPR_GT = 0, OPR_GE = 0, | ||
1007 | } | ||
1008 | function luaK:posfix(fs, op, e1, e2) | ||
1009 | -- needed because e1 = e2 doesn't copy values... | ||
1010 | -- * in 5.0.x, only k/info/aux/t/f copied, t for AND, f for OR | ||
1011 | -- but here, all elements are copied for completeness' sake | ||
1012 | local function copyexp(e1, e2) | ||
1013 | e1.k = e2.k | ||
1014 | e1.info = e2.info; e1.aux = e2.aux | ||
1015 | e1.nval = e2.nval | ||
1016 | e1.t = e2.t; e1.f = e2.f | ||
1017 | end | ||
1018 | if op == "OPR_AND" then | ||
1019 | lua_assert(e1.t == self.NO_JUMP) -- list must be closed | ||
1020 | self:dischargevars(fs, e2) | ||
1021 | e2.f = self:concat(fs, e2.f, e1.f) | ||
1022 | copyexp(e1, e2) | ||
1023 | elseif op == "OPR_OR" then | ||
1024 | lua_assert(e1.f == self.NO_JUMP) -- list must be closed | ||
1025 | self:dischargevars(fs, e2) | ||
1026 | e2.t = self:concat(fs, e2.t, e1.t) | ||
1027 | copyexp(e1, e2) | ||
1028 | elseif op == "OPR_CONCAT" then | ||
1029 | self:exp2val(fs, e2) | ||
1030 | if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then | ||
1031 | lua_assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1) | ||
1032 | self:freeexp(fs, e1) | ||
1033 | luaP:SETARG_B(self:getcode(fs, e2), e1.info) | ||
1034 | e1.k = "VRELOCABLE" | ||
1035 | e1.info = e2.info | ||
1036 | else | ||
1037 | self:exp2nextreg(fs, e2) -- operand must be on the 'stack' | ||
1038 | self:codearith(fs, "OP_CONCAT", e1, e2) | ||
1039 | end | ||
1040 | else | ||
1041 | -- the following uses a table lookup in place of conditionals | ||
1042 | local arith = self.arith_op[op] | ||
1043 | if arith then | ||
1044 | self:codearith(fs, arith, e1, e2) | ||
1045 | else | ||
1046 | local comp = self.comp_op[op] | ||
1047 | if comp then | ||
1048 | self:codecomp(fs, comp, self.comp_cond[op], e1, e2) | ||
1049 | else | ||
1050 | lua_assert(0) | ||
1051 | end | ||
1052 | end--if arith | ||
1053 | end--if op | ||
1054 | end | ||
1055 | |||
1056 | ------------------------------------------------------------------------ | ||
1057 | -- adjusts debug information for last instruction written, in order to | ||
1058 | -- change the line where item comes into existence | ||
1059 | -- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat() | ||
1060 | ------------------------------------------------------------------------ | ||
1061 | function luaK:fixline(fs, line) | ||
1062 | fs.f.lineinfo[fs.pc - 1] = line | ||
1063 | end | ||
1064 | |||
1065 | ------------------------------------------------------------------------ | ||
1066 | -- general function to write an instruction into the instruction buffer, | ||
1067 | -- sets debug information too | ||
1068 | -- * used in luaK:codeABC(), luaK:codeABx() | ||
1069 | -- * called directly by (lparser) luaY:whilestat() | ||
1070 | ------------------------------------------------------------------------ | ||
1071 | function luaK:code(fs, i, line) | ||
1072 | local f = fs.f | ||
1073 | self:dischargejpc(fs) -- 'pc' will change | ||
1074 | -- put new instruction in code array | ||
1075 | luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil, | ||
1076 | luaY.MAX_INT, "code size overflow") | ||
1077 | f.code[fs.pc] = i | ||
1078 | -- save corresponding line information | ||
1079 | luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil, | ||
1080 | luaY.MAX_INT, "code size overflow") | ||
1081 | f.lineinfo[fs.pc] = line | ||
1082 | local pc = fs.pc | ||
1083 | fs.pc = fs.pc + 1 | ||
1084 | return pc | ||
1085 | end | ||
1086 | |||
1087 | ------------------------------------------------------------------------ | ||
1088 | -- writes an instruction of type ABC | ||
1089 | -- * calls luaK:code() | ||
1090 | ------------------------------------------------------------------------ | ||
1091 | function luaK:codeABC(fs, o, a, b, c) | ||
1092 | lua_assert(luaP:getOpMode(o) == luaP.OpMode.iABC) | ||
1093 | lua_assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0) | ||
1094 | lua_assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0) | ||
1095 | return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline) | ||
1096 | end | ||
1097 | |||
1098 | ------------------------------------------------------------------------ | ||
1099 | -- writes an instruction of type ABx | ||
1100 | -- * calls luaK:code(), called by luaK:codeAsBx() | ||
1101 | ------------------------------------------------------------------------ | ||
1102 | function luaK:codeABx(fs, o, a, bc) | ||
1103 | lua_assert(luaP:getOpMode(o) == luaP.OpMode.iABx or | ||
1104 | luaP:getOpMode(o) == luaP.OpMode.iAsBx) | ||
1105 | lua_assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN) | ||
1106 | return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline) | ||
1107 | end | ||
1108 | |||
1109 | ------------------------------------------------------------------------ | ||
1110 | -- | ||
1111 | -- * used in (lparser) luaY:closelistfield(), luaY:lastlistfield() | ||
1112 | ------------------------------------------------------------------------ | ||
1113 | function luaK:setlist(fs, base, nelems, tostore) | ||
1114 | local c = math.floor((nelems - 1)/luaP.LFIELDS_PER_FLUSH) + 1 | ||
1115 | local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore | ||
1116 | lua_assert(tostore ~= 0) | ||
1117 | if c <= luaP.MAXARG_C then | ||
1118 | self:codeABC(fs, "OP_SETLIST", base, b, c) | ||
1119 | else | ||
1120 | self:codeABC(fs, "OP_SETLIST", base, b, 0) | ||
1121 | self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline) | ||
1122 | end | ||
1123 | fs.freereg = base + 1 -- free registers with list values | ||
1124 | end | ||
1125 | |||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/ldump.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/ldump.lua deleted file mode 100644 index b9380e1..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/ldump.lua +++ /dev/null | |||
@@ -1,372 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | ldump.lua | ||
4 | Save precompiled Lua chunks | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * WARNING! byte order (little endian) and data type sizes for header | ||
18 | -- signature values hard-coded; see luaU:header | ||
19 | -- * chunk writer generators are included, see below | ||
20 | -- * one significant difference is that instructions are still in table | ||
21 | -- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to | ||
22 | -- convert them into 4-char strings | ||
23 | -- | ||
24 | -- Not implemented: | ||
25 | -- * DumpVar, DumpMem has been removed | ||
26 | -- * DumpVector folded into folded into DumpDebug, DumpCode | ||
27 | -- | ||
28 | -- Added: | ||
29 | -- * for convenience, the following two functions have been added: | ||
30 | -- luaU:make_setS: create a chunk writer that writes to a string | ||
31 | -- luaU:make_setF: create a chunk writer that writes to a file | ||
32 | -- (lua.h contains a typedef for lua_Writer/lua_Chunkwriter, and | ||
33 | -- a Lua-based implementation exists, writer() in lstrlib.c) | ||
34 | -- * luaU:ttype(o) (from lobject.h) | ||
35 | -- * for converting number types to its binary equivalent: | ||
36 | -- luaU:from_double(x): encode double value for writing | ||
37 | -- luaU:from_int(x): encode integer value for writing | ||
38 | -- (error checking is limited for these conversion functions) | ||
39 | -- (double conversion does not support denormals or NaNs) | ||
40 | -- | ||
41 | -- Changed in 5.1.x: | ||
42 | -- * the dumper was mostly rewritten in Lua 5.1.x, so notes on the | ||
43 | -- differences between 5.0.x and 5.1.x is limited | ||
44 | -- * LUAC_VERSION bumped to 0x51, LUAC_FORMAT added | ||
45 | -- * developer is expected to adjust LUAC_FORMAT in order to identify | ||
46 | -- non-standard binary chunk formats | ||
47 | -- * header signature code is smaller, has been simplified, and is | ||
48 | -- tested as a single unit; its logic is shared with the undumper | ||
49 | -- * no more endian conversion, invalid endianness mean rejection | ||
50 | -- * opcode field sizes are no longer exposed in the header | ||
51 | -- * code moved to front of a prototype, followed by constants | ||
52 | -- * debug information moved to the end of the binary chunk, and the | ||
53 | -- relevant functions folded into a single function | ||
54 | -- * luaU:dump returns a writer status code | ||
55 | -- * chunk writer now implements status code because dumper uses it | ||
56 | -- * luaU:endianness removed | ||
57 | ----------------------------------------------------------------------]] | ||
58 | |||
59 | --requires luaP | ||
60 | luaU = {} | ||
61 | |||
62 | -- mark for precompiled code ('<esc>Lua') (from lua.h) | ||
63 | luaU.LUA_SIGNATURE = "\27Lua" | ||
64 | |||
65 | -- constants used by dumper (from lua.h) | ||
66 | luaU.LUA_TNUMBER = 3 | ||
67 | luaU.LUA_TSTRING = 4 | ||
68 | luaU.LUA_TNIL = 0 | ||
69 | luaU.LUA_TBOOLEAN = 1 | ||
70 | luaU.LUA_TNONE = -1 | ||
71 | |||
72 | -- constants for header of binary files (from lundump.h) | ||
73 | luaU.LUAC_VERSION = 0x51 -- this is Lua 5.1 | ||
74 | luaU.LUAC_FORMAT = 0 -- this is the official format | ||
75 | luaU.LUAC_HEADERSIZE = 12 -- size of header of binary files | ||
76 | |||
77 | --[[-------------------------------------------------------------------- | ||
78 | -- Additional functions to handle chunk writing | ||
79 | -- * to use make_setS and make_setF, see test_ldump.lua elsewhere | ||
80 | ----------------------------------------------------------------------]] | ||
81 | |||
82 | ------------------------------------------------------------------------ | ||
83 | -- create a chunk writer that writes to a string | ||
84 | -- * returns the writer function and a table containing the string | ||
85 | -- * to get the final result, look in buff.data | ||
86 | ------------------------------------------------------------------------ | ||
87 | function luaU:make_setS() | ||
88 | local buff = {} | ||
89 | buff.data = "" | ||
90 | local writer = | ||
91 | function(s, buff) -- chunk writer | ||
92 | if not s then return 0 end | ||
93 | buff.data = buff.data..s | ||
94 | return 0 | ||
95 | end | ||
96 | return writer, buff | ||
97 | end | ||
98 | |||
99 | ------------------------------------------------------------------------ | ||
100 | -- create a chunk writer that writes to a file | ||
101 | -- * returns the writer function and a table containing the file handle | ||
102 | -- * if a nil is passed, then writer should close the open file | ||
103 | ------------------------------------------------------------------------ | ||
104 | function luaU:make_setF(filename) | ||
105 | local buff = {} | ||
106 | buff.h = io.open(filename, "wb") | ||
107 | if not buff.h then return nil end | ||
108 | local writer = | ||
109 | function(s, buff) -- chunk writer | ||
110 | if not buff.h then return 0 end | ||
111 | if not s then | ||
112 | if buff.h:close() then return 0 end | ||
113 | else | ||
114 | if buff.h:write(s) then return 0 end | ||
115 | end | ||
116 | return 1 | ||
117 | end | ||
118 | return writer, buff | ||
119 | end | ||
120 | |||
121 | ------------------------------------------------------------------------ | ||
122 | -- works like the lobject.h version except that TObject used in these | ||
123 | -- scripts only has a 'value' field, no 'tt' field (native types used) | ||
124 | ------------------------------------------------------------------------ | ||
125 | function luaU:ttype(o) | ||
126 | local tt = type(o.value) | ||
127 | if tt == "number" then return self.LUA_TNUMBER | ||
128 | elseif tt == "string" then return self.LUA_TSTRING | ||
129 | elseif tt == "nil" then return self.LUA_TNIL | ||
130 | elseif tt == "boolean" then return self.LUA_TBOOLEAN | ||
131 | else | ||
132 | return self.LUA_TNONE -- the rest should not appear | ||
133 | end | ||
134 | end | ||
135 | |||
136 | ----------------------------------------------------------------------- | ||
137 | -- converts a IEEE754 double number to an 8-byte little-endian string | ||
138 | -- * luaU:from_double() and luaU:from_int() are adapted from ChunkBake | ||
139 | -- * supports +/- Infinity, but not denormals or NaNs | ||
140 | ----------------------------------------------------------------------- | ||
141 | function luaU:from_double(x) | ||
142 | local function grab_byte(v) | ||
143 | local c = v % 256 | ||
144 | return (v - c) / 256, string.char(c) | ||
145 | end | ||
146 | local sign = 0 | ||
147 | if x < 0 then sign = 1; x = -x end | ||
148 | local mantissa, exponent = math.frexp(x) | ||
149 | if x == 0 then -- zero | ||
150 | mantissa, exponent = 0, 0 | ||
151 | elseif x == 1/0 then | ||
152 | mantissa, exponent = 0, 2047 | ||
153 | else | ||
154 | mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53) | ||
155 | exponent = exponent + 1022 | ||
156 | end | ||
157 | local v, byte = "" -- convert to bytes | ||
158 | x = math.floor(mantissa) | ||
159 | for i = 1,6 do | ||
160 | x, byte = grab_byte(x); v = v..byte -- 47:0 | ||
161 | end | ||
162 | x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48 | ||
163 | x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56 | ||
164 | return v | ||
165 | end | ||
166 | |||
167 | ----------------------------------------------------------------------- | ||
168 | -- converts a number to a little-endian 32-bit integer string | ||
169 | -- * input value assumed to not overflow, can be signed/unsigned | ||
170 | ----------------------------------------------------------------------- | ||
171 | function luaU:from_int(x) | ||
172 | local v = "" | ||
173 | x = math.floor(x) | ||
174 | if x < 0 then x = 4294967296 + x end -- ULONG_MAX+1 | ||
175 | for i = 1, 4 do | ||
176 | local c = x % 256 | ||
177 | v = v..string.char(c); x = math.floor(x / 256) | ||
178 | end | ||
179 | return v | ||
180 | end | ||
181 | |||
182 | --[[-------------------------------------------------------------------- | ||
183 | -- Functions to make a binary chunk | ||
184 | -- * many functions have the size parameter removed, since output is | ||
185 | -- in the form of a string and some sizes are implicit or hard-coded | ||
186 | ----------------------------------------------------------------------]] | ||
187 | |||
188 | --[[-------------------------------------------------------------------- | ||
189 | -- struct DumpState: | ||
190 | -- L -- lua_State (not used in this script) | ||
191 | -- writer -- lua_Writer (chunk writer function) | ||
192 | -- data -- void* (chunk writer context or data already written) | ||
193 | -- strip -- if true, don't write any debug information | ||
194 | -- status -- if non-zero, an error has occured | ||
195 | ----------------------------------------------------------------------]] | ||
196 | |||
197 | ------------------------------------------------------------------------ | ||
198 | -- dumps a block of bytes | ||
199 | -- * lua_unlock(D.L), lua_lock(D.L) unused | ||
200 | ------------------------------------------------------------------------ | ||
201 | function luaU:DumpBlock(b, D) | ||
202 | if D.status == 0 then | ||
203 | -- lua_unlock(D->L); | ||
204 | D.status = D.write(b, D.data) | ||
205 | -- lua_lock(D->L); | ||
206 | end | ||
207 | end | ||
208 | |||
209 | ------------------------------------------------------------------------ | ||
210 | -- dumps a char | ||
211 | ------------------------------------------------------------------------ | ||
212 | function luaU:DumpChar(y, D) | ||
213 | self:DumpBlock(string.char(y), D) | ||
214 | end | ||
215 | |||
216 | ------------------------------------------------------------------------ | ||
217 | -- dumps a 32-bit signed or unsigned integer (for int) (hard-coded) | ||
218 | ------------------------------------------------------------------------ | ||
219 | function luaU:DumpInt(x, D) | ||
220 | self:DumpBlock(self:from_int(x), D) | ||
221 | end | ||
222 | |||
223 | ------------------------------------------------------------------------ | ||
224 | -- dumps a lua_Number (hard-coded as a double) | ||
225 | ------------------------------------------------------------------------ | ||
226 | function luaU:DumpNumber(x, D) | ||
227 | self:DumpBlock(self:from_double(x), D) | ||
228 | end | ||
229 | |||
230 | ------------------------------------------------------------------------ | ||
231 | -- dumps a Lua string (size type is hard-coded) | ||
232 | ------------------------------------------------------------------------ | ||
233 | function luaU:DumpString(s, D) | ||
234 | if s == nil then | ||
235 | self:DumpInt(0, D) | ||
236 | else | ||
237 | s = s.."\0" -- include trailing '\0' | ||
238 | self:DumpInt(#s, D) | ||
239 | self:DumpBlock(s, D) | ||
240 | end | ||
241 | end | ||
242 | |||
243 | ------------------------------------------------------------------------ | ||
244 | -- dumps instruction block from function prototype | ||
245 | ------------------------------------------------------------------------ | ||
246 | function luaU:DumpCode(f, D) | ||
247 | local n = f.sizecode | ||
248 | --was DumpVector | ||
249 | self:DumpInt(n, D) | ||
250 | for i = 0, n - 1 do | ||
251 | self:DumpBlock(luaP:Instruction(f.code[i]), D) | ||
252 | end | ||
253 | end | ||
254 | |||
255 | ------------------------------------------------------------------------ | ||
256 | -- dump constant pool from function prototype | ||
257 | -- * bvalue(o), nvalue(o) and rawtsvalue(o) macros removed | ||
258 | ------------------------------------------------------------------------ | ||
259 | function luaU:DumpConstants(f, D) | ||
260 | local n = f.sizek | ||
261 | self:DumpInt(n, D) | ||
262 | for i = 0, n - 1 do | ||
263 | local o = f.k[i] -- TValue | ||
264 | local tt = self:ttype(o) | ||
265 | self:DumpChar(tt, D) | ||
266 | if tt == self.LUA_TNIL then | ||
267 | elseif tt == self.LUA_TBOOLEAN then | ||
268 | self:DumpChar(o.value and 1 or 0, D) | ||
269 | elseif tt == self.LUA_TNUMBER then | ||
270 | self:DumpNumber(o.value, D) | ||
271 | elseif tt == self.LUA_TSTRING then | ||
272 | self:DumpString(o.value, D) | ||
273 | else | ||
274 | --lua_assert(0) -- cannot happen | ||
275 | end | ||
276 | end | ||
277 | n = f.sizep | ||
278 | self:DumpInt(n, D) | ||
279 | for i = 0, n - 1 do | ||
280 | self:DumpFunction(f.p[i], f.source, D) | ||
281 | end | ||
282 | end | ||
283 | |||
284 | ------------------------------------------------------------------------ | ||
285 | -- dump debug information | ||
286 | ------------------------------------------------------------------------ | ||
287 | function luaU:DumpDebug(f, D) | ||
288 | local n | ||
289 | n = D.strip and 0 or f.sizelineinfo -- dump line information | ||
290 | --was DumpVector | ||
291 | self:DumpInt(n, D) | ||
292 | for i = 0, n - 1 do | ||
293 | self:DumpInt(f.lineinfo[i], D) | ||
294 | end | ||
295 | n = D.strip and 0 or f.sizelocvars -- dump local information | ||
296 | self:DumpInt(n, D) | ||
297 | for i = 0, n - 1 do | ||
298 | self:DumpString(f.locvars[i].varname, D) | ||
299 | self:DumpInt(f.locvars[i].startpc, D) | ||
300 | self:DumpInt(f.locvars[i].endpc, D) | ||
301 | end | ||
302 | n = D.strip and 0 or f.sizeupvalues -- dump upvalue information | ||
303 | self:DumpInt(n, D) | ||
304 | for i = 0, n - 1 do | ||
305 | self:DumpString(f.upvalues[i], D) | ||
306 | end | ||
307 | end | ||
308 | |||
309 | ------------------------------------------------------------------------ | ||
310 | -- dump child function prototypes from function prototype | ||
311 | ------------------------------------------------------------------------ | ||
312 | function luaU:DumpFunction(f, p, D) | ||
313 | local source = f.source | ||
314 | if source == p or D.strip then source = nil end | ||
315 | self:DumpString(source, D) | ||
316 | self:DumpInt(f.lineDefined, D) | ||
317 | self:DumpInt(f.lastlinedefined, D) | ||
318 | self:DumpChar(f.nups, D) | ||
319 | self:DumpChar(f.numparams, D) | ||
320 | self:DumpChar(f.is_vararg, D) | ||
321 | self:DumpChar(f.maxstacksize, D) | ||
322 | self:DumpCode(f, D) | ||
323 | self:DumpConstants(f, D) | ||
324 | self:DumpDebug(f, D) | ||
325 | end | ||
326 | |||
327 | ------------------------------------------------------------------------ | ||
328 | -- dump Lua header section (some sizes hard-coded) | ||
329 | ------------------------------------------------------------------------ | ||
330 | function luaU:DumpHeader(D) | ||
331 | local h = self:header() | ||
332 | assert(#h == self.LUAC_HEADERSIZE) -- fixed buffer now an assert | ||
333 | self:DumpBlock(h, D) | ||
334 | end | ||
335 | |||
336 | ------------------------------------------------------------------------ | ||
337 | -- make header (from lundump.c) | ||
338 | -- returns the header string | ||
339 | ------------------------------------------------------------------------ | ||
340 | function luaU:header() | ||
341 | local x = 1 | ||
342 | return self.LUA_SIGNATURE.. | ||
343 | string.char( | ||
344 | self.LUAC_VERSION, | ||
345 | self.LUAC_FORMAT, | ||
346 | x, -- endianness (1=little) | ||
347 | 4, -- sizeof(int) | ||
348 | 4, -- sizeof(size_t) | ||
349 | 4, -- sizeof(Instruction) | ||
350 | 8, -- sizeof(lua_Number) | ||
351 | 0) -- is lua_Number integral? | ||
352 | end | ||
353 | |||
354 | ------------------------------------------------------------------------ | ||
355 | -- dump Lua function as precompiled chunk | ||
356 | -- (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) | ||
357 | -- * w, data are created from make_setS, make_setF | ||
358 | ------------------------------------------------------------------------ | ||
359 | function luaU:dump(L, f, w, data, strip) | ||
360 | local D = {} -- DumpState | ||
361 | D.L = L | ||
362 | D.write = w | ||
363 | D.data = data | ||
364 | D.strip = strip | ||
365 | D.status = 0 | ||
366 | self:DumpHeader(D) | ||
367 | self:DumpFunction(f, nil, D) | ||
368 | -- added: for a chunk writer writing to a file, this final call with | ||
369 | -- nil data is to indicate to the writer to close the file | ||
370 | D.write(nil, D.data) | ||
371 | return D.status | ||
372 | end | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/llex.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/llex.lua deleted file mode 100644 index 7949326..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/llex.lua +++ /dev/null | |||
@@ -1,686 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | llex.lua | ||
4 | Lua lexical analyzer in Lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * intended to 'imitate' llex.c code; performance is not a concern | ||
18 | -- * tokens are strings; code structure largely retained | ||
19 | -- * deleted stuff (compared to llex.c) are noted, comments retained | ||
20 | -- * nextc() returns the currently read character to simplify coding | ||
21 | -- here; next() in llex.c does not return anything | ||
22 | -- * compatibility code is marked with "--#" comments | ||
23 | -- | ||
24 | -- Added: | ||
25 | -- * luaX:chunkid (function luaO_chunkid from lobject.c) | ||
26 | -- * luaX:str2d (function luaO_str2d from lobject.c) | ||
27 | -- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h) | ||
28 | -- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h) | ||
29 | -- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h) | ||
30 | -- | ||
31 | -- To use the lexer: | ||
32 | -- (1) luaX:init() to initialize the lexer | ||
33 | -- (2) luaX:setinput() to set the input stream to lex | ||
34 | -- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens, | ||
35 | -- until "TK_EOS": luaX:next() | ||
36 | -- * since EOZ is returned as a string, be careful when regexp testing | ||
37 | -- | ||
38 | -- Not implemented: | ||
39 | -- * luaX_newstring: not required by this Lua implementation | ||
40 | -- * buffer MAX_SIZET size limit (from llimits.h) test not implemented | ||
41 | -- in the interest of performance | ||
42 | -- * locale-aware number handling is largely redundant as Lua's | ||
43 | -- tonumber() function is already capable of this | ||
44 | -- | ||
45 | -- Changed in 5.1.x: | ||
46 | -- * TK_NAME token order moved down | ||
47 | -- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed | ||
48 | -- * token struct renamed to lower case (LS -> ls) | ||
49 | -- * LexState struct: removed nestlevel, added decpoint | ||
50 | -- * error message functions have been greatly simplified | ||
51 | -- * token2string renamed to luaX_tokens, exposed in llex.h | ||
52 | -- * lexer now handles all kinds of newlines, including CRLF | ||
53 | -- * shbang first line handling removed from luaX:setinput; | ||
54 | -- it is now done in lauxlib.c (luaL_loadfile) | ||
55 | -- * next(ls) macro renamed to nextc(ls) due to new luaX_next function | ||
56 | -- * EXTRABUFF and MAXNOCHECK removed due to lexer changes | ||
57 | -- * checkbuffer(ls, len) macro deleted | ||
58 | -- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint, | ||
59 | -- luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d | ||
60 | -- * luaX:read_numeral is now more promiscuous in slurping characters; | ||
61 | -- hexadecimal numbers was added, locale-aware decimal points too | ||
62 | -- * luaX:skip_sep is new; used by luaX:read_long_string | ||
63 | -- * luaX:read_long_string handles new-style long blocks, with some | ||
64 | -- optional compatibility code | ||
65 | -- * luaX:llex: parts changed to support new-style long blocks | ||
66 | -- * luaX:llex: readname functionality has been folded in | ||
67 | -- * luaX:llex: removed test for control characters | ||
68 | ----------------------------------------------------------------------]] | ||
69 | |||
70 | luaX = {} | ||
71 | |||
72 | -- FIRST_RESERVED is not required as tokens are manipulated as strings | ||
73 | -- TOKEN_LEN deleted; maximum length of a reserved word not needed | ||
74 | |||
75 | ------------------------------------------------------------------------ | ||
76 | -- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED | ||
77 | ------------------------------------------------------------------------ | ||
78 | |||
79 | -- terminal symbols denoted by reserved words: TK_AND to TK_WHILE | ||
80 | -- other terminal symbols: TK_NAME to TK_EOS | ||
81 | luaX.RESERVED = [[ | ||
82 | TK_AND and | ||
83 | TK_BREAK break | ||
84 | TK_DO do | ||
85 | TK_ELSE else | ||
86 | TK_ELSEIF elseif | ||
87 | TK_END end | ||
88 | TK_FALSE false | ||
89 | TK_FOR for | ||
90 | TK_FUNCTION function | ||
91 | TK_IF if | ||
92 | TK_IN in | ||
93 | TK_LOCAL local | ||
94 | TK_NIL nil | ||
95 | TK_NOT not | ||
96 | TK_OR or | ||
97 | TK_REPEAT repeat | ||
98 | TK_RETURN return | ||
99 | TK_THEN then | ||
100 | TK_TRUE true | ||
101 | TK_UNTIL until | ||
102 | TK_WHILE while | ||
103 | TK_CONCAT .. | ||
104 | TK_DOTS ... | ||
105 | TK_EQ == | ||
106 | TK_GE >= | ||
107 | TK_LE <= | ||
108 | TK_NE ~= | ||
109 | TK_NAME <name> | ||
110 | TK_NUMBER <number> | ||
111 | TK_STRING <string> | ||
112 | TK_EOS <eof>]] | ||
113 | |||
114 | -- NUM_RESERVED is not required; number of reserved words | ||
115 | |||
116 | --[[-------------------------------------------------------------------- | ||
117 | -- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed | ||
118 | -- so that lexer functions can use its table element, ls.t.seminfo | ||
119 | -- | ||
120 | -- SemInfo (struct no longer needed, a mixed-type value is used) | ||
121 | -- | ||
122 | -- Token (struct of ls.t and ls.lookahead): | ||
123 | -- token -- token symbol | ||
124 | -- seminfo -- semantics information | ||
125 | -- | ||
126 | -- LexState (struct of ls; ls is initialized by luaX:setinput): | ||
127 | -- current -- current character (charint) | ||
128 | -- linenumber -- input line counter | ||
129 | -- lastline -- line of last token 'consumed' | ||
130 | -- t -- current token (table: struct Token) | ||
131 | -- lookahead -- look ahead token (table: struct Token) | ||
132 | -- fs -- 'FuncState' is private to the parser | ||
133 | -- L -- LuaState | ||
134 | -- z -- input stream | ||
135 | -- buff -- buffer for tokens | ||
136 | -- source -- current source name | ||
137 | -- decpoint -- locale decimal point | ||
138 | -- nestlevel -- level of nested non-terminals | ||
139 | ----------------------------------------------------------------------]] | ||
140 | |||
141 | -- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init | ||
142 | |||
143 | luaX.MAXSRC = 80 | ||
144 | luaX.MAX_INT = 2147483645 -- constants from elsewhere (see above) | ||
145 | luaX.LUA_QS = "'%s'" | ||
146 | luaX.LUA_COMPAT_LSTR = 1 | ||
147 | --luaX.MAX_SIZET = 4294967293 | ||
148 | |||
149 | ------------------------------------------------------------------------ | ||
150 | -- initialize lexer | ||
151 | -- * original luaX_init has code to create and register token strings | ||
152 | -- * luaX.tokens: TK_* -> token | ||
153 | -- * luaX.enums: token -> TK_* (used in luaX:llex) | ||
154 | ------------------------------------------------------------------------ | ||
155 | function luaX:init() | ||
156 | local tokens, enums = {}, {} | ||
157 | for v in string.gmatch(self.RESERVED, "[^\n]+") do | ||
158 | local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)") | ||
159 | tokens[tok] = str | ||
160 | enums[str] = tok | ||
161 | end | ||
162 | self.tokens = tokens | ||
163 | self.enums = enums | ||
164 | end | ||
165 | |||
166 | ------------------------------------------------------------------------ | ||
167 | -- returns a suitably-formatted chunk name or id | ||
168 | -- * from lobject.c, used in llex.c and ldebug.c | ||
169 | -- * the result, out, is returned (was first argument) | ||
170 | ------------------------------------------------------------------------ | ||
171 | function luaX:chunkid(source, bufflen) | ||
172 | local out | ||
173 | local first = string.sub(source, 1, 1) | ||
174 | if first == "=" then | ||
175 | out = string.sub(source, 2, bufflen) -- remove first char | ||
176 | else -- out = "source", or "...source" | ||
177 | if first == "@" then | ||
178 | source = string.sub(source, 2) -- skip the '@' | ||
179 | bufflen = bufflen - #" '...' " | ||
180 | local l = #source | ||
181 | out = "" | ||
182 | if l > bufflen then | ||
183 | source = string.sub(source, 1 + l - bufflen) -- get last part of file name | ||
184 | out = out.."..." | ||
185 | end | ||
186 | out = out..source | ||
187 | else -- out = [string "string"] | ||
188 | local len = string.find(source, "[\n\r]") -- stop at first newline | ||
189 | len = len and (len - 1) or #source | ||
190 | bufflen = bufflen - #(" [string \"...\"] ") | ||
191 | if len > bufflen then len = bufflen end | ||
192 | out = "[string \"" | ||
193 | if len < #source then -- must truncate? | ||
194 | out = out..string.sub(source, 1, len).."..." | ||
195 | else | ||
196 | out = out..source | ||
197 | end | ||
198 | out = out.."\"]" | ||
199 | end | ||
200 | end | ||
201 | return out | ||
202 | end | ||
203 | |||
204 | --[[-------------------------------------------------------------------- | ||
205 | -- Support functions for lexer | ||
206 | -- * all lexer errors eventually reaches lexerror: | ||
207 | syntaxerror -> lexerror | ||
208 | ----------------------------------------------------------------------]] | ||
209 | |||
210 | ------------------------------------------------------------------------ | ||
211 | -- look up token and return keyword if found (also called by parser) | ||
212 | ------------------------------------------------------------------------ | ||
213 | function luaX:token2str(ls, token) | ||
214 | if string.sub(token, 1, 3) ~= "TK_" then | ||
215 | if string.find(token, "%c") then | ||
216 | return string.format("char(%d)", string.byte(token)) | ||
217 | end | ||
218 | return token | ||
219 | else | ||
220 | return self.tokens[token] | ||
221 | end | ||
222 | end | ||
223 | |||
224 | ------------------------------------------------------------------------ | ||
225 | -- throws a lexer error | ||
226 | -- * txtToken has been made local to luaX:lexerror | ||
227 | -- * can't communicate LUA_ERRSYNTAX, so it is unimplemented | ||
228 | ------------------------------------------------------------------------ | ||
229 | function luaX:lexerror(ls, msg, token) | ||
230 | local function txtToken(ls, token) | ||
231 | if token == "TK_NAME" or | ||
232 | token == "TK_STRING" or | ||
233 | token == "TK_NUMBER" then | ||
234 | return ls.buff | ||
235 | else | ||
236 | return self:token2str(ls, token) | ||
237 | end | ||
238 | end | ||
239 | local buff = self:chunkid(ls.source, self.MAXSRC) | ||
240 | local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg) | ||
241 | if token then | ||
242 | msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token)) | ||
243 | end | ||
244 | -- luaD_throw(ls->L, LUA_ERRSYNTAX) | ||
245 | error(msg) | ||
246 | end | ||
247 | |||
248 | ------------------------------------------------------------------------ | ||
249 | -- throws a syntax error (mainly called by parser) | ||
250 | -- * ls.t.token has to be set by the function calling luaX:llex | ||
251 | -- (see luaX:next and luaX:lookahead elsewhere in this file) | ||
252 | ------------------------------------------------------------------------ | ||
253 | function luaX:syntaxerror(ls, msg) | ||
254 | self:lexerror(ls, msg, ls.t.token) | ||
255 | end | ||
256 | |||
257 | ------------------------------------------------------------------------ | ||
258 | -- move on to next line | ||
259 | ------------------------------------------------------------------------ | ||
260 | function luaX:currIsNewline(ls) | ||
261 | return ls.current == "\n" or ls.current == "\r" | ||
262 | end | ||
263 | |||
264 | function luaX:inclinenumber(ls) | ||
265 | local old = ls.current | ||
266 | -- lua_assert(currIsNewline(ls)) | ||
267 | self:nextc(ls) -- skip '\n' or '\r' | ||
268 | if self:currIsNewline(ls) and ls.current ~= old then | ||
269 | self:nextc(ls) -- skip '\n\r' or '\r\n' | ||
270 | end | ||
271 | ls.linenumber = ls.linenumber + 1 | ||
272 | if ls.linenumber >= self.MAX_INT then | ||
273 | self:syntaxerror(ls, "chunk has too many lines") | ||
274 | end | ||
275 | end | ||
276 | |||
277 | ------------------------------------------------------------------------ | ||
278 | -- initializes an input stream for lexing | ||
279 | -- * if ls (the lexer state) is passed as a table, then it is filled in, | ||
280 | -- otherwise it has to be retrieved as a return value | ||
281 | -- * LUA_MINBUFFER not used; buffer handling not required any more | ||
282 | ------------------------------------------------------------------------ | ||
283 | function luaX:setinput(L, ls, z, source) | ||
284 | if not ls then ls = {} end -- create struct | ||
285 | if not ls.lookahead then ls.lookahead = {} end | ||
286 | if not ls.t then ls.t = {} end | ||
287 | ls.decpoint = "." | ||
288 | ls.L = L | ||
289 | ls.lookahead.token = "TK_EOS" -- no look-ahead token | ||
290 | ls.z = z | ||
291 | ls.fs = nil | ||
292 | ls.linenumber = 1 | ||
293 | ls.lastline = 1 | ||
294 | ls.source = source | ||
295 | self:nextc(ls) -- read first char | ||
296 | end | ||
297 | |||
298 | --[[-------------------------------------------------------------------- | ||
299 | -- LEXICAL ANALYZER | ||
300 | ----------------------------------------------------------------------]] | ||
301 | |||
302 | ------------------------------------------------------------------------ | ||
303 | -- checks if current character read is found in the set 'set' | ||
304 | ------------------------------------------------------------------------ | ||
305 | function luaX:check_next(ls, set) | ||
306 | if not string.find(set, ls.current, 1, 1) then | ||
307 | return false | ||
308 | end | ||
309 | self:save_and_next(ls) | ||
310 | return true | ||
311 | end | ||
312 | |||
313 | ------------------------------------------------------------------------ | ||
314 | -- retrieve next token, checking the lookahead buffer if necessary | ||
315 | -- * note that the macro next(ls) in llex.c is now luaX:nextc | ||
316 | -- * utilized used in lparser.c (various places) | ||
317 | ------------------------------------------------------------------------ | ||
318 | function luaX:next(ls) | ||
319 | ls.lastline = ls.linenumber | ||
320 | if ls.lookahead.token ~= "TK_EOS" then -- is there a look-ahead token? | ||
321 | -- this must be copy-by-value | ||
322 | ls.t.seminfo = ls.lookahead.seminfo -- use this one | ||
323 | ls.t.token = ls.lookahead.token | ||
324 | ls.lookahead.token = "TK_EOS" -- and discharge it | ||
325 | else | ||
326 | ls.t.token = self:llex(ls, ls.t) -- read next token | ||
327 | end | ||
328 | end | ||
329 | |||
330 | ------------------------------------------------------------------------ | ||
331 | -- fill in the lookahead buffer | ||
332 | -- * utilized used in lparser.c:constructor | ||
333 | ------------------------------------------------------------------------ | ||
334 | function luaX:lookahead(ls) | ||
335 | -- lua_assert(ls.lookahead.token == "TK_EOS") | ||
336 | ls.lookahead.token = self:llex(ls, ls.lookahead) | ||
337 | end | ||
338 | |||
339 | ------------------------------------------------------------------------ | ||
340 | -- gets the next character and returns it | ||
341 | -- * this is the next() macro in llex.c; see notes at the beginning | ||
342 | ------------------------------------------------------------------------ | ||
343 | function luaX:nextc(ls) | ||
344 | local c = luaZ:zgetc(ls.z) | ||
345 | ls.current = c | ||
346 | return c | ||
347 | end | ||
348 | |||
349 | ------------------------------------------------------------------------ | ||
350 | -- saves the given character into the token buffer | ||
351 | -- * buffer handling code removed, not used in this implementation | ||
352 | -- * test for maximum token buffer length not used, makes things faster | ||
353 | ------------------------------------------------------------------------ | ||
354 | |||
355 | function luaX:save(ls, c) | ||
356 | local buff = ls.buff | ||
357 | -- if you want to use this, please uncomment luaX.MAX_SIZET further up | ||
358 | --if #buff > self.MAX_SIZET then | ||
359 | -- self:lexerror(ls, "lexical element too long") | ||
360 | --end | ||
361 | ls.buff = buff..c | ||
362 | end | ||
363 | |||
364 | ------------------------------------------------------------------------ | ||
365 | -- save current character into token buffer, grabs next character | ||
366 | -- * like luaX:nextc, returns the character read for convenience | ||
367 | ------------------------------------------------------------------------ | ||
368 | function luaX:save_and_next(ls) | ||
369 | self:save(ls, ls.current) | ||
370 | return self:nextc(ls) | ||
371 | end | ||
372 | |||
373 | ------------------------------------------------------------------------ | ||
374 | -- LUA_NUMBER | ||
375 | -- * luaX:read_numeral is the main lexer function to read a number | ||
376 | -- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions | ||
377 | ------------------------------------------------------------------------ | ||
378 | |||
379 | ------------------------------------------------------------------------ | ||
380 | -- string to number converter (was luaO_str2d from lobject.c) | ||
381 | -- * returns the number, nil if fails (originally returns a boolean) | ||
382 | -- * conversion function originally lua_str2number(s,p), a macro which | ||
383 | -- maps to the strtod() function by default (from luaconf.h) | ||
384 | ------------------------------------------------------------------------ | ||
385 | function luaX:str2d(s) | ||
386 | local result = tonumber(s) | ||
387 | if result then return result end | ||
388 | -- conversion failed | ||
389 | if string.lower(string.sub(s, 1, 2)) == "0x" then -- maybe an hexadecimal constant? | ||
390 | result = tonumber(s, 16) | ||
391 | if result then return result end -- most common case | ||
392 | -- Was: invalid trailing characters? | ||
393 | -- In C, this function then skips over trailing spaces. | ||
394 | -- true is returned if nothing else is found except for spaces. | ||
395 | -- If there is still something else, then it returns a false. | ||
396 | -- All this is not necessary using Lua's tonumber. | ||
397 | end | ||
398 | return nil | ||
399 | end | ||
400 | |||
401 | ------------------------------------------------------------------------ | ||
402 | -- single-character replacement, for locale-aware decimal points | ||
403 | ------------------------------------------------------------------------ | ||
404 | function luaX:buffreplace(ls, from, to) | ||
405 | local result, buff = "", ls.buff | ||
406 | for p = 1, #buff do | ||
407 | local c = string.sub(buff, p, p) | ||
408 | if c == from then c = to end | ||
409 | result = result..c | ||
410 | end | ||
411 | ls.buff = result | ||
412 | end | ||
413 | |||
414 | ------------------------------------------------------------------------ | ||
415 | -- Attempt to convert a number by translating '.' decimal points to | ||
416 | -- the decimal point character used by the current locale. This is not | ||
417 | -- needed in Yueliang as Lua's tonumber() is already locale-aware. | ||
418 | -- Instead, the code is here in case the user implements localeconv(). | ||
419 | ------------------------------------------------------------------------ | ||
420 | function luaX:trydecpoint(ls, Token) | ||
421 | -- format error: try to update decimal point separator | ||
422 | local old = ls.decpoint | ||
423 | -- translate the following to Lua if you implement localeconv(): | ||
424 | -- struct lconv *cv = localeconv(); | ||
425 | -- ls->decpoint = (cv ? cv->decimal_point[0] : '.'); | ||
426 | self:buffreplace(ls, old, ls.decpoint) -- try updated decimal separator | ||
427 | local seminfo = self:str2d(ls.buff) | ||
428 | Token.seminfo = seminfo | ||
429 | if not seminfo then | ||
430 | -- format error with correct decimal point: no more options | ||
431 | self:buffreplace(ls, ls.decpoint, ".") -- undo change (for error message) | ||
432 | self:lexerror(ls, "malformed number", "TK_NUMBER") | ||
433 | end | ||
434 | end | ||
435 | |||
436 | ------------------------------------------------------------------------ | ||
437 | -- main number conversion function | ||
438 | -- * "^%w$" needed in the scan in order to detect "EOZ" | ||
439 | ------------------------------------------------------------------------ | ||
440 | function luaX:read_numeral(ls, Token) | ||
441 | -- lua_assert(string.find(ls.current, "%d")) | ||
442 | repeat | ||
443 | self:save_and_next(ls) | ||
444 | until string.find(ls.current, "%D") and ls.current ~= "." | ||
445 | if self:check_next(ls, "Ee") then -- 'E'? | ||
446 | self:check_next(ls, "+-") -- optional exponent sign | ||
447 | end | ||
448 | while string.find(ls.current, "^%w$") or ls.current == "_" do | ||
449 | self:save_and_next(ls) | ||
450 | end | ||
451 | self:buffreplace(ls, ".", ls.decpoint) -- follow locale for decimal point | ||
452 | local seminfo = self:str2d(ls.buff) | ||
453 | Token.seminfo = seminfo | ||
454 | if not seminfo then -- format error? | ||
455 | self:trydecpoint(ls, Token) -- try to update decimal point separator | ||
456 | end | ||
457 | end | ||
458 | |||
459 | ------------------------------------------------------------------------ | ||
460 | -- count separators ("=") in a long string delimiter | ||
461 | -- * used by luaX:read_long_string | ||
462 | ------------------------------------------------------------------------ | ||
463 | function luaX:skip_sep(ls) | ||
464 | local count = 0 | ||
465 | local s = ls.current | ||
466 | -- lua_assert(s == "[" or s == "]") | ||
467 | self:save_and_next(ls) | ||
468 | while ls.current == "=" do | ||
469 | self:save_and_next(ls) | ||
470 | count = count + 1 | ||
471 | end | ||
472 | return (ls.current == s) and count or (-count) - 1 | ||
473 | end | ||
474 | |||
475 | ------------------------------------------------------------------------ | ||
476 | -- reads a long string or long comment | ||
477 | ------------------------------------------------------------------------ | ||
478 | function luaX:read_long_string(ls, Token, sep) | ||
479 | local cont = 0 | ||
480 | self:save_and_next(ls) -- skip 2nd '[' | ||
481 | if self:currIsNewline(ls) then -- string starts with a newline? | ||
482 | self:inclinenumber(ls) -- skip it | ||
483 | end | ||
484 | while true do | ||
485 | local c = ls.current | ||
486 | if c == "EOZ" then | ||
487 | self:lexerror(ls, Token and "unfinished long string" or | ||
488 | "unfinished long comment", "TK_EOS") | ||
489 | elseif c == "[" then | ||
490 | --# compatibility code start | ||
491 | if self.LUA_COMPAT_LSTR then | ||
492 | if self:skip_sep(ls) == sep then | ||
493 | self:save_and_next(ls) -- skip 2nd '[' | ||
494 | cont = cont + 1 | ||
495 | --# compatibility code start | ||
496 | if self.LUA_COMPAT_LSTR == 1 then | ||
497 | if sep == 0 then | ||
498 | self:lexerror(ls, "nesting of [[...]] is deprecated", "[") | ||
499 | end | ||
500 | end | ||
501 | --# compatibility code end | ||
502 | end | ||
503 | end | ||
504 | --# compatibility code end | ||
505 | elseif c == "]" then | ||
506 | if self:skip_sep(ls) == sep then | ||
507 | self:save_and_next(ls) -- skip 2nd ']' | ||
508 | --# compatibility code start | ||
509 | if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then | ||
510 | cont = cont - 1 | ||
511 | if sep == 0 and cont >= 0 then break end | ||
512 | end | ||
513 | --# compatibility code end | ||
514 | break | ||
515 | end | ||
516 | elseif self:currIsNewline(ls) then | ||
517 | self:save(ls, "\n") | ||
518 | self:inclinenumber(ls) | ||
519 | if not Token then ls.buff = "" end -- avoid wasting space | ||
520 | else -- default | ||
521 | if Token then | ||
522 | self:save_and_next(ls) | ||
523 | else | ||
524 | self:nextc(ls) | ||
525 | end | ||
526 | end--if c | ||
527 | end--while | ||
528 | if Token then | ||
529 | local p = 3 + sep | ||
530 | Token.seminfo = string.sub(ls.buff, p, -p) | ||
531 | end | ||
532 | end | ||
533 | |||
534 | ------------------------------------------------------------------------ | ||
535 | -- reads a string | ||
536 | -- * has been restructured significantly compared to the original C code | ||
537 | ------------------------------------------------------------------------ | ||
538 | |||
539 | function luaX:read_string(ls, del, Token) | ||
540 | self:save_and_next(ls) | ||
541 | while ls.current ~= del do | ||
542 | local c = ls.current | ||
543 | if c == "EOZ" then | ||
544 | self:lexerror(ls, "unfinished string", "TK_EOS") | ||
545 | elseif self:currIsNewline(ls) then | ||
546 | self:lexerror(ls, "unfinished string", "TK_STRING") | ||
547 | elseif c == "\\" then | ||
548 | c = self:nextc(ls) -- do not save the '\' | ||
549 | if self:currIsNewline(ls) then -- go through | ||
550 | self:save(ls, "\n") | ||
551 | self:inclinenumber(ls) | ||
552 | elseif c ~= "EOZ" then -- will raise an error next loop | ||
553 | -- escapes handling greatly simplified here: | ||
554 | local i = string.find("abfnrtv", c, 1, 1) | ||
555 | if i then | ||
556 | self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i)) | ||
557 | self:nextc(ls) | ||
558 | elseif not string.find(c, "%d") then | ||
559 | self:save_and_next(ls) -- handles \\, \", \', and \? | ||
560 | else -- \xxx | ||
561 | c, i = 0, 0 | ||
562 | repeat | ||
563 | c = 10 * c + ls.current | ||
564 | self:nextc(ls) | ||
565 | i = i + 1 | ||
566 | until i >= 3 or not string.find(ls.current, "%d") | ||
567 | if c > 255 then -- UCHAR_MAX | ||
568 | self:lexerror(ls, "escape sequence too large", "TK_STRING") | ||
569 | end | ||
570 | self:save(ls, string.char(c)) | ||
571 | end | ||
572 | end | ||
573 | else | ||
574 | self:save_and_next(ls) | ||
575 | end--if c | ||
576 | end--while | ||
577 | self:save_and_next(ls) -- skip delimiter | ||
578 | Token.seminfo = string.sub(ls.buff, 2, -2) | ||
579 | end | ||
580 | |||
581 | ------------------------------------------------------------------------ | ||
582 | -- main lexer function | ||
583 | ------------------------------------------------------------------------ | ||
584 | function luaX:llex(ls, Token) | ||
585 | ls.buff = "" | ||
586 | while true do | ||
587 | local c = ls.current | ||
588 | ---------------------------------------------------------------- | ||
589 | if self:currIsNewline(ls) then | ||
590 | self:inclinenumber(ls) | ||
591 | ---------------------------------------------------------------- | ||
592 | elseif c == "-" then | ||
593 | c = self:nextc(ls) | ||
594 | if c ~= "-" then return "-" end | ||
595 | -- else is a comment | ||
596 | local sep = -1 | ||
597 | if self:nextc(ls) == '[' then | ||
598 | sep = self:skip_sep(ls) | ||
599 | ls.buff = "" -- 'skip_sep' may dirty the buffer | ||
600 | end | ||
601 | if sep >= 0 then | ||
602 | self:read_long_string(ls, nil, sep) -- long comment | ||
603 | ls.buff = "" | ||
604 | else -- else short comment | ||
605 | while not self:currIsNewline(ls) and ls.current ~= "EOZ" do | ||
606 | self:nextc(ls) | ||
607 | end | ||
608 | end | ||
609 | ---------------------------------------------------------------- | ||
610 | elseif c == "[" then | ||
611 | local sep = self:skip_sep(ls) | ||
612 | if sep >= 0 then | ||
613 | self:read_long_string(ls, Token, sep) | ||
614 | return "TK_STRING" | ||
615 | elseif sep == -1 then | ||
616 | return "[" | ||
617 | else | ||
618 | self:lexerror(ls, "invalid long string delimiter", "TK_STRING") | ||
619 | end | ||
620 | ---------------------------------------------------------------- | ||
621 | elseif c == "=" then | ||
622 | c = self:nextc(ls) | ||
623 | if c ~= "=" then return "=" | ||
624 | else self:nextc(ls); return "TK_EQ" end | ||
625 | ---------------------------------------------------------------- | ||
626 | elseif c == "<" then | ||
627 | c = self:nextc(ls) | ||
628 | if c ~= "=" then return "<" | ||
629 | else self:nextc(ls); return "TK_LE" end | ||
630 | ---------------------------------------------------------------- | ||
631 | elseif c == ">" then | ||
632 | c = self:nextc(ls) | ||
633 | if c ~= "=" then return ">" | ||
634 | else self:nextc(ls); return "TK_GE" end | ||
635 | ---------------------------------------------------------------- | ||
636 | elseif c == "~" then | ||
637 | c = self:nextc(ls) | ||
638 | if c ~= "=" then return "~" | ||
639 | else self:nextc(ls); return "TK_NE" end | ||
640 | ---------------------------------------------------------------- | ||
641 | elseif c == "\"" or c == "'" then | ||
642 | self:read_string(ls, c, Token) | ||
643 | return "TK_STRING" | ||
644 | ---------------------------------------------------------------- | ||
645 | elseif c == "." then | ||
646 | c = self:save_and_next(ls) | ||
647 | if self:check_next(ls, ".") then | ||
648 | if self:check_next(ls, ".") then | ||
649 | return "TK_DOTS" -- ... | ||
650 | else return "TK_CONCAT" -- .. | ||
651 | end | ||
652 | elseif not string.find(c, "%d") then | ||
653 | return "." | ||
654 | else | ||
655 | self:read_numeral(ls, Token) | ||
656 | return "TK_NUMBER" | ||
657 | end | ||
658 | ---------------------------------------------------------------- | ||
659 | elseif c == "EOZ" then | ||
660 | return "TK_EOS" | ||
661 | ---------------------------------------------------------------- | ||
662 | else -- default | ||
663 | if string.find(c, "%s") then | ||
664 | -- lua_assert(self:currIsNewline(ls)) | ||
665 | self:nextc(ls) | ||
666 | elseif string.find(c, "%d") then | ||
667 | self:read_numeral(ls, Token) | ||
668 | return "TK_NUMBER" | ||
669 | elseif string.find(c, "[_%a]") then | ||
670 | -- identifier or reserved word | ||
671 | repeat | ||
672 | c = self:save_and_next(ls) | ||
673 | until c == "EOZ" or not string.find(c, "[_%w]") | ||
674 | local ts = ls.buff | ||
675 | local tok = self.enums[ts] | ||
676 | if tok then return tok end -- reserved word? | ||
677 | Token.seminfo = ts | ||
678 | return "TK_NAME" | ||
679 | else | ||
680 | self:nextc(ls) | ||
681 | return c -- single-char tokens (+ - / ...) | ||
682 | end | ||
683 | ---------------------------------------------------------------- | ||
684 | end--if c | ||
685 | end--while | ||
686 | end | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lopcodes.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lopcodes.lua deleted file mode 100644 index e7dbbe8..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lopcodes.lua +++ /dev/null | |||
@@ -1,432 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | lopcodes.lua | ||
4 | Lua 5 virtual machine opcodes in Lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * an Instruction is a table with OP, A, B, C, Bx elements; this | ||
18 | -- makes the code easy to follow and should allow instruction handling | ||
19 | -- to work with doubles and ints | ||
20 | -- * WARNING luaP:Instruction outputs instructions encoded in little- | ||
21 | -- endian form and field size and positions are hard-coded | ||
22 | -- | ||
23 | -- Not implemented: | ||
24 | -- * | ||
25 | -- | ||
26 | -- Added: | ||
27 | -- * luaP:CREATE_Inst(c): create an inst from a number (for OP_SETLIST) | ||
28 | -- * luaP:Instruction(i): convert field elements to a 4-char string | ||
29 | -- * luaP:DecodeInst(x): convert 4-char string into field elements | ||
30 | -- | ||
31 | -- Changed in 5.1.x: | ||
32 | -- * POS_OP added, instruction field positions changed | ||
33 | -- * some symbol names may have changed, e.g. LUAI_BITSINT | ||
34 | -- * new operators for RK indices: BITRK, ISK(x), INDEXK(r), RKASK(x) | ||
35 | -- * OP_MOD, OP_LEN is new | ||
36 | -- * OP_TEST is now OP_TESTSET, OP_TEST is new | ||
37 | -- * OP_FORLOOP, OP_TFORLOOP adjusted, OP_FORPREP is new | ||
38 | -- * OP_TFORPREP deleted | ||
39 | -- * OP_SETLIST and OP_SETLISTO merged and extended | ||
40 | -- * OP_VARARG is new | ||
41 | -- * many changes to implementation of OpMode data | ||
42 | ----------------------------------------------------------------------]] | ||
43 | |||
44 | luaP = {} | ||
45 | |||
46 | --[[ | ||
47 | =========================================================================== | ||
48 | We assume that instructions are unsigned numbers. | ||
49 | All instructions have an opcode in the first 6 bits. | ||
50 | Instructions can have the following fields: | ||
51 | 'A' : 8 bits | ||
52 | 'B' : 9 bits | ||
53 | 'C' : 9 bits | ||
54 | 'Bx' : 18 bits ('B' and 'C' together) | ||
55 | 'sBx' : signed Bx | ||
56 | |||
57 | A signed argument is represented in excess K; that is, the number | ||
58 | value is the unsigned value minus K. K is exactly the maximum value | ||
59 | for that argument (so that -max is represented by 0, and +max is | ||
60 | represented by 2*max), which is half the maximum for the corresponding | ||
61 | unsigned argument. | ||
62 | =========================================================================== | ||
63 | --]] | ||
64 | |||
65 | luaP.OpMode = { iABC = 0, iABx = 1, iAsBx = 2 } -- basic instruction format | ||
66 | |||
67 | ------------------------------------------------------------------------ | ||
68 | -- size and position of opcode arguments. | ||
69 | -- * WARNING size and position is hard-coded elsewhere in this script | ||
70 | ------------------------------------------------------------------------ | ||
71 | luaP.SIZE_C = 9 | ||
72 | luaP.SIZE_B = 9 | ||
73 | luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B | ||
74 | luaP.SIZE_A = 8 | ||
75 | |||
76 | luaP.SIZE_OP = 6 | ||
77 | |||
78 | luaP.POS_OP = 0 | ||
79 | luaP.POS_A = luaP.POS_OP + luaP.SIZE_OP | ||
80 | luaP.POS_C = luaP.POS_A + luaP.SIZE_A | ||
81 | luaP.POS_B = luaP.POS_C + luaP.SIZE_C | ||
82 | luaP.POS_Bx = luaP.POS_C | ||
83 | |||
84 | ------------------------------------------------------------------------ | ||
85 | -- limits for opcode arguments. | ||
86 | -- we use (signed) int to manipulate most arguments, | ||
87 | -- so they must fit in LUAI_BITSINT-1 bits (-1 for sign) | ||
88 | ------------------------------------------------------------------------ | ||
89 | -- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is | ||
90 | -- running on a Lua VM with double or int as LUA_NUMBER | ||
91 | |||
92 | luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1 | ||
93 | luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed | ||
94 | |||
95 | luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1 | ||
96 | luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1 | ||
97 | luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1 | ||
98 | |||
99 | -- creates a mask with 'n' 1 bits at position 'p' | ||
100 | -- MASK1(n,p) deleted, not required | ||
101 | -- creates a mask with 'n' 0 bits at position 'p' | ||
102 | -- MASK0(n,p) deleted, not required | ||
103 | |||
104 | --[[-------------------------------------------------------------------- | ||
105 | Visual representation for reference: | ||
106 | |||
107 | 31 | | | 0 bit position | ||
108 | +-----+-----+-----+----------+ | ||
109 | | B | C | A | Opcode | iABC format | ||
110 | +-----+-----+-----+----------+ | ||
111 | - 9 - 9 - 8 - 6 - field sizes | ||
112 | +-----+-----+-----+----------+ | ||
113 | | [s]Bx | A | Opcode | iABx | iAsBx format | ||
114 | +-----+-----+-----+----------+ | ||
115 | |||
116 | ----------------------------------------------------------------------]] | ||
117 | |||
118 | ------------------------------------------------------------------------ | ||
119 | -- the following macros help to manipulate instructions | ||
120 | -- * changed to a table object representation, very clean compared to | ||
121 | -- the [nightmare] alternatives of using a number or a string | ||
122 | -- * Bx is a separate element from B and C, since there is never a need | ||
123 | -- to split Bx in the parser or code generator | ||
124 | ------------------------------------------------------------------------ | ||
125 | |||
126 | -- these accept or return opcodes in the form of string names | ||
127 | function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end | ||
128 | function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end | ||
129 | |||
130 | function luaP:GETARG_A(i) return i.A end | ||
131 | function luaP:SETARG_A(i, u) i.A = u end | ||
132 | |||
133 | function luaP:GETARG_B(i) return i.B end | ||
134 | function luaP:SETARG_B(i, b) i.B = b end | ||
135 | |||
136 | function luaP:GETARG_C(i) return i.C end | ||
137 | function luaP:SETARG_C(i, b) i.C = b end | ||
138 | |||
139 | function luaP:GETARG_Bx(i) return i.Bx end | ||
140 | function luaP:SETARG_Bx(i, b) i.Bx = b end | ||
141 | |||
142 | function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end | ||
143 | function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end | ||
144 | |||
145 | function luaP:CREATE_ABC(o,a,b,c) | ||
146 | return {OP = self.OpCode[o], A = a, B = b, C = c} | ||
147 | end | ||
148 | |||
149 | function luaP:CREATE_ABx(o,a,bc) | ||
150 | return {OP = self.OpCode[o], A = a, Bx = bc} | ||
151 | end | ||
152 | |||
153 | ------------------------------------------------------------------------ | ||
154 | -- create an instruction from a number (for OP_SETLIST) | ||
155 | ------------------------------------------------------------------------ | ||
156 | function luaP:CREATE_Inst(c) | ||
157 | local o = c % 64 | ||
158 | c = (c - o) / 64 | ||
159 | local a = c % 256 | ||
160 | c = (c - a) / 256 | ||
161 | return self:CREATE_ABx(o, a, c) | ||
162 | end | ||
163 | |||
164 | ------------------------------------------------------------------------ | ||
165 | -- returns a 4-char string little-endian encoded form of an instruction | ||
166 | ------------------------------------------------------------------------ | ||
167 | function luaP:Instruction(i) | ||
168 | if i.Bx then | ||
169 | -- change to OP/A/B/C format | ||
170 | i.C = i.Bx % 512 | ||
171 | i.B = (i.Bx - i.C) / 512 | ||
172 | end | ||
173 | local I = i.A * 64 + i.OP | ||
174 | local c0 = I % 256 | ||
175 | I = i.C * 64 + (I - c0) / 256 -- 6 bits of A left | ||
176 | local c1 = I % 256 | ||
177 | I = i.B * 128 + (I - c1) / 256 -- 7 bits of C left | ||
178 | local c2 = I % 256 | ||
179 | local c3 = (I - c2) / 256 | ||
180 | return string.char(c0, c1, c2, c3) | ||
181 | end | ||
182 | |||
183 | ------------------------------------------------------------------------ | ||
184 | -- decodes a 4-char little-endian string into an instruction struct | ||
185 | ------------------------------------------------------------------------ | ||
186 | function luaP:DecodeInst(x) | ||
187 | local byte = string.byte | ||
188 | local i = {} | ||
189 | local I = byte(x, 1) | ||
190 | local op = I % 64 | ||
191 | i.OP = op | ||
192 | I = byte(x, 2) * 4 + (I - op) / 64 -- 2 bits of c0 left | ||
193 | local a = I % 256 | ||
194 | i.A = a | ||
195 | I = byte(x, 3) * 4 + (I - a) / 256 -- 2 bits of c1 left | ||
196 | local c = I % 512 | ||
197 | i.C = c | ||
198 | i.B = byte(x, 4) * 2 + (I - c) / 512 -- 1 bits of c2 left | ||
199 | local opmode = self.OpMode[tonumber(string.sub(self.opmodes[op + 1], 7, 7))] | ||
200 | if opmode ~= "iABC" then | ||
201 | i.Bx = i.B * 512 + i.C | ||
202 | end | ||
203 | return i | ||
204 | end | ||
205 | |||
206 | ------------------------------------------------------------------------ | ||
207 | -- Macros to operate RK indices | ||
208 | -- * these use arithmetic instead of bit ops | ||
209 | ------------------------------------------------------------------------ | ||
210 | |||
211 | -- this bit 1 means constant (0 means register) | ||
212 | luaP.BITRK = math.ldexp(1, luaP.SIZE_B - 1) | ||
213 | |||
214 | -- test whether value is a constant | ||
215 | function luaP:ISK(x) return x >= self.BITRK end | ||
216 | |||
217 | -- gets the index of the constant | ||
218 | function luaP:INDEXK(r) return x - self.BITRK end | ||
219 | |||
220 | luaP.MAXINDEXRK = luaP.BITRK - 1 | ||
221 | |||
222 | -- code a constant index as a RK value | ||
223 | function luaP:RKASK(x) return x + self.BITRK end | ||
224 | |||
225 | ------------------------------------------------------------------------ | ||
226 | -- invalid register that fits in 8 bits | ||
227 | ------------------------------------------------------------------------ | ||
228 | luaP.NO_REG = luaP.MAXARG_A | ||
229 | |||
230 | ------------------------------------------------------------------------ | ||
231 | -- R(x) - register | ||
232 | -- Kst(x) - constant (in constant table) | ||
233 | -- RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) | ||
234 | ------------------------------------------------------------------------ | ||
235 | |||
236 | ------------------------------------------------------------------------ | ||
237 | -- grep "ORDER OP" if you change these enums | ||
238 | ------------------------------------------------------------------------ | ||
239 | |||
240 | --[[-------------------------------------------------------------------- | ||
241 | Lua virtual machine opcodes (enum OpCode): | ||
242 | ------------------------------------------------------------------------ | ||
243 | name args description | ||
244 | ------------------------------------------------------------------------ | ||
245 | OP_MOVE A B R(A) := R(B) | ||
246 | OP_LOADK A Bx R(A) := Kst(Bx) | ||
247 | OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++ | ||
248 | OP_LOADNIL A B R(A) := ... := R(B) := nil | ||
249 | OP_GETUPVAL A B R(A) := UpValue[B] | ||
250 | OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)] | ||
251 | OP_GETTABLE A B C R(A) := R(B)[RK(C)] | ||
252 | OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A) | ||
253 | OP_SETUPVAL A B UpValue[B] := R(A) | ||
254 | OP_SETTABLE A B C R(A)[RK(B)] := RK(C) | ||
255 | OP_NEWTABLE A B C R(A) := {} (size = B,C) | ||
256 | OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] | ||
257 | OP_ADD A B C R(A) := RK(B) + RK(C) | ||
258 | OP_SUB A B C R(A) := RK(B) - RK(C) | ||
259 | OP_MUL A B C R(A) := RK(B) * RK(C) | ||
260 | OP_DIV A B C R(A) := RK(B) / RK(C) | ||
261 | OP_MOD A B C R(A) := RK(B) % RK(C) | ||
262 | OP_POW A B C R(A) := RK(B) ^ RK(C) | ||
263 | OP_UNM A B R(A) := -R(B) | ||
264 | OP_NOT A B R(A) := not R(B) | ||
265 | OP_LEN A B R(A) := length of R(B) | ||
266 | OP_CONCAT A B C R(A) := R(B).. ... ..R(C) | ||
267 | OP_JMP sBx pc+=sBx | ||
268 | OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++ | ||
269 | OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++ | ||
270 | OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++ | ||
271 | OP_TEST A C if not (R(A) <=> C) then pc++ | ||
272 | OP_TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else pc++ | ||
273 | OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) | ||
274 | OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1)) | ||
275 | OP_RETURN A B return R(A), ... ,R(A+B-2) (see note) | ||
276 | OP_FORLOOP A sBx R(A)+=R(A+2); | ||
277 | if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) } | ||
278 | OP_FORPREP A sBx R(A)-=R(A+2); pc+=sBx | ||
279 | OP_TFORLOOP A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); | ||
280 | if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ | ||
281 | OP_SETLIST A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B | ||
282 | OP_CLOSE A close all variables in the stack up to (>=) R(A) | ||
283 | OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) | ||
284 | OP_VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg | ||
285 | ----------------------------------------------------------------------]] | ||
286 | |||
287 | luaP.opnames = {} -- opcode names | ||
288 | luaP.OpCode = {} -- lookup name -> number | ||
289 | luaP.ROpCode = {} -- lookup number -> name | ||
290 | |||
291 | ------------------------------------------------------------------------ | ||
292 | -- ORDER OP | ||
293 | ------------------------------------------------------------------------ | ||
294 | local i = 0 | ||
295 | for v in string.gmatch([[ | ||
296 | MOVE LOADK LOADBOOL LOADNIL GETUPVAL | ||
297 | GETGLOBAL GETTABLE SETGLOBAL SETUPVAL SETTABLE | ||
298 | NEWTABLE SELF ADD SUB MUL | ||
299 | DIV MOD POW UNM NOT | ||
300 | LEN CONCAT JMP EQ LT | ||
301 | LE TEST TESTSET CALL TAILCALL | ||
302 | RETURN FORLOOP FORPREP TFORLOOP SETLIST | ||
303 | CLOSE CLOSURE VARARG | ||
304 | ]], "%S+") do | ||
305 | local n = "OP_"..v | ||
306 | luaP.opnames[i] = v | ||
307 | luaP.OpCode[n] = i | ||
308 | luaP.ROpCode[i] = n | ||
309 | i = i + 1 | ||
310 | end | ||
311 | luaP.NUM_OPCODES = i | ||
312 | |||
313 | --[[ | ||
314 | =========================================================================== | ||
315 | Notes: | ||
316 | (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, | ||
317 | and can be 0: OP_CALL then sets 'top' to last_result+1, so | ||
318 | next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'. | ||
319 | (*) In OP_VARARG, if (B == 0) then use actual number of varargs and | ||
320 | set top (like in OP_CALL with C == 0). | ||
321 | (*) In OP_RETURN, if (B == 0) then return up to 'top' | ||
322 | (*) In OP_SETLIST, if (B == 0) then B = 'top'; | ||
323 | if (C == 0) then next 'instruction' is real C | ||
324 | (*) For comparisons, A specifies what condition the test should accept | ||
325 | (true or false). | ||
326 | (*) All 'skips' (pc++) assume that next instruction is a jump | ||
327 | =========================================================================== | ||
328 | --]] | ||
329 | |||
330 | --[[-------------------------------------------------------------------- | ||
331 | masks for instruction properties. The format is: | ||
332 | bits 0-1: op mode | ||
333 | bits 2-3: C arg mode | ||
334 | bits 4-5: B arg mode | ||
335 | bit 6: instruction set register A | ||
336 | bit 7: operator is a test | ||
337 | |||
338 | for OpArgMask: | ||
339 | OpArgN - argument is not used | ||
340 | OpArgU - argument is used | ||
341 | OpArgR - argument is a register or a jump offset | ||
342 | OpArgK - argument is a constant or register/constant | ||
343 | ----------------------------------------------------------------------]] | ||
344 | |||
345 | -- was enum OpArgMask | ||
346 | luaP.OpArgMask = { OpArgN = 0, OpArgU = 1, OpArgR = 2, OpArgK = 3 } | ||
347 | |||
348 | ------------------------------------------------------------------------ | ||
349 | -- e.g. to compare with symbols, luaP:getOpMode(...) == luaP.OpCode.iABC | ||
350 | -- * accepts opcode parameter as strings, e.g. "OP_MOVE" | ||
351 | ------------------------------------------------------------------------ | ||
352 | |||
353 | function luaP:getOpMode(m) | ||
354 | return self.opmodes[self.OpCode[m]] % 4 | ||
355 | end | ||
356 | |||
357 | function luaP:getBMode(m) | ||
358 | return math.floor(self.opmodes[self.OpCode[m]] / 16) % 4 | ||
359 | end | ||
360 | |||
361 | function luaP:getCMode(m) | ||
362 | return math.floor(self.opmodes[self.OpCode[m]] / 4) % 4 | ||
363 | end | ||
364 | |||
365 | function luaP:testAMode(m) | ||
366 | return math.floor(self.opmodes[self.OpCode[m]] / 64) % 2 | ||
367 | end | ||
368 | |||
369 | function luaP:testTMode(m) | ||
370 | return math.floor(self.opmodes[self.OpCode[m]] / 128) | ||
371 | end | ||
372 | |||
373 | -- luaP_opnames[] is set above, as the luaP.opnames table | ||
374 | |||
375 | -- number of list items to accumulate before a SETLIST instruction | ||
376 | luaP.LFIELDS_PER_FLUSH = 50 | ||
377 | |||
378 | ------------------------------------------------------------------------ | ||
379 | -- build instruction properties array | ||
380 | -- * deliberately coded to look like the C equivalent | ||
381 | ------------------------------------------------------------------------ | ||
382 | local function opmode(t, a, b, c, m) | ||
383 | local luaP = luaP | ||
384 | return t * 128 + a * 64 + | ||
385 | luaP.OpArgMask[b] * 16 + luaP.OpArgMask[c] * 4 + luaP.OpMode[m] | ||
386 | end | ||
387 | |||
388 | -- ORDER OP | ||
389 | luaP.opmodes = { | ||
390 | -- T A B C mode opcode | ||
391 | opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_LOADK | ||
392 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_LOADBOOL | ||
393 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LOADNIL | ||
394 | opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_GETUPVAL | ||
395 | opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_GETGLOBAL | ||
396 | opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_GETTABLE | ||
397 | opmode(0, 0, "OpArgK", "OpArgN", "iABx"), -- OP_SETGLOBAL | ||
398 | opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_SETUPVAL | ||
399 | opmode(0, 0, "OpArgK", "OpArgK", "iABC"), -- OP_SETTABLE | ||
400 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_NEWTABLE | ||
401 | opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_SELF | ||
402 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_ADD | ||
403 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_SUB | ||
404 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MUL | ||
405 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_DIV | ||
406 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MOD | ||
407 | opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_POW | ||
408 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_UNM | ||
409 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_NOT | ||
410 | opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LEN | ||
411 | opmode(0, 1, "OpArgR", "OpArgR", "iABC"), -- OP_CONCAT | ||
412 | opmode(0, 0, "OpArgR", "OpArgN", "iAsBx"), -- OP_JMP | ||
413 | opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_EQ | ||
414 | opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LT | ||
415 | opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LE | ||
416 | opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TEST | ||
417 | opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TESTSET | ||
418 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_CALL | ||
419 | opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_TAILCALL | ||
420 | opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_RETURN | ||
421 | opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORLOOP | ||
422 | opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORPREP | ||
423 | opmode(1, 0, "OpArgN", "OpArgU", "iABC"), -- OP_TFORLOOP | ||
424 | opmode(0, 0, "OpArgU", "OpArgU", "iABC"), -- OP_SETLIST | ||
425 | opmode(0, 0, "OpArgN", "OpArgN", "iABC"), -- OP_CLOSE | ||
426 | opmode(0, 1, "OpArgU", "OpArgN", "iABx"), -- OP_CLOSURE | ||
427 | opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_VARARG | ||
428 | } | ||
429 | -- an awkward way to set a zero-indexed table... | ||
430 | luaP.opmodes[0] = | ||
431 | opmode(0, 1, "OpArgR", "OpArgN", "iABC") -- OP_MOVE | ||
432 | |||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lparser.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lparser.lua deleted file mode 100644 index 2535056..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lparser.lua +++ /dev/null | |||
@@ -1,1747 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | lparser.lua | ||
4 | Lua 5 parser in Lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * some unused C code that were not converted are kept as comments | ||
18 | -- * LUA_COMPAT_VARARG option changed into a comment block | ||
19 | -- * for value/size specific code added, look for 'NOTE: ' | ||
20 | -- | ||
21 | -- Not implemented: | ||
22 | -- * luaX_newstring not needed by this Lua implementation | ||
23 | -- * luaG_checkcode() in lua_assert is not currently implemented | ||
24 | -- | ||
25 | -- Added: | ||
26 | -- * some constants added from various header files | ||
27 | -- * luaY.LUA_QS used in error_expected, check_match (from luaconf.h) | ||
28 | -- * luaY:LUA_QL needed for error messages (from luaconf.h) | ||
29 | -- * luaY:growvector (from lmem.h) -- skeleton only, limit checking | ||
30 | -- * luaY.SHRT_MAX (from <limits.h>) for registerlocalvar | ||
31 | -- * luaY:newproto (from lfunc.c) | ||
32 | -- * luaY:int2fb (from lobject.c) | ||
33 | -- * NOTE: HASARG_MASK, for implementing a VARARG_HASARG bit operation | ||
34 | -- * NOTE: value-specific code for VARARG_NEEDSARG to replace a bitop | ||
35 | -- | ||
36 | -- Changed in 5.1.x: | ||
37 | -- * various code changes are not detailed... | ||
38 | -- * names of constants may have changed, e.g. added a LUAI_ prefix | ||
39 | -- * struct expkind: added VKNUM, VVARARG; VCALL's info changed? | ||
40 | -- * struct expdesc: added nval | ||
41 | -- * struct FuncState: upvalues data type changed to upvaldesc | ||
42 | -- * macro hasmultret is new | ||
43 | -- * function checklimit moved to parser from lexer | ||
44 | -- * functions anchor_token, errorlimit, checknext are new | ||
45 | -- * checknext is new, equivalent to 5.0.x's check, see check too | ||
46 | -- * luaY:next and luaY:lookahead moved to lexer | ||
47 | -- * break keyword no longer skipped in luaY:breakstat | ||
48 | -- * function new_localvarstr replaced by new_localvarliteral | ||
49 | -- * registerlocalvar limits local variables to SHRT_MAX | ||
50 | -- * create_local deleted, new_localvarliteral used instead | ||
51 | -- * constant LUAI_MAXUPVALUES increased to 60 | ||
52 | -- * constants MAXPARAMS, LUA_MAXPARSERLEVEL, MAXSTACK removed | ||
53 | -- * function interface changed: singlevaraux, singlevar | ||
54 | -- * enterlevel and leavelevel uses nCcalls to track call depth | ||
55 | -- * added a name argument to main entry function, luaY:parser | ||
56 | -- * function luaY_index changed to yindex | ||
57 | -- * luaY:int2fb()'s table size encoding format has been changed | ||
58 | -- * luaY:log2() no longer needed for table constructors | ||
59 | -- * function code_params deleted, functionality folded in parlist | ||
60 | -- * vararg flags handling (is_vararg) changes; also see VARARG_* | ||
61 | -- * LUA_COMPATUPSYNTAX section for old-style upvalues removed | ||
62 | -- * repeatstat() calls chunk() instead of block() | ||
63 | -- * function interface changed: cond, test_then_block | ||
64 | -- * while statement implementation considerably simplified; MAXEXPWHILE | ||
65 | -- and EXTRAEXP no longer required, no limits to the complexity of a | ||
66 | -- while condition | ||
67 | -- * repeat, forbody statement implementation has major changes, | ||
68 | -- mostly due to new scoping behaviour of local variables | ||
69 | -- * OPR_MULT renamed to OPR_MUL | ||
70 | ----------------------------------------------------------------------]] | ||
71 | |||
72 | --requires luaP, luaX, luaK | ||
73 | luaY = {} | ||
74 | |||
75 | --[[-------------------------------------------------------------------- | ||
76 | -- Expression descriptor | ||
77 | -- * expkind changed to string constants; luaY:assignment was the only | ||
78 | -- function to use a relational operator with this enumeration | ||
79 | -- VVOID -- no value | ||
80 | -- VNIL -- no value | ||
81 | -- VTRUE -- no value | ||
82 | -- VFALSE -- no value | ||
83 | -- VK -- info = index of constant in 'k' | ||
84 | -- VKNUM -- nval = numerical value | ||
85 | -- VLOCAL -- info = local register | ||
86 | -- VUPVAL, -- info = index of upvalue in 'upvalues' | ||
87 | -- VGLOBAL -- info = index of table; aux = index of global name in 'k' | ||
88 | -- VINDEXED -- info = table register; aux = index register (or 'k') | ||
89 | -- VJMP -- info = instruction pc | ||
90 | -- VRELOCABLE -- info = instruction pc | ||
91 | -- VNONRELOC -- info = result register | ||
92 | -- VCALL -- info = instruction pc | ||
93 | -- VVARARG -- info = instruction pc | ||
94 | } ----------------------------------------------------------------------]] | ||
95 | |||
96 | --[[-------------------------------------------------------------------- | ||
97 | -- * expdesc in Lua 5.1.x has a union u and another struct s; this Lua | ||
98 | -- implementation ignores all instances of u and s usage | ||
99 | -- struct expdesc: | ||
100 | -- k -- (enum: expkind) | ||
101 | -- info, aux -- (int, int) | ||
102 | -- nval -- (lua_Number) | ||
103 | -- t -- patch list of 'exit when true' | ||
104 | -- f -- patch list of 'exit when false' | ||
105 | ----------------------------------------------------------------------]] | ||
106 | |||
107 | --[[-------------------------------------------------------------------- | ||
108 | -- struct upvaldesc: | ||
109 | -- k -- (lu_byte) | ||
110 | -- info -- (lu_byte) | ||
111 | ----------------------------------------------------------------------]] | ||
112 | |||
113 | --[[-------------------------------------------------------------------- | ||
114 | -- state needed to generate code for a given function | ||
115 | -- struct FuncState: | ||
116 | -- f -- current function header (table: Proto) | ||
117 | -- h -- table to find (and reuse) elements in 'k' (table: Table) | ||
118 | -- prev -- enclosing function (table: FuncState) | ||
119 | -- ls -- lexical state (table: LexState) | ||
120 | -- L -- copy of the Lua state (table: lua_State) | ||
121 | -- bl -- chain of current blocks (table: BlockCnt) | ||
122 | -- pc -- next position to code (equivalent to 'ncode') | ||
123 | -- lasttarget -- 'pc' of last 'jump target' | ||
124 | -- jpc -- list of pending jumps to 'pc' | ||
125 | -- freereg -- first free register | ||
126 | -- nk -- number of elements in 'k' | ||
127 | -- np -- number of elements in 'p' | ||
128 | -- nlocvars -- number of elements in 'locvars' | ||
129 | -- nactvar -- number of active local variables | ||
130 | -- upvalues[LUAI_MAXUPVALUES] -- upvalues (table: upvaldesc) | ||
131 | -- actvar[LUAI_MAXVARS] -- declared-variable stack | ||
132 | ----------------------------------------------------------------------]] | ||
133 | |||
134 | ------------------------------------------------------------------------ | ||
135 | -- constants used by parser | ||
136 | -- * picks up duplicate values from luaX if required | ||
137 | ------------------------------------------------------------------------ | ||
138 | luaY.LUA_QS = luaX.LUA_QS or "'%s'" -- (from luaconf.h) | ||
139 | |||
140 | luaY.SHRT_MAX = 32767 -- (from <limits.h>) | ||
141 | luaY.LUAI_MAXVARS = 200 -- (luaconf.h) | ||
142 | luaY.LUAI_MAXUPVALUES = 60 -- (luaconf.h) | ||
143 | luaY.MAX_INT = luaX.MAX_INT or 2147483645 -- (from llimits.h) | ||
144 | -- * INT_MAX-2 for 32-bit systems | ||
145 | luaY.LUAI_MAXCCALLS = 200 -- (from luaconf.h) | ||
146 | |||
147 | luaY.VARARG_HASARG = 1 -- (from lobject.h) | ||
148 | -- NOTE: HASARG_MASK is value-specific | ||
149 | luaY.HASARG_MASK = 2 -- this was added for a bitop in parlist() | ||
150 | luaY.VARARG_ISVARARG = 2 | ||
151 | -- NOTE: there is some value-specific code that involves VARARG_NEEDSARG | ||
152 | luaY.VARARG_NEEDSARG = 4 | ||
153 | |||
154 | luaY.LUA_MULTRET = -1 -- (lua.h) | ||
155 | |||
156 | --[[-------------------------------------------------------------------- | ||
157 | -- other functions | ||
158 | ----------------------------------------------------------------------]] | ||
159 | |||
160 | ------------------------------------------------------------------------ | ||
161 | -- LUA_QL describes how error messages quote program elements. | ||
162 | -- CHANGE it if you want a different appearance. (from luaconf.h) | ||
163 | ------------------------------------------------------------------------ | ||
164 | function luaY:LUA_QL(x) | ||
165 | return "'"..x.."'" | ||
166 | end | ||
167 | |||
168 | ------------------------------------------------------------------------ | ||
169 | -- this is a stripped-down luaM_growvector (from lmem.h) which is a | ||
170 | -- macro based on luaM_growaux (in lmem.c); all the following does is | ||
171 | -- reproduce the size limit checking logic of the original function | ||
172 | -- so that error behaviour is identical; all arguments preserved for | ||
173 | -- convenience, even those which are unused | ||
174 | -- * set the t field to nil, since this originally does a sizeof(t) | ||
175 | -- * size (originally a pointer) is never updated, their final values | ||
176 | -- are set by luaY:close_func(), so overall things should still work | ||
177 | ------------------------------------------------------------------------ | ||
178 | function luaY:growvector(L, v, nelems, size, t, limit, e) | ||
179 | if nelems >= limit then | ||
180 | error(e) -- was luaG_runerror | ||
181 | end | ||
182 | end | ||
183 | |||
184 | ------------------------------------------------------------------------ | ||
185 | -- initialize a new function prototype structure (from lfunc.c) | ||
186 | -- * used only in open_func() | ||
187 | ------------------------------------------------------------------------ | ||
188 | function luaY:newproto(L) | ||
189 | local f = {} -- Proto | ||
190 | -- luaC_link(L, obj2gco(f), LUA_TPROTO); /* GC */ | ||
191 | f.k = {} | ||
192 | f.sizek = 0 | ||
193 | f.p = {} | ||
194 | f.sizep = 0 | ||
195 | f.code = {} | ||
196 | f.sizecode = 0 | ||
197 | f.sizelineinfo = 0 | ||
198 | f.sizeupvalues = 0 | ||
199 | f.nups = 0 | ||
200 | f.upvalues = {} | ||
201 | f.numparams = 0 | ||
202 | f.is_vararg = 0 | ||
203 | f.maxstacksize = 0 | ||
204 | f.lineinfo = {} | ||
205 | f.sizelocvars = 0 | ||
206 | f.locvars = {} | ||
207 | f.lineDefined = 0 | ||
208 | f.lastlinedefined = 0 | ||
209 | f.source = nil | ||
210 | return f | ||
211 | end | ||
212 | |||
213 | ------------------------------------------------------------------------ | ||
214 | -- converts an integer to a "floating point byte", represented as | ||
215 | -- (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if | ||
216 | -- eeeee != 0 and (xxx) otherwise. | ||
217 | ------------------------------------------------------------------------ | ||
218 | function luaY:int2fb(x) | ||
219 | local e = 0 -- exponent | ||
220 | while x >= 16 do | ||
221 | x = math.floor((x + 1) / 2) | ||
222 | e = e + 1 | ||
223 | end | ||
224 | if x < 8 then | ||
225 | return x | ||
226 | else | ||
227 | return ((e + 1) * 8) + (x - 8) | ||
228 | end | ||
229 | end | ||
230 | |||
231 | --[[-------------------------------------------------------------------- | ||
232 | -- parser functions | ||
233 | ----------------------------------------------------------------------]] | ||
234 | |||
235 | ------------------------------------------------------------------------ | ||
236 | -- true of the kind of expression produces multiple return values | ||
237 | ------------------------------------------------------------------------ | ||
238 | function luaY:hasmultret(k) | ||
239 | return k == "VCALL" or k == "VVARARG" | ||
240 | end | ||
241 | |||
242 | ------------------------------------------------------------------------ | ||
243 | -- convenience function to access active local i, returns entry | ||
244 | ------------------------------------------------------------------------ | ||
245 | function luaY:getlocvar(fs, i) | ||
246 | return fs.f.locvars[ fs.actvar[i] ] | ||
247 | end | ||
248 | |||
249 | ------------------------------------------------------------------------ | ||
250 | -- check a limit, string m provided as an error message | ||
251 | ------------------------------------------------------------------------ | ||
252 | function luaY:checklimit(fs, v, l, m) | ||
253 | if v > l then self:errorlimit(fs, l, m) end | ||
254 | end | ||
255 | |||
256 | --[[-------------------------------------------------------------------- | ||
257 | -- nodes for block list (list of active blocks) | ||
258 | -- struct BlockCnt: | ||
259 | -- previous -- chain (table: BlockCnt) | ||
260 | -- breaklist -- list of jumps out of this loop | ||
261 | -- nactvar -- # active local variables outside the breakable structure | ||
262 | -- upval -- true if some variable in the block is an upvalue (boolean) | ||
263 | -- isbreakable -- true if 'block' is a loop (boolean) | ||
264 | ----------------------------------------------------------------------]] | ||
265 | |||
266 | ------------------------------------------------------------------------ | ||
267 | -- prototypes for recursive non-terminal functions | ||
268 | ------------------------------------------------------------------------ | ||
269 | -- prototypes deleted; not required in Lua | ||
270 | |||
271 | ------------------------------------------------------------------------ | ||
272 | -- reanchor if last token is has a constant string, see close_func() | ||
273 | -- * used only in close_func() | ||
274 | ------------------------------------------------------------------------ | ||
275 | function luaY:anchor_token(ls) | ||
276 | if ls.t.token == "TK_NAME" or ls.t.token == "TK_STRING" then | ||
277 | -- not relevant to Lua implementation of parser | ||
278 | -- local ts = ls.t.seminfo | ||
279 | -- luaX_newstring(ls, getstr(ts), ts->tsv.len); /* C */ | ||
280 | end | ||
281 | end | ||
282 | |||
283 | ------------------------------------------------------------------------ | ||
284 | -- throws a syntax error if token expected is not there | ||
285 | ------------------------------------------------------------------------ | ||
286 | function luaY:error_expected(ls, token) | ||
287 | luaX:syntaxerror(ls, | ||
288 | string.format(self.LUA_QS.." expected", luaX:token2str(ls, token))) | ||
289 | end | ||
290 | |||
291 | ------------------------------------------------------------------------ | ||
292 | -- prepares error message for display, for limits exceeded | ||
293 | -- * used only in checklimit() | ||
294 | ------------------------------------------------------------------------ | ||
295 | function luaY:errorlimit(fs, limit, what) | ||
296 | local msg = (fs.f.linedefined == 0) and | ||
297 | string.format("main function has more than %d %s", limit, what) or | ||
298 | string.format("function at line %d has more than %d %s", | ||
299 | fs.f.linedefined, limit, what) | ||
300 | luaX:lexerror(fs.ls, msg, 0) | ||
301 | end | ||
302 | |||
303 | ------------------------------------------------------------------------ | ||
304 | -- tests for a token, returns outcome | ||
305 | -- * return value changed to boolean | ||
306 | ------------------------------------------------------------------------ | ||
307 | function luaY:testnext(ls, c) | ||
308 | if ls.t.token == c then | ||
309 | luaX:next(ls) | ||
310 | return true | ||
311 | else | ||
312 | return false | ||
313 | end | ||
314 | end | ||
315 | |||
316 | ------------------------------------------------------------------------ | ||
317 | -- check for existence of a token, throws error if not found | ||
318 | ------------------------------------------------------------------------ | ||
319 | function luaY:check(ls, c) | ||
320 | if ls.t.token ~= c then | ||
321 | self:error_expected(ls, c) | ||
322 | end | ||
323 | end | ||
324 | |||
325 | ------------------------------------------------------------------------ | ||
326 | -- verify existence of a token, then skip it | ||
327 | ------------------------------------------------------------------------ | ||
328 | function luaY:checknext(ls, c) | ||
329 | self:check(ls, c) | ||
330 | luaX:next(ls) | ||
331 | end | ||
332 | |||
333 | ------------------------------------------------------------------------ | ||
334 | -- throws error if condition not matched | ||
335 | ------------------------------------------------------------------------ | ||
336 | function luaY:check_condition(ls, c, msg) | ||
337 | if not c then luaX:syntaxerror(ls, msg) end | ||
338 | end | ||
339 | |||
340 | ------------------------------------------------------------------------ | ||
341 | -- verifies token conditions are met or else throw error | ||
342 | ------------------------------------------------------------------------ | ||
343 | function luaY:check_match(ls, what, who, where) | ||
344 | if not self:testnext(ls, what) then | ||
345 | if where == ls.linenumber then | ||
346 | self:error_expected(ls, what) | ||
347 | else | ||
348 | luaX:syntaxerror(ls, string.format( | ||
349 | self.LUA_QS.." expected (to close "..self.LUA_QS.." at line %d)", | ||
350 | luaX:token2str(ls, what), luaX:token2str(ls, who), where)) | ||
351 | end | ||
352 | end | ||
353 | end | ||
354 | |||
355 | ------------------------------------------------------------------------ | ||
356 | -- expect that token is a name, return the name | ||
357 | ------------------------------------------------------------------------ | ||
358 | function luaY:str_checkname(ls) | ||
359 | self:check(ls, "TK_NAME") | ||
360 | local ts = ls.t.seminfo | ||
361 | luaX:next(ls) | ||
362 | return ts | ||
363 | end | ||
364 | |||
365 | ------------------------------------------------------------------------ | ||
366 | -- initialize a struct expdesc, expression description data structure | ||
367 | ------------------------------------------------------------------------ | ||
368 | function luaY:init_exp(e, k, i) | ||
369 | e.f, e.t = luaK.NO_JUMP, luaK.NO_JUMP | ||
370 | e.k = k | ||
371 | e.info = i | ||
372 | end | ||
373 | |||
374 | ------------------------------------------------------------------------ | ||
375 | -- adds given string s in string pool, sets e as VK | ||
376 | ------------------------------------------------------------------------ | ||
377 | function luaY:codestring(ls, e, s) | ||
378 | self:init_exp(e, "VK", luaK:stringK(ls.fs, s)) | ||
379 | end | ||
380 | |||
381 | ------------------------------------------------------------------------ | ||
382 | -- consume a name token, adds it to string pool, sets e as VK | ||
383 | ------------------------------------------------------------------------ | ||
384 | function luaY:checkname(ls, e) | ||
385 | self:codestring(ls, e, self:str_checkname(ls)) | ||
386 | end | ||
387 | |||
388 | ------------------------------------------------------------------------ | ||
389 | -- creates struct entry for a local variable | ||
390 | -- * used only in new_localvar() | ||
391 | ------------------------------------------------------------------------ | ||
392 | function luaY:registerlocalvar(ls, varname) | ||
393 | local fs = ls.fs | ||
394 | local f = fs.f | ||
395 | self:growvector(ls.L, f.locvars, fs.nlocvars, f.sizelocvars, | ||
396 | nil, self.SHRT_MAX, "too many local variables") | ||
397 | -- loop to initialize empty f.locvar positions not required | ||
398 | f.locvars[fs.nlocvars] = {} -- LocVar | ||
399 | f.locvars[fs.nlocvars].varname = varname | ||
400 | -- luaC_objbarrier(ls.L, f, varname) /* GC */ | ||
401 | local nlocvars = fs.nlocvars | ||
402 | fs.nlocvars = fs.nlocvars + 1 | ||
403 | return nlocvars | ||
404 | end | ||
405 | |||
406 | ------------------------------------------------------------------------ | ||
407 | -- creates a new local variable given a name and an offset from nactvar | ||
408 | -- * used in fornum(), forlist(), parlist(), body() | ||
409 | ------------------------------------------------------------------------ | ||
410 | function luaY:new_localvarliteral(ls, v, n) | ||
411 | self:new_localvar(ls, v, n) | ||
412 | end | ||
413 | |||
414 | ------------------------------------------------------------------------ | ||
415 | -- register a local variable, set in active variable list | ||
416 | ------------------------------------------------------------------------ | ||
417 | function luaY:new_localvar(ls, name, n) | ||
418 | local fs = ls.fs | ||
419 | self:checklimit(fs, fs.nactvar + n + 1, self.LUAI_MAXVARS, "local variables") | ||
420 | fs.actvar[fs.nactvar + n] = self:registerlocalvar(ls, name) | ||
421 | end | ||
422 | |||
423 | ------------------------------------------------------------------------ | ||
424 | -- adds nvars number of new local variables, set debug information | ||
425 | ------------------------------------------------------------------------ | ||
426 | function luaY:adjustlocalvars(ls, nvars) | ||
427 | local fs = ls.fs | ||
428 | fs.nactvar = fs.nactvar + nvars | ||
429 | for i = nvars, 1, -1 do | ||
430 | self:getlocvar(fs, fs.nactvar - i).startpc = fs.pc | ||
431 | end | ||
432 | end | ||
433 | |||
434 | ------------------------------------------------------------------------ | ||
435 | -- removes a number of locals, set debug information | ||
436 | ------------------------------------------------------------------------ | ||
437 | function luaY:removevars(ls, tolevel) | ||
438 | local fs = ls.fs | ||
439 | while fs.nactvar > tolevel do | ||
440 | fs.nactvar = fs.nactvar - 1 | ||
441 | self:getlocvar(fs, fs.nactvar).endpc = fs.pc | ||
442 | end | ||
443 | end | ||
444 | |||
445 | ------------------------------------------------------------------------ | ||
446 | -- returns an existing upvalue index based on the given name, or | ||
447 | -- creates a new upvalue struct entry and returns the new index | ||
448 | -- * used only in singlevaraux() | ||
449 | ------------------------------------------------------------------------ | ||
450 | function luaY:indexupvalue(fs, name, v) | ||
451 | local f = fs.f | ||
452 | for i = 0, f.nups - 1 do | ||
453 | if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then | ||
454 | lua_assert(f.upvalues[i] == name) | ||
455 | return i | ||
456 | end | ||
457 | end | ||
458 | -- new one | ||
459 | self:checklimit(fs, f.nups + 1, self.LUAI_MAXUPVALUES, "upvalues") | ||
460 | self:growvector(fs.L, f.upvalues, f.nups, f.sizeupvalues, | ||
461 | nil, self.MAX_INT, "") | ||
462 | -- loop to initialize empty f.upvalues positions not required | ||
463 | f.upvalues[f.nups] = name | ||
464 | -- luaC_objbarrier(fs->L, f, name); /* GC */ | ||
465 | lua_assert(v.k == "VLOCAL" or v.k == "VUPVAL") | ||
466 | -- this is a partial copy; only k & info fields used | ||
467 | fs.upvalues[f.nups] = { k = v.k, info = v.info } | ||
468 | local nups = f.nups | ||
469 | f.nups = f.nups + 1 | ||
470 | return nups | ||
471 | end | ||
472 | |||
473 | ------------------------------------------------------------------------ | ||
474 | -- search the local variable namespace of the given fs for a match | ||
475 | -- * used only in singlevaraux() | ||
476 | ------------------------------------------------------------------------ | ||
477 | function luaY:searchvar(fs, n) | ||
478 | for i = fs.nactvar - 1, 0, -1 do | ||
479 | if n == self:getlocvar(fs, i).varname then | ||
480 | return i | ||
481 | end | ||
482 | end | ||
483 | return -1 -- not found | ||
484 | end | ||
485 | |||
486 | ------------------------------------------------------------------------ | ||
487 | -- * mark upvalue flags in function states up to a given level | ||
488 | -- * used only in singlevaraux() | ||
489 | ------------------------------------------------------------------------ | ||
490 | function luaY:markupval(fs, level) | ||
491 | local bl = fs.bl | ||
492 | while bl and bl.nactvar > level do bl = bl.previous end | ||
493 | if bl then bl.upval = true end | ||
494 | end | ||
495 | |||
496 | ------------------------------------------------------------------------ | ||
497 | -- handle locals, globals and upvalues and related processing | ||
498 | -- * search mechanism is recursive, calls itself to search parents | ||
499 | -- * used only in singlevar() | ||
500 | ------------------------------------------------------------------------ | ||
501 | function luaY:singlevaraux(fs, n, var, base) | ||
502 | if fs == nil then -- no more levels? | ||
503 | self:init_exp(var, "VGLOBAL", luaP.NO_REG) -- default is global variable | ||
504 | return "VGLOBAL" | ||
505 | else | ||
506 | local v = self:searchvar(fs, n) -- look up at current level | ||
507 | if v >= 0 then | ||
508 | self:init_exp(var, "VLOCAL", v) | ||
509 | if base == 0 then | ||
510 | self:markupval(fs, v) -- local will be used as an upval | ||
511 | end | ||
512 | return "VLOCAL" | ||
513 | else -- not found at current level; try upper one | ||
514 | if self:singlevaraux(fs.prev, n, var, 0) == "VGLOBAL" then | ||
515 | return "VGLOBAL" | ||
516 | end | ||
517 | var.info = self:indexupvalue(fs, n, var) -- else was LOCAL or UPVAL | ||
518 | var.k = "VUPVAL" -- upvalue in this level | ||
519 | return "VUPVAL" | ||
520 | end--if v | ||
521 | end--if fs | ||
522 | end | ||
523 | |||
524 | ------------------------------------------------------------------------ | ||
525 | -- consume a name token, creates a variable (global|local|upvalue) | ||
526 | -- * used in prefixexp(), funcname() | ||
527 | ------------------------------------------------------------------------ | ||
528 | function luaY:singlevar(ls, var) | ||
529 | local varname = self:str_checkname(ls) | ||
530 | local fs = ls.fs | ||
531 | if self:singlevaraux(fs, varname, var, 1) == "VGLOBAL" then | ||
532 | var.info = luaK:stringK(fs, varname) -- info points to global name | ||
533 | end | ||
534 | end | ||
535 | |||
536 | ------------------------------------------------------------------------ | ||
537 | -- adjust RHS to match LHS in an assignment | ||
538 | -- * used in assignment(), forlist(), localstat() | ||
539 | ------------------------------------------------------------------------ | ||
540 | function luaY:adjust_assign(ls, nvars, nexps, e) | ||
541 | local fs = ls.fs | ||
542 | local extra = nvars - nexps | ||
543 | if self:hasmultret(e.k) then | ||
544 | extra = extra + 1 -- includes call itself | ||
545 | if extra <= 0 then extra = 0 end | ||
546 | luaK:setreturns(fs, e, extra) -- last exp. provides the difference | ||
547 | if extra > 1 then luaK:reserveregs(fs, extra - 1) end | ||
548 | else | ||
549 | if e.k ~= "VVOID" then luaK:exp2nextreg(fs, e) end -- close last expression | ||
550 | if extra > 0 then | ||
551 | local reg = fs.freereg | ||
552 | luaK:reserveregs(fs, extra) | ||
553 | luaK:_nil(fs, reg, extra) | ||
554 | end | ||
555 | end | ||
556 | end | ||
557 | |||
558 | ------------------------------------------------------------------------ | ||
559 | -- tracks and limits parsing depth, assert check at end of parsing | ||
560 | ------------------------------------------------------------------------ | ||
561 | function luaY:enterlevel(ls) | ||
562 | ls.L.nCcalls = ls.L.nCcalls + 1 | ||
563 | if ls.L.nCcalls > self.LUAI_MAXCCALLS then | ||
564 | luaX:lexerror(ls, "chunk has too many syntax levels", 0) | ||
565 | end | ||
566 | end | ||
567 | |||
568 | ------------------------------------------------------------------------ | ||
569 | -- tracks parsing depth, a pair with luaY:enterlevel() | ||
570 | ------------------------------------------------------------------------ | ||
571 | function luaY:leavelevel(ls) | ||
572 | ls.L.nCcalls = ls.L.nCcalls - 1 | ||
573 | end | ||
574 | |||
575 | ------------------------------------------------------------------------ | ||
576 | -- enters a code unit, initializes elements | ||
577 | ------------------------------------------------------------------------ | ||
578 | function luaY:enterblock(fs, bl, isbreakable) | ||
579 | bl.breaklist = luaK.NO_JUMP | ||
580 | bl.isbreakable = isbreakable | ||
581 | bl.nactvar = fs.nactvar | ||
582 | bl.upval = false | ||
583 | bl.previous = fs.bl | ||
584 | fs.bl = bl | ||
585 | lua_assert(fs.freereg == fs.nactvar) | ||
586 | end | ||
587 | |||
588 | ------------------------------------------------------------------------ | ||
589 | -- leaves a code unit, close any upvalues | ||
590 | ------------------------------------------------------------------------ | ||
591 | function luaY:leaveblock(fs) | ||
592 | local bl = fs.bl | ||
593 | fs.bl = bl.previous | ||
594 | self:removevars(fs.ls, bl.nactvar) | ||
595 | if bl.upval then | ||
596 | luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0) | ||
597 | end | ||
598 | -- a block either controls scope or breaks (never both) | ||
599 | lua_assert(not bl.isbreakable or not bl.upval) | ||
600 | lua_assert(bl.nactvar == fs.nactvar) | ||
601 | fs.freereg = fs.nactvar -- free registers | ||
602 | luaK:patchtohere(fs, bl.breaklist) | ||
603 | end | ||
604 | |||
605 | ------------------------------------------------------------------------ | ||
606 | -- implement the instantiation of a function prototype, append list of | ||
607 | -- upvalues after the instantiation instruction | ||
608 | -- * used only in body() | ||
609 | ------------------------------------------------------------------------ | ||
610 | function luaY:pushclosure(ls, func, v) | ||
611 | local fs = ls.fs | ||
612 | local f = fs.f | ||
613 | self:growvector(ls.L, f.p, fs.np, f.sizep, nil, | ||
614 | luaP.MAXARG_Bx, "constant table overflow") | ||
615 | -- loop to initialize empty f.p positions not required | ||
616 | f.p[fs.np] = func.f | ||
617 | fs.np = fs.np + 1 | ||
618 | -- luaC_objbarrier(ls->L, f, func->f); /* C */ | ||
619 | self:init_exp(v, "VRELOCABLE", luaK:codeABx(fs, "OP_CLOSURE", 0, fs.np - 1)) | ||
620 | for i = 0, func.f.nups - 1 do | ||
621 | local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL" | ||
622 | luaK:codeABC(fs, o, 0, func.upvalues[i].info, 0) | ||
623 | end | ||
624 | end | ||
625 | |||
626 | ------------------------------------------------------------------------ | ||
627 | -- opening of a function | ||
628 | ------------------------------------------------------------------------ | ||
629 | function luaY:open_func(ls, fs) | ||
630 | local L = ls.L | ||
631 | local f = self:newproto(ls.L) | ||
632 | fs.f = f | ||
633 | fs.prev = ls.fs -- linked list of funcstates | ||
634 | fs.ls = ls | ||
635 | fs.L = L | ||
636 | ls.fs = fs | ||
637 | fs.pc = 0 | ||
638 | fs.lasttarget = -1 | ||
639 | fs.jpc = luaK.NO_JUMP | ||
640 | fs.freereg = 0 | ||
641 | fs.nk = 0 | ||
642 | fs.np = 0 | ||
643 | fs.nlocvars = 0 | ||
644 | fs.nactvar = 0 | ||
645 | fs.bl = nil | ||
646 | f.source = ls.source | ||
647 | f.maxstacksize = 2 -- registers 0/1 are always valid | ||
648 | fs.h = {} -- constant table; was luaH_new call | ||
649 | -- anchor table of constants and prototype (to avoid being collected) | ||
650 | -- sethvalue2s(L, L->top, fs->h); incr_top(L); /* C */ | ||
651 | -- setptvalue2s(L, L->top, f); incr_top(L); | ||
652 | end | ||
653 | |||
654 | ------------------------------------------------------------------------ | ||
655 | -- closing of a function | ||
656 | ------------------------------------------------------------------------ | ||
657 | function luaY:close_func(ls) | ||
658 | local L = ls.L | ||
659 | local fs = ls.fs | ||
660 | local f = fs.f | ||
661 | self:removevars(ls, 0) | ||
662 | luaK:ret(fs, 0, 0) -- final return | ||
663 | -- luaM_reallocvector deleted for f->code, f->lineinfo, f->k, f->p, | ||
664 | -- f->locvars, f->upvalues; not required for Lua table arrays | ||
665 | f.sizecode = fs.pc | ||
666 | f.sizelineinfo = fs.pc | ||
667 | f.sizek = fs.nk | ||
668 | f.sizep = fs.np | ||
669 | f.sizelocvars = fs.nlocvars | ||
670 | f.sizeupvalues = f.nups | ||
671 | --lua_assert(luaG_checkcode(f)) -- currently not implemented | ||
672 | lua_assert(fs.bl == nil) | ||
673 | ls.fs = fs.prev | ||
674 | -- the following is not required for this implementation; kept here | ||
675 | -- for completeness | ||
676 | -- L->top -= 2; /* remove table and prototype from the stack */ | ||
677 | -- last token read was anchored in defunct function; must reanchor it | ||
678 | if fs then self:anchor_token(ls) end | ||
679 | end | ||
680 | |||
681 | ------------------------------------------------------------------------ | ||
682 | -- parser initialization function | ||
683 | -- * note additional sub-tables needed for LexState, FuncState | ||
684 | ------------------------------------------------------------------------ | ||
685 | function luaY:parser(L, z, buff, name) | ||
686 | local lexstate = {} -- LexState | ||
687 | lexstate.t = {} | ||
688 | lexstate.lookahead = {} | ||
689 | local funcstate = {} -- FuncState | ||
690 | funcstate.upvalues = {} | ||
691 | funcstate.actvar = {} | ||
692 | -- the following nCcalls initialization added for convenience | ||
693 | L.nCcalls = 0 | ||
694 | lexstate.buff = buff | ||
695 | luaX:setinput(L, lexstate, z, name) | ||
696 | self:open_func(lexstate, funcstate) | ||
697 | funcstate.f.is_vararg = self.VARARG_ISVARARG -- main func. is always vararg | ||
698 | luaX:next(lexstate) -- read first token | ||
699 | self:chunk(lexstate) | ||
700 | self:check(lexstate, "TK_EOS") | ||
701 | self:close_func(lexstate) | ||
702 | lua_assert(funcstate.prev == nil) | ||
703 | lua_assert(funcstate.f.nups == 0) | ||
704 | lua_assert(lexstate.fs == nil) | ||
705 | return funcstate.f | ||
706 | end | ||
707 | |||
708 | --[[-------------------------------------------------------------------- | ||
709 | -- GRAMMAR RULES | ||
710 | ----------------------------------------------------------------------]] | ||
711 | |||
712 | ------------------------------------------------------------------------ | ||
713 | -- parse a function name suffix, for function call specifications | ||
714 | -- * used in primaryexp(), funcname() | ||
715 | ------------------------------------------------------------------------ | ||
716 | function luaY:field(ls, v) | ||
717 | -- field -> ['.' | ':'] NAME | ||
718 | local fs = ls.fs | ||
719 | local key = {} -- expdesc | ||
720 | luaK:exp2anyreg(fs, v) | ||
721 | luaX:next(ls) -- skip the dot or colon | ||
722 | self:checkname(ls, key) | ||
723 | luaK:indexed(fs, v, key) | ||
724 | end | ||
725 | |||
726 | ------------------------------------------------------------------------ | ||
727 | -- parse a table indexing suffix, for constructors, expressions | ||
728 | -- * used in recfield(), primaryexp() | ||
729 | ------------------------------------------------------------------------ | ||
730 | function luaY:yindex(ls, v) | ||
731 | -- index -> '[' expr ']' | ||
732 | luaX:next(ls) -- skip the '[' | ||
733 | self:expr(ls, v) | ||
734 | luaK:exp2val(ls.fs, v) | ||
735 | self:checknext(ls, "]") | ||
736 | end | ||
737 | |||
738 | --[[-------------------------------------------------------------------- | ||
739 | -- Rules for Constructors | ||
740 | ----------------------------------------------------------------------]] | ||
741 | |||
742 | --[[-------------------------------------------------------------------- | ||
743 | -- struct ConsControl: | ||
744 | -- v -- last list item read (table: struct expdesc) | ||
745 | -- t -- table descriptor (table: struct expdesc) | ||
746 | -- nh -- total number of 'record' elements | ||
747 | -- na -- total number of array elements | ||
748 | -- tostore -- number of array elements pending to be stored | ||
749 | ----------------------------------------------------------------------]] | ||
750 | |||
751 | ------------------------------------------------------------------------ | ||
752 | -- parse a table record (hash) field | ||
753 | -- * used in constructor() | ||
754 | ------------------------------------------------------------------------ | ||
755 | function luaY:recfield(ls, cc) | ||
756 | -- recfield -> (NAME | '['exp1']') = exp1 | ||
757 | local fs = ls.fs | ||
758 | local reg = ls.fs.freereg | ||
759 | local key, val = {}, {} -- expdesc | ||
760 | if ls.t.token == "TK_NAME" then | ||
761 | self:checklimit(fs, cc.nh, self.MAX_INT, "items in a constructor") | ||
762 | self:checkname(ls, key) | ||
763 | else -- ls->t.token == '[' | ||
764 | self:yindex(ls, key) | ||
765 | end | ||
766 | cc.nh = cc.nh + 1 | ||
767 | self:checknext(ls, "=") | ||
768 | local rkkey = luaK:exp2RK(fs, key) | ||
769 | self:expr(ls, val) | ||
770 | luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, rkkey, luaK:exp2RK(fs, val)) | ||
771 | fs.freereg = reg -- free registers | ||
772 | end | ||
773 | |||
774 | ------------------------------------------------------------------------ | ||
775 | -- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH) | ||
776 | -- * used in constructor() | ||
777 | ------------------------------------------------------------------------ | ||
778 | function luaY:closelistfield(fs, cc) | ||
779 | if cc.v.k == "VVOID" then return end -- there is no list item | ||
780 | luaK:exp2nextreg(fs, cc.v) | ||
781 | cc.v.k = "VVOID" | ||
782 | if cc.tostore == luaP.LFIELDS_PER_FLUSH then | ||
783 | luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) -- flush | ||
784 | cc.tostore = 0 -- no more items pending | ||
785 | end | ||
786 | end | ||
787 | |||
788 | ------------------------------------------------------------------------ | ||
789 | -- emit a set list instruction at the end of parsing list constructor | ||
790 | -- * used in constructor() | ||
791 | ------------------------------------------------------------------------ | ||
792 | function luaY:lastlistfield(fs, cc) | ||
793 | if cc.tostore == 0 then return end | ||
794 | if self:hasmultret(cc.v.k) then | ||
795 | luaK:setmultret(fs, cc.v) | ||
796 | luaK:setlist(fs, cc.t.info, cc.na, self.LUA_MULTRET) | ||
797 | cc.na = cc.na - 1 -- do not count last expression (unknown number of elements) | ||
798 | else | ||
799 | if cc.v.k ~= "VVOID" then | ||
800 | luaK:exp2nextreg(fs, cc.v) | ||
801 | end | ||
802 | luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) | ||
803 | end | ||
804 | end | ||
805 | |||
806 | ------------------------------------------------------------------------ | ||
807 | -- parse a table list (array) field | ||
808 | -- * used in constructor() | ||
809 | ------------------------------------------------------------------------ | ||
810 | function luaY:listfield(ls, cc) | ||
811 | self:expr(ls, cc.v) | ||
812 | self:checklimit(ls.fs, cc.na, self.MAX_INT, "items in a constructor") | ||
813 | cc.na = cc.na + 1 | ||
814 | cc.tostore = cc.tostore + 1 | ||
815 | end | ||
816 | |||
817 | ------------------------------------------------------------------------ | ||
818 | -- parse a table constructor | ||
819 | -- * used in funcargs(), simpleexp() | ||
820 | ------------------------------------------------------------------------ | ||
821 | function luaY:constructor(ls, t) | ||
822 | -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}' | ||
823 | -- field -> recfield | listfield | ||
824 | -- fieldsep -> ',' | ';' | ||
825 | local fs = ls.fs | ||
826 | local line = ls.linenumber | ||
827 | local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0) | ||
828 | local cc = {} -- ConsControl | ||
829 | cc.v = {} | ||
830 | cc.na, cc.nh, cc.tostore = 0, 0, 0 | ||
831 | cc.t = t | ||
832 | self:init_exp(t, "VRELOCABLE", pc) | ||
833 | self:init_exp(cc.v, "VVOID", 0) -- no value (yet) | ||
834 | luaK:exp2nextreg(ls.fs, t) -- fix it at stack top (for gc) | ||
835 | self:checknext(ls, "{") | ||
836 | repeat | ||
837 | lua_assert(cc.v.k == "VVOID" or cc.tostore > 0) | ||
838 | if ls.t.token == "}" then break end | ||
839 | self:closelistfield(fs, cc) | ||
840 | local c = ls.t.token | ||
841 | |||
842 | if c == "TK_NAME" then -- may be listfields or recfields | ||
843 | luaX:lookahead(ls) | ||
844 | if ls.lookahead.token ~= "=" then -- expression? | ||
845 | self:listfield(ls, cc) | ||
846 | else | ||
847 | self:recfield(ls, cc) | ||
848 | end | ||
849 | elseif c == "[" then -- constructor_item -> recfield | ||
850 | self:recfield(ls, cc) | ||
851 | else -- constructor_part -> listfield | ||
852 | self:listfield(ls, cc) | ||
853 | end | ||
854 | until not self:testnext(ls, ",") and not self:testnext(ls, ";") | ||
855 | self:check_match(ls, "}", "{", line) | ||
856 | self:lastlistfield(fs, cc) | ||
857 | luaP:SETARG_B(fs.f.code[pc], self:int2fb(cc.na)) -- set initial array size | ||
858 | luaP:SETARG_C(fs.f.code[pc], self:int2fb(cc.nh)) -- set initial table size | ||
859 | end | ||
860 | |||
861 | -- }====================================================================== | ||
862 | |||
863 | ------------------------------------------------------------------------ | ||
864 | -- parse the arguments (parameters) of a function declaration | ||
865 | -- * used in body() | ||
866 | ------------------------------------------------------------------------ | ||
867 | function luaY:parlist(ls) | ||
868 | -- parlist -> [ param { ',' param } ] | ||
869 | local fs = ls.fs | ||
870 | local f = fs.f | ||
871 | local nparams = 0 | ||
872 | f.is_vararg = 0 | ||
873 | if ls.t.token ~= ")" then -- is 'parlist' not empty? | ||
874 | repeat | ||
875 | local c = ls.t.token | ||
876 | if c == "TK_NAME" then -- param -> NAME | ||
877 | self:new_localvar(ls, self:str_checkname(ls), nparams) | ||
878 | nparams = nparams + 1 | ||
879 | elseif c == "TK_DOTS" then -- param -> `...' | ||
880 | luaX:next(ls) | ||
881 | -- [[ | ||
882 | -- #if defined(LUA_COMPAT_VARARG) | ||
883 | -- use `arg' as default name | ||
884 | self:new_localvarliteral(ls, "arg", nparams) | ||
885 | nparams = nparams + 1 | ||
886 | f.is_vararg = self.VARARG_HASARG + self.VARARG_NEEDSARG | ||
887 | -- #endif | ||
888 | --]] | ||
889 | f.is_vararg = f.is_vararg + self.VARARG_ISVARARG | ||
890 | else | ||
891 | luaX:syntaxerror(ls, "<name> or "..self:LUA_QL("...").." expected") | ||
892 | end | ||
893 | until f.is_vararg ~= 0 or not self:testnext(ls, ",") | ||
894 | end--if | ||
895 | self:adjustlocalvars(ls, nparams) | ||
896 | -- NOTE: the following works only when HASARG_MASK is 2! | ||
897 | f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK) | ||
898 | luaK:reserveregs(fs, fs.nactvar) -- reserve register for parameters | ||
899 | end | ||
900 | |||
901 | ------------------------------------------------------------------------ | ||
902 | -- parse function declaration body | ||
903 | -- * used in simpleexp(), localfunc(), funcstat() | ||
904 | ------------------------------------------------------------------------ | ||
905 | function luaY:body(ls, e, needself, line) | ||
906 | -- body -> '(' parlist ')' chunk END | ||
907 | local new_fs = {} -- FuncState | ||
908 | new_fs.upvalues = {} | ||
909 | new_fs.actvar = {} | ||
910 | self:open_func(ls, new_fs) | ||
911 | new_fs.f.lineDefined = line | ||
912 | self:checknext(ls, "(") | ||
913 | if needself then | ||
914 | self:new_localvarliteral(ls, "self", 0) | ||
915 | self:adjustlocalvars(ls, 1) | ||
916 | end | ||
917 | self:parlist(ls) | ||
918 | self:checknext(ls, ")") | ||
919 | self:chunk(ls) | ||
920 | new_fs.f.lastlinedefined = ls.linenumber | ||
921 | self:check_match(ls, "TK_END", "TK_FUNCTION", line) | ||
922 | self:close_func(ls) | ||
923 | self:pushclosure(ls, new_fs, e) | ||
924 | end | ||
925 | |||
926 | ------------------------------------------------------------------------ | ||
927 | -- parse a list of comma-separated expressions | ||
928 | -- * used is multiple locations | ||
929 | ------------------------------------------------------------------------ | ||
930 | function luaY:explist1(ls, v) | ||
931 | -- explist1 -> expr { ',' expr } | ||
932 | local n = 1 -- at least one expression | ||
933 | self:expr(ls, v) | ||
934 | while self:testnext(ls, ",") do | ||
935 | luaK:exp2nextreg(ls.fs, v) | ||
936 | self:expr(ls, v) | ||
937 | n = n + 1 | ||
938 | end | ||
939 | return n | ||
940 | end | ||
941 | |||
942 | ------------------------------------------------------------------------ | ||
943 | -- parse the parameters of a function call | ||
944 | -- * contrast with parlist(), used in function declarations | ||
945 | -- * used in primaryexp() | ||
946 | ------------------------------------------------------------------------ | ||
947 | function luaY:funcargs(ls, f) | ||
948 | local fs = ls.fs | ||
949 | local args = {} -- expdesc | ||
950 | local nparams | ||
951 | local line = ls.linenumber | ||
952 | local c = ls.t.token | ||
953 | if c == "(" then -- funcargs -> '(' [ explist1 ] ')' | ||
954 | if line ~= ls.lastline then | ||
955 | luaX:syntaxerror(ls, "ambiguous syntax (function call x new statement)") | ||
956 | end | ||
957 | luaX:next(ls) | ||
958 | if ls.t.token == ")" then -- arg list is empty? | ||
959 | args.k = "VVOID" | ||
960 | else | ||
961 | self:explist1(ls, args) | ||
962 | luaK:setmultret(fs, args) | ||
963 | end | ||
964 | self:check_match(ls, ")", "(", line) | ||
965 | elseif c == "{" then -- funcargs -> constructor | ||
966 | self:constructor(ls, args) | ||
967 | elseif c == "TK_STRING" then -- funcargs -> STRING | ||
968 | self:codestring(ls, args, ls.t.seminfo) | ||
969 | luaX:next(ls) -- must use 'seminfo' before 'next' | ||
970 | else | ||
971 | luaX:syntaxerror(ls, "function arguments expected") | ||
972 | return | ||
973 | end | ||
974 | lua_assert(f.k == "VNONRELOC") | ||
975 | local base = f.info -- base register for call | ||
976 | if self:hasmultret(args.k) then | ||
977 | nparams = self.LUA_MULTRET -- open call | ||
978 | else | ||
979 | if args.k ~= "VVOID" then | ||
980 | luaK:exp2nextreg(fs, args) -- close last argument | ||
981 | end | ||
982 | nparams = fs.freereg - (base + 1) | ||
983 | end | ||
984 | self:init_exp(f, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2)) | ||
985 | luaK:fixline(fs, line) | ||
986 | fs.freereg = base + 1 -- call remove function and arguments and leaves | ||
987 | -- (unless changed) one result | ||
988 | end | ||
989 | |||
990 | --[[-------------------------------------------------------------------- | ||
991 | -- Expression parsing | ||
992 | ----------------------------------------------------------------------]] | ||
993 | |||
994 | ------------------------------------------------------------------------ | ||
995 | -- parses an expression in parentheses or a single variable | ||
996 | -- * used in primaryexp() | ||
997 | ------------------------------------------------------------------------ | ||
998 | function luaY:prefixexp(ls, v) | ||
999 | -- prefixexp -> NAME | '(' expr ')' | ||
1000 | local c = ls.t.token | ||
1001 | if c == "(" then | ||
1002 | local line = ls.linenumber | ||
1003 | luaX:next(ls) | ||
1004 | self:expr(ls, v) | ||
1005 | self:check_match(ls, ")", "(", line) | ||
1006 | luaK:dischargevars(ls.fs, v) | ||
1007 | elseif c == "TK_NAME" then | ||
1008 | self:singlevar(ls, v) | ||
1009 | else | ||
1010 | luaX:syntaxerror(ls, "unexpected symbol") | ||
1011 | end--if c | ||
1012 | return | ||
1013 | end | ||
1014 | |||
1015 | ------------------------------------------------------------------------ | ||
1016 | -- parses a prefixexp (an expression in parentheses or a single variable) | ||
1017 | -- or a function call specification | ||
1018 | -- * used in simpleexp(), assignment(), exprstat() | ||
1019 | ------------------------------------------------------------------------ | ||
1020 | function luaY:primaryexp(ls, v) | ||
1021 | -- primaryexp -> | ||
1022 | -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } | ||
1023 | local fs = ls.fs | ||
1024 | self:prefixexp(ls, v) | ||
1025 | while true do | ||
1026 | local c = ls.t.token | ||
1027 | if c == "." then -- field | ||
1028 | self:field(ls, v) | ||
1029 | elseif c == "[" then -- '[' exp1 ']' | ||
1030 | local key = {} -- expdesc | ||
1031 | luaK:exp2anyreg(fs, v) | ||
1032 | self:yindex(ls, key) | ||
1033 | luaK:indexed(fs, v, key) | ||
1034 | elseif c == ":" then -- ':' NAME funcargs | ||
1035 | local key = {} -- expdesc | ||
1036 | luaX:next(ls) | ||
1037 | self:checkname(ls, key) | ||
1038 | luaK:_self(fs, v, key) | ||
1039 | self:funcargs(ls, v) | ||
1040 | elseif c == "(" or c == "TK_STRING" or c == "{" then -- funcargs | ||
1041 | luaK:exp2nextreg(fs, v) | ||
1042 | self:funcargs(ls, v) | ||
1043 | else | ||
1044 | return | ||
1045 | end--if c | ||
1046 | end--while | ||
1047 | end | ||
1048 | |||
1049 | ------------------------------------------------------------------------ | ||
1050 | -- parses general expression types, constants handled here | ||
1051 | -- * used in subexpr() | ||
1052 | ------------------------------------------------------------------------ | ||
1053 | function luaY:simpleexp(ls, v) | ||
1054 | -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | | ||
1055 | -- constructor | FUNCTION body | primaryexp | ||
1056 | local c = ls.t.token | ||
1057 | if c == "TK_NUMBER" then | ||
1058 | self:init_exp(v, "VKNUM", 0) | ||
1059 | v.nval = ls.t.seminfo | ||
1060 | elseif c == "TK_STRING" then | ||
1061 | self:codestring(ls, v, ls.t.seminfo) | ||
1062 | elseif c == "TK_NIL" then | ||
1063 | self:init_exp(v, "VNIL", 0) | ||
1064 | elseif c == "TK_TRUE" then | ||
1065 | self:init_exp(v, "VTRUE", 0) | ||
1066 | elseif c == "TK_FALSE" then | ||
1067 | self:init_exp(v, "VFALSE", 0) | ||
1068 | elseif c == "TK_DOTS" then -- vararg | ||
1069 | local fs = ls.fs | ||
1070 | self:check_condition(ls, fs.f.is_vararg ~= 0, | ||
1071 | "cannot use "..self:LUA_QL("...").." outside a vararg function"); | ||
1072 | -- NOTE: the following substitutes for a bitop, but is value-specific | ||
1073 | local is_vararg = fs.f.is_vararg | ||
1074 | if is_vararg >= self.VARARG_NEEDSARG then | ||
1075 | fs.f.is_vararg = is_vararg - self.VARARG_NEEDSARG -- don't need 'arg' | ||
1076 | end | ||
1077 | self:init_exp(v, "VVARARG", luaK:codeABC(fs, "OP_VARARG", 0, 1, 0)) | ||
1078 | elseif c == "{" then -- constructor | ||
1079 | self:constructor(ls, v) | ||
1080 | return | ||
1081 | elseif c == "TK_FUNCTION" then | ||
1082 | luaX:next(ls) | ||
1083 | self:body(ls, v, false, ls.linenumber) | ||
1084 | return | ||
1085 | else | ||
1086 | self:primaryexp(ls, v) | ||
1087 | return | ||
1088 | end--if c | ||
1089 | luaX:next(ls) | ||
1090 | end | ||
1091 | |||
1092 | ------------------------------------------------------------------------ | ||
1093 | -- Translates unary operators tokens if found, otherwise returns | ||
1094 | -- OPR_NOUNOPR. getunopr() and getbinopr() are used in subexpr(). | ||
1095 | -- * used in subexpr() | ||
1096 | ------------------------------------------------------------------------ | ||
1097 | function luaY:getunopr(op) | ||
1098 | if op == "TK_NOT" then | ||
1099 | return "OPR_NOT" | ||
1100 | elseif op == "-" then | ||
1101 | return "OPR_MINUS" | ||
1102 | elseif op == "#" then | ||
1103 | return "OPR_LEN" | ||
1104 | else | ||
1105 | return "OPR_NOUNOPR" | ||
1106 | end | ||
1107 | end | ||
1108 | |||
1109 | ------------------------------------------------------------------------ | ||
1110 | -- Translates binary operator tokens if found, otherwise returns | ||
1111 | -- OPR_NOBINOPR. Code generation uses OPR_* style tokens. | ||
1112 | -- * used in subexpr() | ||
1113 | ------------------------------------------------------------------------ | ||
1114 | luaY.getbinopr_table = { | ||
1115 | ["+"] = "OPR_ADD", | ||
1116 | ["-"] = "OPR_SUB", | ||
1117 | ["*"] = "OPR_MUL", | ||
1118 | ["/"] = "OPR_DIV", | ||
1119 | ["%"] = "OPR_MOD", | ||
1120 | ["^"] = "OPR_POW", | ||
1121 | ["TK_CONCAT"] = "OPR_CONCAT", | ||
1122 | ["TK_NE"] = "OPR_NE", | ||
1123 | ["TK_EQ"] = "OPR_EQ", | ||
1124 | ["<"] = "OPR_LT", | ||
1125 | ["TK_LE"] = "OPR_LE", | ||
1126 | [">"] = "OPR_GT", | ||
1127 | ["TK_GE"] = "OPR_GE", | ||
1128 | ["TK_AND"] = "OPR_AND", | ||
1129 | ["TK_OR"] = "OPR_OR", | ||
1130 | } | ||
1131 | function luaY:getbinopr(op) | ||
1132 | local opr = self.getbinopr_table[op] | ||
1133 | if opr then return opr else return "OPR_NOBINOPR" end | ||
1134 | end | ||
1135 | |||
1136 | ------------------------------------------------------------------------ | ||
1137 | -- the following priority table consists of pairs of left/right values | ||
1138 | -- for binary operators (was a static const struct); grep for ORDER OPR | ||
1139 | -- * the following struct is replaced: | ||
1140 | -- static const struct { | ||
1141 | -- lu_byte left; /* left priority for each binary operator */ | ||
1142 | -- lu_byte right; /* right priority */ | ||
1143 | -- } priority[] = { /* ORDER OPR */ | ||
1144 | ------------------------------------------------------------------------ | ||
1145 | luaY.priority = { | ||
1146 | {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, -- `+' `-' `/' `%' | ||
1147 | {10, 9}, {5, 4}, -- power and concat (right associative) | ||
1148 | {3, 3}, {3, 3}, -- equality | ||
1149 | {3, 3}, {3, 3}, {3, 3}, {3, 3}, -- order | ||
1150 | {2, 2}, {1, 1} -- logical (and/or) | ||
1151 | } | ||
1152 | |||
1153 | luaY.UNARY_PRIORITY = 8 -- priority for unary operators | ||
1154 | |||
1155 | ------------------------------------------------------------------------ | ||
1156 | -- Parse subexpressions. Includes handling of unary operators and binary | ||
1157 | -- operators. A subexpr is given the rhs priority level of the operator | ||
1158 | -- immediately left of it, if any (limit is -1 if none,) and if a binop | ||
1159 | -- is found, limit is compared with the lhs priority level of the binop | ||
1160 | -- in order to determine which executes first. | ||
1161 | ------------------------------------------------------------------------ | ||
1162 | |||
1163 | ------------------------------------------------------------------------ | ||
1164 | -- subexpr -> (simpleexp | unop subexpr) { binop subexpr } | ||
1165 | -- where 'binop' is any binary operator with a priority higher than 'limit' | ||
1166 | -- * for priority lookups with self.priority[], 1=left and 2=right | ||
1167 | -- * recursively called | ||
1168 | -- * used in expr() | ||
1169 | ------------------------------------------------------------------------ | ||
1170 | function luaY:subexpr(ls, v, limit) | ||
1171 | self:enterlevel(ls) | ||
1172 | local uop = self:getunopr(ls.t.token) | ||
1173 | if uop ~= "OPR_NOUNOPR" then | ||
1174 | luaX:next(ls) | ||
1175 | self:subexpr(ls, v, self.UNARY_PRIORITY) | ||
1176 | luaK:prefix(ls.fs, uop, v) | ||
1177 | else | ||
1178 | self:simpleexp(ls, v) | ||
1179 | end | ||
1180 | -- expand while operators have priorities higher than 'limit' | ||
1181 | local op = self:getbinopr(ls.t.token) | ||
1182 | while op ~= "OPR_NOBINOPR" and self.priority[luaK.BinOpr[op] + 1][1] > limit do | ||
1183 | local v2 = {} -- expdesc | ||
1184 | luaX:next(ls) | ||
1185 | luaK:infix(ls.fs, op, v) | ||
1186 | -- read sub-expression with higher priority | ||
1187 | local nextop = self:subexpr(ls, v2, self.priority[luaK.BinOpr[op] + 1][2]) | ||
1188 | luaK:posfix(ls.fs, op, v, v2) | ||
1189 | op = nextop | ||
1190 | end | ||
1191 | self:leavelevel(ls) | ||
1192 | return op -- return first untreated operator | ||
1193 | end | ||
1194 | |||
1195 | ------------------------------------------------------------------------ | ||
1196 | -- Expression parsing starts here. Function subexpr is entered with the | ||
1197 | -- left operator (which is non-existent) priority of -1, which is lower | ||
1198 | -- than all actual operators. Expr information is returned in parm v. | ||
1199 | -- * used in multiple locations | ||
1200 | ------------------------------------------------------------------------ | ||
1201 | function luaY:expr(ls, v) | ||
1202 | self:subexpr(ls, v, 0) | ||
1203 | end | ||
1204 | |||
1205 | -- }==================================================================== | ||
1206 | |||
1207 | --[[-------------------------------------------------------------------- | ||
1208 | -- Rules for Statements | ||
1209 | ----------------------------------------------------------------------]] | ||
1210 | |||
1211 | ------------------------------------------------------------------------ | ||
1212 | -- checks next token, used as a look-ahead | ||
1213 | -- * returns boolean instead of 0|1 | ||
1214 | -- * used in retstat(), chunk() | ||
1215 | ------------------------------------------------------------------------ | ||
1216 | function luaY:block_follow(token) | ||
1217 | if token == "TK_ELSE" or token == "TK_ELSEIF" or token == "TK_END" | ||
1218 | or token == "TK_UNTIL" or token == "TK_EOS" then | ||
1219 | return true | ||
1220 | else | ||
1221 | return false | ||
1222 | end | ||
1223 | end | ||
1224 | |||
1225 | ------------------------------------------------------------------------ | ||
1226 | -- parse a code block or unit | ||
1227 | -- * used in multiple functions | ||
1228 | ------------------------------------------------------------------------ | ||
1229 | function luaY:block(ls) | ||
1230 | -- block -> chunk | ||
1231 | local fs = ls.fs | ||
1232 | local bl = {} -- BlockCnt | ||
1233 | self:enterblock(fs, bl, false) | ||
1234 | self:chunk(ls) | ||
1235 | lua_assert(bl.breaklist == luaK.NO_JUMP) | ||
1236 | self:leaveblock(fs) | ||
1237 | end | ||
1238 | |||
1239 | ------------------------------------------------------------------------ | ||
1240 | -- structure to chain all variables in the left-hand side of an | ||
1241 | -- assignment | ||
1242 | -- struct LHS_assign: | ||
1243 | -- prev -- (table: struct LHS_assign) | ||
1244 | -- v -- variable (global, local, upvalue, or indexed) (table: expdesc) | ||
1245 | ------------------------------------------------------------------------ | ||
1246 | |||
1247 | ------------------------------------------------------------------------ | ||
1248 | -- check whether, in an assignment to a local variable, the local variable | ||
1249 | -- is needed in a previous assignment (to a table). If so, save original | ||
1250 | -- local value in a safe place and use this safe copy in the previous | ||
1251 | -- assignment. | ||
1252 | -- * used in assignment() | ||
1253 | ------------------------------------------------------------------------ | ||
1254 | function luaY:check_conflict(ls, lh, v) | ||
1255 | local fs = ls.fs | ||
1256 | local extra = fs.freereg -- eventual position to save local variable | ||
1257 | local conflict = false | ||
1258 | while lh do | ||
1259 | if lh.v.k == "VINDEXED" then | ||
1260 | if lh.v.info == v.info then -- conflict? | ||
1261 | conflict = true | ||
1262 | lh.v.info = extra -- previous assignment will use safe copy | ||
1263 | end | ||
1264 | if lh.v.aux == v.info then -- conflict? | ||
1265 | conflict = true | ||
1266 | lh.v.aux = extra -- previous assignment will use safe copy | ||
1267 | end | ||
1268 | end | ||
1269 | lh = lh.prev | ||
1270 | end | ||
1271 | if conflict then | ||
1272 | luaK:codeABC(fs, "OP_MOVE", fs.freereg, v.info, 0) -- make copy | ||
1273 | luaK:reserveregs(fs, 1) | ||
1274 | end | ||
1275 | end | ||
1276 | |||
1277 | ------------------------------------------------------------------------ | ||
1278 | -- parse a variable assignment sequence | ||
1279 | -- * recursively called | ||
1280 | -- * used in exprstat() | ||
1281 | ------------------------------------------------------------------------ | ||
1282 | function luaY:assignment(ls, lh, nvars) | ||
1283 | local e = {} -- expdesc | ||
1284 | -- test was: VLOCAL <= lh->v.k && lh->v.k <= VINDEXED | ||
1285 | local c = lh.v.k | ||
1286 | self:check_condition(ls, c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL" | ||
1287 | or c == "VINDEXED", "syntax error") | ||
1288 | if self:testnext(ls, ",") then -- assignment -> ',' primaryexp assignment | ||
1289 | local nv = {} -- LHS_assign | ||
1290 | nv.v = {} | ||
1291 | nv.prev = lh | ||
1292 | self:primaryexp(ls, nv.v) | ||
1293 | if nv.v.k == "VLOCAL" then | ||
1294 | self:check_conflict(ls, lh, nv.v) | ||
1295 | end | ||
1296 | self:checklimit(ls.fs, nvars, self.LUAI_MAXCCALLS - ls.L.nCcalls, | ||
1297 | "variables in assignment") | ||
1298 | self:assignment(ls, nv, nvars + 1) | ||
1299 | else -- assignment -> '=' explist1 | ||
1300 | self:checknext(ls, "=") | ||
1301 | local nexps = self:explist1(ls, e) | ||
1302 | if nexps ~= nvars then | ||
1303 | self:adjust_assign(ls, nvars, nexps, e) | ||
1304 | if nexps > nvars then | ||
1305 | ls.fs.freereg = ls.fs.freereg - (nexps - nvars) -- remove extra values | ||
1306 | end | ||
1307 | else | ||
1308 | luaK:setoneret(ls.fs, e) -- close last expression | ||
1309 | luaK:storevar(ls.fs, lh.v, e) | ||
1310 | return -- avoid default | ||
1311 | end | ||
1312 | end | ||
1313 | self:init_exp(e, "VNONRELOC", ls.fs.freereg - 1) -- default assignment | ||
1314 | luaK:storevar(ls.fs, lh.v, e) | ||
1315 | end | ||
1316 | |||
1317 | ------------------------------------------------------------------------ | ||
1318 | -- parse condition in a repeat statement or an if control structure | ||
1319 | -- * used in repeatstat(), test_then_block() | ||
1320 | ------------------------------------------------------------------------ | ||
1321 | function luaY:cond(ls) | ||
1322 | -- cond -> exp | ||
1323 | local v = {} -- expdesc | ||
1324 | self:expr(ls, v) -- read condition | ||
1325 | if v.k == "VNIL" then v.k = "VFALSE" end -- 'falses' are all equal here | ||
1326 | luaK:goiftrue(ls.fs, v) | ||
1327 | return v.f | ||
1328 | end | ||
1329 | |||
1330 | ------------------------------------------------------------------------ | ||
1331 | -- parse a break statement | ||
1332 | -- * used in statements() | ||
1333 | ------------------------------------------------------------------------ | ||
1334 | function luaY:breakstat(ls) | ||
1335 | -- stat -> BREAK | ||
1336 | local fs = ls.fs | ||
1337 | local bl = fs.bl | ||
1338 | local upval = false | ||
1339 | while bl and not bl.isbreakable do | ||
1340 | if bl.upval then upval = true end | ||
1341 | bl = bl.previous | ||
1342 | end | ||
1343 | if not bl then | ||
1344 | luaX:syntaxerror(ls, "no loop to break") | ||
1345 | end | ||
1346 | if upval then | ||
1347 | luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0) | ||
1348 | end | ||
1349 | bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs)) | ||
1350 | end | ||
1351 | |||
1352 | ------------------------------------------------------------------------ | ||
1353 | -- parse a while-do control structure, body processed by block() | ||
1354 | -- * with dynamic array sizes, MAXEXPWHILE + EXTRAEXP limits imposed by | ||
1355 | -- the function's implementation can be removed | ||
1356 | -- * used in statements() | ||
1357 | ------------------------------------------------------------------------ | ||
1358 | function luaY:whilestat(ls, line) | ||
1359 | -- whilestat -> WHILE cond DO block END | ||
1360 | local fs = ls.fs | ||
1361 | local bl = {} -- BlockCnt | ||
1362 | luaX:next(ls) -- skip WHILE | ||
1363 | local whileinit = luaK:getlabel(fs) | ||
1364 | local condexit = self:cond(ls) | ||
1365 | self:enterblock(fs, bl, true) | ||
1366 | self:checknext(ls, "TK_DO") | ||
1367 | self:block(ls) | ||
1368 | luaK:patchlist(fs, luaK:jump(fs), whileinit) | ||
1369 | self:check_match(ls, "TK_END", "TK_WHILE", line) | ||
1370 | self:leaveblock(fs) | ||
1371 | luaK:patchtohere(fs, condexit) -- false conditions finish the loop | ||
1372 | end | ||
1373 | |||
1374 | ------------------------------------------------------------------------ | ||
1375 | -- parse a repeat-until control structure, body parsed by chunk() | ||
1376 | -- * used in statements() | ||
1377 | ------------------------------------------------------------------------ | ||
1378 | function luaY:repeatstat(ls, line) | ||
1379 | -- repeatstat -> REPEAT block UNTIL cond | ||
1380 | local fs = ls.fs | ||
1381 | local repeat_init = luaK:getlabel(fs) | ||
1382 | local bl1, bl2 = {}, {} -- BlockCnt | ||
1383 | self:enterblock(fs, bl1, true) -- loop block | ||
1384 | self:enterblock(fs, bl2, false) -- scope block | ||
1385 | luaX:next(ls) -- skip REPEAT | ||
1386 | self:chunk(ls) | ||
1387 | self:check_match(ls, "TK_UNTIL", "TK_REPEAT", line) | ||
1388 | local condexit = self:cond(ls) -- read condition (inside scope block) | ||
1389 | if not bl2.upval then -- no upvalues? | ||
1390 | self:leaveblock(fs) -- finish scope | ||
1391 | luaK:patchlist(ls.fs, condexit, repeat_init) -- close the loop | ||
1392 | else -- complete semantics when there are upvalues | ||
1393 | self:breakstat(ls) -- if condition then break | ||
1394 | luaK:patchtohere(ls.fs, condexit) -- else... | ||
1395 | self:leaveblock(fs) -- finish scope... | ||
1396 | luaK:patchlist(ls.fs, luaK:jump(fs), repeat_init) -- and repeat | ||
1397 | end | ||
1398 | self:leaveblock(fs) -- finish loop | ||
1399 | end | ||
1400 | |||
1401 | ------------------------------------------------------------------------ | ||
1402 | -- parse the single expressions needed in numerical for loops | ||
1403 | -- * used in fornum() | ||
1404 | ------------------------------------------------------------------------ | ||
1405 | function luaY:exp1(ls) | ||
1406 | local e = {} -- expdesc | ||
1407 | self:expr(ls, e) | ||
1408 | local k = e.k | ||
1409 | luaK:exp2nextreg(ls.fs, e) | ||
1410 | return k | ||
1411 | end | ||
1412 | |||
1413 | ------------------------------------------------------------------------ | ||
1414 | -- parse a for loop body for both versions of the for loop | ||
1415 | -- * used in fornum(), forlist() | ||
1416 | ------------------------------------------------------------------------ | ||
1417 | function luaY:forbody(ls, base, line, nvars, isnum) | ||
1418 | -- forbody -> DO block | ||
1419 | local bl = {} -- BlockCnt | ||
1420 | local fs = ls.fs | ||
1421 | self:adjustlocalvars(ls, 3) -- control variables | ||
1422 | self:checknext(ls, "TK_DO") | ||
1423 | local prep = isnum and luaK:codeAsBx(fs, "OP_FORPREP", base, luaK.NO_JUMP) | ||
1424 | or luaK:jump(fs) | ||
1425 | self:enterblock(fs, bl, false) -- scope for declared variables | ||
1426 | self:adjustlocalvars(ls, nvars) | ||
1427 | luaK:reserveregs(fs, nvars) | ||
1428 | self:block(ls) | ||
1429 | self:leaveblock(fs) -- end of scope for declared variables | ||
1430 | luaK:patchtohere(fs, prep) | ||
1431 | local endfor = isnum and luaK:codeAsBx(fs, "OP_FORLOOP", base, luaK.NO_JUMP) | ||
1432 | or luaK:codeABC(fs, "OP_TFORLOOP", base, 0, nvars) | ||
1433 | luaK:fixline(fs, line) -- pretend that `OP_FOR' starts the loop | ||
1434 | luaK:patchlist(fs, isnum and endfor or luaK:jump(fs), prep + 1) | ||
1435 | end | ||
1436 | |||
1437 | ------------------------------------------------------------------------ | ||
1438 | -- parse a numerical for loop, calls forbody() | ||
1439 | -- * used in forstat() | ||
1440 | ------------------------------------------------------------------------ | ||
1441 | function luaY:fornum(ls, varname, line) | ||
1442 | -- fornum -> NAME = exp1,exp1[,exp1] forbody | ||
1443 | local fs = ls.fs | ||
1444 | local base = fs.freereg | ||
1445 | self:new_localvarliteral(ls, "(for index)", 0) | ||
1446 | self:new_localvarliteral(ls, "(for limit)", 1) | ||
1447 | self:new_localvarliteral(ls, "(for step)", 2) | ||
1448 | self:new_localvar(ls, varname, 3) | ||
1449 | self:checknext(ls, '=') | ||
1450 | self:exp1(ls) -- initial value | ||
1451 | self:checknext(ls, ",") | ||
1452 | self:exp1(ls) -- limit | ||
1453 | if self:testnext(ls, ",") then | ||
1454 | self:exp1(ls) -- optional step | ||
1455 | else -- default step = 1 | ||
1456 | luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1)) | ||
1457 | luaK:reserveregs(fs, 1) | ||
1458 | end | ||
1459 | self:forbody(ls, base, line, 1, true) | ||
1460 | end | ||
1461 | |||
1462 | ------------------------------------------------------------------------ | ||
1463 | -- parse a generic for loop, calls forbody() | ||
1464 | -- * used in forstat() | ||
1465 | ------------------------------------------------------------------------ | ||
1466 | function luaY:forlist(ls, indexname) | ||
1467 | -- forlist -> NAME {,NAME} IN explist1 forbody | ||
1468 | local fs = ls.fs | ||
1469 | local e = {} -- expdesc | ||
1470 | local nvars = 0 | ||
1471 | local base = fs.freereg | ||
1472 | -- create control variables | ||
1473 | self:new_localvarliteral(ls, "(for generator)", nvars) | ||
1474 | nvars = nvars + 1 | ||
1475 | self:new_localvarliteral(ls, "(for state)", nvars) | ||
1476 | nvars = nvars + 1 | ||
1477 | self:new_localvarliteral(ls, "(for control)", nvars) | ||
1478 | nvars = nvars + 1 | ||
1479 | -- create declared variables | ||
1480 | self:new_localvar(ls, indexname, nvars) | ||
1481 | nvars = nvars + 1 | ||
1482 | while self:testnext(ls, ",") do | ||
1483 | self:new_localvar(ls, self:str_checkname(ls), nvars) | ||
1484 | nvars = nvars + 1 | ||
1485 | end | ||
1486 | self:checknext(ls, "TK_IN") | ||
1487 | local line = ls.linenumber | ||
1488 | self:adjust_assign(ls, 3, self:explist1(ls, e), e) | ||
1489 | luaK:checkstack(fs, 3) -- extra space to call generator | ||
1490 | self:forbody(ls, base, line, nvars - 3, false) | ||
1491 | end | ||
1492 | |||
1493 | ------------------------------------------------------------------------ | ||
1494 | -- initial parsing for a for loop, calls fornum() or forlist() | ||
1495 | -- * used in statements() | ||
1496 | ------------------------------------------------------------------------ | ||
1497 | function luaY:forstat(ls, line) | ||
1498 | -- forstat -> FOR (fornum | forlist) END | ||
1499 | local fs = ls.fs | ||
1500 | local bl = {} -- BlockCnt | ||
1501 | self:enterblock(fs, bl, true) -- scope for loop and control variables | ||
1502 | luaX:next(ls) -- skip `for' | ||
1503 | local varname = self:str_checkname(ls) -- first variable name | ||
1504 | local c = ls.t.token | ||
1505 | if c == "=" then | ||
1506 | self:fornum(ls, varname, line) | ||
1507 | elseif c == "," or c == "TK_IN" then | ||
1508 | self:forlist(ls, varname) | ||
1509 | else | ||
1510 | luaX:syntaxerror(ls, self:LUA_QL("=").." or "..self:LUA_QL("in").." expected") | ||
1511 | end | ||
1512 | self:check_match(ls, "TK_END", "TK_FOR", line) | ||
1513 | self:leaveblock(fs) -- loop scope (`break' jumps to this point) | ||
1514 | end | ||
1515 | |||
1516 | ------------------------------------------------------------------------ | ||
1517 | -- parse part of an if control structure, including the condition | ||
1518 | -- * used in ifstat() | ||
1519 | ------------------------------------------------------------------------ | ||
1520 | function luaY:test_then_block(ls) | ||
1521 | -- test_then_block -> [IF | ELSEIF] cond THEN block | ||
1522 | luaX:next(ls) -- skip IF or ELSEIF | ||
1523 | local condexit = self:cond(ls) | ||
1524 | self:checknext(ls, "TK_THEN") | ||
1525 | self:block(ls) -- `then' part | ||
1526 | return condexit | ||
1527 | end | ||
1528 | |||
1529 | ------------------------------------------------------------------------ | ||
1530 | -- parse an if control structure | ||
1531 | -- * used in statements() | ||
1532 | ------------------------------------------------------------------------ | ||
1533 | function luaY:ifstat(ls, line) | ||
1534 | -- ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END | ||
1535 | local fs = ls.fs | ||
1536 | local escapelist = luaK.NO_JUMP | ||
1537 | local flist = self:test_then_block(ls) -- IF cond THEN block | ||
1538 | while ls.t.token == "TK_ELSEIF" do | ||
1539 | escapelist = luaK:concat(fs, escapelist, luaK:jump(fs)) | ||
1540 | luaK:patchtohere(fs, flist) | ||
1541 | flist = self:test_then_block(ls) -- ELSEIF cond THEN block | ||
1542 | end | ||
1543 | if ls.t.token == "TK_ELSE" then | ||
1544 | escapelist = luaK:concat(fs, escapelist, luaK:jump(fs)) | ||
1545 | luaK:patchtohere(fs, flist) | ||
1546 | luaX:next(ls) -- skip ELSE (after patch, for correct line info) | ||
1547 | self:block(ls) -- 'else' part | ||
1548 | else | ||
1549 | escapelist = luaK:concat(fs, escapelist, flist) | ||
1550 | end | ||
1551 | luaK:patchtohere(fs, escapelist) | ||
1552 | self:check_match(ls, "TK_END", "TK_IF", line) | ||
1553 | end | ||
1554 | |||
1555 | ------------------------------------------------------------------------ | ||
1556 | -- parse a local function statement | ||
1557 | -- * used in statements() | ||
1558 | ------------------------------------------------------------------------ | ||
1559 | function luaY:localfunc(ls) | ||
1560 | local v, b = {}, {} -- expdesc | ||
1561 | local fs = ls.fs | ||
1562 | self:new_localvar(ls, self:str_checkname(ls), 0) | ||
1563 | self:init_exp(v, "VLOCAL", fs.freereg) | ||
1564 | luaK:reserveregs(fs, 1) | ||
1565 | self:adjustlocalvars(ls, 1) | ||
1566 | self:body(ls, b, false, ls.linenumber) | ||
1567 | luaK:storevar(fs, v, b) | ||
1568 | -- debug information will only see the variable after this point! | ||
1569 | self:getlocvar(fs, fs.nactvar - 1).startpc = fs.pc | ||
1570 | end | ||
1571 | |||
1572 | ------------------------------------------------------------------------ | ||
1573 | -- parse a local variable declaration statement | ||
1574 | -- * used in statements() | ||
1575 | ------------------------------------------------------------------------ | ||
1576 | function luaY:localstat(ls) | ||
1577 | -- stat -> LOCAL NAME {',' NAME} ['=' explist1] | ||
1578 | local nvars = 0 | ||
1579 | local nexps | ||
1580 | local e = {} -- expdesc | ||
1581 | repeat | ||
1582 | self:new_localvar(ls, self:str_checkname(ls), nvars) | ||
1583 | nvars = nvars + 1 | ||
1584 | until not self:testnext(ls, ",") | ||
1585 | if self:testnext(ls, "=") then | ||
1586 | nexps = self:explist1(ls, e) | ||
1587 | else | ||
1588 | e.k = "VVOID" | ||
1589 | nexps = 0 | ||
1590 | end | ||
1591 | self:adjust_assign(ls, nvars, nexps, e) | ||
1592 | self:adjustlocalvars(ls, nvars) | ||
1593 | end | ||
1594 | |||
1595 | ------------------------------------------------------------------------ | ||
1596 | -- parse a function name specification | ||
1597 | -- * used in funcstat() | ||
1598 | ------------------------------------------------------------------------ | ||
1599 | function luaY:funcname(ls, v) | ||
1600 | -- funcname -> NAME {field} [':' NAME] | ||
1601 | local needself = false | ||
1602 | self:singlevar(ls, v) | ||
1603 | while ls.t.token == "." do | ||
1604 | self:field(ls, v) | ||
1605 | end | ||
1606 | if ls.t.token == ":" then | ||
1607 | needself = true | ||
1608 | self:field(ls, v) | ||
1609 | end | ||
1610 | return needself | ||
1611 | end | ||
1612 | |||
1613 | ------------------------------------------------------------------------ | ||
1614 | -- parse a function statement | ||
1615 | -- * used in statements() | ||
1616 | ------------------------------------------------------------------------ | ||
1617 | function luaY:funcstat(ls, line) | ||
1618 | -- funcstat -> FUNCTION funcname body | ||
1619 | local v, b = {}, {} -- expdesc | ||
1620 | luaX:next(ls) -- skip FUNCTION | ||
1621 | local needself = self:funcname(ls, v) | ||
1622 | self:body(ls, b, needself, line) | ||
1623 | luaK:storevar(ls.fs, v, b) | ||
1624 | luaK:fixline(ls.fs, line) -- definition 'happens' in the first line | ||
1625 | end | ||
1626 | |||
1627 | ------------------------------------------------------------------------ | ||
1628 | -- parse a function call with no returns or an assignment statement | ||
1629 | -- * used in statements() | ||
1630 | ------------------------------------------------------------------------ | ||
1631 | function luaY:exprstat(ls) | ||
1632 | -- stat -> func | assignment | ||
1633 | local fs = ls.fs | ||
1634 | local v = {} -- LHS_assign | ||
1635 | v.v = {} | ||
1636 | self:primaryexp(ls, v.v) | ||
1637 | if v.v.k == "VCALL" then -- stat -> func | ||
1638 | luaP:SETARG_C(luaK:getcode(fs, v.v), 1) -- call statement uses no results | ||
1639 | else -- stat -> assignment | ||
1640 | v.prev = nil | ||
1641 | self:assignment(ls, v, 1) | ||
1642 | end | ||
1643 | end | ||
1644 | |||
1645 | ------------------------------------------------------------------------ | ||
1646 | -- parse a return statement | ||
1647 | -- * used in statements() | ||
1648 | ------------------------------------------------------------------------ | ||
1649 | function luaY:retstat(ls) | ||
1650 | -- stat -> RETURN explist | ||
1651 | local fs = ls.fs | ||
1652 | local e = {} -- expdesc | ||
1653 | local first, nret -- registers with returned values | ||
1654 | luaX:next(ls) -- skip RETURN | ||
1655 | if self:block_follow(ls.t.token) or ls.t.token == ";" then | ||
1656 | first, nret = 0, 0 -- return no values | ||
1657 | else | ||
1658 | nret = self:explist1(ls, e) -- optional return values | ||
1659 | if self:hasmultret(e.k) then | ||
1660 | luaK:setmultret(fs, e) | ||
1661 | if e.k == "VCALL" and nret == 1 then -- tail call? | ||
1662 | luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL") | ||
1663 | lua_assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar) | ||
1664 | end | ||
1665 | first = fs.nactvar | ||
1666 | nret = self.LUA_MULTRET -- return all values | ||
1667 | else | ||
1668 | if nret == 1 then -- only one single value? | ||
1669 | first = luaK:exp2anyreg(fs, e) | ||
1670 | else | ||
1671 | luaK:exp2nextreg(fs, e) -- values must go to the 'stack' | ||
1672 | first = fs.nactvar -- return all 'active' values | ||
1673 | lua_assert(nret == fs.freereg - first) | ||
1674 | end | ||
1675 | end--if | ||
1676 | end--if | ||
1677 | luaK:ret(fs, first, nret) | ||
1678 | end | ||
1679 | |||
1680 | ------------------------------------------------------------------------ | ||
1681 | -- initial parsing for statements, calls a lot of functions | ||
1682 | -- * returns boolean instead of 0|1 | ||
1683 | -- * used in chunk() | ||
1684 | ------------------------------------------------------------------------ | ||
1685 | function luaY:statement(ls) | ||
1686 | local line = ls.linenumber -- may be needed for error messages | ||
1687 | local c = ls.t.token | ||
1688 | if c == "TK_IF" then -- stat -> ifstat | ||
1689 | self:ifstat(ls, line) | ||
1690 | return false | ||
1691 | elseif c == "TK_WHILE" then -- stat -> whilestat | ||
1692 | self:whilestat(ls, line) | ||
1693 | return false | ||
1694 | elseif c == "TK_DO" then -- stat -> DO block END | ||
1695 | luaX:next(ls) -- skip DO | ||
1696 | self:block(ls) | ||
1697 | self:check_match(ls, "TK_END", "TK_DO", line) | ||
1698 | return false | ||
1699 | elseif c == "TK_FOR" then -- stat -> forstat | ||
1700 | self:forstat(ls, line) | ||
1701 | return false | ||
1702 | elseif c == "TK_REPEAT" then -- stat -> repeatstat | ||
1703 | self:repeatstat(ls, line) | ||
1704 | return false | ||
1705 | elseif c == "TK_FUNCTION" then -- stat -> funcstat | ||
1706 | self:funcstat(ls, line) | ||
1707 | return false | ||
1708 | elseif c == "TK_LOCAL" then -- stat -> localstat | ||
1709 | luaX:next(ls) -- skip LOCAL | ||
1710 | if self:testnext(ls, "TK_FUNCTION") then -- local function? | ||
1711 | self:localfunc(ls) | ||
1712 | else | ||
1713 | self:localstat(ls) | ||
1714 | end | ||
1715 | return false | ||
1716 | elseif c == "TK_RETURN" then -- stat -> retstat | ||
1717 | self:retstat(ls) | ||
1718 | return true -- must be last statement | ||
1719 | elseif c == "TK_BREAK" then -- stat -> breakstat | ||
1720 | luaX:next(ls) -- skip BREAK | ||
1721 | self:breakstat(ls) | ||
1722 | return true -- must be last statement | ||
1723 | else | ||
1724 | self:exprstat(ls) | ||
1725 | return false -- to avoid warnings | ||
1726 | end--if c | ||
1727 | end | ||
1728 | |||
1729 | ------------------------------------------------------------------------ | ||
1730 | -- parse a chunk, which consists of a bunch of statements | ||
1731 | -- * used in parser(), body(), block(), repeatstat() | ||
1732 | ------------------------------------------------------------------------ | ||
1733 | function luaY:chunk(ls) | ||
1734 | -- chunk -> { stat [';'] } | ||
1735 | local islast = false | ||
1736 | self:enterlevel(ls) | ||
1737 | while not islast and not self:block_follow(ls.t.token) do | ||
1738 | islast = self:statement(ls) | ||
1739 | self:testnext(ls, ";") | ||
1740 | lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg and | ||
1741 | ls.fs.freereg >= ls.fs.nactvar) | ||
1742 | ls.fs.freereg = ls.fs.nactvar -- free registers | ||
1743 | end | ||
1744 | self:leavelevel(ls) | ||
1745 | end | ||
1746 | |||
1747 | -- }====================================================================== | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/luac.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/luac.lua deleted file mode 100644 index 5f12f79..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/luac.lua +++ /dev/null | |||
@@ -1,71 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | luac.lua | ||
4 | Primitive luac in Lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * based on luac.lua in the test directory of the 5.1.2 distribution | ||
18 | -- * usage: lua luac.lua file.lua | ||
19 | ----------------------------------------------------------------------]] | ||
20 | |||
21 | ------------------------------------------------------------------------ | ||
22 | -- load and initialize the required modules | ||
23 | ------------------------------------------------------------------------ | ||
24 | dofile("lzio.lua") | ||
25 | dofile("llex.lua") | ||
26 | dofile("lopcodes.lua") | ||
27 | dofile("ldump.lua") | ||
28 | dofile("lcode.lua") | ||
29 | dofile("lparser.lua") | ||
30 | |||
31 | luaX:init() -- required by llex | ||
32 | local LuaState = {} -- dummy, not actually used, but retained since | ||
33 | -- the intention is to complete a straight port | ||
34 | |||
35 | ------------------------------------------------------------------------ | ||
36 | -- interfacing to yueliang | ||
37 | ------------------------------------------------------------------------ | ||
38 | |||
39 | -- currently asserts are enabled because the codebase hasn't been tested | ||
40 | -- much (if you don't want asserts, just comment them out) | ||
41 | function lua_assert(test) | ||
42 | if not test then error("assertion failed!") end | ||
43 | end | ||
44 | |||
45 | function yloadfile(filename) | ||
46 | -- luaZ:make_getF returns a file chunk reader | ||
47 | -- luaZ:init returns a zio input stream | ||
48 | local zio = luaZ:init(luaZ:make_getF(filename), nil) | ||
49 | if not zio then return end | ||
50 | -- luaY:parser parses the input stream | ||
51 | -- func is the function prototype in tabular form; in C, func can | ||
52 | -- now be used directly by the VM, this can't be done in Lua | ||
53 | local func = luaY:parser(LuaState, zio, nil, "@"..filename) | ||
54 | -- luaU:make_setS returns a string chunk writer | ||
55 | local writer, buff = luaU:make_setS() | ||
56 | -- luaU:dump builds a binary chunk | ||
57 | luaU:dump(LuaState, func, writer, buff) | ||
58 | -- a string.dump equivalent in returned | ||
59 | return buff.data | ||
60 | end | ||
61 | |||
62 | ------------------------------------------------------------------------ | ||
63 | -- command line interface | ||
64 | ------------------------------------------------------------------------ | ||
65 | |||
66 | assert(arg[1] ~= nil and arg[2] == nil, "usage: lua luac.lua file.lua") | ||
67 | local f = assert(io.open("luac.out","wb")) | ||
68 | assert(f:write(assert(yloadfile(arg[1])))) | ||
69 | assert(io.close(f)) | ||
70 | |||
71 | --end | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lzio.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lzio.lua deleted file mode 100644 index b5ea985..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lzio.lua +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | lzio.lua | ||
4 | Lua buffered streams in Lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * EOZ is implemented as a string, "EOZ" | ||
18 | -- * Format of z structure (ZIO) | ||
19 | -- z.n -- bytes still unread | ||
20 | -- z.p -- last read position position in buffer | ||
21 | -- z.reader -- chunk reader function | ||
22 | -- z.data -- additional data | ||
23 | -- * Current position, p, is now last read index instead of a pointer | ||
24 | -- | ||
25 | -- Not implemented: | ||
26 | -- * luaZ_lookahead: used only in lapi.c:lua_load to detect binary chunk | ||
27 | -- * luaZ_read: used only in lundump.c:ezread to read +1 bytes | ||
28 | -- * luaZ_openspace: dropped; let Lua handle buffers as strings (used in | ||
29 | -- lundump.c:LoadString & lvm.c:luaV_concat) | ||
30 | -- * luaZ buffer macros: dropped; buffers are handled as strings | ||
31 | -- * lauxlib.c:getF reader implementation has an extraline flag to | ||
32 | -- skip over a shbang (#!) line, this is not implemented here | ||
33 | -- | ||
34 | -- Added: | ||
35 | -- (both of the following are vaguely adapted from lauxlib.c) | ||
36 | -- * luaZ:make_getS: create Reader from a string | ||
37 | -- * luaZ:make_getF: create Reader that reads from a file | ||
38 | -- | ||
39 | -- Changed in 5.1.x: | ||
40 | -- * Chunkreader renamed to Reader (ditto with Chunkwriter) | ||
41 | -- * Zio struct: no more name string, added Lua state for reader | ||
42 | -- (however, Yueliang readers do not require a Lua state) | ||
43 | ----------------------------------------------------------------------]] | ||
44 | |||
45 | luaZ = {} | ||
46 | |||
47 | ------------------------------------------------------------------------ | ||
48 | -- * reader() should return a string, or nil if nothing else to parse. | ||
49 | -- Additional data can be set only during stream initialization | ||
50 | -- * Readers are handled in lauxlib.c, see luaL_load(file|buffer|string) | ||
51 | -- * LUAL_BUFFERSIZE=BUFSIZ=512 in make_getF() (located in luaconf.h) | ||
52 | -- * Original Reader typedef: | ||
53 | -- const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); | ||
54 | -- * This Lua chunk reader implementation: | ||
55 | -- returns string or nil, no arguments to function | ||
56 | ------------------------------------------------------------------------ | ||
57 | |||
58 | ------------------------------------------------------------------------ | ||
59 | -- create a chunk reader from a source string | ||
60 | ------------------------------------------------------------------------ | ||
61 | function luaZ:make_getS(buff) | ||
62 | local b = buff | ||
63 | return function() -- chunk reader anonymous function here | ||
64 | if not b then return nil end | ||
65 | local data = b | ||
66 | b = nil | ||
67 | return data | ||
68 | end | ||
69 | end | ||
70 | |||
71 | ------------------------------------------------------------------------ | ||
72 | -- create a chunk reader from a source file | ||
73 | ------------------------------------------------------------------------ | ||
74 | function luaZ:make_getF(filename) | ||
75 | local LUAL_BUFFERSIZE = 512 | ||
76 | local h = io.open(filename, "r") | ||
77 | if not h then return nil end | ||
78 | return function() -- chunk reader anonymous function here | ||
79 | if not h or io.type(h) == "closed file" then return nil end | ||
80 | local buff = h:read(LUAL_BUFFERSIZE) | ||
81 | if not buff then h:close(); h = nil end | ||
82 | return buff | ||
83 | end | ||
84 | end | ||
85 | |||
86 | ------------------------------------------------------------------------ | ||
87 | -- creates a zio input stream | ||
88 | -- returns the ZIO structure, z | ||
89 | ------------------------------------------------------------------------ | ||
90 | function luaZ:init(reader, data) | ||
91 | if not reader then return end | ||
92 | local z = {} | ||
93 | z.reader = reader | ||
94 | z.data = data or "" | ||
95 | z.name = name | ||
96 | -- set up additional data for reading | ||
97 | if not data or data == "" then z.n = 0 else z.n = #data end | ||
98 | z.p = 0 | ||
99 | return z | ||
100 | end | ||
101 | |||
102 | ------------------------------------------------------------------------ | ||
103 | -- fill up input buffer | ||
104 | ------------------------------------------------------------------------ | ||
105 | function luaZ:fill(z) | ||
106 | local buff = z.reader() | ||
107 | z.data = buff | ||
108 | if not buff or buff == "" then return "EOZ" end | ||
109 | z.n, z.p = #buff - 1, 1 | ||
110 | return string.sub(buff, 1, 1) | ||
111 | end | ||
112 | |||
113 | ------------------------------------------------------------------------ | ||
114 | -- get next character from the input stream | ||
115 | -- * local n, p are used to optimize code generation | ||
116 | ------------------------------------------------------------------------ | ||
117 | function luaZ:zgetc(z) | ||
118 | local n, p = z.n, z.p + 1 | ||
119 | if n > 0 then | ||
120 | z.n, z.p = n - 1, p | ||
121 | return string.sub(z.data, p, p) | ||
122 | else | ||
123 | return self:fill(z) | ||
124 | end | ||
125 | end | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/bench_llex.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/bench_llex.lua deleted file mode 100644 index b904470..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/bench_llex.lua +++ /dev/null | |||
@@ -1,99 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | bench_llex.lua | ||
4 | Benchmark test for llex.lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | dofile("../lzio.lua") | ||
16 | dofile("../llex.lua") | ||
17 | luaX:init() | ||
18 | |||
19 | ------------------------------------------------------------------------ | ||
20 | -- load in a standard set of sample files | ||
21 | -- * file set is 5.0.3 front end set sans luac.lua | ||
22 | ------------------------------------------------------------------------ | ||
23 | |||
24 | local fileset, totalsize = {}, 0 | ||
25 | for fn in string.gmatch([[ | ||
26 | ../../orig-5.0.3/lcode.lua | ||
27 | ../../orig-5.0.3/ldump.lua | ||
28 | ../../orig-5.0.3/llex.lua | ||
29 | ../../orig-5.0.3/lopcodes.lua | ||
30 | ../../orig-5.0.3/lparser.lua | ||
31 | ../../orig-5.0.3/lzio.lua | ||
32 | ]], "%S+") do | ||
33 | fileset[#fileset+1] = fn | ||
34 | end | ||
35 | |||
36 | for i = 1, #fileset do | ||
37 | local fn = fileset[i] | ||
38 | local inf = io.open(fn, "rb") | ||
39 | if not inf then | ||
40 | error("failed to open "..fn.." for reading") | ||
41 | end | ||
42 | local data = inf:read("*a") | ||
43 | local data_sz = #data | ||
44 | inf:close() | ||
45 | if not data or data_sz == 0 then | ||
46 | error("failed to read data from "..fn.." or file is zero-length") | ||
47 | end | ||
48 | totalsize = totalsize + data_sz | ||
49 | fileset[i] = data | ||
50 | end | ||
51 | |||
52 | ------------------------------------------------------------------------ | ||
53 | -- benchmark tester | ||
54 | ------------------------------------------------------------------------ | ||
55 | |||
56 | local DURATION = 5 -- how long the benchmark should run | ||
57 | |||
58 | local L = {} -- LuaState | ||
59 | local LS = {} -- LexState | ||
60 | |||
61 | local time = os.time | ||
62 | local lexedsize = 0 | ||
63 | local tnow, elapsed = time(), 0 | ||
64 | |||
65 | while time() == tnow do end -- wait for second to click over | ||
66 | tnow = time() | ||
67 | |||
68 | while true do | ||
69 | for i = 1, #fileset do | ||
70 | ------------------------------------------------------------ | ||
71 | local chunk = fileset[i] | ||
72 | local z = luaZ:init(luaZ:make_getS(chunk), nil) | ||
73 | luaX:setinput(L, LS, z, "=string") | ||
74 | while true do | ||
75 | LS.t.token = luaX:llex(LS, LS.t) | ||
76 | local tok, seminfo = LS.t.token, LS.t.seminfo | ||
77 | if tok == "TK_EOS" then break end | ||
78 | end | ||
79 | ------------------------------------------------------------ | ||
80 | lexedsize = lexedsize + #chunk | ||
81 | if time() > tnow then | ||
82 | tnow = time() | ||
83 | elapsed = elapsed + 1 | ||
84 | if elapsed >= DURATION then | ||
85 | -- report performance of lexer | ||
86 | lexedsize = lexedsize / 1024 | ||
87 | local speed = lexedsize / DURATION | ||
88 | print("Lexer performance:") | ||
89 | print("Size of data lexed (KB): "..string.format("%.1f", lexedsize)) | ||
90 | print("Speed of lexer (KB/s): "..string.format("%.1f", speed)) | ||
91 | -- repeat until user breaks program | ||
92 | elapsed = 0 | ||
93 | end | ||
94 | end | ||
95 | ------------------------------------------------------------ | ||
96 | end--for | ||
97 | end--while | ||
98 | |||
99 | -- end of script | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/sample.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/sample.lua deleted file mode 100644 index dc6eaee..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/sample.lua +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | local a = 47 | ||
2 | local b = "hello, world!" | ||
3 | print(a, b) | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_ldump.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_ldump.lua deleted file mode 100644 index 2d113dd..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_ldump.lua +++ /dev/null | |||
@@ -1,99 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | test_ldump.lua | ||
4 | Test for ldump.lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | ------------------------------------------------------------------------ | ||
16 | -- test dump chunkwriter style | ||
17 | ------------------------------------------------------------------------ | ||
18 | |||
19 | dofile("../lopcodes.lua") | ||
20 | dofile("../ldump.lua") | ||
21 | |||
22 | -- Original typedef: | ||
23 | --int (*lua_Chunkwriter) (lua_State *L, const void* p, size_t sz, void* ud); | ||
24 | |||
25 | local MyWriter, MyBuff = luaU:make_setS() | ||
26 | if not MyWriter then | ||
27 | error("failed to initialize using make_setS") | ||
28 | end | ||
29 | MyWriter("hello, ", MyBuff) | ||
30 | MyWriter("world!", MyBuff) | ||
31 | print(MyBuff.data) | ||
32 | |||
33 | local MyWriter, MyBuff = luaU:make_setF("try.txt") | ||
34 | if not MyWriter then | ||
35 | error("failed to initialize using make_setF") | ||
36 | end | ||
37 | MyWriter("hello, ", MyBuff) | ||
38 | MyWriter("world!", MyBuff) | ||
39 | MyWriter(nil, MyBuff) | ||
40 | |||
41 | ------------------------------------------------------------------------ | ||
42 | -- test output of a function prototype | ||
43 | -- * data can be copied from a ChunkSpy listing output | ||
44 | ------------------------------------------------------------------------ | ||
45 | -- local a = 47 | ||
46 | -- local b = "hello, world!" | ||
47 | -- print(a, b) | ||
48 | ------------------------------------------------------------------------ | ||
49 | |||
50 | local F = {} | ||
51 | F.source = "sample.lua" | ||
52 | F.lineDefined = 0 | ||
53 | F.lastlinedefined = 0 | ||
54 | F.nups = 0 | ||
55 | F.numparams = 0 | ||
56 | F.is_vararg = 2 | ||
57 | F.maxstacksize = 5 | ||
58 | F.sizecode = 7 | ||
59 | F.code = {} | ||
60 | F.code[0] = { OP = 1, A = 0, Bx = 0 } | ||
61 | F.code[1] = { OP = 1, A = 1, Bx = 1 } | ||
62 | F.code[2] = { OP = 5, A = 2, Bx = 2 } | ||
63 | F.code[3] = { OP = 0, A = 3, B = 0, C = 0 } | ||
64 | F.code[4] = { OP = 0, A = 4, B = 1, C = 0 } | ||
65 | F.code[5] = { OP = 28, A = 2, B = 3, C = 1 } | ||
66 | F.code[6] = { OP = 30, A = 0, B = 1, C = 0 } | ||
67 | F.sizek = 3 | ||
68 | F.k = {} | ||
69 | F.k[0] = { value = 47 } | ||
70 | F.k[1] = { value = "hello, world!" } | ||
71 | F.k[2] = { value = "print" } | ||
72 | F.sizep = 0 | ||
73 | F.p = {} | ||
74 | F.sizelineinfo = 7 | ||
75 | F.lineinfo = {} | ||
76 | F.lineinfo[0] = 1 | ||
77 | F.lineinfo[1] = 2 | ||
78 | F.lineinfo[2] = 3 | ||
79 | F.lineinfo[3] = 3 | ||
80 | F.lineinfo[4] = 3 | ||
81 | F.lineinfo[5] = 3 | ||
82 | F.lineinfo[6] = 3 | ||
83 | F.sizelocvars = 2 | ||
84 | F.locvars = {} | ||
85 | F.locvars[0] = { varname = "a", startpc = 1, endpc = 6 } | ||
86 | F.locvars[1] = { varname = "b", startpc = 2, endpc = 6 } | ||
87 | F.sizeupvalues = 0 | ||
88 | F.upvalues = {} | ||
89 | |||
90 | local L = {} | ||
91 | --[[ | ||
92 | local Writer, Buff = luaU:make_setS() | ||
93 | luaU:dump(L, F, Writer, Buff) | ||
94 | for i = 1, string.len(Buff.data) do | ||
95 | io.stdout:write(string.byte(string.sub(Buff.data, i, i)).." ") | ||
96 | end | ||
97 | --]] | ||
98 | local Writer, Buff = luaU:make_setF("try.out") | ||
99 | luaU:dump(L, F, Writer, Buff) | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_llex.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_llex.lua deleted file mode 100644 index 0548476..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_llex.lua +++ /dev/null | |||
@@ -1,580 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | test_llex.lua | ||
4 | Test for llex.lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | ------------------------------------------------------------------------ | ||
16 | -- if BRIEF is not set to false, auto-test will silently succeed | ||
17 | ------------------------------------------------------------------------ | ||
18 | BRIEF = true -- if set to true, messages are less verbose | ||
19 | |||
20 | dofile("../lzio.lua") | ||
21 | dofile("../llex.lua") | ||
22 | luaX:init() | ||
23 | |||
24 | ------------------------------------------------------------------------ | ||
25 | -- simple manual tests | ||
26 | ------------------------------------------------------------------------ | ||
27 | |||
28 | --[[ | ||
29 | local L = {} -- LuaState | ||
30 | local LS = {} -- LexState | ||
31 | |||
32 | local function dump(z) | ||
33 | luaX:setinput(L, LS, z, z.name) | ||
34 | while true do | ||
35 | LS.t.token = luaX:lex(LS, LS.t) | ||
36 | local tok, seminfo = LS.t.token, LS.t.seminfo | ||
37 | if tok == "TK_NAME" then | ||
38 | seminfo = " "..seminfo | ||
39 | elseif tok == "TK_NUMBER" then | ||
40 | seminfo = " "..seminfo | ||
41 | elseif tok == "TK_STRING" then | ||
42 | seminfo = " '"..seminfo.."'" | ||
43 | else | ||
44 | seminfo = "" | ||
45 | end | ||
46 | io.stdout:write(tok..seminfo.."\n") | ||
47 | if tok == "TK_EOS" then break end | ||
48 | end | ||
49 | end | ||
50 | |||
51 | local function try_string(chunk) | ||
52 | dump(luaZ:init(luaZ:make_getS(chunk), nil, "=string")) | ||
53 | end | ||
54 | local function try_file(filename) | ||
55 | dump(luaZ:init(luaZ:make_getF(filename), nil, filename)) | ||
56 | end | ||
57 | |||
58 | z = try_string("local c = luaZ:zgetc(z)") | ||
59 | z = try_file("test_lzio.lua") | ||
60 | z = try_file("test_llex.lua") | ||
61 | os.exit() | ||
62 | --]] | ||
63 | |||
64 | ------------------------------------------------------------------------ | ||
65 | -- auto-testing of simple test cases to validate lexer behaviour: | ||
66 | -- * NOTE coverage has not been checked; not comprehensive | ||
67 | -- * only test cases with non-empty comments are processed | ||
68 | -- * if no result, then the output is displayed for manual decision | ||
69 | -- (output may be used to set expected success or fail text) | ||
70 | -- * cases expected to be successful may be a partial match | ||
71 | -- * cases expected to fail may also be a partial match | ||
72 | ------------------------------------------------------------------------ | ||
73 | |||
74 | -- [[ | ||
75 | local function auto_test() | ||
76 | local PASS, FAIL = true, false | ||
77 | ------------------------------------------------------------------ | ||
78 | -- table of test cases | ||
79 | ------------------------------------------------------------------ | ||
80 | local test_cases = | ||
81 | { | ||
82 | ------------------------------------------------------------- | ||
83 | --{ "comment", -- comment about the test | ||
84 | -- "chunk", -- chunk to test | ||
85 | -- PASS, -- PASS or FAIL outcome | ||
86 | -- "output", -- output to compare against | ||
87 | --}, | ||
88 | ------------------------------------------------------------- | ||
89 | { "empty chunk string, test EOS", | ||
90 | "", | ||
91 | PASS, "1 TK_EOS", | ||
92 | }, | ||
93 | ------------------------------------------------------------- | ||
94 | { "line number counting", | ||
95 | "\n\n\r\n", | ||
96 | PASS, "4 TK_EOS", | ||
97 | }, | ||
98 | ------------------------------------------------------------- | ||
99 | { "various whitespaces", | ||
100 | " \n\t\t\n \t \t \n\n", | ||
101 | PASS, "5 TK_EOS", | ||
102 | }, | ||
103 | ------------------------------------------------------------- | ||
104 | { "short comment ending in EOS", | ||
105 | "-- moo moo", | ||
106 | PASS, "1 TK_EOS", | ||
107 | }, | ||
108 | ------------------------------------------------------------- | ||
109 | { "short comment ending in newline", | ||
110 | "-- moo moo\n", | ||
111 | PASS, "2 TK_EOS", | ||
112 | }, | ||
113 | ------------------------------------------------------------- | ||
114 | { "several lines of short comments", | ||
115 | "--moo\n-- moo moo\n\n--\tmoo\n", | ||
116 | PASS, "5 TK_EOS", | ||
117 | }, | ||
118 | ------------------------------------------------------------- | ||
119 | { "basic block comment 1", | ||
120 | "--[[bovine]]", | ||
121 | PASS, "1 TK_EOS", | ||
122 | }, | ||
123 | ------------------------------------------------------------- | ||
124 | { "basic block comment 2", | ||
125 | "--[=[bovine]=]", | ||
126 | PASS, "1 TK_EOS", | ||
127 | }, | ||
128 | ------------------------------------------------------------- | ||
129 | { "basic block comment 3", | ||
130 | "--[====[-[[bovine]]-]====]", | ||
131 | PASS, "1 TK_EOS", | ||
132 | }, | ||
133 | ------------------------------------------------------------- | ||
134 | { "unterminated block comment 1", | ||
135 | "--[[bovine", | ||
136 | FAIL, ":1: unfinished long comment near '<eof>'", | ||
137 | }, | ||
138 | ------------------------------------------------------------- | ||
139 | { "unterminated block comment 2", | ||
140 | "--[==[bovine", | ||
141 | FAIL, ":1: unfinished long comment near '<eof>'", | ||
142 | }, | ||
143 | ------------------------------------------------------------- | ||
144 | { "unterminated block comment 3", | ||
145 | "--[[bovine]", | ||
146 | FAIL, ":1: unfinished long comment near '<eof>'", | ||
147 | }, | ||
148 | ------------------------------------------------------------- | ||
149 | { "unterminated block comment 4", | ||
150 | "--[[bovine\nmoo moo\nwoof", | ||
151 | FAIL, ":3: unfinished long comment near '<eof>'", | ||
152 | }, | ||
153 | ------------------------------------------------------------- | ||
154 | { "basic long string 1", | ||
155 | "\n[[bovine]]\n", | ||
156 | PASS, "2 TK_STRING = bovine\n3 TK_EOS", | ||
157 | }, | ||
158 | ------------------------------------------------------------- | ||
159 | { "basic long string 2", | ||
160 | "\n[=[bovine]=]\n", | ||
161 | PASS, "2 TK_STRING = bovine\n3 TK_EOS", | ||
162 | }, | ||
163 | ------------------------------------------------------------- | ||
164 | { "first newline consumed in long string", | ||
165 | "[[\nmoo]]", | ||
166 | PASS, "2 TK_STRING = moo\n2 TK_EOS", | ||
167 | }, | ||
168 | ------------------------------------------------------------- | ||
169 | { "multiline long string 1", | ||
170 | "[[moo\nmoo moo\n]]", | ||
171 | PASS, "3 TK_STRING = moo\nmoo moo\n\n3 TK_EOS", | ||
172 | }, | ||
173 | ------------------------------------------------------------- | ||
174 | { "multiline long string 2", | ||
175 | "[===[moo\n[=[moo moo]=]\n]===]", | ||
176 | PASS, "3 TK_STRING = moo\n[=[moo moo]=]\n\n3 TK_EOS", | ||
177 | }, | ||
178 | ------------------------------------------------------------- | ||
179 | { "unterminated long string 1", | ||
180 | "\n[[\nbovine", | ||
181 | FAIL, ":3: unfinished long string near '<eof>'", | ||
182 | }, | ||
183 | ------------------------------------------------------------- | ||
184 | { "unterminated long string 2", | ||
185 | "[[bovine]", | ||
186 | FAIL, ":1: unfinished long string near '<eof>'", | ||
187 | }, | ||
188 | ------------------------------------------------------------- | ||
189 | { "unterminated long string 2", | ||
190 | "[==[bovine]==", | ||
191 | FAIL, ":1: unfinished long string near '<eof>'", | ||
192 | }, | ||
193 | ------------------------------------------------------------- | ||
194 | { "complex long string 1", | ||
195 | "[=[moo[[moo]]moo]=]", | ||
196 | PASS, "moo[[moo]]moo", | ||
197 | }, | ||
198 | ------------------------------------------------------------- | ||
199 | { "complex long string 2", | ||
200 | "[=[moo[[moo[[[[]]]]moo]]moo]=]", | ||
201 | PASS, "moo[[moo[[[[]]]]moo]]moo", | ||
202 | }, | ||
203 | ------------------------------------------------------------- | ||
204 | { "complex long string 3", | ||
205 | "[=[[[[[]]]][[[[]]]]]=]", | ||
206 | PASS, "[[[[]]]][[[[]]]]", | ||
207 | }, | ||
208 | ------------------------------------------------------------- | ||
209 | { "deprecated long string 1", | ||
210 | "[[moo[[moo]]moo]]", | ||
211 | FAIL, ":1: nesting of [[...]] is deprecated near '['", | ||
212 | }, | ||
213 | ------------------------------------------------------------- | ||
214 | { "deprecated long string 2", | ||
215 | "[[[[ \n", | ||
216 | FAIL, ":1: nesting of [[...]] is deprecated near '['", | ||
217 | }, | ||
218 | ------------------------------------------------------------- | ||
219 | { "deprecated long string 3", | ||
220 | "[[moo[[moo[[[[]]]]moo]]moo]]", | ||
221 | FAIL, ":1: nesting of [[...]] is deprecated near '['", | ||
222 | }, | ||
223 | ------------------------------------------------------------- | ||
224 | { "deprecated long string 4", | ||
225 | "[[[[[[]]]][[[[]]]]]]", | ||
226 | FAIL, ":1: nesting of [[...]] is deprecated near '['", | ||
227 | }, | ||
228 | ------------------------------------------------------------- | ||
229 | { "brackets in long strings 1", | ||
230 | "[[moo[moo]]", | ||
231 | PASS, "moo[moo", | ||
232 | }, | ||
233 | ------------------------------------------------------------- | ||
234 | { "brackets in long strings 2", | ||
235 | "[=[moo[[moo]moo]]moo]=]", | ||
236 | PASS, "moo[[moo]moo]]moo", | ||
237 | }, | ||
238 | ------------------------------------------------------------- | ||
239 | { "unprocessed escapes in long strings", | ||
240 | [[ [=[\a\b\f\n\r\t\v\123]=] ]], | ||
241 | PASS, [[\a\b\f\n\r\t\v\123]], | ||
242 | }, | ||
243 | ------------------------------------------------------------- | ||
244 | { "unbalanced long string", | ||
245 | "[[moo]]moo]]", | ||
246 | PASS, "1 TK_STRING = moo\n1 TK_NAME = moo\n1 CHAR = ']'\n1 CHAR = ']'\n1 TK_EOS", | ||
247 | }, | ||
248 | ------------------------------------------------------------- | ||
249 | { "keywords 1", | ||
250 | "and break do else", | ||
251 | PASS, "1 TK_AND\n1 TK_BREAK\n1 TK_DO\n1 TK_ELSE\n1 TK_EOS", | ||
252 | }, | ||
253 | ------------------------------------------------------------- | ||
254 | { "keywords 2", | ||
255 | "elseif end false for", | ||
256 | PASS, "1 TK_ELSEIF\n1 TK_END\n1 TK_FALSE\n1 TK_FOR\n1 TK_EOS", | ||
257 | }, | ||
258 | ------------------------------------------------------------- | ||
259 | { "keywords 3", | ||
260 | "function if in local nil", | ||
261 | PASS, "1 TK_FUNCTION\n1 TK_IF\n1 TK_IN\n1 TK_LOCAL\n1 TK_NIL\n1 TK_EOS", | ||
262 | }, | ||
263 | ------------------------------------------------------------- | ||
264 | { "keywords 4", | ||
265 | "not or repeat return", | ||
266 | PASS, "1 TK_NOT\n1 TK_OR\n1 TK_REPEAT\n1 TK_RETURN\n1 TK_EOS", | ||
267 | }, | ||
268 | ------------------------------------------------------------- | ||
269 | { "keywords 5", | ||
270 | "then true until while", | ||
271 | PASS, "1 TK_THEN\n1 TK_TRUE\n1 TK_UNTIL\n1 TK_WHILE\n1 TK_EOS", | ||
272 | }, | ||
273 | ------------------------------------------------------------- | ||
274 | { "concat and dots", | ||
275 | ".. ...", | ||
276 | PASS, "1 TK_CONCAT\n1 TK_DOTS\n1 TK_EOS", | ||
277 | }, | ||
278 | ------------------------------------------------------------- | ||
279 | -- NOTE: in Lua 5.1.x, shbang handling is no longer performed | ||
280 | -- in the lexer; it is now done in lauxlib.c (luaL_loadfile) | ||
281 | -- so the following cannot be performed by the lexer... | ||
282 | ------------------------------------------------------------- | ||
283 | --{ "shbang handling 1", | ||
284 | -- "#blahblah", | ||
285 | -- PASS, "1 TK_EOS", | ||
286 | --}, | ||
287 | ------------------------------------------------------------- | ||
288 | --{ "shbang handling 2", | ||
289 | -- "#blahblah\nmoo moo\n", | ||
290 | -- PASS, "2 TK_NAME = moo\n2 TK_NAME = moo\n3 TK_EOS", | ||
291 | --}, | ||
292 | ------------------------------------------------------------- | ||
293 | { "empty string", | ||
294 | [['']], | ||
295 | PASS, "1 TK_STRING = \n1 TK_EOS", | ||
296 | }, | ||
297 | ------------------------------------------------------------- | ||
298 | { "single-quoted string", | ||
299 | [['bovine']], | ||
300 | PASS, "1 TK_STRING = bovine\n1 TK_EOS", | ||
301 | }, | ||
302 | ------------------------------------------------------------- | ||
303 | { "double-quoted string", | ||
304 | [["bovine"]], | ||
305 | PASS, "1 TK_STRING = bovine\n1 TK_EOS", | ||
306 | }, | ||
307 | ------------------------------------------------------------- | ||
308 | { "unterminated string 1", | ||
309 | [['moo ]], | ||
310 | FAIL, ":1: unfinished string near '<eof>'", | ||
311 | }, | ||
312 | ------------------------------------------------------------- | ||
313 | { "unterminated string 2", | ||
314 | [["moo \n]], | ||
315 | FAIL, ":1: unfinished string near '<eof>'", | ||
316 | }, | ||
317 | ------------------------------------------------------------- | ||
318 | { "escaped newline in string, line number counted", | ||
319 | "\"moo\\\nmoo\\\nmoo\"", | ||
320 | PASS, "3 TK_STRING = moo\nmoo\nmoo\n3 TK_EOS", | ||
321 | }, | ||
322 | ------------------------------------------------------------- | ||
323 | { "escaped characters in string 1", | ||
324 | [["moo\amoo"]], | ||
325 | PASS, "1 TK_STRING = moo\amoo", | ||
326 | }, | ||
327 | ------------------------------------------------------------- | ||
328 | { "escaped characters in string 2", | ||
329 | [["moo\bmoo"]], | ||
330 | PASS, "1 TK_STRING = moo\bmoo", | ||
331 | }, | ||
332 | ------------------------------------------------------------- | ||
333 | { "escaped characters in string 3", | ||
334 | [["moo\f\n\r\t\vmoo"]], | ||
335 | PASS, "1 TK_STRING = moo\f\n\r\t\vmoo", | ||
336 | }, | ||
337 | ------------------------------------------------------------- | ||
338 | { "escaped characters in string 4", | ||
339 | [["\\ \" \' \? \[ \]"]], | ||
340 | PASS, "1 TK_STRING = \\ \" \' \? \[ \]", | ||
341 | }, | ||
342 | ------------------------------------------------------------- | ||
343 | { "escaped characters in string 5", | ||
344 | [["\z \k \: \;"]], | ||
345 | PASS, "1 TK_STRING = z k : ;", | ||
346 | }, | ||
347 | ------------------------------------------------------------- | ||
348 | { "escaped characters in string 6", | ||
349 | [["\8 \65 \160 \180K \097097"]], | ||
350 | PASS, "1 TK_STRING = \8 \65 \160 \180K \097097\n", | ||
351 | }, | ||
352 | ------------------------------------------------------------- | ||
353 | { "escaped characters in string 7", | ||
354 | [["\666"]], | ||
355 | FAIL, ":1: escape sequence too large near '\"'", | ||
356 | }, | ||
357 | ------------------------------------------------------------- | ||
358 | { "simple numbers", | ||
359 | "123 123+", | ||
360 | PASS, "1 TK_NUMBER = 123\n1 TK_NUMBER = 123\n1 CHAR = '+'\n1 TK_EOS", | ||
361 | }, | ||
362 | ------------------------------------------------------------- | ||
363 | { "longer numbers", | ||
364 | "1234567890 12345678901234567890", | ||
365 | PASS, "1 TK_NUMBER = 1234567890\n1 TK_NUMBER = 1.2345678901235e+19\n", | ||
366 | }, | ||
367 | ------------------------------------------------------------- | ||
368 | { "fractional numbers", | ||
369 | ".123 .12345678901234567890", | ||
370 | PASS, "1 TK_NUMBER = 0.123\n1 TK_NUMBER = 0.12345678901235\n", | ||
371 | }, | ||
372 | ------------------------------------------------------------- | ||
373 | { "more numbers with decimal points", | ||
374 | "12345.67890", | ||
375 | PASS, "1 TK_NUMBER = 12345.6789\n", | ||
376 | }, | ||
377 | ------------------------------------------------------------- | ||
378 | { "malformed number with decimal points", | ||
379 | "1.1.", | ||
380 | FAIL, ":1: malformed number near '1.1.'", | ||
381 | }, | ||
382 | ------------------------------------------------------------- | ||
383 | { "double decimal points", | ||
384 | ".1.1", | ||
385 | FAIL, ":1: malformed number near '.1.1'", | ||
386 | }, | ||
387 | ------------------------------------------------------------- | ||
388 | { "double dots within numbers", | ||
389 | "1..1", | ||
390 | FAIL, ":1: malformed number near '1..1'", | ||
391 | }, | ||
392 | ------------------------------------------------------------- | ||
393 | { "incomplete exponential numbers", | ||
394 | "123e", | ||
395 | FAIL, ":1: malformed number near '123e'", | ||
396 | }, | ||
397 | ------------------------------------------------------------- | ||
398 | { "exponential numbers 1", | ||
399 | "1234e5 1234e5.", | ||
400 | PASS, "1 TK_NUMBER = 123400000\n1 TK_NUMBER = 123400000\n1 CHAR = '.'", | ||
401 | }, | ||
402 | ------------------------------------------------------------- | ||
403 | { "exponential numbers 2", | ||
404 | "1234e56 1.23e123", | ||
405 | PASS, "1 TK_NUMBER = 1.234e+59\n1 TK_NUMBER = 1.23e+123\n", | ||
406 | }, | ||
407 | ------------------------------------------------------------- | ||
408 | { "exponential numbers 3", | ||
409 | "12.34e+", | ||
410 | FAIL, ":1: malformed number near '12.34e+'", | ||
411 | }, | ||
412 | ------------------------------------------------------------- | ||
413 | { "exponential numbers 4", | ||
414 | "12.34e+5 123.4e-5 1234.E+5", | ||
415 | PASS, "1 TK_NUMBER = 1234000\n1 TK_NUMBER = 0.001234\n1 TK_NUMBER = 123400000\n", | ||
416 | }, | ||
417 | ------------------------------------------------------------- | ||
418 | { "hexadecimal numbers", | ||
419 | "0x00FF 0X1234 0xDEADBEEF", | ||
420 | PASS, "1 TK_NUMBER = 255\n1 TK_NUMBER = 4660\n1 TK_NUMBER = 3735928559\n", | ||
421 | }, | ||
422 | ------------------------------------------------------------- | ||
423 | { "invalid hexadecimal numbers 1", | ||
424 | "0xFOO", | ||
425 | FAIL, ":1: malformed number near '0xFOO'", | ||
426 | }, | ||
427 | ------------------------------------------------------------- | ||
428 | { "invalid hexadecimal numbers 2", | ||
429 | "0.BAR", | ||
430 | FAIL, ":1: malformed number near '0.BAR'", | ||
431 | }, | ||
432 | ------------------------------------------------------------- | ||
433 | { "invalid hexadecimal numbers 3", | ||
434 | "0BAZ", | ||
435 | FAIL, ":1: malformed number near '0BAZ'", | ||
436 | }, | ||
437 | ------------------------------------------------------------- | ||
438 | { "single character symbols 1", | ||
439 | "= > < ~ #", | ||
440 | PASS, "1 CHAR = '='\n1 CHAR = '>'\n1 CHAR = '<'\n1 CHAR = '~'\n1 CHAR = '#'\n", | ||
441 | }, | ||
442 | ------------------------------------------------------------- | ||
443 | { "double character symbols", | ||
444 | "== >= <= ~=", | ||
445 | PASS, "1 TK_EQ\n1 TK_GE\n1 TK_LE\n1 TK_NE\n", | ||
446 | }, | ||
447 | ------------------------------------------------------------- | ||
448 | { "simple identifiers", | ||
449 | "abc ABC", | ||
450 | PASS, "1 TK_NAME = abc\n1 TK_NAME = ABC\n1 TK_EOS", | ||
451 | }, | ||
452 | ------------------------------------------------------------- | ||
453 | { "more identifiers", | ||
454 | "_abc _ABC", | ||
455 | PASS, "1 TK_NAME = _abc\n1 TK_NAME = _ABC\n1 TK_EOS", | ||
456 | }, | ||
457 | ------------------------------------------------------------- | ||
458 | { "still more identifiers", | ||
459 | "_aB_ _123", | ||
460 | PASS, "1 TK_NAME = _aB_\n1 TK_NAME = _123\n1 TK_EOS", | ||
461 | }, | ||
462 | ------------------------------------------------------------- | ||
463 | -- NOTE: in Lua 5.1.x, this test is no longer performed | ||
464 | ------------------------------------------------------------- | ||
465 | --{ "invalid control character", | ||
466 | -- "\4", | ||
467 | -- FAIL, ":1: invalid control char near 'char(4)'", | ||
468 | --}, | ||
469 | ------------------------------------------------------------- | ||
470 | { "single character symbols 2", | ||
471 | "` ! @ $ %", | ||
472 | PASS, "1 CHAR = '`'\n1 CHAR = '!'\n1 CHAR = '@'\n1 CHAR = '$'\n1 CHAR = '%'\n", | ||
473 | }, | ||
474 | ------------------------------------------------------------- | ||
475 | { "single character symbols 3", | ||
476 | "^ & * ( )", | ||
477 | PASS, "1 CHAR = '^'\n1 CHAR = '&'\n1 CHAR = '*'\n1 CHAR = '('\n1 CHAR = ')'\n", | ||
478 | }, | ||
479 | ------------------------------------------------------------- | ||
480 | { "single character symbols 4", | ||
481 | "_ - + \\ |", | ||
482 | PASS, "1 TK_NAME = _\n1 CHAR = '-'\n1 CHAR = '+'\n1 CHAR = '\\'\n1 CHAR = '|'\n", | ||
483 | }, | ||
484 | ------------------------------------------------------------- | ||
485 | { "single character symbols 5", | ||
486 | "{ } [ ] :", | ||
487 | PASS, "1 CHAR = '{'\n1 CHAR = '}'\n1 CHAR = '['\n1 CHAR = ']'\n1 CHAR = ':'\n", | ||
488 | }, | ||
489 | ------------------------------------------------------------- | ||
490 | { "single character symbols 6", | ||
491 | "; , . / ?", | ||
492 | PASS, "1 CHAR = ';'\n1 CHAR = ','\n1 CHAR = '.'\n1 CHAR = '/'\n1 CHAR = '?'\n", | ||
493 | }, | ||
494 | ------------------------------------------------------------- | ||
495 | } | ||
496 | ------------------------------------------------------------------ | ||
497 | -- perform a test case | ||
498 | ------------------------------------------------------------------ | ||
499 | function do_test_case(count, test_case) | ||
500 | if comment == "" then return end -- skip empty entries | ||
501 | local comment, chunk, outcome, matcher = unpack(test_case) | ||
502 | local result = PASS | ||
503 | local output = "" | ||
504 | -- initialize lexer | ||
505 | local L, LS = {}, {} | ||
506 | local z = luaZ:init(luaZ:make_getS(chunk), nil) | ||
507 | luaX:setinput(L, LS, z, "=test") | ||
508 | -- lexer test loop | ||
509 | repeat | ||
510 | -- protected call | ||
511 | local status, token = pcall(luaX.llex, luaX, LS, LS.t) | ||
512 | LS.t.token = token | ||
513 | output = output..LS.linenumber.." " | ||
514 | if status then | ||
515 | -- successful call | ||
516 | if string.len(token) > 1 then | ||
517 | if token == "TK_NAME" | ||
518 | or token == "TK_NUMBER" | ||
519 | or token == "TK_STRING" then | ||
520 | token = token.." = "..LS.t.seminfo | ||
521 | end | ||
522 | elseif string.byte(token) >= 32 then -- displayable chars | ||
523 | token = "CHAR = '"..token.."'" | ||
524 | else -- control characters | ||
525 | token = "CHAR = (".. string.byte(token)..")" | ||
526 | end | ||
527 | output = output..token.."\n" | ||
528 | else | ||
529 | -- failed call | ||
530 | output = output..token -- token is the error message | ||
531 | result = FAIL | ||
532 | break | ||
533 | end | ||
534 | until LS.t.token == "TK_EOS" | ||
535 | -- decision making and reporting | ||
536 | local head = "Test "..count..": "..comment | ||
537 | if matcher == "" then | ||
538 | -- nothing to check against, display for manual check | ||
539 | print(head.."\nMANUAL please check manually".. | ||
540 | "\n--chunk---------------------------------\n"..chunk.. | ||
541 | "\n--actual--------------------------------\n"..output.. | ||
542 | "\n\n") | ||
543 | return | ||
544 | else | ||
545 | if outcome == PASS then | ||
546 | -- success expected, may be a partial match | ||
547 | if string.find(output, matcher, 1, 1) and result == PASS then | ||
548 | if not BRIEF then print(head.."\nOK expected success\n") end | ||
549 | return | ||
550 | end | ||
551 | else | ||
552 | -- failure expected, may be a partial match | ||
553 | if string.find(output, matcher, 1, 1) and result == FAIL then | ||
554 | if not BRIEF then print(head.."\nOK expected failure\n") end | ||
555 | return | ||
556 | end | ||
557 | end | ||
558 | -- failed because of unmatched string or boolean result | ||
559 | local function passfail(status) | ||
560 | if status == PASS then return "PASS" else return "FAIL" end | ||
561 | end | ||
562 | print(head.." *FAILED*".. | ||
563 | "\noutcome="..passfail(outcome).. | ||
564 | "\nactual= "..passfail(result).. | ||
565 | "\n--chunk---------------------------------\n"..chunk.. | ||
566 | "\n--expected------------------------------\n"..matcher.. | ||
567 | "\n--actual--------------------------------\n"..output.. | ||
568 | "\n\n") | ||
569 | end | ||
570 | end | ||
571 | ------------------------------------------------------------------ | ||
572 | -- perform auto testing | ||
573 | ------------------------------------------------------------------ | ||
574 | for i,test_case in ipairs(test_cases) do | ||
575 | do_test_case(i, test_case) | ||
576 | end | ||
577 | end | ||
578 | |||
579 | auto_test() | ||
580 | --]] | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lparser.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lparser.lua deleted file mode 100644 index 8c7abf4..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lparser.lua +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | test_lparser.lua | ||
4 | Test for lparser.lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | ------------------------------------------------------------------------ | ||
16 | -- test the whole kaboodle | ||
17 | ------------------------------------------------------------------------ | ||
18 | |||
19 | dofile("../lzio.lua") | ||
20 | dofile("../llex.lua") | ||
21 | dofile("../lopcodes.lua") | ||
22 | dofile("../ldump.lua") | ||
23 | dofile("../lcode.lua") | ||
24 | dofile("../lparser.lua") | ||
25 | |||
26 | function lua_assert(test) | ||
27 | if not test then error("assertion failed!") end | ||
28 | end | ||
29 | |||
30 | luaX:init() | ||
31 | |||
32 | ------------------------------------------------------------------------ | ||
33 | -- try 1 | ||
34 | ------------------------------------------------------------------------ | ||
35 | local zio = luaZ:init(luaZ:make_getS("local a = 1"), nil) | ||
36 | local LuaState = {} | ||
37 | local Func = luaY:parser(LuaState, zio, nil, "=string") | ||
38 | |||
39 | --[[ | ||
40 | for i, v in Func do | ||
41 | if type(v) == "string" or type(v) == "number" then | ||
42 | print(i, v) | ||
43 | elseif type(v) == "table" then | ||
44 | print(i, "TABLE") | ||
45 | end | ||
46 | end | ||
47 | --]] | ||
48 | |||
49 | local Writer, Buff = luaU:make_setF("parse1.out") | ||
50 | luaU:dump(LuaState, Func, Writer, Buff) | ||
51 | |||
52 | ------------------------------------------------------------------------ | ||
53 | -- try 2 | ||
54 | ------------------------------------------------------------------------ | ||
55 | |||
56 | zio = luaZ:init(luaZ:make_getF("sample.lua"), nil) | ||
57 | Func = luaY:parser(LuaState, zio, nil, "@sample.lua") | ||
58 | Writer, Buff = luaU:make_setF("parse2.out") | ||
59 | luaU:dump(LuaState, Func, Writer, Buff) | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lparser2.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lparser2.lua deleted file mode 100644 index e9fa188..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lparser2.lua +++ /dev/null | |||
@@ -1,202 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | test_lparser2.lua | ||
4 | Test for lparser.lua, using the test case file | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * the test cases are in the test_lua directory (test_parser-5.1.lua) | ||
18 | ----------------------------------------------------------------------]] | ||
19 | |||
20 | -- * true if you want an output of all failure cases in native Lua, | ||
21 | -- for checking whether test cases fail where you intend them to | ||
22 | local DEBUG_FAILS = false | ||
23 | |||
24 | ------------------------------------------------------------------------ | ||
25 | -- test the whole kaboodle | ||
26 | ------------------------------------------------------------------------ | ||
27 | |||
28 | dofile("../lzio.lua") | ||
29 | dofile("../llex.lua") | ||
30 | dofile("../lopcodes.lua") | ||
31 | dofile("../ldump.lua") | ||
32 | dofile("../lcode.lua") | ||
33 | dofile("../lparser.lua") | ||
34 | |||
35 | function lua_assert(test) | ||
36 | if not test then error("assertion failed!") end | ||
37 | end | ||
38 | |||
39 | luaX:init() | ||
40 | |||
41 | ------------------------------------------------------------------------ | ||
42 | -- load test cases | ||
43 | ------------------------------------------------------------------------ | ||
44 | |||
45 | dofile("../../test_lua/test_parser-5.1.lua") | ||
46 | |||
47 | local test, expect, heading = {}, {}, {} | ||
48 | local total, total_pass, total_fail = 0, 0, 0 | ||
49 | |||
50 | for ln in string.gmatch(tests_source, "([^\n]*)\n") do | ||
51 | if string.find(ln, "^%s*%-%-") then | ||
52 | -- comment, ignore | ||
53 | else | ||
54 | local m, _, head = string.find(ln, "^%s*(TESTS:%s*.*)$") | ||
55 | if m then | ||
56 | heading[total + 1] = head -- informational heading | ||
57 | else | ||
58 | total = total + 1 | ||
59 | local n, _, flag = string.find(ln, "%s*%-%-%s*FAIL%s*$") | ||
60 | if n then -- FAIL test case | ||
61 | ln = string.sub(ln, 1, n - 1) -- remove comment | ||
62 | expect[total] = "FAIL" | ||
63 | total_fail = total_fail + 1 | ||
64 | else -- PASS test case | ||
65 | expect[total] = "PASS" | ||
66 | total_pass = total_pass + 1 | ||
67 | end--n | ||
68 | test[total] = ln | ||
69 | end--m | ||
70 | end--ln | ||
71 | end--for | ||
72 | |||
73 | print("Tests loaded: "..total.." (total), " | ||
74 | ..total_pass.." (passes), " | ||
75 | ..total_fail.." (fails)") | ||
76 | |||
77 | ------------------------------------------------------------------------ | ||
78 | -- verify test cases using native Lua | ||
79 | ------------------------------------------------------------------------ | ||
80 | |||
81 | local last_head = "TESTS: no heading yet" | ||
82 | for i = 1, total do | ||
83 | local test_case, expected, head = test[i], expect[i], heading[i] | ||
84 | -- show progress | ||
85 | if head then | ||
86 | last_head = head | ||
87 | if DEBUG_FAILS then print("\n"..head.."\n") end | ||
88 | end | ||
89 | ------------------------------------------------------------------ | ||
90 | -- perform test | ||
91 | local f, err = loadstring(test_case) | ||
92 | -- look at outcome | ||
93 | ------------------------------------------------------------------ | ||
94 | if f then-- actual PASS | ||
95 | if expected == "FAIL" then | ||
96 | print("\nVerified as PASS but expected to FAIL".. | ||
97 | "\n-------------------------------------") | ||
98 | print("Lastest heading: "..last_head) | ||
99 | print("TEST: "..test_case) | ||
100 | os.exit() | ||
101 | end | ||
102 | ------------------------------------------------------------------ | ||
103 | else-- actual FAIL | ||
104 | if expected == "PASS" then | ||
105 | print("\nVerified as FAIL but expected to PASS".. | ||
106 | "\n-------------------------------------") | ||
107 | print("Lastest heading: "..last_head) | ||
108 | print("TEST: "..test_case) | ||
109 | print("ERROR: "..err) | ||
110 | os.exit() | ||
111 | end | ||
112 | if DEBUG_FAILS then | ||
113 | print("TEST: "..test_case) | ||
114 | print("ERROR: "..err.."\n") | ||
115 | end | ||
116 | ------------------------------------------------------------------ | ||
117 | end--f | ||
118 | end--for | ||
119 | |||
120 | print("Test cases verified using native Lua, no anomalies.") | ||
121 | |||
122 | ------------------------------------------------------------------------ | ||
123 | -- dump binary chunks to a file if something goes wrong | ||
124 | ------------------------------------------------------------------------ | ||
125 | local function Dump(data, filename) | ||
126 | h = io.open(filename, "wb") | ||
127 | if not h then error("failed to open "..filename.." for writing") end | ||
128 | h:write(data) | ||
129 | h:close() | ||
130 | end | ||
131 | |||
132 | ------------------------------------------------------------------------ | ||
133 | -- test using Yueliang front end | ||
134 | ------------------------------------------------------------------------ | ||
135 | |||
136 | local last_head = "TESTS: no heading yet" | ||
137 | for i = 1, total do | ||
138 | local test_case, expected, head = test[i], expect[i], heading[i] | ||
139 | -- show progress | ||
140 | if head then last_head = head end | ||
141 | ------------------------------------------------------------------ | ||
142 | -- perform test | ||
143 | local LuaState = {} | ||
144 | local zio = luaZ:init(luaZ:make_getS(test_case), nil) | ||
145 | local status, func = pcall(luaY.parser, luaY, LuaState, zio, nil, "test") | ||
146 | -- look at outcome | ||
147 | ------------------------------------------------------------------ | ||
148 | if status then-- actual PASS | ||
149 | if expected == "PASS" then | ||
150 | -- actual PASS and expected PASS, so check binary chunks | ||
151 | local writer, buff = luaU:make_setS() | ||
152 | luaU:dump(LuaState, func, writer, buff) | ||
153 | local bc1 = buff.data -- Yueliang's output | ||
154 | local f = loadstring(test_case, "test") | ||
155 | local bc2 = string.dump(f) -- Lua's output | ||
156 | local die | ||
157 | -- compare outputs | ||
158 | if #bc1 ~= #bc2 then | ||
159 | Dump(bc1, "bc1.out") | ||
160 | Dump(bc2, "bc2.out") | ||
161 | die = "binary chunk sizes different" | ||
162 | elseif bc1 ~= bc2 then | ||
163 | Dump(bc1, "bc1.out") | ||
164 | Dump(bc2, "bc2.out") | ||
165 | die = "binary chunks different" | ||
166 | else | ||
167 | -- everything checks out! | ||
168 | end | ||
169 | if die then | ||
170 | print("\nTested PASS and expected to PASS, but chunks different".. | ||
171 | "\n------------------------------------------------------") | ||
172 | print("Reason: "..die) | ||
173 | print("Lastest heading: "..last_head) | ||
174 | print("TEST: "..test_case) | ||
175 | os.exit() | ||
176 | end | ||
177 | else-- expected FAIL | ||
178 | print("\nTested as PASS but expected to FAIL".. | ||
179 | "\n-----------------------------------") | ||
180 | print("Lastest heading: "..last_head) | ||
181 | print("TEST: "..test_case) | ||
182 | os.exit() | ||
183 | end | ||
184 | ------------------------------------------------------------------ | ||
185 | else-- actual FAIL | ||
186 | if expected == "PASS" then | ||
187 | print("\nTested as FAIL but expected to PASS".. | ||
188 | "\n-----------------------------------") | ||
189 | print("Lastest heading: "..last_head) | ||
190 | print("TEST: "..test_case) | ||
191 | print("ERROR: "..err) | ||
192 | os.exit() | ||
193 | end | ||
194 | ------------------------------------------------------------------ | ||
195 | end--status | ||
196 | io.stdout:write("\rTesting ["..i.."]...") | ||
197 | end--for | ||
198 | print(" done.") | ||
199 | |||
200 | print("Test cases run on Yueliang, no anomalies.") | ||
201 | |||
202 | -- end | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lzio.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lzio.lua deleted file mode 100644 index c3879f1..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_lzio.lua +++ /dev/null | |||
@@ -1,41 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | test_lzio.lua | ||
4 | Test for lzio.lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | -- manual test for lzio.lua lua-style chunk reader | ||
16 | |||
17 | dofile("../lzio.lua") | ||
18 | |||
19 | local z | ||
20 | function dump(z) | ||
21 | while true do | ||
22 | local c = luaZ:zgetc(z) | ||
23 | io.stdout:write("("..c..")") | ||
24 | if c == "EOZ" then break end | ||
25 | end | ||
26 | io.stdout:write("\n") | ||
27 | end | ||
28 | |||
29 | -- luaZ:make_getS or luaZ:make_getF creates a chunk reader | ||
30 | -- luaZ:init makes a zio stream | ||
31 | |||
32 | -- [[ | ||
33 | z = luaZ:init(luaZ:make_getS("hello, world!"), nil, "=string") | ||
34 | dump(z) | ||
35 | z = luaZ:init(luaZ:make_getS(", world!"), "hello", "=string") | ||
36 | dump(z) | ||
37 | z = luaZ:init(luaZ:make_getS("line1\nline2\n"), "", "=string") | ||
38 | dump(z) | ||
39 | z = luaZ:init(luaZ:make_getF("test_lzio.lua"), nil, "=string") | ||
40 | dump(z) | ||
41 | --]] | ||
diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_number.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_number.lua deleted file mode 100644 index 2c94f40..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/test/test_number.lua +++ /dev/null | |||
@@ -1,174 +0,0 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | test_number.lua | ||
4 | Test for Lua-based number conversion functions in ldump.lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * luaU:from_int(value) does not have overflow checks, but this | ||
18 | -- can presumably be put in for debugging purposes. | ||
19 | -- * TODO: double conversion does not support denormals or NaNs | ||
20 | -- * apparently 0/0 == 0/0 is false (Lua 5.0.2 on Win32/Mingw), so | ||
21 | -- can't use to check for NaNs | ||
22 | ----------------------------------------------------------------------]] | ||
23 | |||
24 | dofile("../ldump.lua") | ||
25 | |||
26 | ------------------------------------------------------------------------ | ||
27 | -- convert hex string representation to a byte string | ||
28 | -- * must have an even number of hex digits | ||
29 | ------------------------------------------------------------------------ | ||
30 | local function from_hexstring(s) | ||
31 | local bs = "" | ||
32 | for i = 1, string.len(s), 2 do | ||
33 | local asc = tonumber(string.sub(s, i, i + 1), 16) | ||
34 | bs = bs..string.char(asc) | ||
35 | end | ||
36 | return bs | ||
37 | end | ||
38 | |||
39 | ------------------------------------------------------------------------ | ||
40 | -- convert a byte string to a hex string representation | ||
41 | -- * big-endian, easier to grok | ||
42 | ------------------------------------------------------------------------ | ||
43 | local function to_hexstring(s) | ||
44 | local hs = "" | ||
45 | for i = string.len(s), 1, -1 do | ||
46 | local c = string.byte(string.sub(s, i, i)) | ||
47 | hs = hs..string.format("%02X", c) | ||
48 | end | ||
49 | return hs | ||
50 | end | ||
51 | |||
52 | ------------------------------------------------------------------------ | ||
53 | -- tests for 32-bit signed/unsigned integer | ||
54 | ------------------------------------------------------------------------ | ||
55 | local function test_int(value, expected) | ||
56 | local actual = to_hexstring(luaU:from_int(value)) | ||
57 | if not expected or expected == "" then | ||
58 | print(value..": "..actual) | ||
59 | elseif actual ~= expected then | ||
60 | print(value..": FAILED!\n".. | ||
61 | "Converted: "..actual.."\n".. | ||
62 | "Expected: "..expected) | ||
63 | return true | ||
64 | end | ||
65 | return false | ||
66 | end | ||
67 | |||
68 | local table_int = { | ||
69 | ["0"] = "00000000", | ||
70 | ["1"] = "00000001", | ||
71 | ["256"] = "00000100", | ||
72 | ["-256"] = "FFFFFF00", | ||
73 | ["-1"] = "FFFFFFFF", | ||
74 | ["2147483647"] = "7FFFFFFF", -- LONG_MAX | ||
75 | ["-2147483648"] = "80000000", -- LONG_MIN | ||
76 | ["4294967295"] = "FFFFFFFF", -- ULONG_MAX | ||
77 | --[""] = "", | ||
78 | } | ||
79 | |||
80 | local success = true | ||
81 | print("Testing luaU:from_int():") | ||
82 | for i, v in pairs(table_int) do | ||
83 | local test_value = tonumber(i) | ||
84 | local expected = v | ||
85 | if test_int(test_value, expected) then | ||
86 | success = false | ||
87 | end | ||
88 | end | ||
89 | if success then | ||
90 | print("All test numbers passed okay.\n") | ||
91 | else | ||
92 | print("There were one or more failures.\n") | ||
93 | end | ||
94 | |||
95 | ------------------------------------------------------------------------ | ||
96 | -- tests for IEEE 754 64-bit double | ||
97 | ------------------------------------------------------------------------ | ||
98 | |||
99 | local function test_double(value, expected) | ||
100 | local actual = to_hexstring(luaU:from_double(value)) | ||
101 | if not expected or expected == "" then | ||
102 | print(value..": "..actual) | ||
103 | elseif actual ~= expected then | ||
104 | print(value..": FAILED!\n".. | ||
105 | "Converted: "..actual.."\n".. | ||
106 | "Expected: "..expected) | ||
107 | return true | ||
108 | end | ||
109 | return false | ||
110 | end | ||
111 | |||
112 | -- special values, see testing loop for actual lookup | ||
113 | Infinity = 1/0 | ||
114 | Infinity_neg = -1/0 | ||
115 | |||
116 | -- can't seem to do a comparison test with NaN, so leave them | ||
117 | -- (need to check the IEEE standard on this...) | ||
118 | NaN = 0/0 | ||
119 | NaN_neg = -0/0 | ||
120 | --["NaN"] = "", -- 7FF8000000000000 (djgpp) | ||
121 | --["NaN_neg"] = "", -- FFF8000000000000 (djgpp) | ||
122 | |||
123 | local table_double = { | ||
124 | -- 0 for exponent, 0 for mantissa | ||
125 | ["0"] = "0000000000000000", | ||
126 | -- 3FF is bias of 1023, so (-1)^0 * (1+0) * 2^0 | ||
127 | ["1"] = "3FF0000000000000", | ||
128 | -- BFF has sign bit on, so (-1)^1 * (1+0) * 2^0 | ||
129 | ["-1"] = "BFF0000000000000", | ||
130 | -- 3FC is bias of 1020, so (-1)^0 * (1+0) * 2^-3 | ||
131 | ["0.125"] = "3FC0000000000000", | ||
132 | ["0.250"] = "3FD0000000000000", | ||
133 | ["0.500"] = "3FE0000000000000", | ||
134 | -- 40F is bias of 1039, so (-1)^0 * (1+0) * 2^16 | ||
135 | ["65536"] = "40F0000000000000", | ||
136 | -- 7FF is bias of 2047, 0 for mantissa | ||
137 | ["Infinity"] = "7FF0000000000000", | ||
138 | -- FFF has sign bit on, 0 for mantissa | ||
139 | ["Infinity_neg"] = "FFF0000000000000", | ||
140 | -- DBL_MIN, exponent=001 ( 1), mantissa=0000000000000 | ||
141 | ["2.2250738585072014e-308"] = "0010000000000000", | ||
142 | -- DBL_MAX, exponent=7FE (2046), mantissa=FFFFFFFFFFFFF | ||
143 | ["1.7976931348623157e+308"] = "7FEFFFFFFFFFFFFF", | ||
144 | --[[ | ||
145 | -- * the following is for float numbers only * | ||
146 | -- FLT_MIN, exponent=01 ( 1), mantissa=000000 | ||
147 | -- altervative value for FLT_MIN: 1.17549435e-38F | ||
148 | ["1.1754943508222875081e-38"] = "00800000", | ||
149 | -- FLT_MAX, exponent=FE (254), mantissa=7FFFFF | ||
150 | -- altervative value for FLT_MAX: 3.402823466e+38F | ||
151 | ["3.4028234663852885982e+38"] = "7F7FFFFF", | ||
152 | --]] | ||
153 | --[""] = "", | ||
154 | } | ||
155 | |||
156 | local success = true | ||
157 | print("Testing luaU:from_double():") | ||
158 | for i, v in pairs(table_double) do | ||
159 | local test_value | ||
160 | if not string.find(i, "%d") then | ||
161 | test_value = _G[i] | ||
162 | else | ||
163 | test_value = tonumber(i) | ||
164 | end | ||
165 | local expected = v | ||
166 | if test_double(test_value, expected) then | ||
167 | success = false | ||
168 | end | ||
169 | end | ||
170 | if success then | ||
171 | print("All test numbers passed okay.\n") | ||
172 | else | ||
173 | print("There were one or more failures.\n") | ||
174 | end | ||