· 5 years ago · Aug 30, 2020, 10:38 PM
1--[[
2 Credit to einsteinK.
3 Credit to Stravant for LBI.
4
5 Credit to the creators of all the other modules used in this.
6
7 Sceleratis was here and decided modify some things.
8
9 einsteinK was here again to fix a bug in LBI for if-statements
10--]]
11
12local waitDeps = {
13 'Rerubi';
14 'LuaK';
15 'LuaP';
16 'LuaU';
17 'LuaX';
18 'LuaY';
19 'LuaZ';
20}
21
22for i,v in pairs(waitDeps) do script:WaitForChild(v) end
23
24local luaX = require(script.LuaX)
25local luaY = require(script.LuaY)
26local luaZ = require(script.LuaZ)
27local luaU = require(script.LuaU)
28local rerubi = require(script.Rerubi)
29
30luaX:init()
31local LuaState = {}
32
33getfenv().script = nil
34
35return function(str,env)
36 local f,writer,buff,name
37 local env = env or getfenv(2)
38 local name = (env.script and env.script:GetFullName())
39 local ran,error = pcall(function()
40 local zio = luaZ:init(luaZ:make_getS(str), nil)
41 if not zio then return error() end
42 local func = luaY:parser(LuaState, zio, nil, name or "nil")
43 writer, buff = luaU:make_setS()
44 luaU:dump(LuaState, func, writer, buff)
45 f = rerubi(buff.data, env)
46 end)
47
48 if ran then
49 return f,buff.data
50 else
51 return nil,error
52 end
53end
54
55
56
57------------------------------------------------------------------------
58
59
60--[[--------------------------------------------------------------------
61
62 lcode.lua
63 Lua 5 code generator in Lua
64 This file is part of Yueliang.
65
66 Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
67 The COPYRIGHT file describes the conditions
68 under which this software may be distributed.
69
70 See the ChangeLog for more information.
71
72----------------------------------------------------------------------]]
73
74--[[--------------------------------------------------------------------
75-- Notes:
76-- * one function manipulate a pointer argument with a simple data type
77-- (can't be emulated by a table, ambiguous), now returns that value:
78-- luaK:concat(fs, l1, l2)
79-- * luaM_growvector uses the faux luaY:growvector, for limit checking
80-- * some function parameters changed to boolean, additional code
81-- translates boolean back to 1/0 for instruction fields
82--
83-- Not implemented:
84-- * NOTE there is a failed assert in luaK:addk, a porting problem
85--
86-- Added:
87-- * constant MAXSTACK from llimits.h
88-- * luaK:ttisnumber(o) (from lobject.h)
89-- * luaK:nvalue(o) (from lobject.h)
90-- * luaK:setnilvalue(o) (from lobject.h)
91-- * luaK:setnvalue(o, x) (from lobject.h)
92-- * luaK:setbvalue(o, x) (from lobject.h)
93-- * luaK:sethvalue(o, x) (from lobject.h), parameter L deleted
94-- * luaK:setsvalue(o, x) (from lobject.h), parameter L deleted
95-- * luaK:numadd, luaK:numsub, luaK:nummul, luaK:numdiv, luaK:nummod,
96-- luaK:numpow, luaK:numunm, luaK:numisnan (from luaconf.h)
97-- * copyexp(e1, e2) added in luaK:posfix to copy expdesc struct
98--
99-- Changed in 5.1.x:
100-- * enum BinOpr has a new entry, OPR_MOD
101-- * enum UnOpr has a new entry, OPR_LEN
102-- * binopistest, unused in 5.0.x, has been deleted
103-- * macro setmultret is new
104-- * functions isnumeral, luaK_ret, boolK are new
105-- * funcion nilK was named nil_constant in 5.0.x
106-- * function interface changed: need_value, patchtestreg, concat
107-- * TObject now a TValue
108-- * functions luaK_setreturns, luaK_setoneret are new
109-- * function luaK:setcallreturns deleted, to be replaced by:
110-- luaK:setmultret, luaK:ret, luaK:setreturns, luaK:setoneret
111-- * functions constfolding, codearith, codecomp are new
112-- * luaK:codebinop has been deleted
113-- * function luaK_setlist is new
114-- * OPR_MULT renamed to OPR_MUL
115----------------------------------------------------------------------]]
116
117-- requires luaP, luaX, luaY
118local luaK = {}
119local luaP = require(script.Parent.LuaP)
120local luaX = require(script.Parent.LuaX)
121
122------------------------------------------------------------------------
123-- constants used by code generator
124------------------------------------------------------------------------
125-- maximum stack for a Lua function
126luaK.MAXSTACK = 250 -- (from llimits.h)
127
128--[[--------------------------------------------------------------------
129-- other functions
130----------------------------------------------------------------------]]
131
132------------------------------------------------------------------------
133-- emulation of TValue macros (these are from lobject.h)
134-- * TValue is a table since lcode passes references around
135-- * tt member field removed, using Lua's type() instead
136-- * for setsvalue, sethvalue, parameter L (deleted here) in lobject.h
137-- is used in an assert for testing, see checkliveness(g,obj)
138------------------------------------------------------------------------
139function luaK:ttisnumber(o)
140 if o then return type(o.value) == "number" else return false end
141end
142function luaK:nvalue(o) return o.value end
143function luaK:setnilvalue(o) o.value = nil end
144function luaK:setsvalue(o, x) o.value = x end
145luaK.setnvalue = luaK.setsvalue
146luaK.sethvalue = luaK.setsvalue
147luaK.setbvalue = luaK.setsvalue
148
149------------------------------------------------------------------------
150-- The luai_num* macros define the primitive operations over numbers.
151-- * this is not the entire set of primitive operations from luaconf.h
152-- * used in luaK:constfolding()
153------------------------------------------------------------------------
154function luaK:numadd(a, b) return a + b end
155function luaK:numsub(a, b) return a - b end
156function luaK:nummul(a, b) return a * b end
157function luaK:numdiv(a, b) return a / b end
158function luaK:nummod(a, b) return a % b end
159 -- ((a) - floor((a)/(b))*(b)) /* actual, for reference */
160function luaK:numpow(a, b) return a ^ b end
161function luaK:numunm(a) return -a end
162function luaK:numisnan(a) return not a == a end
163 -- a NaN cannot equal another NaN
164
165--[[--------------------------------------------------------------------
166-- code generator functions
167----------------------------------------------------------------------]]
168
169------------------------------------------------------------------------
170-- Marks the end of a patch list. It is an invalid value both as an absolute
171-- address, and as a list link (would link an element to itself).
172------------------------------------------------------------------------
173luaK.NO_JUMP = -1
174
175------------------------------------------------------------------------
176-- grep "ORDER OPR" if you change these enums
177------------------------------------------------------------------------
178luaK.BinOpr = {
179 OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5,
180 OPR_CONCAT = 6,
181 OPR_NE = 7, OPR_EQ = 8,
182 OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12,
183 OPR_AND = 13, OPR_OR = 14,
184 OPR_NOBINOPR = 15,
185}
186
187-- * UnOpr is used by luaK:prefix's op argument, but not directly used
188-- because the function receives the symbols as strings, e.g. "OPR_NOT"
189luaK.UnOpr = {
190 OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3
191}
192
193------------------------------------------------------------------------
194-- returns the instruction object for given e (expdesc), was a macro
195------------------------------------------------------------------------
196function luaK:getcode(fs, e)
197 return fs.f.code[e.info]
198end
199
200------------------------------------------------------------------------
201-- codes an instruction with a signed Bx (sBx) field, was a macro
202-- * used in luaK:jump(), (lparser) luaY:forbody()
203------------------------------------------------------------------------
204function luaK:codeAsBx(fs, o, A, sBx)
205 return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx)
206end
207
208------------------------------------------------------------------------
209-- set the expdesc e instruction for multiple returns, was a macro
210------------------------------------------------------------------------
211function luaK:setmultret(fs, e)
212 self:setreturns(fs, e, luaY.LUA_MULTRET)
213end
214
215------------------------------------------------------------------------
216-- there is a jump if patch lists are not identical, was a macro
217-- * used in luaK:exp2reg(), luaK:exp2anyreg(), luaK:exp2val()
218------------------------------------------------------------------------
219function luaK:hasjumps(e)
220 return e.t ~= e.f
221end
222
223------------------------------------------------------------------------
224-- true if the expression is a constant number (for constant folding)
225-- * used in constfolding(), infix()
226------------------------------------------------------------------------
227function luaK:isnumeral(e)
228 return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP
229end
230
231------------------------------------------------------------------------
232-- codes loading of nil, optimization done if consecutive locations
233-- * used in luaK:discharge2reg(), (lparser) luaY:adjust_assign()
234------------------------------------------------------------------------
235function luaK:_nil(fs, from, n)
236 if fs.pc > fs.lasttarget then -- no jumps to current position?
237 if fs.pc == 0 then -- function start?
238 if from >= fs.nactvar then
239 return -- positions are already clean
240 end
241 else
242 local previous = fs.f.code[fs.pc - 1]
243 if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then
244 local pfrom = luaP:GETARG_A(previous)
245 local pto = luaP:GETARG_B(previous)
246 if pfrom <= from and from <= pto + 1 then -- can connect both?
247 if from + n - 1 > pto then
248 luaP:SETARG_B(previous, from + n - 1)
249 end
250 return
251 end
252 end
253 end
254 end
255 self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) -- else no optimization
256end
257
258------------------------------------------------------------------------
259--
260-- * used in multiple locations
261------------------------------------------------------------------------
262function luaK:jump(fs)
263 local jpc = fs.jpc -- save list of jumps to here
264 fs.jpc = self.NO_JUMP
265 local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP)
266 j = self:concat(fs, j, jpc) -- keep them on hold
267 return j
268end
269
270------------------------------------------------------------------------
271-- codes a RETURN instruction
272-- * used in luaY:close_func(), luaY:retstat()
273------------------------------------------------------------------------
274function luaK:ret(fs, first, nret)
275 self:codeABC(fs, "OP_RETURN", first, nret + 1, 0)
276end
277
278------------------------------------------------------------------------
279--
280-- * used in luaK:jumponcond(), luaK:codecomp()
281------------------------------------------------------------------------
282function luaK:condjump(fs, op, A, B, C)
283 self:codeABC(fs, op, A, B, C)
284 return self:jump(fs)
285end
286
287------------------------------------------------------------------------
288--
289-- * used in luaK:patchlistaux(), luaK:concat()
290------------------------------------------------------------------------
291function luaK:fixjump(fs, pc, dest)
292 local jmp = fs.f.code[pc]
293 local offset = dest - (pc + 1)
294 assert(dest ~= self.NO_JUMP)
295 if math.abs(offset) > luaP.MAXARG_sBx then
296 luaX:syntaxerror(fs.ls, "control structure too long")
297 end
298 luaP:SETARG_sBx(jmp, offset)
299end
300
301------------------------------------------------------------------------
302-- returns current 'pc' and marks it as a jump target (to avoid wrong
303-- optimizations with consecutive instructions not in the same basic block).
304-- * used in multiple locations
305-- * fs.lasttarget tested only by luaK:_nil() when optimizing OP_LOADNIL
306------------------------------------------------------------------------
307function luaK:getlabel(fs)
308 fs.lasttarget = fs.pc
309 return fs.pc
310end
311
312------------------------------------------------------------------------
313--
314-- * used in luaK:need_value(), luaK:removevalues(), luaK:patchlistaux(),
315-- luaK:concat()
316------------------------------------------------------------------------
317function luaK:getjump(fs, pc)
318 local offset = luaP:GETARG_sBx(fs.f.code[pc])
319 if offset == self.NO_JUMP then -- point to itself represents end of list
320 return self.NO_JUMP -- end of list
321 else
322 return (pc + 1) + offset -- turn offset into absolute position
323 end
324end
325
326------------------------------------------------------------------------
327--
328-- * used in luaK:need_value(), luaK:patchtestreg(), luaK:invertjump()
329------------------------------------------------------------------------
330function luaK:getjumpcontrol(fs, pc)
331 local pi = fs.f.code[pc]
332 local ppi = fs.f.code[pc - 1]
333 if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then
334 return ppi
335 else
336 return pi
337 end
338end
339
340------------------------------------------------------------------------
341-- check whether list has any jump that do not produce a value
342-- (or produce an inverted value)
343-- * return value changed to boolean
344-- * used only in luaK:exp2reg()
345------------------------------------------------------------------------
346function luaK:need_value(fs, list)
347 while list ~= self.NO_JUMP do
348 local i = self:getjumpcontrol(fs, list)
349 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then return true end
350 list = self:getjump(fs, list)
351 end
352 return false -- not found
353end
354
355------------------------------------------------------------------------
356--
357-- * used in luaK:removevalues(), luaK:patchlistaux()
358------------------------------------------------------------------------
359function luaK:patchtestreg(fs, node, reg)
360 local i = self:getjumpcontrol(fs, node)
361 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then
362 return false -- cannot patch other instructions
363 end
364 if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then
365 luaP:SETARG_A(i, reg)
366 else -- no register to put value or register already has the value
367 -- due to use of a table as i, i cannot be replaced by another table
368 -- so the following is required; there is no change to ARG_C
369 luaP:SET_OPCODE(i, "OP_TEST")
370 local b = luaP:GETARG_B(i)
371 luaP:SETARG_A(i, b)
372 luaP:SETARG_B(i, 0)
373 -- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); /* C */
374 end
375 return true
376end
377
378------------------------------------------------------------------------
379--
380-- * used only in luaK:codenot()
381------------------------------------------------------------------------
382function luaK:removevalues(fs, list)
383 while list ~= self.NO_JUMP do
384 self:patchtestreg(fs, list, luaP.NO_REG)
385 list = self:getjump(fs, list)
386 end
387end
388
389------------------------------------------------------------------------
390--
391-- * used in luaK:dischargejpc(), luaK:patchlist(), luaK:exp2reg()
392------------------------------------------------------------------------
393function luaK:patchlistaux(fs, list, vtarget, reg, dtarget)
394 while list ~= self.NO_JUMP do
395 local _next = self:getjump(fs, list)
396 if self:patchtestreg(fs, list, reg) then
397 self:fixjump(fs, list, vtarget)
398 else
399 self:fixjump(fs, list, dtarget) -- jump to default target
400 end
401 list = _next
402 end
403end
404
405------------------------------------------------------------------------
406--
407-- * used only in luaK:code()
408------------------------------------------------------------------------
409function luaK:dischargejpc(fs)
410 self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc)
411 fs.jpc = self.NO_JUMP
412end
413
414------------------------------------------------------------------------
415--
416-- * used in (lparser) luaY:whilestat(), luaY:repeatstat(), luaY:forbody()
417------------------------------------------------------------------------
418function luaK:patchlist(fs, list, target)
419 if target == fs.pc then
420 self:patchtohere(fs, list)
421 else
422 assert(target < fs.pc)
423 self:patchlistaux(fs, list, target, luaP.NO_REG, target)
424 end
425end
426
427------------------------------------------------------------------------
428--
429-- * used in multiple locations
430------------------------------------------------------------------------
431function luaK:patchtohere(fs, list)
432 self:getlabel(fs)
433 fs.jpc = self:concat(fs, fs.jpc, list)
434end
435
436------------------------------------------------------------------------
437-- * l1 was a pointer, now l1 is returned and callee assigns the value
438-- * used in multiple locations
439------------------------------------------------------------------------
440function luaK:concat(fs, l1, l2)
441 if l2 == self.NO_JUMP then return l1
442 elseif l1 == self.NO_JUMP then
443 return l2
444 else
445 local list = l1
446 local _next = self:getjump(fs, list)
447 while _next ~= self.NO_JUMP do -- find last element
448 list = _next
449 _next = self:getjump(fs, list)
450 end
451 self:fixjump(fs, list, l2)
452 end
453 return l1
454end
455
456------------------------------------------------------------------------
457--
458-- * used in luaK:reserveregs(), (lparser) luaY:forlist()
459------------------------------------------------------------------------
460function luaK:checkstack(fs, n)
461 local newstack = fs.freereg + n
462 if newstack > fs.f.maxstacksize then
463 if newstack >= self.MAXSTACK then
464 luaX:syntaxerror(fs.ls, "function or expression too complex")
465 end
466 fs.f.maxstacksize = newstack
467 end
468end
469
470------------------------------------------------------------------------
471--
472-- * used in multiple locations
473------------------------------------------------------------------------
474function luaK:reserveregs(fs, n)
475 self:checkstack(fs, n)
476 fs.freereg = fs.freereg + n
477end
478
479------------------------------------------------------------------------
480--
481-- * used in luaK:freeexp(), luaK:dischargevars()
482------------------------------------------------------------------------
483function luaK:freereg(fs, reg)
484 if not luaP:ISK(reg) and reg >= fs.nactvar then
485 fs.freereg = fs.freereg - 1
486 assert(reg == fs.freereg)
487 end
488end
489
490------------------------------------------------------------------------
491--
492-- * used in multiple locations
493------------------------------------------------------------------------
494function luaK:freeexp(fs, e)
495 if e.k == "VNONRELOC" then
496 self:freereg(fs, e.info)
497 end
498end
499
500------------------------------------------------------------------------
501-- * TODO NOTE implementation is not 100% correct, since the assert fails
502-- * luaH_set, setobj deleted; direct table access used instead
503-- * used in luaK:stringK(), luaK:numberK(), luaK:boolK(), luaK:nilK()
504------------------------------------------------------------------------
505function luaK:addk(fs, k, v)
506 local L = fs.L
507 local idx = fs.h[k.value]
508 --TValue *idx = luaH_set(L, fs->h, k); /* C */
509 local f = fs.f
510 if self:ttisnumber(idx) then
511 --TODO this assert currently FAILS (last tested for 5.0.2)
512 --assert(fs.f.k[self:nvalue(idx)] == v)
513 --assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); /* C */
514 return self:nvalue(idx)
515 else -- constant not found; create a new entry
516 idx = {}
517 self:setnvalue(idx, fs.nk)
518 fs.h[k.value] = idx
519 -- setnvalue(idx, cast_num(fs->nk)); /* C */
520 luaY:growvector(L, f.k, fs.nk, f.sizek, nil,
521 luaP.MAXARG_Bx, "constant table overflow")
522 -- loop to initialize empty f.k positions not required
523 f.k[fs.nk] = v
524 -- setobj(L, &f->k[fs->nk], v); /* C */
525 -- luaC_barrier(L, f, v); /* GC */
526 local nk = fs.nk
527 fs.nk = fs.nk + 1
528 return nk
529 end
530
531end
532
533------------------------------------------------------------------------
534-- creates and sets a string object
535-- * used in (lparser) luaY:codestring(), luaY:singlevar()
536------------------------------------------------------------------------
537function luaK:stringK(fs, s)
538 local o = {} -- TValue
539 self:setsvalue(o, s)
540 return self:addk(fs, o, o)
541end
542
543------------------------------------------------------------------------
544-- creates and sets a number object
545-- * used in luaK:prefix() for negative (or negation of) numbers
546-- * used in (lparser) luaY:simpleexp(), luaY:fornum()
547------------------------------------------------------------------------
548function luaK:numberK(fs, r)
549 local o = {} -- TValue
550 self:setnvalue(o, r)
551 return self:addk(fs, o, o)
552end
553
554------------------------------------------------------------------------
555-- creates and sets a boolean object
556-- * used only in luaK:exp2RK()
557------------------------------------------------------------------------
558function luaK:boolK(fs, b)
559 local o = {} -- TValue
560 self:setbvalue(o, b)
561 return self:addk(fs, o, o)
562end
563
564------------------------------------------------------------------------
565-- creates and sets a nil object
566-- * used only in luaK:exp2RK()
567------------------------------------------------------------------------
568function luaK:nilK(fs)
569 local k, v = {}, {} -- TValue
570 self:setnilvalue(v)
571 -- cannot use nil as key; instead use table itself to represent nil
572 self:sethvalue(k, fs.h)
573 return self:addk(fs, k, v)
574end
575
576------------------------------------------------------------------------
577--
578-- * used in luaK:setmultret(), (lparser) luaY:adjust_assign()
579------------------------------------------------------------------------
580function luaK:setreturns(fs, e, nresults)
581 if e.k == "VCALL" then -- expression is an open function call?
582 luaP:SETARG_C(self:getcode(fs, e), nresults + 1)
583 elseif e.k == "VVARARG" then
584 luaP:SETARG_B(self:getcode(fs, e), nresults + 1);
585 luaP:SETARG_A(self:getcode(fs, e), fs.freereg);
586 luaK:reserveregs(fs, 1)
587 end
588end
589
590------------------------------------------------------------------------
591--
592-- * used in luaK:dischargevars(), (lparser) luaY:assignment()
593------------------------------------------------------------------------
594function luaK:setoneret(fs, e)
595 if e.k == "VCALL" then -- expression is an open function call?
596 e.k = "VNONRELOC"
597 e.info = luaP:GETARG_A(self:getcode(fs, e))
598 elseif e.k == "VVARARG" then
599 luaP:SETARG_B(self:getcode(fs, e), 2)
600 e.k = "VRELOCABLE" -- can relocate its simple result
601 end
602end
603
604------------------------------------------------------------------------
605--
606-- * used in multiple locations
607------------------------------------------------------------------------
608function luaK:dischargevars(fs, e)
609 local k = e.k
610 if k == "VLOCAL" then
611 e.k = "VNONRELOC"
612 elseif k == "VUPVAL" then
613 e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0)
614 e.k = "VRELOCABLE"
615 elseif k == "VGLOBAL" then
616 e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info)
617 e.k = "VRELOCABLE"
618 elseif k == "VINDEXED" then
619 self:freereg(fs, e.aux)
620 self:freereg(fs, e.info)
621 e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux)
622 e.k = "VRELOCABLE"
623 elseif k == "VVARARG" or k == "VCALL" then
624 self:setoneret(fs, e)
625 else
626 -- there is one value available (somewhere)
627 end
628end
629
630------------------------------------------------------------------------
631--
632-- * used only in luaK:exp2reg()
633------------------------------------------------------------------------
634function luaK:code_label(fs, A, b, jump)
635 self:getlabel(fs) -- those instructions may be jump targets
636 return self:codeABC(fs, "OP_LOADBOOL", A, b, jump)
637end
638
639------------------------------------------------------------------------
640--
641-- * used in luaK:discharge2anyreg(), luaK:exp2reg()
642------------------------------------------------------------------------
643function luaK:discharge2reg(fs, e, reg)
644 self:dischargevars(fs, e)
645 local k = e.k
646 if k == "VNIL" then
647 self:_nil(fs, reg, 1)
648 elseif k == "VFALSE" or k == "VTRUE" then
649 self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0)
650 elseif k == "VK" then
651 self:codeABx(fs, "OP_LOADK", reg, e.info)
652 elseif k == "VKNUM" then
653 self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval))
654 elseif k == "VRELOCABLE" then
655 local pc = self:getcode(fs, e)
656 luaP:SETARG_A(pc, reg)
657 elseif k == "VNONRELOC" then
658 if reg ~= e.info then
659 self:codeABC(fs, "OP_MOVE", reg, e.info, 0)
660 end
661 else
662 assert(e.k == "VVOID" or e.k == "VJMP")
663 return -- nothing to do...
664 end
665 e.info = reg
666 e.k = "VNONRELOC"
667end
668
669------------------------------------------------------------------------
670--
671-- * used in luaK:jumponcond(), luaK:codenot()
672------------------------------------------------------------------------
673function luaK:discharge2anyreg(fs, e)
674 if e.k ~= "VNONRELOC" then
675 self:reserveregs(fs, 1)
676 self:discharge2reg(fs, e, fs.freereg - 1)
677 end
678end
679
680------------------------------------------------------------------------
681--
682-- * used in luaK:exp2nextreg(), luaK:exp2anyreg(), luaK:storevar()
683------------------------------------------------------------------------
684function luaK:exp2reg(fs, e, reg)
685 self:discharge2reg(fs, e, reg)
686 if e.k == "VJMP" then
687 e.t = self:concat(fs, e.t, e.info) -- put this jump in 't' list
688 end
689 if self:hasjumps(e) then
690 local final -- position after whole expression
691 local p_f = self.NO_JUMP -- position of an eventual LOAD false
692 local p_t = self.NO_JUMP -- position of an eventual LOAD true
693 if self:need_value(fs, e.t) or self:need_value(fs, e.f) then
694 local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs)
695 p_f = self:code_label(fs, reg, 0, 1)
696 p_t = self:code_label(fs, reg, 1, 0)
697 self:patchtohere(fs, fj)
698 end
699 final = self:getlabel(fs)
700 self:patchlistaux(fs, e.f, final, reg, p_f)
701 self:patchlistaux(fs, e.t, final, reg, p_t)
702 end
703 e.f, e.t = self.NO_JUMP, self.NO_JUMP
704 e.info = reg
705 e.k = "VNONRELOC"
706end
707
708------------------------------------------------------------------------
709--
710-- * used in multiple locations
711------------------------------------------------------------------------
712function luaK:exp2nextreg(fs, e)
713 self:dischargevars(fs, e)
714 self:freeexp(fs, e)
715 self:reserveregs(fs, 1)
716 self:exp2reg(fs, e, fs.freereg - 1)
717end
718
719------------------------------------------------------------------------
720--
721-- * used in multiple locations
722------------------------------------------------------------------------
723function luaK:exp2anyreg(fs, e)
724 self:dischargevars(fs, e)
725 if e.k == "VNONRELOC" then
726 if not self:hasjumps(e) then -- exp is already in a register
727 return e.info
728 end
729 if e.info >= fs.nactvar then -- reg. is not a local?
730 self:exp2reg(fs, e, e.info) -- put value on it
731 return e.info
732 end
733 end
734 self:exp2nextreg(fs, e) -- default
735 return e.info
736end
737
738------------------------------------------------------------------------
739--
740-- * used in luaK:exp2RK(), luaK:prefix(), luaK:posfix()
741-- * used in (lparser) luaY:yindex()
742------------------------------------------------------------------------
743function luaK:exp2val(fs, e)
744 if self:hasjumps(e) then
745 self:exp2anyreg(fs, e)
746 else
747 self:dischargevars(fs, e)
748 end
749end
750
751------------------------------------------------------------------------
752--
753-- * used in multiple locations
754------------------------------------------------------------------------
755function luaK:exp2RK(fs, e)
756 self:exp2val(fs, e)
757 local k = e.k
758 if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then
759 if fs.nk <= luaP.MAXINDEXRK then -- constant fit in RK operand?
760 -- converted from a 2-deep ternary operator expression
761 if e.k == "VNIL" then
762 e.info = self:nilK(fs)
763 else
764 e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval)
765 or self:boolK(fs, e.k == "VTRUE")
766 end
767 e.k = "VK"
768 return luaP:RKASK(e.info)
769 end
770 elseif k == "VK" then
771 if e.info <= luaP.MAXINDEXRK then -- constant fit in argC?
772 return luaP:RKASK(e.info)
773 end
774 else
775 -- default
776 end
777 -- not a constant in the right range: put it in a register
778 return self:exp2anyreg(fs, e)
779end
780
781------------------------------------------------------------------------
782--
783-- * used in (lparser) luaY:assignment(), luaY:localfunc(), luaY:funcstat()
784------------------------------------------------------------------------
785function luaK:storevar(fs, var, ex)
786 local k = var.k
787 if k == "VLOCAL" then
788 self:freeexp(fs, ex)
789 self:exp2reg(fs, ex, var.info)
790 return
791 elseif k == "VUPVAL" then
792 local e = self:exp2anyreg(fs, ex)
793 self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0)
794 elseif k == "VGLOBAL" then
795 local e = self:exp2anyreg(fs, ex)
796 self:codeABx(fs, "OP_SETGLOBAL", e, var.info)
797 elseif k == "VINDEXED" then
798 local e = self:exp2RK(fs, ex)
799 self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e)
800 else
801 assert(0) -- invalid var kind to store
802 end
803 self:freeexp(fs, ex)
804end
805
806------------------------------------------------------------------------
807--
808-- * used only in (lparser) luaY:primaryexp()
809------------------------------------------------------------------------
810function luaK:_self(fs, e, key)
811 self:exp2anyreg(fs, e)
812 self:freeexp(fs, e)
813 local func = fs.freereg
814 self:reserveregs(fs, 2)
815 self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key))
816 self:freeexp(fs, key)
817 e.info = func
818 e.k = "VNONRELOC"
819end
820
821------------------------------------------------------------------------
822--
823-- * used in luaK:goiftrue(), luaK:codenot()
824------------------------------------------------------------------------
825function luaK:invertjump(fs, e)
826 local pc = self:getjumpcontrol(fs, e.info)
827 assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and
828 luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and
829 luaP:GET_OPCODE(pc) ~= "OP_TEST")
830 luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0)
831end
832
833------------------------------------------------------------------------
834--
835-- * used in luaK:goiftrue(), luaK:goiffalse()
836------------------------------------------------------------------------
837function luaK:jumponcond(fs, e, cond)
838 if e.k == "VRELOCABLE" then
839 local ie = self:getcode(fs, e)
840 if luaP:GET_OPCODE(ie) == "OP_NOT" then
841 fs.pc = fs.pc - 1 -- remove previous OP_NOT
842 return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1)
843 end
844 -- else go through
845 end
846 self:discharge2anyreg(fs, e)
847 self:freeexp(fs, e)
848 return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0)
849end
850
851------------------------------------------------------------------------
852--
853-- * used in luaK:infix(), (lparser) luaY:cond()
854------------------------------------------------------------------------
855function luaK:goiftrue(fs, e)
856 local pc -- pc of last jump
857 self:dischargevars(fs, e)
858 local k = e.k
859 if k == "VK" or k == "VKNUM" or k == "VTRUE" then
860 pc = self.NO_JUMP -- always true; do nothing
861 elseif k == "VFALSE" then
862 pc = self:jump(fs) -- always jump
863 elseif k == "VJMP" then
864 self:invertjump(fs, e)
865 pc = e.info
866 else
867 pc = self:jumponcond(fs, e, false)
868 end
869 e.f = self:concat(fs, e.f, pc) -- insert last jump in `f' list
870 self:patchtohere(fs, e.t)
871 e.t = self.NO_JUMP
872end
873
874------------------------------------------------------------------------
875--
876-- * used in luaK:infix()
877------------------------------------------------------------------------
878function luaK:goiffalse(fs, e)
879 local pc -- pc of last jump
880 self:dischargevars(fs, e)
881 local k = e.k
882 if k == "VNIL" or k == "VFALSE"then
883 pc = self.NO_JUMP -- always false; do nothing
884 elseif k == "VTRUE" then
885 pc = self:jump(fs) -- always jump
886 elseif k == "VJMP" then
887 pc = e.info
888 else
889 pc = self:jumponcond(fs, e, true)
890 end
891 e.t = self:concat(fs, e.t, pc) -- insert last jump in `t' list
892 self:patchtohere(fs, e.f)
893 e.f = self.NO_JUMP
894end
895
896------------------------------------------------------------------------
897--
898-- * used only in luaK:prefix()
899------------------------------------------------------------------------
900function luaK:codenot(fs, e)
901 self:dischargevars(fs, e)
902 local k = e.k
903 if k == "VNIL" or k == "VFALSE" then
904 e.k = "VTRUE"
905 elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then
906 e.k = "VFALSE"
907 elseif k == "VJMP" then
908 self:invertjump(fs, e)
909 elseif k == "VRELOCABLE" or k == "VNONRELOC" then
910 self:discharge2anyreg(fs, e)
911 self:freeexp(fs, e)
912 e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0)
913 e.k = "VRELOCABLE"
914 else
915 assert(0) -- cannot happen
916 end
917 -- interchange true and false lists
918 e.f, e.t = e.t, e.f
919 self:removevalues(fs, e.f)
920 self:removevalues(fs, e.t)
921end
922
923------------------------------------------------------------------------
924--
925-- * used in (lparser) luaY:field(), luaY:primaryexp()
926------------------------------------------------------------------------
927function luaK:indexed(fs, t, k)
928 t.aux = self:exp2RK(fs, k)
929 t.k = "VINDEXED"
930end
931
932------------------------------------------------------------------------
933--
934-- * used only in luaK:codearith()
935------------------------------------------------------------------------
936function luaK:constfolding(op, e1, e2)
937 local r
938 if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end
939 local v1 = e1.nval
940 local v2 = e2.nval
941 if op == "OP_ADD" then
942 r = self:numadd(v1, v2)
943 elseif op == "OP_SUB" then
944 r = self:numsub(v1, v2)
945 elseif op == "OP_MUL" then
946 r = self:nummul(v1, v2)
947 elseif op == "OP_DIV" then
948 if v2 == 0 then return false end -- do not attempt to divide by 0
949 r = self:numdiv(v1, v2)
950 elseif op == "OP_MOD" then
951 if v2 == 0 then return false end -- do not attempt to divide by 0
952 r = self:nummod(v1, v2)
953 elseif op == "OP_POW" then
954 r = self:numpow(v1, v2)
955 elseif op == "OP_UNM" then
956 r = self:numunm(v1)
957 elseif op == "OP_LEN" then
958 return false -- no constant folding for 'len'
959 else
960 assert(0)
961 r = 0
962 end
963 if self:numisnan(r) then return false end -- do not attempt to produce NaN
964 e1.nval = r
965 return true
966end
967
968------------------------------------------------------------------------
969--
970-- * used in luaK:prefix(), luaK:posfix()
971------------------------------------------------------------------------
972function luaK:codearith(fs, op, e1, e2)
973 if self:constfolding(op, e1, e2) then
974 return
975 else
976 local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0
977 local o1 = self:exp2RK(fs, e1)
978 if o1 > o2 then
979 self:freeexp(fs, e1)
980 self:freeexp(fs, e2)
981 else
982 self:freeexp(fs, e2)
983 self:freeexp(fs, e1)
984 end
985 e1.info = self:codeABC(fs, op, 0, o1, o2)
986 e1.k = "VRELOCABLE"
987 end
988end
989
990------------------------------------------------------------------------
991--
992-- * used only in luaK:posfix()
993------------------------------------------------------------------------
994function luaK:codecomp(fs, op, cond, e1, e2)
995 local o1 = self:exp2RK(fs, e1)
996 local o2 = self:exp2RK(fs, e2)
997 self:freeexp(fs, e2)
998 self:freeexp(fs, e1)
999 if cond == 0 and op ~= "OP_EQ" then
1000 -- exchange args to replace by `<' or `<='
1001 o1, o2 = o2, o1 -- o1 <==> o2
1002 cond = 1
1003 end
1004 e1.info = self:condjump(fs, op, cond, o1, o2)
1005 e1.k = "VJMP"
1006end
1007
1008------------------------------------------------------------------------
1009--
1010-- * used only in (lparser) luaY:subexpr()
1011------------------------------------------------------------------------
1012function luaK:prefix(fs, op, e)
1013 local e2 = {} -- expdesc
1014 e2.t, e2.f = self.NO_JUMP, self.NO_JUMP
1015 e2.k = "VKNUM"
1016 e2.nval = 0
1017 if op == "OPR_MINUS" then
1018 if not self:isnumeral(e) then
1019 self:exp2anyreg(fs, e) -- cannot operate on non-numeric constants
1020 end
1021 self:codearith(fs, "OP_UNM", e, e2)
1022 elseif op == "OPR_NOT" then
1023 self:codenot(fs, e)
1024 elseif op == "OPR_LEN" then
1025 self:exp2anyreg(fs, e) -- cannot operate on constants
1026 self:codearith(fs, "OP_LEN", e, e2)
1027 else
1028 assert(0)
1029 end
1030end
1031
1032------------------------------------------------------------------------
1033--
1034-- * used only in (lparser) luaY:subexpr()
1035------------------------------------------------------------------------
1036function luaK:infix(fs, op, v)
1037 if op == "OPR_AND" then
1038 self:goiftrue(fs, v)
1039 elseif op == "OPR_OR" then
1040 self:goiffalse(fs, v)
1041 elseif op == "OPR_CONCAT" then
1042 self:exp2nextreg(fs, v) -- operand must be on the 'stack'
1043 elseif op == "OPR_ADD" or op == "OPR_SUB" or
1044 op == "OPR_MUL" or op == "OPR_DIV" or
1045 op == "OPR_MOD" or op == "OPR_POW" then
1046 if not self:isnumeral(v) then self:exp2RK(fs, v) end
1047 else
1048 self:exp2RK(fs, v)
1049 end
1050end
1051
1052------------------------------------------------------------------------
1053--
1054-- * used only in (lparser) luaY:subexpr()
1055------------------------------------------------------------------------
1056-- table lookups to simplify testing
1057luaK.arith_op = {
1058 OPR_ADD = "OP_ADD", OPR_SUB = "OP_SUB", OPR_MUL = "OP_MUL",
1059 OPR_DIV = "OP_DIV", OPR_MOD = "OP_MOD", OPR_POW = "OP_POW",
1060}
1061luaK.comp_op = {
1062 OPR_EQ = "OP_EQ", OPR_NE = "OP_EQ", OPR_LT = "OP_LT",
1063 OPR_LE = "OP_LE", OPR_GT = "OP_LT", OPR_GE = "OP_LE",
1064}
1065luaK.comp_cond = {
1066 OPR_EQ = 1, OPR_NE = 0, OPR_LT = 1,
1067 OPR_LE = 1, OPR_GT = 0, OPR_GE = 0,
1068}
1069function luaK:posfix(fs, op, e1, e2)
1070 -- needed because e1 = e2 doesn't copy values...
1071 -- * in 5.0.x, only k/info/aux/t/f copied, t for AND, f for OR
1072 -- but here, all elements are copied for completeness' sake
1073 local function copyexp(e1, e2)
1074 e1.k = e2.k
1075 e1.info = e2.info; e1.aux = e2.aux
1076 e1.nval = e2.nval
1077 e1.t = e2.t; e1.f = e2.f
1078 end
1079 if op == "OPR_AND" then
1080 assert(e1.t == self.NO_JUMP) -- list must be closed
1081 self:dischargevars(fs, e2)
1082 e2.f = self:concat(fs, e2.f, e1.f)
1083 copyexp(e1, e2)
1084 elseif op == "OPR_OR" then
1085 assert(e1.f == self.NO_JUMP) -- list must be closed
1086 self:dischargevars(fs, e2)
1087 e2.t = self:concat(fs, e2.t, e1.t)
1088 copyexp(e1, e2)
1089 elseif op == "OPR_CONCAT" then
1090 self:exp2val(fs, e2)
1091 if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then
1092 assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1)
1093 self:freeexp(fs, e1)
1094 luaP:SETARG_B(self:getcode(fs, e2), e1.info)
1095 e1.k = "VRELOCABLE"
1096 e1.info = e2.info
1097 else
1098 self:exp2nextreg(fs, e2) -- operand must be on the 'stack'
1099 self:codearith(fs, "OP_CONCAT", e1, e2)
1100 end
1101 else
1102 -- the following uses a table lookup in place of conditionals
1103 local arith = self.arith_op[op]
1104 if arith then
1105 self:codearith(fs, arith, e1, e2)
1106 else
1107 local comp = self.comp_op[op]
1108 if comp then
1109 self:codecomp(fs, comp, self.comp_cond[op], e1, e2)
1110 else
1111 assert(0)
1112 end
1113 end--if arith
1114 end--if op
1115end
1116
1117------------------------------------------------------------------------
1118-- adjusts debug information for last instruction written, in order to
1119-- change the line where item comes into existence
1120-- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat()
1121------------------------------------------------------------------------
1122function luaK:fixline(fs, line)
1123 fs.f.lineinfo[fs.pc - 1] = line
1124end
1125
1126------------------------------------------------------------------------
1127-- general function to write an instruction into the instruction buffer,
1128-- sets debug information too
1129-- * used in luaK:codeABC(), luaK:codeABx()
1130-- * called directly by (lparser) luaY:whilestat()
1131------------------------------------------------------------------------
1132function luaK:code(fs, i, line)
1133 local f = fs.f
1134 self:dischargejpc(fs) -- 'pc' will change
1135 -- put new instruction in code array
1136 luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil,
1137 luaY.MAX_INT, "code size overflow")
1138 f.code[fs.pc] = i
1139 -- save corresponding line information
1140 luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil,
1141 luaY.MAX_INT, "code size overflow")
1142 f.lineinfo[fs.pc] = line
1143 local pc = fs.pc
1144 fs.pc = fs.pc + 1
1145 return pc
1146end
1147
1148------------------------------------------------------------------------
1149-- writes an instruction of type ABC
1150-- * calls luaK:code()
1151------------------------------------------------------------------------
1152function luaK:codeABC(fs, o, a, b, c)
1153 assert(luaP:getOpMode(o) == luaP.OpMode.iABC)
1154 assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0)
1155 assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0)
1156 return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline)
1157end
1158
1159------------------------------------------------------------------------
1160-- writes an instruction of type ABx
1161-- * calls luaK:code(), called by luaK:codeAsBx()
1162------------------------------------------------------------------------
1163function luaK:codeABx(fs, o, a, bc)
1164 assert(luaP:getOpMode(o) == luaP.OpMode.iABx or
1165 luaP:getOpMode(o) == luaP.OpMode.iAsBx)
1166 assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN)
1167 return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline)
1168end
1169
1170------------------------------------------------------------------------
1171--
1172-- * used in (lparser) luaY:closelistfield(), luaY:lastlistfield()
1173------------------------------------------------------------------------
1174function luaK:setlist(fs, base, nelems, tostore)
1175 local c = math.floor((nelems - 1)/luaP.LFIELDS_PER_FLUSH) + 1
1176 local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore
1177 assert(tostore ~= 0)
1178 if c <= luaP.MAXARG_C then
1179 self:codeABC(fs, "OP_SETLIST", base, b, c)
1180 else
1181 self:codeABC(fs, "OP_SETLIST", base, b, 0)
1182 self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline)
1183 end
1184 fs.freereg = base + 1 -- free registers with list values
1185end
1186
1187return function(a) luaY = a return luaK end
1188
1189
1190------------------------------------------------------
1191
1192
1193
1194--[[--------------------------------------------------------------------
1195
1196 lopcodes.lua
1197 Lua 5 virtual machine opcodes in Lua
1198 This file is part of Yueliang.
1199
1200 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
1201 The COPYRIGHT file describes the conditions
1202 under which this software may be distributed.
1203
1204 See the ChangeLog for more information.
1205
1206----------------------------------------------------------------------]]
1207
1208--[[--------------------------------------------------------------------
1209-- Notes:
1210-- * an Instruction is a table with OP, A, B, C, Bx elements; this
1211-- makes the code easy to follow and should allow instruction handling
1212-- to work with doubles and ints
1213-- * WARNING luaP:Instruction outputs instructions encoded in little-
1214-- endian form and field size and positions are hard-coded
1215--
1216-- Not implemented:
1217-- *
1218--
1219-- Added:
1220-- * luaP:CREATE_Inst(c): create an inst from a number (for OP_SETLIST)
1221-- * luaP:Instruction(i): convert field elements to a 4-char string
1222-- * luaP:DecodeInst(x): convert 4-char string into field elements
1223--
1224-- Changed in 5.1.x:
1225-- * POS_OP added, instruction field positions changed
1226-- * some symbol names may have changed, e.g. LUAI_BITSINT
1227-- * new operators for RK indices: BITRK, ISK(x), INDEXK(r), RKASK(x)
1228-- * OP_MOD, OP_LEN is new
1229-- * OP_TEST is now OP_TESTSET, OP_TEST is new
1230-- * OP_FORLOOP, OP_TFORLOOP adjusted, OP_FORPREP is new
1231-- * OP_TFORPREP deleted
1232-- * OP_SETLIST and OP_SETLISTO merged and extended
1233-- * OP_VARARG is new
1234-- * many changes to implementation of OpMode data
1235----------------------------------------------------------------------]]
1236
1237local luaP = {}
1238
1239--[[
1240===========================================================================
1241 We assume that instructions are unsigned numbers.
1242 All instructions have an opcode in the first 6 bits.
1243 Instructions can have the following fields:
1244 'A' : 8 bits
1245 'B' : 9 bits
1246 'C' : 9 bits
1247 'Bx' : 18 bits ('B' and 'C' together)
1248 'sBx' : signed Bx
1249
1250 A signed argument is represented in excess K; that is, the number
1251 value is the unsigned value minus K. K is exactly the maximum value
1252 for that argument (so that -max is represented by 0, and +max is
1253 represented by 2*max), which is half the maximum for the corresponding
1254 unsigned argument.
1255===========================================================================
1256--]]
1257
1258luaP.OpMode = { iABC = 0, iABx = 1, iAsBx = 2 } -- basic instruction format
1259
1260------------------------------------------------------------------------
1261-- size and position of opcode arguments.
1262-- * WARNING size and position is hard-coded elsewhere in this script
1263------------------------------------------------------------------------
1264luaP.SIZE_C = 9
1265luaP.SIZE_B = 9
1266luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
1267luaP.SIZE_A = 8
1268
1269luaP.SIZE_OP = 6
1270
1271luaP.POS_OP = 0
1272luaP.POS_A = luaP.POS_OP + luaP.SIZE_OP
1273luaP.POS_C = luaP.POS_A + luaP.SIZE_A
1274luaP.POS_B = luaP.POS_C + luaP.SIZE_C
1275luaP.POS_Bx = luaP.POS_C
1276
1277------------------------------------------------------------------------
1278-- limits for opcode arguments.
1279-- we use (signed) int to manipulate most arguments,
1280-- so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
1281------------------------------------------------------------------------
1282-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
1283-- running on a Lua VM with double or int as LUA_NUMBER
1284
1285luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
1286luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
1287
1288luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
1289luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
1290luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
1291
1292-- creates a mask with 'n' 1 bits at position 'p'
1293-- MASK1(n,p) deleted, not required
1294-- creates a mask with 'n' 0 bits at position 'p'
1295-- MASK0(n,p) deleted, not required
1296
1297--[[--------------------------------------------------------------------
1298 Visual representation for reference:
1299
1300 31 | | | 0 bit position
1301 +-----+-----+-----+----------+
1302 | B | C | A | Opcode | iABC format
1303 +-----+-----+-----+----------+
1304 - 9 - 9 - 8 - 6 - field sizes
1305 +-----+-----+-----+----------+
1306 | [s]Bx | A | Opcode | iABx | iAsBx format
1307 +-----+-----+-----+----------+
1308
1309----------------------------------------------------------------------]]
1310
1311------------------------------------------------------------------------
1312-- the following macros help to manipulate instructions
1313-- * changed to a table object representation, very clean compared to
1314-- the [nightmare] alternatives of using a number or a string
1315-- * Bx is a separate element from B and C, since there is never a need
1316-- to split Bx in the parser or code generator
1317------------------------------------------------------------------------
1318
1319-- these accept or return opcodes in the form of string names
1320function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
1321function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
1322
1323function luaP:GETARG_A(i) return i.A end
1324function luaP:SETARG_A(i, u) i.A = u end
1325
1326function luaP:GETARG_B(i) return i.B end
1327function luaP:SETARG_B(i, b) i.B = b end
1328
1329function luaP:GETARG_C(i) return i.C end
1330function luaP:SETARG_C(i, b) i.C = b end
1331
1332function luaP:GETARG_Bx(i) return i.Bx end
1333function luaP:SETARG_Bx(i, b) i.Bx = b end
1334
1335function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
1336function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
1337
1338function luaP:CREATE_ABC(o,a,b,c)
1339 return {OP = self.OpCode[o], A = a, B = b, C = c}
1340end
1341
1342function luaP:CREATE_ABx(o,a,bc)
1343 return {OP = self.OpCode[o], A = a, Bx = bc}
1344end
1345
1346------------------------------------------------------------------------
1347-- create an instruction from a number (for OP_SETLIST)
1348------------------------------------------------------------------------
1349function luaP:CREATE_Inst(c)
1350 local o = c % 64
1351 c = (c - o) / 64
1352 local a = c % 256
1353 c = (c - a) / 256
1354 return self:CREATE_ABx(o, a, c)
1355end
1356
1357------------------------------------------------------------------------
1358-- returns a 4-char string little-endian encoded form of an instruction
1359------------------------------------------------------------------------
1360function luaP:Instruction(i)
1361 if i.Bx then
1362 -- change to OP/A/B/C format
1363 i.C = i.Bx % 512
1364 i.B = (i.Bx - i.C) / 512
1365 end
1366 local I = i.A * 64 + i.OP
1367 local c0 = I % 256
1368 I = i.C * 64 + (I - c0) / 256 -- 6 bits of A left
1369 local c1 = I % 256
1370 I = i.B * 128 + (I - c1) / 256 -- 7 bits of C left
1371 local c2 = I % 256
1372 local c3 = (I - c2) / 256
1373 return string.char(c0, c1, c2, c3)
1374end
1375
1376------------------------------------------------------------------------
1377-- decodes a 4-char little-endian string into an instruction struct
1378------------------------------------------------------------------------
1379function luaP:DecodeInst(x)
1380 local byte = string.byte
1381 local i = {}
1382 local I = byte(x, 1)
1383 local op = I % 64
1384 i.OP = op
1385 I = byte(x, 2) * 4 + (I - op) / 64 -- 2 bits of c0 left
1386 local a = I % 256
1387 i.A = a
1388 I = byte(x, 3) * 4 + (I - a) / 256 -- 2 bits of c1 left
1389 local c = I % 512
1390 i.C = c
1391 i.B = byte(x, 4) * 2 + (I - c) / 512 -- 1 bits of c2 left
1392 local opmode = self.OpMode[tonumber(string.sub(self.opmodes[op + 1], 7, 7))]
1393 if opmode ~= "iABC" then
1394 i.Bx = i.B * 512 + i.C
1395 end
1396 return i
1397end
1398
1399------------------------------------------------------------------------
1400-- Macros to operate RK indices
1401-- * these use arithmetic instead of bit ops
1402------------------------------------------------------------------------
1403
1404-- this bit 1 means constant (0 means register)
1405luaP.BITRK = math.ldexp(1, luaP.SIZE_B - 1)
1406
1407-- test whether value is a constant
1408function luaP:ISK(x) return x >= self.BITRK end
1409
1410-- gets the index of the constant
1411function luaP:INDEXK(x) return x - self.BITRK end
1412
1413luaP.MAXINDEXRK = luaP.BITRK - 1
1414
1415-- code a constant index as a RK value
1416function luaP:RKASK(x) return x + self.BITRK end
1417
1418------------------------------------------------------------------------
1419-- invalid register that fits in 8 bits
1420------------------------------------------------------------------------
1421luaP.NO_REG = luaP.MAXARG_A
1422
1423------------------------------------------------------------------------
1424-- R(x) - register
1425-- Kst(x) - constant (in constant table)
1426-- RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
1427------------------------------------------------------------------------
1428
1429------------------------------------------------------------------------
1430-- grep "ORDER OP" if you change these enums
1431------------------------------------------------------------------------
1432
1433--[[--------------------------------------------------------------------
1434Lua virtual machine opcodes (enum OpCode):
1435------------------------------------------------------------------------
1436name args description
1437------------------------------------------------------------------------
1438OP_MOVE A B R(A) := R(B)
1439OP_LOADK A Bx R(A) := Kst(Bx)
1440OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++
1441OP_LOADNIL A B R(A) := ... := R(B) := nil
1442OP_GETUPVAL A B R(A) := UpValue[B]
1443OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
1444OP_GETTABLE A B C R(A) := R(B)[RK(C)]
1445OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
1446OP_SETUPVAL A B UpValue[B] := R(A)
1447OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
1448OP_NEWTABLE A B C R(A) := {} (size = B,C)
1449OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
1450OP_ADD A B C R(A) := RK(B) + RK(C)
1451OP_SUB A B C R(A) := RK(B) - RK(C)
1452OP_MUL A B C R(A) := RK(B) * RK(C)
1453OP_DIV A B C R(A) := RK(B) / RK(C)
1454OP_MOD A B C R(A) := RK(B) % RK(C)
1455OP_POW A B C R(A) := RK(B) ^ RK(C)
1456OP_UNM A B R(A) := -R(B)
1457OP_NOT A B R(A) := not R(B)
1458OP_LEN A B R(A) := length of R(B)
1459OP_CONCAT A B C R(A) := R(B).. ... ..R(C)
1460OP_JMP sBx pc+=sBx
1461OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++
1462OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++
1463OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++
1464OP_TEST A C if not (R(A) <=> C) then pc++
1465OP_TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else pc++
1466OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
1467OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1))
1468OP_RETURN A B return R(A), ... ,R(A+B-2) (see note)
1469OP_FORLOOP A sBx R(A)+=R(A+2);
1470 if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
1471OP_FORPREP A sBx R(A)-=R(A+2); pc+=sBx
1472OP_TFORLOOP A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
1473 if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++
1474OP_SETLIST A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
1475OP_CLOSE A close all variables in the stack up to (>=) R(A)
1476OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
1477OP_VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg
1478----------------------------------------------------------------------]]
1479
1480luaP.opnames = {} -- opcode names
1481luaP.OpCode = {} -- lookup name -> number
1482luaP.ROpCode = {} -- lookup number -> name
1483
1484------------------------------------------------------------------------
1485-- ORDER OP
1486------------------------------------------------------------------------
1487local i = 0
1488for v in string.gmatch([[
1489MOVE LOADK LOADBOOL LOADNIL GETUPVAL
1490GETGLOBAL GETTABLE SETGLOBAL SETUPVAL SETTABLE
1491NEWTABLE SELF ADD SUB MUL
1492DIV MOD POW UNM NOT
1493LEN CONCAT JMP EQ LT
1494LE TEST TESTSET CALL TAILCALL
1495RETURN FORLOOP FORPREP TFORLOOP SETLIST
1496CLOSE CLOSURE VARARG
1497]], "%S+") do
1498 local n = "OP_"..v
1499 luaP.opnames[i] = v
1500 luaP.OpCode[n] = i
1501 luaP.ROpCode[i] = n
1502 i = i + 1
1503end
1504luaP.NUM_OPCODES = i
1505
1506--[[
1507===========================================================================
1508 Notes:
1509 (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
1510 and can be 0: OP_CALL then sets 'top' to last_result+1, so
1511 next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
1512 (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
1513 set top (like in OP_CALL with C == 0).
1514 (*) In OP_RETURN, if (B == 0) then return up to 'top'
1515 (*) In OP_SETLIST, if (B == 0) then B = 'top';
1516 if (C == 0) then next 'instruction' is real C
1517 (*) For comparisons, A specifies what condition the test should accept
1518 (true or false).
1519 (*) All 'skips' (pc++) assume that next instruction is a jump
1520===========================================================================
1521--]]
1522
1523--[[--------------------------------------------------------------------
1524 masks for instruction properties. The format is:
1525 bits 0-1: op mode
1526 bits 2-3: C arg mode
1527 bits 4-5: B arg mode
1528 bit 6: instruction set register A
1529 bit 7: operator is a test
1530
1531 for OpArgMask:
1532 OpArgN - argument is not used
1533 OpArgU - argument is used
1534 OpArgR - argument is a register or a jump offset
1535 OpArgK - argument is a constant or register/constant
1536----------------------------------------------------------------------]]
1537
1538-- was enum OpArgMask
1539luaP.OpArgMask = { OpArgN = 0, OpArgU = 1, OpArgR = 2, OpArgK = 3 }
1540
1541------------------------------------------------------------------------
1542-- e.g. to compare with symbols, luaP:getOpMode(...) == luaP.OpCode.iABC
1543-- * accepts opcode parameter as strings, e.g. "OP_MOVE"
1544------------------------------------------------------------------------
1545
1546function luaP:getOpMode(m)
1547 return self.opmodes[self.OpCode[m]] % 4
1548end
1549
1550function luaP:getBMode(m)
1551 return math.floor(self.opmodes[self.OpCode[m]] / 16) % 4
1552end
1553
1554function luaP:getCMode(m)
1555 return math.floor(self.opmodes[self.OpCode[m]] / 4) % 4
1556end
1557
1558function luaP:testAMode(m)
1559 return math.floor(self.opmodes[self.OpCode[m]] / 64) % 2
1560end
1561
1562function luaP:testTMode(m)
1563 return math.floor(self.opmodes[self.OpCode[m]] / 128)
1564end
1565
1566-- luaP_opnames[] is set above, as the luaP.opnames table
1567
1568-- number of list items to accumulate before a SETLIST instruction
1569luaP.LFIELDS_PER_FLUSH = 50
1570
1571------------------------------------------------------------------------
1572-- build instruction properties array
1573-- * deliberately coded to look like the C equivalent
1574------------------------------------------------------------------------
1575local function opmode(t, a, b, c, m)
1576 local luaP = luaP
1577 return t * 128 + a * 64 +
1578 luaP.OpArgMask[b] * 16 + luaP.OpArgMask[c] * 4 + luaP.OpMode[m]
1579end
1580
1581-- ORDER OP
1582luaP.opmodes = {
1583-- T A B C mode opcode
1584 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_LOADK
1585 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_LOADBOOL
1586 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LOADNIL
1587 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_GETUPVAL
1588 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_GETGLOBAL
1589 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_GETTABLE
1590 opmode(0, 0, "OpArgK", "OpArgN", "iABx"), -- OP_SETGLOBAL
1591 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_SETUPVAL
1592 opmode(0, 0, "OpArgK", "OpArgK", "iABC"), -- OP_SETTABLE
1593 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_NEWTABLE
1594 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_SELF
1595 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_ADD
1596 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_SUB
1597 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MUL
1598 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_DIV
1599 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MOD
1600 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_POW
1601 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_UNM
1602 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_NOT
1603 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LEN
1604 opmode(0, 1, "OpArgR", "OpArgR", "iABC"), -- OP_CONCAT
1605 opmode(0, 0, "OpArgR", "OpArgN", "iAsBx"), -- OP_JMP
1606 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_EQ
1607 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LT
1608 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LE
1609 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TEST
1610 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TESTSET
1611 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_CALL
1612 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_TAILCALL
1613 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_RETURN
1614 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORLOOP
1615 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORPREP
1616 opmode(1, 0, "OpArgN", "OpArgU", "iABC"), -- OP_TFORLOOP
1617 opmode(0, 0, "OpArgU", "OpArgU", "iABC"), -- OP_SETLIST
1618 opmode(0, 0, "OpArgN", "OpArgN", "iABC"), -- OP_CLOSE
1619 opmode(0, 1, "OpArgU", "OpArgN", "iABx"), -- OP_CLOSURE
1620 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_VARARG
1621}
1622-- an awkward way to set a zero-indexed table...
1623luaP.opmodes[0] =
1624 opmode(0, 1, "OpArgR", "OpArgN", "iABC") -- OP_MOVE
1625
1626return luaP
1627
1628
1629
1630-------------------------------------------
1631
1632
1633--[[--------------------------------------------------------------------
1634
1635 ldump.lua
1636 Save precompiled Lua chunks
1637 This file is part of Yueliang.
1638
1639 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
1640 The COPYRIGHT file describes the conditions
1641 under which this software may be distributed.
1642
1643 See the ChangeLog for more information.
1644
1645----------------------------------------------------------------------]]
1646
1647--[[--------------------------------------------------------------------
1648-- Notes:
1649-- * WARNING! byte order (little endian) and data type sizes for header
1650-- signature values hard-coded; see luaU:header
1651-- * chunk writer generators are included, see below
1652-- * one significant difference is that instructions are still in table
1653-- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
1654-- convert them into 4-char strings
1655--
1656-- Not implemented:
1657-- * DumpVar, DumpMem has been removed
1658-- * DumpVector folded into folded into DumpDebug, DumpCode
1659--
1660-- Added:
1661-- * for convenience, the following two functions have been added:
1662-- luaU:make_setS: create a chunk writer that writes to a string
1663-- luaU:make_setF: create a chunk writer that writes to a file
1664-- (lua.h contains a typedef for lua_Writer/lua_Chunkwriter, and
1665-- a Lua-based implementation exists, writer() in lstrlib.c)
1666-- * luaU:ttype(o) (from lobject.h)
1667-- * for converting number types to its binary equivalent:
1668-- luaU:from_double(x): encode double value for writing
1669-- luaU:from_int(x): encode integer value for writing
1670-- (error checking is limited for these conversion functions)
1671-- (double conversion does not support denormals or NaNs)
1672--
1673-- Changed in 5.1.x:
1674-- * the dumper was mostly rewritten in Lua 5.1.x, so notes on the
1675-- differences between 5.0.x and 5.1.x is limited
1676-- * LUAC_VERSION bumped to 0x51, LUAC_FORMAT added
1677-- * developer is expected to adjust LUAC_FORMAT in order to identify
1678-- non-standard binary chunk formats
1679-- * header signature code is smaller, has been simplified, and is
1680-- tested as a single unit; its logic is shared with the undumper
1681-- * no more endian conversion, invalid endianness mean rejection
1682-- * opcode field sizes are no longer exposed in the header
1683-- * code moved to front of a prototype, followed by constants
1684-- * debug information moved to the end of the binary chunk, and the
1685-- relevant functions folded into a single function
1686-- * luaU:dump returns a writer status code
1687-- * chunk writer now implements status code because dumper uses it
1688-- * luaU:endianness removed
1689----------------------------------------------------------------------]]
1690
1691--requires luaP
1692local luaU = {}
1693local luaP = require(script.Parent.LuaP)
1694
1695-- mark for precompiled code ('<esc>Lua') (from lua.h)
1696luaU.LUA_SIGNATURE = "\27Lua"
1697
1698-- constants used by dumper (from lua.h)
1699luaU.LUA_TNUMBER = 3
1700luaU.LUA_TSTRING = 4
1701luaU.LUA_TNIL = 0
1702luaU.LUA_TBOOLEAN = 1
1703luaU.LUA_TNONE = -1
1704
1705-- constants for header of binary files (from lundump.h)
1706luaU.LUAC_VERSION = 0x51 -- this is Lua 5.1
1707luaU.LUAC_FORMAT = 0 -- this is the official format
1708luaU.LUAC_HEADERSIZE = 12 -- size of header of binary files
1709
1710--[[--------------------------------------------------------------------
1711-- Additional functions to handle chunk writing
1712-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
1713----------------------------------------------------------------------]]
1714
1715------------------------------------------------------------------------
1716-- create a chunk writer that writes to a string
1717-- * returns the writer function and a table containing the string
1718-- * to get the final result, look in buff.data
1719------------------------------------------------------------------------
1720function luaU:make_setS()
1721 local buff = {}
1722 buff.data = ""
1723 local writer =
1724 function(s, buff) -- chunk writer
1725 if not s then return 0 end
1726 buff.data = buff.data..s
1727 return 0
1728 end
1729 return writer, buff
1730end
1731
1732------------------------------------------------------------------------
1733-- create a chunk writer that writes to a file
1734-- * returns the writer function and a table containing the file handle
1735-- * if a nil is passed, then writer should close the open file
1736------------------------------------------------------------------------
1737
1738--[[
1739function luaU:make_setF(filename)
1740 local buff = {}
1741 buff.h = io.open(filename, "wb")
1742 if not buff.h then return nil end
1743 local writer =
1744 function(s, buff) -- chunk writer
1745 if not buff.h then return 0 end
1746 if not s then
1747 if buff.h:close() then return 0 end
1748 else
1749 if buff.h:write(s) then return 0 end
1750 end
1751 return 1
1752 end
1753 return writer, buff
1754end--]]
1755
1756------------------------------------------------------------------------
1757-- works like the lobject.h version except that TObject used in these
1758-- scripts only has a 'value' field, no 'tt' field (native types used)
1759------------------------------------------------------------------------
1760function luaU:ttype(o)
1761 local tt = type(o.value)
1762 if tt == "number" then return self.LUA_TNUMBER
1763 elseif tt == "string" then return self.LUA_TSTRING
1764 elseif tt == "nil" then return self.LUA_TNIL
1765 elseif tt == "boolean" then return self.LUA_TBOOLEAN
1766 else
1767 return self.LUA_TNONE -- the rest should not appear
1768 end
1769end
1770
1771-----------------------------------------------------------------------
1772-- converts a IEEE754 double number to an 8-byte little-endian string
1773-- * luaU:from_double() and luaU:from_int() are adapted from ChunkBake
1774-- * supports +/- Infinity, but not denormals or NaNs
1775-----------------------------------------------------------------------
1776function luaU:from_double(x)
1777 local function grab_byte(v)
1778 local c = v % 256
1779 return (v - c) / 256, string.char(c)
1780 end
1781 local sign = 0
1782 if x < 0 then sign = 1; x = -x end
1783 local mantissa, exponent = math.frexp(x)
1784 if x == 0 then -- zero
1785 mantissa, exponent = 0, 0
1786 elseif x == 1/0 then
1787 mantissa, exponent = 0, 2047
1788 else
1789 mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
1790 exponent = exponent + 1022
1791 end
1792 local v, byte = "" -- convert to bytes
1793 x = math.floor(mantissa)
1794 for i = 1,6 do
1795 x, byte = grab_byte(x); v = v..byte -- 47:0
1796 end
1797 x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
1798 x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
1799 return v
1800end
1801
1802-----------------------------------------------------------------------
1803-- converts a number to a little-endian 32-bit integer string
1804-- * input value assumed to not overflow, can be signed/unsigned
1805-----------------------------------------------------------------------
1806function luaU:from_int(x)
1807 local v = ""
1808 x = math.floor(x)
1809 if x < 0 then x = 4294967296 + x end -- ULONG_MAX+1
1810 for i = 1, 4 do
1811 local c = x % 256
1812 v = v..string.char(c); x = math.floor(x / 256)
1813 end
1814 return v
1815end
1816
1817--[[--------------------------------------------------------------------
1818-- Functions to make a binary chunk
1819-- * many functions have the size parameter removed, since output is
1820-- in the form of a string and some sizes are implicit or hard-coded
1821----------------------------------------------------------------------]]
1822
1823--[[--------------------------------------------------------------------
1824-- struct DumpState:
1825-- L -- lua_State (not used in this script)
1826-- writer -- lua_Writer (chunk writer function)
1827-- data -- void* (chunk writer context or data already written)
1828-- strip -- if true, don't write any debug information
1829-- status -- if non-zero, an error has occured
1830----------------------------------------------------------------------]]
1831
1832------------------------------------------------------------------------
1833-- dumps a block of bytes
1834-- * lua_unlock(D.L), lua_lock(D.L) unused
1835------------------------------------------------------------------------
1836function luaU:DumpBlock(b, D)
1837 if D.status == 0 then
1838 -- lua_unlock(D->L);
1839 D.status = D.write(b, D.data)
1840 -- lua_lock(D->L);
1841 end
1842end
1843
1844------------------------------------------------------------------------
1845-- dumps a char
1846------------------------------------------------------------------------
1847function luaU:DumpChar(y, D)
1848 self:DumpBlock(string.char(y), D)
1849end
1850
1851------------------------------------------------------------------------
1852-- dumps a 32-bit signed or unsigned integer (for int) (hard-coded)
1853------------------------------------------------------------------------
1854function luaU:DumpInt(x, D)
1855 self:DumpBlock(self:from_int(x), D)
1856end
1857
1858------------------------------------------------------------------------
1859-- dumps a lua_Number (hard-coded as a double)
1860------------------------------------------------------------------------
1861function luaU:DumpNumber(x, D)
1862 self:DumpBlock(self:from_double(x), D)
1863end
1864
1865------------------------------------------------------------------------
1866-- dumps a Lua string (size type is hard-coded)
1867------------------------------------------------------------------------
1868function luaU:DumpString(s, D)
1869 if s == nil then
1870 self:DumpInt(0, D)
1871 else
1872 s = s.."\0" -- include trailing '\0'
1873 self:DumpInt(#s, D)
1874 self:DumpBlock(s, D)
1875 end
1876end
1877
1878------------------------------------------------------------------------
1879-- dumps instruction block from function prototype
1880------------------------------------------------------------------------
1881function luaU:DumpCode(f, D)
1882 local n = f.sizecode
1883 --was DumpVector
1884 self:DumpInt(n, D)
1885 for i = 0, n - 1 do
1886 self:DumpBlock(luaP:Instruction(f.code[i]), D)
1887 end
1888end
1889
1890------------------------------------------------------------------------
1891-- dump constant pool from function prototype
1892-- * bvalue(o), nvalue(o) and rawtsvalue(o) macros removed
1893------------------------------------------------------------------------
1894function luaU:DumpConstants(f, D)
1895 local n = f.sizek
1896 self:DumpInt(n, D)
1897 for i = 0, n - 1 do
1898 local o = f.k[i] -- TValue
1899 local tt = self:ttype(o)
1900 self:DumpChar(tt, D)
1901 if tt == self.LUA_TNIL then
1902 elseif tt == self.LUA_TBOOLEAN then
1903 self:DumpChar(o.value and 1 or 0, D)
1904 elseif tt == self.LUA_TNUMBER then
1905 self:DumpNumber(o.value, D)
1906 elseif tt == self.LUA_TSTRING then
1907 self:DumpString(o.value, D)
1908 else
1909 --lua_assert(0) -- cannot happen
1910 end
1911 end
1912 n = f.sizep
1913 self:DumpInt(n, D)
1914 for i = 0, n - 1 do
1915 self:DumpFunction(f.p[i], f.source, D)
1916 end
1917end
1918
1919------------------------------------------------------------------------
1920-- dump debug information
1921------------------------------------------------------------------------
1922function luaU:DumpDebug(f, D)
1923 local n
1924 n = D.strip and 0 or f.sizelineinfo -- dump line information
1925 --was DumpVector
1926 self:DumpInt(n, D)
1927 for i = 0, n - 1 do
1928 self:DumpInt(f.lineinfo[i], D)
1929 end
1930 n = D.strip and 0 or f.sizelocvars -- dump local information
1931 self:DumpInt(n, D)
1932 for i = 0, n - 1 do
1933 self:DumpString(f.locvars[i].varname, D)
1934 self:DumpInt(f.locvars[i].startpc, D)
1935 self:DumpInt(f.locvars[i].endpc, D)
1936 end
1937 n = D.strip and 0 or f.sizeupvalues -- dump upvalue information
1938 self:DumpInt(n, D)
1939 for i = 0, n - 1 do
1940 self:DumpString(f.upvalues[i], D)
1941 end
1942end
1943
1944------------------------------------------------------------------------
1945-- dump child function prototypes from function prototype
1946------------------------------------------------------------------------
1947function luaU:DumpFunction(f, p, D)
1948 local source = f.source
1949 if source == p or D.strip then source = nil end
1950 self:DumpString(source, D)
1951 self:DumpInt(f.lineDefined, D)
1952 self:DumpInt(f.lastlinedefined, D)
1953 self:DumpChar(f.nups, D)
1954 self:DumpChar(f.numparams, D)
1955 self:DumpChar(f.is_vararg, D)
1956 self:DumpChar(f.maxstacksize, D)
1957 self:DumpCode(f, D)
1958 self:DumpConstants(f, D)
1959 self:DumpDebug(f, D)
1960end
1961
1962------------------------------------------------------------------------
1963-- dump Lua header section (some sizes hard-coded)
1964------------------------------------------------------------------------
1965function luaU:DumpHeader(D)
1966 local h = self:header()
1967 assert(#h == self.LUAC_HEADERSIZE) -- fixed buffer now an assert
1968 self:DumpBlock(h, D)
1969end
1970
1971------------------------------------------------------------------------
1972-- make header (from lundump.c)
1973-- returns the header string
1974------------------------------------------------------------------------
1975function luaU:header()
1976 local x = 1
1977 return self.LUA_SIGNATURE..
1978 string.char(
1979 self.LUAC_VERSION,
1980 self.LUAC_FORMAT,
1981 x, -- endianness (1=little)
1982 4, -- sizeof(int)
1983 4, -- sizeof(size_t)
1984 4, -- sizeof(Instruction)
1985 8, -- sizeof(lua_Number)
1986 0) -- is lua_Number integral?
1987end
1988
1989------------------------------------------------------------------------
1990-- dump Lua function as precompiled chunk
1991-- (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
1992-- * w, data are created from make_setS, make_setF
1993------------------------------------------------------------------------
1994function luaU:dump(L, f, w, data, strip)
1995 local D = {} -- DumpState
1996 D.L = L
1997 D.write = w
1998 D.data = data
1999 D.strip = strip
2000 D.status = 0
2001 self:DumpHeader(D)
2002 self:DumpFunction(f, nil, D)
2003 -- added: for a chunk writer writing to a file, this final call with
2004 -- nil data is to indicate to the writer to close the file
2005 D.write(nil, D.data)
2006 return D.status
2007end
2008
2009return luaU
2010
2011
2012-------------------------------------
2013
2014
2015
2016--[[--------------------------------------------------------------------
2017
2018 llex.lua
2019 Lua lexical analyzer in Lua
2020 This file is part of Yueliang.
2021
2022 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
2023 The COPYRIGHT file describes the conditions
2024 under which this software may be distributed.
2025
2026 See the ChangeLog for more information.
2027
2028----------------------------------------------------------------------]]
2029
2030--[[--------------------------------------------------------------------
2031-- Notes:
2032-- * intended to 'imitate' llex.c code; performance is not a concern
2033-- * tokens are strings; code structure largely retained
2034-- * deleted stuff (compared to llex.c) are noted, comments retained
2035-- * nextc() returns the currently read character to simplify coding
2036-- here; next() in llex.c does not return anything
2037-- * compatibility code is marked with "--#" comments
2038--
2039-- Added:
2040-- * luaX:chunkid (function luaO_chunkid from lobject.c)
2041-- * luaX:str2d (function luaO_str2d from lobject.c)
2042-- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
2043-- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
2044-- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
2045--
2046-- To use the lexer:
2047-- (1) luaX:init() to initialize the lexer
2048-- (2) luaX:setinput() to set the input stream to lex
2049-- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
2050-- until "TK_EOS": luaX:next()
2051-- * since EOZ is returned as a string, be careful when regexp testing
2052--
2053-- Not implemented:
2054-- * luaX_newstring: not required by this Lua implementation
2055-- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
2056-- in the interest of performance
2057-- * locale-aware number handling is largely redundant as Lua's
2058-- tonumber() function is already capable of this
2059--
2060-- Changed in 5.1.x:
2061-- * TK_NAME token order moved down
2062-- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
2063-- * token struct renamed to lower case (LS -> ls)
2064-- * LexState struct: removed nestlevel, added decpoint
2065-- * error message functions have been greatly simplified
2066-- * token2string renamed to luaX_tokens, exposed in llex.h
2067-- * lexer now handles all kinds of newlines, including CRLF
2068-- * shbang first line handling removed from luaX:setinput;
2069-- it is now done in lauxlib.c (luaL_loadfile)
2070-- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
2071-- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
2072-- * checkbuffer(ls, len) macro deleted
2073-- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
2074-- luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
2075-- * luaX:read_numeral is now more promiscuous in slurping characters;
2076-- hexadecimal numbers was added, locale-aware decimal points too
2077-- * luaX:skip_sep is new; used by luaX:read_long_string
2078-- * luaX:read_long_string handles new-style long blocks, with some
2079-- optional compatibility code
2080-- * luaX:llex: parts changed to support new-style long blocks
2081-- * luaX:llex: readname functionality has been folded in
2082-- * luaX:llex: removed test for control characters
2083--
2084--------------------------------------------------------------------]]
2085
2086local luaZ = require(script.Parent.LuaZ)
2087
2088local luaX = {}
2089
2090-- FIRST_RESERVED is not required as tokens are manipulated as strings
2091-- TOKEN_LEN deleted; maximum length of a reserved word not needed
2092
2093------------------------------------------------------------------------
2094-- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
2095------------------------------------------------------------------------
2096
2097-- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
2098-- other terminal symbols: TK_NAME to TK_EOS
2099luaX.RESERVED = [[
2100TK_AND and
2101TK_BREAK break
2102TK_DO do
2103TK_ELSE else
2104TK_ELSEIF elseif
2105TK_END end
2106TK_FALSE false
2107TK_FOR for
2108TK_FUNCTION function
2109TK_IF if
2110TK_IN in
2111TK_LOCAL local
2112TK_NIL nil
2113TK_NOT not
2114TK_OR or
2115TK_REPEAT repeat
2116TK_RETURN return
2117TK_THEN then
2118TK_TRUE true
2119TK_UNTIL until
2120TK_WHILE while
2121TK_CONCAT ..
2122TK_DOTS ...
2123TK_EQ ==
2124TK_GE >=
2125TK_LE <=
2126TK_NE ~=
2127TK_NAME <name>
2128TK_NUMBER <number>
2129TK_STRING <string>
2130TK_EOS <eof>]]
2131
2132-- NUM_RESERVED is not required; number of reserved words
2133
2134--[[--------------------------------------------------------------------
2135-- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
2136-- so that lexer functions can use its table element, ls.t.seminfo
2137--
2138-- SemInfo (struct no longer needed, a mixed-type value is used)
2139--
2140-- Token (struct of ls.t and ls.lookahead):
2141-- token -- token symbol
2142-- seminfo -- semantics information
2143--
2144-- LexState (struct of ls; ls is initialized by luaX:setinput):
2145-- current -- current character (charint)
2146-- linenumber -- input line counter
2147-- lastline -- line of last token 'consumed'
2148-- t -- current token (table: struct Token)
2149-- lookahead -- look ahead token (table: struct Token)
2150-- fs -- 'FuncState' is private to the parser
2151-- L -- LuaState
2152-- z -- input stream
2153-- buff -- buffer for tokens
2154-- source -- current source name
2155-- decpoint -- locale decimal point
2156-- nestlevel -- level of nested non-terminals
2157----------------------------------------------------------------------]]
2158
2159-- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init
2160
2161luaX.MAXSRC = 80
2162luaX.MAX_INT = 2147483645 -- constants from elsewhere (see above)
2163luaX.LUA_QS = "'%s'"
2164luaX.LUA_COMPAT_LSTR = 1
2165--luaX.MAX_SIZET = 4294967293
2166
2167------------------------------------------------------------------------
2168-- initialize lexer
2169-- * original luaX_init has code to create and register token strings
2170-- * luaX.tokens: TK_* -> token
2171-- * luaX.enums: token -> TK_* (used in luaX:llex)
2172------------------------------------------------------------------------
2173function luaX:init()
2174 local tokens, enums = {}, {}
2175 for v in string.gmatch(self.RESERVED, "[^\n]+") do
2176 local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
2177 tokens[tok] = str
2178 enums[str] = tok
2179 end
2180 self.tokens = tokens
2181 self.enums = enums
2182end
2183
2184------------------------------------------------------------------------
2185-- returns a suitably-formatted chunk name or id
2186-- * from lobject.c, used in llex.c and ldebug.c
2187-- * the result, out, is returned (was first argument)
2188------------------------------------------------------------------------
2189function luaX:chunkid(source, bufflen)
2190 local out
2191 local first = string.sub(source, 1, 1)
2192 if first == "=" then
2193 out = string.sub(source, 2, bufflen) -- remove first char
2194 else -- out = "source", or "...source"
2195 if first == "@" then
2196 source = string.sub(source, 2) -- skip the '@'
2197 bufflen = bufflen - #" '...' "
2198 local l = #source
2199 out = ""
2200 if l > bufflen then
2201 source = string.sub(source, 1 + l - bufflen) -- get last part of file name
2202 out = out.."..."
2203 end
2204 out = out..source
2205 else -- out = [string "string"]
2206 local len = string.find(source, "[\n\r]") -- stop at first newline
2207 len = len and (len - 1) or #source
2208 bufflen = bufflen - #(" [string \"...\"] ")
2209 if len > bufflen then len = bufflen end
2210 out = "[string \""
2211 if len < #source then -- must truncate?
2212 out = out..string.sub(source, 1, len).."..."
2213 else
2214 out = out..source
2215 end
2216 out = out.."\"]"
2217 end
2218 end
2219 return out
2220end
2221
2222--[[--------------------------------------------------------------------
2223-- Support functions for lexer
2224-- * all lexer errors eventually reaches lexerror:
2225 syntaxerror -> lexerror
2226----------------------------------------------------------------------]]
2227
2228------------------------------------------------------------------------
2229-- look up token and return keyword if found (also called by parser)
2230------------------------------------------------------------------------
2231function luaX:token2str(ls, token)
2232 if string.sub(token, 1, 3) ~= "TK_" then
2233 if string.find(token, "%c") then
2234 return string.format("char(%d)", string.byte(token))
2235 end
2236 return token
2237 else
2238 end
2239 return self.tokens[token]
2240end
2241
2242------------------------------------------------------------------------
2243-- throws a lexer error
2244-- * txtToken has been made local to luaX:lexerror
2245-- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
2246------------------------------------------------------------------------
2247function luaX:lexerror(ls, msg, token)
2248 local function txtToken(ls, token)
2249 if token == "TK_NAME" or
2250 token == "TK_STRING" or
2251 token == "TK_NUMBER" then
2252 return ls.buff
2253 else
2254 return self:token2str(ls, token)
2255 end
2256 end
2257 local buff = self:chunkid(ls.source, self.MAXSRC)
2258 local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
2259 if token then
2260 msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
2261 end
2262 -- luaD_throw(ls->L, LUA_ERRSYNTAX)
2263 error(msg)
2264end
2265
2266------------------------------------------------------------------------
2267-- throws a syntax error (mainly called by parser)
2268-- * ls.t.token has to be set by the function calling luaX:llex
2269-- (see luaX:next and luaX:lookahead elsewhere in this file)
2270------------------------------------------------------------------------
2271function luaX:syntaxerror(ls, msg)
2272 self:lexerror(ls, msg, ls.t.token)
2273end
2274
2275------------------------------------------------------------------------
2276-- move on to next line
2277------------------------------------------------------------------------
2278function luaX:currIsNewline(ls)
2279 return ls.current == "\n" or ls.current == "\r"
2280end
2281
2282function luaX:inclinenumber(ls)
2283 local old = ls.current
2284 -- lua_assert(currIsNewline(ls))
2285 self:nextc(ls) -- skip '\n' or '\r'
2286 if self:currIsNewline(ls) and ls.current ~= old then
2287 self:nextc(ls) -- skip '\n\r' or '\r\n'
2288 end
2289 ls.linenumber = ls.linenumber + 1
2290 if ls.linenumber >= self.MAX_INT then
2291 self:syntaxerror(ls, "chunk has too many lines")
2292 end
2293end
2294
2295------------------------------------------------------------------------
2296-- initializes an input stream for lexing
2297-- * if ls (the lexer state) is passed as a table, then it is filled in,
2298-- otherwise it has to be retrieved as a return value
2299-- * LUA_MINBUFFER not used; buffer handling not required any more
2300------------------------------------------------------------------------
2301function luaX:setinput(L, ls, z, source)
2302 if not ls then ls = {} end -- create struct
2303 if not ls.lookahead then ls.lookahead = {} end
2304 if not ls.t then ls.t = {} end
2305 ls.decpoint = "."
2306 ls.L = L
2307 ls.lookahead.token = "TK_EOS" -- no look-ahead token
2308 ls.z = z
2309 ls.fs = nil
2310 ls.linenumber = 1
2311 ls.lastline = 1
2312 ls.source = source
2313 self:nextc(ls) -- read first char
2314end
2315
2316--[[--------------------------------------------------------------------
2317-- LEXICAL ANALYZER
2318----------------------------------------------------------------------]]
2319
2320------------------------------------------------------------------------
2321-- checks if current character read is found in the set 'set'
2322------------------------------------------------------------------------
2323function luaX:check_next(ls, set)
2324 if not string.find(set, ls.current, 1, 1) then
2325 return false
2326 end
2327 self:save_and_next(ls)
2328 return true
2329end
2330
2331------------------------------------------------------------------------
2332-- retrieve next token, checking the lookahead buffer if necessary
2333-- * note that the macro next(ls) in llex.c is now luaX:nextc
2334-- * utilized used in lparser.c (various places)
2335------------------------------------------------------------------------
2336function luaX:next(ls)
2337 ls.lastline = ls.linenumber
2338 if ls.lookahead.token ~= "TK_EOS" then -- is there a look-ahead token?
2339 -- this must be copy-by-value
2340 ls.t.seminfo = ls.lookahead.seminfo -- use this one
2341 ls.t.token = ls.lookahead.token
2342 ls.lookahead.token = "TK_EOS" -- and discharge it
2343 else
2344 ls.t.token = self:llex(ls, ls.t) -- read next token
2345 end
2346end
2347
2348------------------------------------------------------------------------
2349-- fill in the lookahead buffer
2350-- * utilized used in lparser.c:constructor
2351------------------------------------------------------------------------
2352function luaX:lookahead(ls)
2353 -- lua_assert(ls.lookahead.token == "TK_EOS")
2354 ls.lookahead.token = self:llex(ls, ls.lookahead)
2355end
2356
2357------------------------------------------------------------------------
2358-- gets the next character and returns it
2359-- * this is the next() macro in llex.c; see notes at the beginning
2360------------------------------------------------------------------------
2361function luaX:nextc(ls)
2362 local c = luaZ:zgetc(ls.z)
2363 ls.current = c
2364 return c
2365end
2366
2367------------------------------------------------------------------------
2368-- saves the given character into the token buffer
2369-- * buffer handling code removed, not used in this implementation
2370-- * test for maximum token buffer length not used, makes things faster
2371------------------------------------------------------------------------
2372
2373function luaX:save(ls, c)
2374 local buff = ls.buff
2375 -- if you want to use this, please uncomment luaX.MAX_SIZET further up
2376 --if #buff > self.MAX_SIZET then
2377 -- self:lexerror(ls, "lexical element too long")
2378 --end
2379 ls.buff = buff..c
2380end
2381
2382------------------------------------------------------------------------
2383-- save current character into token buffer, grabs next character
2384-- * like luaX:nextc, returns the character read for convenience
2385------------------------------------------------------------------------
2386function luaX:save_and_next(ls)
2387 self:save(ls, ls.current)
2388 return self:nextc(ls)
2389end
2390
2391------------------------------------------------------------------------
2392-- LUA_NUMBER
2393-- * luaX:read_numeral is the main lexer function to read a number
2394-- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
2395------------------------------------------------------------------------
2396
2397------------------------------------------------------------------------
2398-- string to number converter (was luaO_str2d from lobject.c)
2399-- * returns the number, nil if fails (originally returns a boolean)
2400-- * conversion function originally lua_str2number(s,p), a macro which
2401-- maps to the strtod() function by default (from luaconf.h)
2402------------------------------------------------------------------------
2403function luaX:str2d(s)
2404 local result = tonumber(s)
2405 if result then return result end
2406 -- conversion failed
2407 if string.lower(string.sub(s, 1, 2)) == "0x" then -- maybe an hexadecimal constant?
2408 result = tonumber(s, 16)
2409 if result then return result end -- most common case
2410 -- Was: invalid trailing characters?
2411 -- In C, this function then skips over trailing spaces.
2412 -- true is returned if nothing else is found except for spaces.
2413 -- If there is still something else, then it returns a false.
2414 -- All this is not necessary using Lua's tonumber.
2415 end
2416 return nil
2417end
2418
2419------------------------------------------------------------------------
2420-- single-character replacement, for locale-aware decimal points
2421------------------------------------------------------------------------
2422function luaX:buffreplace(ls, from, to)
2423 local result, buff = "", ls.buff
2424 for p = 1, #buff do
2425 local c = string.sub(buff, p, p)
2426 if c == from then c = to end
2427 result = result..c
2428 end
2429 ls.buff = result
2430end
2431
2432------------------------------------------------------------------------
2433-- Attempt to convert a number by translating '.' decimal points to
2434-- the decimal point character used by the current locale. This is not
2435-- needed in Yueliang as Lua's tonumber() is already locale-aware.
2436-- Instead, the code is here in case the user implements localeconv().
2437------------------------------------------------------------------------
2438function luaX:trydecpoint(ls, Token)
2439 -- format error: try to update decimal point separator
2440 local old = ls.decpoint
2441 -- translate the following to Lua if you implement localeconv():
2442 -- struct lconv *cv = localeconv();
2443 -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
2444 self:buffreplace(ls, old, ls.decpoint) -- try updated decimal separator
2445 local seminfo = self:str2d(ls.buff)
2446 Token.seminfo = seminfo
2447 if not seminfo then
2448 -- format error with correct decimal point: no more options
2449 self:buffreplace(ls, ls.decpoint, ".") -- undo change (for error message)
2450 self:lexerror(ls, "malformed number", "TK_NUMBER")
2451 end
2452end
2453
2454------------------------------------------------------------------------
2455-- main number conversion function
2456-- * "^%w$" needed in the scan in order to detect "EOZ"
2457------------------------------------------------------------------------
2458function luaX:read_numeral(ls, Token)
2459 -- lua_assert(string.find(ls.current, "%d"))
2460 repeat
2461 self:save_and_next(ls)
2462 until string.find(ls.current, "%D") and ls.current ~= "."
2463 if self:check_next(ls, "Ee") then -- 'E'?
2464 self:check_next(ls, "+-") -- optional exponent sign
2465 end
2466 while string.find(ls.current, "^%w$") or ls.current == "_" do
2467 self:save_and_next(ls)
2468 end
2469 self:buffreplace(ls, ".", ls.decpoint) -- follow locale for decimal point
2470 local seminfo = self:str2d(ls.buff)
2471 Token.seminfo = seminfo
2472 if not seminfo then -- format error?
2473 self:trydecpoint(ls, Token) -- try to update decimal point separator
2474 end
2475end
2476
2477------------------------------------------------------------------------
2478-- count separators ("=") in a long string delimiter
2479-- * used by luaX:read_long_string
2480------------------------------------------------------------------------
2481function luaX:skip_sep(ls)
2482 local count = 0
2483 local s = ls.current
2484 -- lua_assert(s == "[" or s == "]")
2485 self:save_and_next(ls)
2486 while ls.current == "=" do
2487 self:save_and_next(ls)
2488 count = count + 1
2489 end
2490 return (ls.current == s) and count or (-count) - 1
2491end
2492
2493------------------------------------------------------------------------
2494-- reads a long string or long comment
2495------------------------------------------------------------------------
2496function luaX:read_long_string(ls, Token, sep)
2497 local cont = 0
2498 self:save_and_next(ls) -- skip 2nd '['
2499 if self:currIsNewline(ls) then -- string starts with a newline?
2500 self:inclinenumber(ls) -- skip it
2501 end
2502 while true do
2503 local c = ls.current
2504 if c == "EOZ" then
2505 self:lexerror(ls, Token and "unfinished long string" or
2506 "unfinished long comment", "TK_EOS")
2507 elseif c == "[" then
2508 --# compatibility code start
2509 if self.LUA_COMPAT_LSTR then
2510 if self:skip_sep(ls) == sep then
2511 self:save_and_next(ls) -- skip 2nd '['
2512 cont = cont + 1
2513 --# compatibility code start
2514 if self.LUA_COMPAT_LSTR == 1 then
2515 if sep == 0 then
2516 self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
2517 end
2518 end
2519 --# compatibility code end
2520 end
2521 end
2522 --# compatibility code end
2523 elseif c == "]" then
2524 if self:skip_sep(ls) == sep then
2525 self:save_and_next(ls) -- skip 2nd ']'
2526 --# compatibility code start
2527 if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
2528 cont = cont - 1
2529 if sep == 0 and cont >= 0 then break end
2530 end
2531 --# compatibility code end
2532 break
2533 end
2534 elseif self:currIsNewline(ls) then
2535 self:save(ls, "\n")
2536 self:inclinenumber(ls)
2537 if not Token then ls.buff = "" end -- avoid wasting space
2538 else -- default
2539 if Token then
2540 self:save_and_next(ls)
2541 else
2542 self:nextc(ls)
2543 end
2544 end--if c
2545 end--while
2546 if Token then
2547 local p = 3 + sep
2548 Token.seminfo = string.sub(ls.buff, p, -p)
2549 end
2550end
2551
2552------------------------------------------------------------------------
2553-- reads a string
2554-- * has been restructured significantly compared to the original C code
2555------------------------------------------------------------------------
2556
2557function luaX:read_string(ls, del, Token)
2558 self:save_and_next(ls)
2559 while ls.current ~= del do
2560 local c = ls.current
2561 if c == "EOZ" then
2562 self:lexerror(ls, "unfinished string", "TK_EOS")
2563 elseif self:currIsNewline(ls) then
2564 self:lexerror(ls, "unfinished string", "TK_STRING")
2565 elseif c == "\\" then
2566 c = self:nextc(ls) -- do not save the '\'
2567 if self:currIsNewline(ls) then -- go through
2568 self:save(ls, "\n")
2569 self:inclinenumber(ls)
2570 elseif c ~= "EOZ" then -- will raise an error next loop
2571 -- escapes handling greatly simplified here:
2572 local i = string.find("abfnrtv", c, 1, 1)
2573 if i then
2574 self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
2575 self:nextc(ls)
2576 elseif not string.find(c, "%d") then
2577 self:save_and_next(ls) -- handles \\, \", \', and \?
2578 else -- \xxx
2579 c, i = 0, 0
2580 repeat
2581 c = 10 * c + ls.current
2582 self:nextc(ls)
2583 i = i + 1
2584 until i >= 3 or not string.find(ls.current, "%d")
2585 if c > 255 then -- UCHAR_MAX
2586 self:lexerror(ls, "escape sequence too large", "TK_STRING")
2587 end
2588 self:save(ls, string.char(c))
2589 end
2590 end
2591 else
2592 self:save_and_next(ls)
2593 end--if c
2594 end--while
2595 self:save_and_next(ls) -- skip delimiter
2596 Token.seminfo = string.sub(ls.buff, 2, -2)
2597end
2598
2599------------------------------------------------------------------------
2600-- main lexer function
2601------------------------------------------------------------------------
2602function luaX:llex(ls, Token)
2603 ls.buff = ""
2604 while true do
2605 local c = ls.current
2606 ----------------------------------------------------------------
2607 if self:currIsNewline(ls) then
2608 self:inclinenumber(ls)
2609 ----------------------------------------------------------------
2610 elseif c == "-" then
2611 c = self:nextc(ls)
2612 if c ~= "-" then return "-" end
2613 -- else is a comment
2614 local sep = -1
2615 if self:nextc(ls) == '[' then
2616 sep = self:skip_sep(ls)
2617 ls.buff = "" -- 'skip_sep' may dirty the buffer
2618 end
2619 if sep >= 0 then
2620 self:read_long_string(ls, nil, sep) -- long comment
2621 ls.buff = ""
2622 else -- else short comment
2623 while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
2624 self:nextc(ls)
2625 end
2626 end
2627 ----------------------------------------------------------------
2628 elseif c == "[" then
2629 local sep = self:skip_sep(ls)
2630 if sep >= 0 then
2631 self:read_long_string(ls, Token, sep)
2632 return "TK_STRING"
2633 elseif sep == -1 then
2634 return "["
2635 else
2636 self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
2637 end
2638 ----------------------------------------------------------------
2639 elseif c == "=" then
2640 c = self:nextc(ls)
2641 if c ~= "=" then return "="
2642 else self:nextc(ls); return "TK_EQ" end
2643 ----------------------------------------------------------------
2644 elseif c == "<" then
2645 c = self:nextc(ls)
2646 if c ~= "=" then return "<"
2647 else self:nextc(ls); return "TK_LE" end
2648 ----------------------------------------------------------------
2649 elseif c == ">" then
2650 c = self:nextc(ls)
2651 if c ~= "=" then return ">"
2652 else self:nextc(ls); return "TK_GE" end
2653 ----------------------------------------------------------------
2654 elseif c == "~" then
2655 c = self:nextc(ls)
2656 if c ~= "=" then return "~"
2657 else self:nextc(ls); return "TK_NE" end
2658 ----------------------------------------------------------------
2659 elseif c == "\"" or c == "'" then
2660 self:read_string(ls, c, Token)
2661 return "TK_STRING"
2662 ----------------------------------------------------------------
2663 elseif c == "." then
2664 c = self:save_and_next(ls)
2665 if self:check_next(ls, ".") then
2666 if self:check_next(ls, ".") then
2667 return "TK_DOTS" -- ...
2668 else return "TK_CONCAT" -- ..
2669 end
2670 elseif not string.find(c, "%d") then
2671 return "."
2672 else
2673 self:read_numeral(ls, Token)
2674 return "TK_NUMBER"
2675 end
2676 ----------------------------------------------------------------
2677 elseif c == "EOZ" then
2678 return "TK_EOS"
2679 ----------------------------------------------------------------
2680 else -- default
2681 if string.find(c, "%s") then
2682 -- lua_assert(self:currIsNewline(ls))
2683 self:nextc(ls)
2684 elseif string.find(c, "%d") then
2685 self:read_numeral(ls, Token)
2686 return "TK_NUMBER"
2687 elseif string.find(c, "[_%a]") then
2688 -- identifier or reserved word
2689 repeat
2690 c = self:save_and_next(ls)
2691 until c == "EOZ" or not string.find(c, "[_%w]")
2692 local ts = ls.buff
2693 local tok = self.enums[ts]
2694 if tok then return tok end -- reserved word?
2695 Token.seminfo = ts
2696 return "TK_NAME"
2697 else
2698 self:nextc(ls)
2699 return c -- single-char tokens (+ - / ...)
2700 end
2701 ----------------------------------------------------------------
2702 end--if c
2703 end--while
2704end
2705
2706return luaX
2707
2708
2709-----------------------------------------------------
2710
2711
2712--[[--------------------------------------------------------------------
2713
2714 lparser.lua
2715 Lua 5 parser in Lua
2716 This file is part of Yueliang.
2717
2718 Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
2719 The COPYRIGHT file describes the conditions
2720 under which this software may be distributed.
2721
2722 See the ChangeLog for more information.
2723
2724----------------------------------------------------------------------]]
2725
2726--[[--------------------------------------------------------------------
2727-- Notes:
2728-- * some unused C code that were not converted are kept as comments
2729-- * LUA_COMPAT_VARARG option changed into a comment block
2730-- * for value/size specific code added, look for 'NOTE: '
2731--
2732-- Not implemented:
2733-- * luaX_newstring not needed by this Lua implementation
2734-- * luaG_checkcode() in assert is not currently implemented
2735--
2736-- Added:
2737-- * some constants added from various header files
2738-- * luaY.LUA_QS used in error_expected, check_match (from luaconf.h)
2739-- * luaY:LUA_QL needed for error messages (from luaconf.h)
2740-- * luaY:growvector (from lmem.h) -- skeleton only, limit checking
2741-- * luaY.SHRT_MAX (from <limits.h>) for registerlocalvar
2742-- * luaY:newproto (from lfunc.c)
2743-- * luaY:int2fb (from lobject.c)
2744-- * NOTE: HASARG_MASK, for implementing a VARARG_HASARG bit operation
2745-- * NOTE: value-specific code for VARARG_NEEDSARG to replace a bitop
2746--
2747-- Changed in 5.1.x:
2748-- * various code changes are not detailed...
2749-- * names of constants may have changed, e.g. added a LUAI_ prefix
2750-- * struct expkind: added VKNUM, VVARARG; VCALL's info changed?
2751-- * struct expdesc: added nval
2752-- * struct FuncState: upvalues data type changed to upvaldesc
2753-- * macro hasmultret is new
2754-- * function checklimit moved to parser from lexer
2755-- * functions anchor_token, errorlimit, checknext are new
2756-- * checknext is new, equivalent to 5.0.x's check, see check too
2757-- * luaY:next and luaY:lookahead moved to lexer
2758-- * break keyword no longer skipped in luaY:breakstat
2759-- * function new_localvarstr replaced by new_localvarliteral
2760-- * registerlocalvar limits local variables to SHRT_MAX
2761-- * create_local deleted, new_localvarliteral used instead
2762-- * constant LUAI_MAXUPVALUES increased to 60
2763-- * constants MAXPARAMS, LUA_MAXPARSERLEVEL, MAXSTACK removed
2764-- * function interface changed: singlevaraux, singlevar
2765-- * enterlevel and leavelevel uses nCcalls to track call depth
2766-- * added a name argument to main entry function, luaY:parser
2767-- * function luaY_index changed to yindex
2768-- * luaY:int2fb()'s table size encoding format has been changed
2769-- * luaY:log2() no longer needed for table constructors
2770-- * function code_params deleted, functionality folded in parlist
2771-- * vararg flags handling (is_vararg) changes; also see VARARG_*
2772-- * LUA_COMPATUPSYNTAX section for old-style upvalues removed
2773-- * repeatstat() calls chunk() instead of block()
2774-- * function interface changed: cond, test_then_block
2775-- * while statement implementation considerably simplified; MAXEXPWHILE
2776-- and EXTRAEXP no longer required, no limits to the complexity of a
2777-- while condition
2778-- * repeat, forbody statement implementation has major changes,
2779-- mostly due to new scoping behaviour of local variables
2780-- * OPR_MULT renamed to OPR_MUL
2781----------------------------------------------------------------------]]
2782
2783--requires luaP, luaX, luaK
2784local luaY = {}
2785local luaX = require(script.Parent.LuaX)
2786local luaK = require(script.Parent.LuaK)(luaY)
2787local luaP = require(script.Parent.LuaP)
2788
2789--[[--------------------------------------------------------------------
2790-- Expression descriptor
2791-- * expkind changed to string constants; luaY:assignment was the only
2792-- function to use a relational operator with this enumeration
2793-- VVOID -- no value
2794-- VNIL -- no value
2795-- VTRUE -- no value
2796-- VFALSE -- no value
2797-- VK -- info = index of constant in 'k'
2798-- VKNUM -- nval = numerical value
2799-- VLOCAL -- info = local register
2800-- VUPVAL, -- info = index of upvalue in 'upvalues'
2801-- VGLOBAL -- info = index of table; aux = index of global name in 'k'
2802-- VINDEXED -- info = table register; aux = index register (or 'k')
2803-- VJMP -- info = instruction pc
2804-- VRELOCABLE -- info = instruction pc
2805-- VNONRELOC -- info = result register
2806-- VCALL -- info = instruction pc
2807-- VVARARG -- info = instruction pc
2808} ----------------------------------------------------------------------]]
2809
2810--[[--------------------------------------------------------------------
2811-- * expdesc in Lua 5.1.x has a union u and another struct s; this Lua
2812-- implementation ignores all instances of u and s usage
2813-- struct expdesc:
2814-- k -- (enum: expkind)
2815-- info, aux -- (int, int)
2816-- nval -- (lua_Number)
2817-- t -- patch list of 'exit when true'
2818-- f -- patch list of 'exit when false'
2819----------------------------------------------------------------------]]
2820
2821--[[--------------------------------------------------------------------
2822-- struct upvaldesc:
2823-- k -- (lu_byte)
2824-- info -- (lu_byte)
2825----------------------------------------------------------------------]]
2826
2827--[[--------------------------------------------------------------------
2828-- state needed to generate code for a given function
2829-- struct FuncState:
2830-- f -- current function header (table: Proto)
2831-- h -- table to find (and reuse) elements in 'k' (table: Table)
2832-- prev -- enclosing function (table: FuncState)
2833-- ls -- lexical state (table: LexState)
2834-- L -- copy of the Lua state (table: lua_State)
2835-- bl -- chain of current blocks (table: BlockCnt)
2836-- pc -- next position to code (equivalent to 'ncode')
2837-- lasttarget -- 'pc' of last 'jump target'
2838-- jpc -- list of pending jumps to 'pc'
2839-- freereg -- first free register
2840-- nk -- number of elements in 'k'
2841-- np -- number of elements in 'p'
2842-- nlocvars -- number of elements in 'locvars'
2843-- nactvar -- number of active local variables
2844-- upvalues[LUAI_MAXUPVALUES] -- upvalues (table: upvaldesc)
2845-- actvar[LUAI_MAXVARS] -- declared-variable stack
2846----------------------------------------------------------------------]]
2847
2848------------------------------------------------------------------------
2849-- constants used by parser
2850-- * picks up duplicate values from luaX if required
2851------------------------------------------------------------------------
2852
2853luaY.LUA_QS = luaX.LUA_QS or "'%s'" -- (from luaconf.h)
2854
2855luaY.SHRT_MAX = 32767 -- (from <limits.h>)
2856luaY.LUAI_MAXVARS = 200 -- (luaconf.h)
2857luaY.LUAI_MAXUPVALUES = 60 -- (luaconf.h)
2858luaY.MAX_INT = luaX.MAX_INT or 2147483645 -- (from llimits.h)
2859 -- * INT_MAX-2 for 32-bit systems
2860luaY.LUAI_MAXCCALLS = 200 -- (from luaconf.h)
2861
2862luaY.VARARG_HASARG = 1 -- (from lobject.h)
2863-- NOTE: HASARG_MASK is value-specific
2864luaY.HASARG_MASK = 2 -- this was added for a bitop in parlist()
2865luaY.VARARG_ISVARARG = 2
2866-- NOTE: there is some value-specific code that involves VARARG_NEEDSARG
2867luaY.VARARG_NEEDSARG = 4
2868
2869luaY.LUA_MULTRET = -1 -- (lua.h)
2870
2871--[[--------------------------------------------------------------------
2872-- other functions
2873----------------------------------------------------------------------]]
2874
2875------------------------------------------------------------------------
2876-- LUA_QL describes how error messages quote program elements.
2877-- CHANGE it if you want a different appearance. (from luaconf.h)
2878------------------------------------------------------------------------
2879function luaY:LUA_QL(x)
2880 return "'"..x.."'"
2881end
2882
2883------------------------------------------------------------------------
2884-- this is a stripped-down luaM_growvector (from lmem.h) which is a
2885-- macro based on luaM_growaux (in lmem.c); all the following does is
2886-- reproduce the size limit checking logic of the original function
2887-- so that error behaviour is identical; all arguments preserved for
2888-- convenience, even those which are unused
2889-- * set the t field to nil, since this originally does a sizeof(t)
2890-- * size (originally a pointer) is never updated, their final values
2891-- are set by luaY:close_func(), so overall things should still work
2892------------------------------------------------------------------------
2893function luaY:growvector(L, v, nelems, size, t, limit, e)
2894 if nelems >= limit then
2895 error(e) -- was luaG_runerror
2896 end
2897end
2898
2899------------------------------------------------------------------------
2900-- initialize a new function prototype structure (from lfunc.c)
2901-- * used only in open_func()
2902------------------------------------------------------------------------
2903function luaY:newproto(L)
2904 local f = {} -- Proto
2905 -- luaC_link(L, obj2gco(f), LUA_TPROTO); /* GC */
2906 f.k = {}
2907 f.sizek = 0
2908 f.p = {}
2909 f.sizep = 0
2910 f.code = {}
2911 f.sizecode = 0
2912 f.sizelineinfo = 0
2913 f.sizeupvalues = 0
2914 f.nups = 0
2915 f.upvalues = {}
2916 f.numparams = 0
2917 f.is_vararg = 0
2918 f.maxstacksize = 0
2919 f.lineinfo = {}
2920 f.sizelocvars = 0
2921 f.locvars = {}
2922 f.lineDefined = 0
2923 f.lastlinedefined = 0
2924 f.source = nil
2925 return f
2926end
2927
2928------------------------------------------------------------------------
2929-- converts an integer to a "floating point byte", represented as
2930-- (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
2931-- eeeee != 0 and (xxx) otherwise.
2932------------------------------------------------------------------------
2933function luaY:int2fb(x)
2934 local e = 0 -- exponent
2935 while x >= 16 do
2936 x = math.floor((x + 1) / 2)
2937 e = e + 1
2938 end
2939 if x < 8 then
2940 return x
2941 else
2942 return ((e + 1) * 8) + (x - 8)
2943 end
2944end
2945
2946--[[--------------------------------------------------------------------
2947-- parser functions
2948----------------------------------------------------------------------]]
2949
2950------------------------------------------------------------------------
2951-- true of the kind of expression produces multiple return values
2952------------------------------------------------------------------------
2953function luaY:hasmultret(k)
2954 return k == "VCALL" or k == "VVARARG"
2955end
2956
2957------------------------------------------------------------------------
2958-- convenience function to access active local i, returns entry
2959------------------------------------------------------------------------
2960function luaY:getlocvar(fs, i)
2961 return fs.f.locvars[ fs.actvar[i] ]
2962end
2963
2964------------------------------------------------------------------------
2965-- check a limit, string m provided as an error message
2966------------------------------------------------------------------------
2967function luaY:checklimit(fs, v, l, m)
2968 if v > l then self:errorlimit(fs, l, m) end
2969end
2970
2971--[[--------------------------------------------------------------------
2972-- nodes for block list (list of active blocks)
2973-- struct BlockCnt:
2974-- previous -- chain (table: BlockCnt)
2975-- breaklist -- list of jumps out of this loop
2976-- nactvar -- # active local variables outside the breakable structure
2977-- upval -- true if some variable in the block is an upvalue (boolean)
2978-- isbreakable -- true if 'block' is a loop (boolean)
2979----------------------------------------------------------------------]]
2980
2981------------------------------------------------------------------------
2982-- prototypes for recursive non-terminal functions
2983------------------------------------------------------------------------
2984-- prototypes deleted; not required in Lua
2985
2986------------------------------------------------------------------------
2987-- reanchor if last token is has a constant string, see close_func()
2988-- * used only in close_func()
2989------------------------------------------------------------------------
2990function luaY:anchor_token(ls)
2991 if ls.t.token == "TK_NAME" or ls.t.token == "TK_STRING" then
2992 -- not relevant to Lua implementation of parser
2993 -- local ts = ls.t.seminfo
2994 -- luaX_newstring(ls, getstr(ts), ts->tsv.len); /* C */
2995 end
2996end
2997
2998------------------------------------------------------------------------
2999-- throws a syntax error if token expected is not there
3000------------------------------------------------------------------------
3001function luaY:error_expected(ls, token)
3002 luaX:syntaxerror(ls,
3003 string.format(self.LUA_QS.." expected", luaX:token2str(ls, token)))
3004end
3005
3006------------------------------------------------------------------------
3007-- prepares error message for display, for limits exceeded
3008-- * used only in checklimit()
3009------------------------------------------------------------------------
3010function luaY:errorlimit(fs, limit, what)
3011 local msg = (fs.f.linedefined == 0) and
3012 string.format("main function has more than %d %s", limit, what) or
3013 string.format("function at line %d has more than %d %s",
3014 fs.f.linedefined, limit, what)
3015 luaX:lexerror(fs.ls, msg, 0)
3016end
3017
3018------------------------------------------------------------------------
3019-- tests for a token, returns outcome
3020-- * return value changed to boolean
3021------------------------------------------------------------------------
3022function luaY:testnext(ls, c)
3023 if ls.t.token == c then
3024 luaX:next(ls)
3025 return true
3026 else
3027 return false
3028 end
3029end
3030
3031------------------------------------------------------------------------
3032-- check for existence of a token, throws error if not found
3033------------------------------------------------------------------------
3034function luaY:check(ls, c)
3035 if ls.t.token ~= c then
3036 self:error_expected(ls, c)
3037 end
3038end
3039
3040------------------------------------------------------------------------
3041-- verify existence of a token, then skip it
3042------------------------------------------------------------------------
3043function luaY:checknext(ls, c)
3044 self:check(ls, c)
3045 luaX:next(ls)
3046end
3047
3048------------------------------------------------------------------------
3049-- throws error if condition not matched
3050------------------------------------------------------------------------
3051function luaY:check_condition(ls, c, msg)
3052 if not c then luaX:syntaxerror(ls, msg) end
3053end
3054
3055------------------------------------------------------------------------
3056-- verifies token conditions are met or else throw error
3057------------------------------------------------------------------------
3058function luaY:check_match(ls, what, who, where)
3059 if not self:testnext(ls, what) then
3060 if where == ls.linenumber then
3061 self:error_expected(ls, what)
3062 else
3063 luaX:syntaxerror(ls, string.format(
3064 self.LUA_QS.." expected (to close "..self.LUA_QS.." at line %d)",
3065 luaX:token2str(ls, what), luaX:token2str(ls, who), where))
3066 end
3067 end
3068end
3069
3070------------------------------------------------------------------------
3071-- expect that token is a name, return the name
3072------------------------------------------------------------------------
3073function luaY:str_checkname(ls)
3074 self:check(ls, "TK_NAME")
3075 local ts = ls.t.seminfo
3076 luaX:next(ls)
3077 return ts
3078end
3079
3080------------------------------------------------------------------------
3081-- initialize a struct expdesc, expression description data structure
3082------------------------------------------------------------------------
3083function luaY:init_exp(e, k, i)
3084 e.f, e.t = luaK.NO_JUMP, luaK.NO_JUMP
3085 e.k = k
3086 e.info = i
3087end
3088
3089------------------------------------------------------------------------
3090-- adds given string s in string pool, sets e as VK
3091------------------------------------------------------------------------
3092function luaY:codestring(ls, e, s)
3093 self:init_exp(e, "VK", luaK:stringK(ls.fs, s))
3094end
3095
3096------------------------------------------------------------------------
3097-- consume a name token, adds it to string pool, sets e as VK
3098------------------------------------------------------------------------
3099function luaY:checkname(ls, e)
3100 self:codestring(ls, e, self:str_checkname(ls))
3101end
3102
3103------------------------------------------------------------------------
3104-- creates struct entry for a local variable
3105-- * used only in new_localvar()
3106------------------------------------------------------------------------
3107function luaY:registerlocalvar(ls, varname)
3108 local fs = ls.fs
3109 local f = fs.f
3110 self:growvector(ls.L, f.locvars, fs.nlocvars, f.sizelocvars,
3111 nil, self.SHRT_MAX, "too many local variables")
3112 -- loop to initialize empty f.locvar positions not required
3113 f.locvars[fs.nlocvars] = {} -- LocVar
3114 f.locvars[fs.nlocvars].varname = varname
3115 -- luaC_objbarrier(ls.L, f, varname) /* GC */
3116 local nlocvars = fs.nlocvars
3117 fs.nlocvars = fs.nlocvars + 1
3118 return nlocvars
3119end
3120
3121------------------------------------------------------------------------
3122-- creates a new local variable given a name and an offset from nactvar
3123-- * used in fornum(), forlist(), parlist(), body()
3124------------------------------------------------------------------------
3125function luaY:new_localvarliteral(ls, v, n)
3126 self:new_localvar(ls, v, n)
3127end
3128
3129------------------------------------------------------------------------
3130-- register a local variable, set in active variable list
3131------------------------------------------------------------------------
3132function luaY:new_localvar(ls, name, n)
3133 local fs = ls.fs
3134 self:checklimit(fs, fs.nactvar + n + 1, self.LUAI_MAXVARS, "local variables")
3135 fs.actvar[fs.nactvar + n] = self:registerlocalvar(ls, name)
3136end
3137
3138------------------------------------------------------------------------
3139-- adds nvars number of new local variables, set debug information
3140------------------------------------------------------------------------
3141function luaY:adjustlocalvars(ls, nvars)
3142 local fs = ls.fs
3143 fs.nactvar = fs.nactvar + nvars
3144 for i = nvars, 1, -1 do
3145 self:getlocvar(fs, fs.nactvar - i).startpc = fs.pc
3146 end
3147end
3148
3149------------------------------------------------------------------------
3150-- removes a number of locals, set debug information
3151------------------------------------------------------------------------
3152function luaY:removevars(ls, tolevel)
3153 local fs = ls.fs
3154 while fs.nactvar > tolevel do
3155 fs.nactvar = fs.nactvar - 1
3156 self:getlocvar(fs, fs.nactvar).endpc = fs.pc
3157 end
3158end
3159
3160------------------------------------------------------------------------
3161-- returns an existing upvalue index based on the given name, or
3162-- creates a new upvalue struct entry and returns the new index
3163-- * used only in singlevaraux()
3164------------------------------------------------------------------------
3165function luaY:indexupvalue(fs, name, v)
3166 local f = fs.f
3167 for i = 0, f.nups - 1 do
3168 if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then
3169 assert(f.upvalues[i] == name)
3170 return i
3171 end
3172 end
3173 -- new one
3174 self:checklimit(fs, f.nups + 1, self.LUAI_MAXUPVALUES, "upvalues")
3175 self:growvector(fs.L, f.upvalues, f.nups, f.sizeupvalues,
3176 nil, self.MAX_INT, "")
3177 -- loop to initialize empty f.upvalues positions not required
3178 f.upvalues[f.nups] = name
3179 -- luaC_objbarrier(fs->L, f, name); /* GC */
3180 assert(v.k == "VLOCAL" or v.k == "VUPVAL")
3181 -- this is a partial copy; only k & info fields used
3182 fs.upvalues[f.nups] = { k = v.k, info = v.info }
3183 local nups = f.nups
3184 f.nups = f.nups + 1
3185 return nups
3186end
3187
3188------------------------------------------------------------------------
3189-- search the local variable namespace of the given fs for a match
3190-- * used only in singlevaraux()
3191------------------------------------------------------------------------
3192function luaY:searchvar(fs, n)
3193 for i = fs.nactvar - 1, 0, -1 do
3194 if n == self:getlocvar(fs, i).varname then
3195 return i
3196 end
3197 end
3198 return -1 -- not found
3199end
3200
3201------------------------------------------------------------------------
3202-- * mark upvalue flags in function states up to a given level
3203-- * used only in singlevaraux()
3204------------------------------------------------------------------------
3205function luaY:markupval(fs, level)
3206 local bl = fs.bl
3207 while bl and bl.nactvar > level do bl = bl.previous end
3208 if bl then bl.upval = true end
3209end
3210
3211------------------------------------------------------------------------
3212-- handle locals, globals and upvalues and related processing
3213-- * search mechanism is recursive, calls itself to search parents
3214-- * used only in singlevar()
3215------------------------------------------------------------------------
3216function luaY:singlevaraux(fs, n, var, base)
3217 if fs == nil then -- no more levels?
3218 self:init_exp(var, "VGLOBAL", luaP.NO_REG) -- default is global variable
3219 return "VGLOBAL"
3220 else
3221 local v = self:searchvar(fs, n) -- look up at current level
3222 if v >= 0 then
3223 self:init_exp(var, "VLOCAL", v)
3224 if base == 0 then
3225 self:markupval(fs, v) -- local will be used as an upval
3226 end
3227 return "VLOCAL"
3228 else -- not found at current level; try upper one
3229 if self:singlevaraux(fs.prev, n, var, 0) == "VGLOBAL" then
3230 return "VGLOBAL"
3231 end
3232 var.info = self:indexupvalue(fs, n, var) -- else was LOCAL or UPVAL
3233 var.k = "VUPVAL" -- upvalue in this level
3234 return "VUPVAL"
3235 end--if v
3236 end--if fs
3237end
3238
3239------------------------------------------------------------------------
3240-- consume a name token, creates a variable (global|local|upvalue)
3241-- * used in prefixexp(), funcname()
3242------------------------------------------------------------------------
3243function luaY:singlevar(ls, var)
3244 local varname = self:str_checkname(ls)
3245 local fs = ls.fs
3246 if self:singlevaraux(fs, varname, var, 1) == "VGLOBAL" then
3247 var.info = luaK:stringK(fs, varname) -- info points to global name
3248 end
3249end
3250
3251------------------------------------------------------------------------
3252-- adjust RHS to match LHS in an assignment
3253-- * used in assignment(), forlist(), localstat()
3254------------------------------------------------------------------------
3255function luaY:adjust_assign(ls, nvars, nexps, e)
3256 local fs = ls.fs
3257 local extra = nvars - nexps
3258 if self:hasmultret(e.k) then
3259 extra = extra + 1 -- includes call itself
3260 if extra <= 0 then extra = 0 end
3261 luaK:setreturns(fs, e, extra) -- last exp. provides the difference
3262 if extra > 1 then luaK:reserveregs(fs, extra - 1) end
3263 else
3264 if e.k ~= "VVOID" then luaK:exp2nextreg(fs, e) end -- close last expression
3265 if extra > 0 then
3266 local reg = fs.freereg
3267 luaK:reserveregs(fs, extra)
3268 luaK:_nil(fs, reg, extra)
3269 end
3270 end
3271end
3272
3273------------------------------------------------------------------------
3274-- tracks and limits parsing depth, assert check at end of parsing
3275------------------------------------------------------------------------
3276function luaY:enterlevel(ls)
3277 ls.L.nCcalls = ls.L.nCcalls + 1
3278 if ls.L.nCcalls > self.LUAI_MAXCCALLS then
3279 luaX:lexerror(ls, "chunk has too many syntax levels", 0)
3280 end
3281end
3282
3283------------------------------------------------------------------------
3284-- tracks parsing depth, a pair with luaY:enterlevel()
3285------------------------------------------------------------------------
3286function luaY:leavelevel(ls)
3287 ls.L.nCcalls = ls.L.nCcalls - 1
3288end
3289
3290------------------------------------------------------------------------
3291-- enters a code unit, initializes elements
3292------------------------------------------------------------------------
3293function luaY:enterblock(fs, bl, isbreakable)
3294 bl.breaklist = luaK.NO_JUMP
3295 bl.isbreakable = isbreakable
3296 bl.nactvar = fs.nactvar
3297 bl.upval = false
3298 bl.previous = fs.bl
3299 fs.bl = bl
3300 assert(fs.freereg == fs.nactvar)
3301end
3302
3303------------------------------------------------------------------------
3304-- leaves a code unit, close any upvalues
3305------------------------------------------------------------------------
3306function luaY:leaveblock(fs)
3307 local bl = fs.bl
3308 fs.bl = bl.previous
3309 self:removevars(fs.ls, bl.nactvar)
3310 if bl.upval then
3311 luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
3312 end
3313 -- a block either controls scope or breaks (never both)
3314 assert(not bl.isbreakable or not bl.upval)
3315 assert(bl.nactvar == fs.nactvar)
3316 fs.freereg = fs.nactvar -- free registers
3317 luaK:patchtohere(fs, bl.breaklist)
3318end
3319
3320------------------------------------------------------------------------
3321-- implement the instantiation of a function prototype, append list of
3322-- upvalues after the instantiation instruction
3323-- * used only in body()
3324------------------------------------------------------------------------
3325function luaY:pushclosure(ls, func, v)
3326 local fs = ls.fs
3327 local f = fs.f
3328 self:growvector(ls.L, f.p, fs.np, f.sizep, nil,
3329 luaP.MAXARG_Bx, "constant table overflow")
3330 -- loop to initialize empty f.p positions not required
3331 f.p[fs.np] = func.f
3332 fs.np = fs.np + 1
3333 -- luaC_objbarrier(ls->L, f, func->f); /* C */
3334 self:init_exp(v, "VRELOCABLE", luaK:codeABx(fs, "OP_CLOSURE", 0, fs.np - 1))
3335 for i = 0, func.f.nups - 1 do
3336 local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL"
3337 luaK:codeABC(fs, o, 0, func.upvalues[i].info, 0)
3338 end
3339end
3340
3341------------------------------------------------------------------------
3342-- opening of a function
3343------------------------------------------------------------------------
3344function luaY:open_func(ls, fs)
3345 local L = ls.L
3346 local f = self:newproto(ls.L)
3347 fs.f = f
3348 fs.prev = ls.fs -- linked list of funcstates
3349 fs.ls = ls
3350 fs.L = L
3351 ls.fs = fs
3352 fs.pc = 0
3353 fs.lasttarget = -1
3354 fs.jpc = luaK.NO_JUMP
3355 fs.freereg = 0
3356 fs.nk = 0
3357 fs.np = 0
3358 fs.nlocvars = 0
3359 fs.nactvar = 0
3360 fs.bl = nil
3361 f.source = ls.source
3362 f.maxstacksize = 2 -- registers 0/1 are always valid
3363 fs.h = {} -- constant table; was luaH_new call
3364 -- anchor table of constants and prototype (to avoid being collected)
3365 -- sethvalue2s(L, L->top, fs->h); incr_top(L); /* C */
3366 -- setptvalue2s(L, L->top, f); incr_top(L);
3367end
3368
3369------------------------------------------------------------------------
3370-- closing of a function
3371------------------------------------------------------------------------
3372function luaY:close_func(ls)
3373 local L = ls.L
3374 local fs = ls.fs
3375 local f = fs.f
3376 self:removevars(ls, 0)
3377 luaK:ret(fs, 0, 0) -- final return
3378 -- luaM_reallocvector deleted for f->code, f->lineinfo, f->k, f->p,
3379 -- f->locvars, f->upvalues; not required for Lua table arrays
3380 f.sizecode = fs.pc
3381 f.sizelineinfo = fs.pc
3382 f.sizek = fs.nk
3383 f.sizep = fs.np
3384 f.sizelocvars = fs.nlocvars
3385 f.sizeupvalues = f.nups
3386 --assert(luaG_checkcode(f)) -- currently not implemented
3387 assert(fs.bl == nil)
3388 ls.fs = fs.prev
3389 -- the following is not required for this implementation; kept here
3390 -- for completeness
3391 -- L->top -= 2; /* remove table and prototype from the stack */
3392 -- last token read was anchored in defunct function; must reanchor it
3393 if fs then self:anchor_token(ls) end
3394end
3395
3396------------------------------------------------------------------------
3397-- parser initialization function
3398-- * note additional sub-tables needed for LexState, FuncState
3399------------------------------------------------------------------------
3400function luaY:parser(L, z, buff, name)
3401 local lexstate = {} -- LexState
3402 lexstate.t = {}
3403 lexstate.lookahead = {}
3404 local funcstate = {} -- FuncState
3405 funcstate.upvalues = {}
3406 funcstate.actvar = {}
3407 -- the following nCcalls initialization added for convenience
3408 L.nCcalls = 0
3409 lexstate.buff = buff
3410 luaX:setinput(L, lexstate, z, name)
3411 self:open_func(lexstate, funcstate)
3412 funcstate.f.is_vararg = self.VARARG_ISVARARG -- main func. is always vararg
3413 luaX:next(lexstate) -- read first token
3414 self:chunk(lexstate)
3415 self:check(lexstate, "TK_EOS")
3416 self:close_func(lexstate)
3417 assert(funcstate.prev == nil)
3418 assert(funcstate.f.nups == 0)
3419 assert(lexstate.fs == nil)
3420 return funcstate.f
3421end
3422
3423--[[--------------------------------------------------------------------
3424-- GRAMMAR RULES
3425----------------------------------------------------------------------]]
3426
3427------------------------------------------------------------------------
3428-- parse a function name suffix, for function call specifications
3429-- * used in primaryexp(), funcname()
3430------------------------------------------------------------------------
3431function luaY:field(ls, v)
3432 -- field -> ['.' | ':'] NAME
3433 local fs = ls.fs
3434 local key = {} -- expdesc
3435 luaK:exp2anyreg(fs, v)
3436 luaX:next(ls) -- skip the dot or colon
3437 self:checkname(ls, key)
3438 luaK:indexed(fs, v, key)
3439end
3440
3441------------------------------------------------------------------------
3442-- parse a table indexing suffix, for constructors, expressions
3443-- * used in recfield(), primaryexp()
3444------------------------------------------------------------------------
3445function luaY:yindex(ls, v)
3446 -- index -> '[' expr ']'
3447 luaX:next(ls) -- skip the '['
3448 self:expr(ls, v)
3449 luaK:exp2val(ls.fs, v)
3450 self:checknext(ls, "]")
3451end
3452
3453--[[--------------------------------------------------------------------
3454-- Rules for Constructors
3455----------------------------------------------------------------------]]
3456
3457--[[--------------------------------------------------------------------
3458-- struct ConsControl:
3459-- v -- last list item read (table: struct expdesc)
3460-- t -- table descriptor (table: struct expdesc)
3461-- nh -- total number of 'record' elements
3462-- na -- total number of array elements
3463-- tostore -- number of array elements pending to be stored
3464----------------------------------------------------------------------]]
3465
3466------------------------------------------------------------------------
3467-- parse a table record (hash) field
3468-- * used in constructor()
3469------------------------------------------------------------------------
3470function luaY:recfield(ls, cc)
3471 -- recfield -> (NAME | '['exp1']') = exp1
3472 local fs = ls.fs
3473 local reg = ls.fs.freereg
3474 local key, val = {}, {} -- expdesc
3475 if ls.t.token == "TK_NAME" then
3476 self:checklimit(fs, cc.nh, self.MAX_INT, "items in a constructor")
3477 self:checkname(ls, key)
3478 else -- ls->t.token == '['
3479 self:yindex(ls, key)
3480 end
3481 cc.nh = cc.nh + 1
3482 self:checknext(ls, "=")
3483 local rkkey = luaK:exp2RK(fs, key)
3484 self:expr(ls, val)
3485 luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, rkkey, luaK:exp2RK(fs, val))
3486 fs.freereg = reg -- free registers
3487end
3488
3489------------------------------------------------------------------------
3490-- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH)
3491-- * used in constructor()
3492------------------------------------------------------------------------
3493function luaY:closelistfield(fs, cc)
3494 if cc.v.k == "VVOID" then return end -- there is no list item
3495 luaK:exp2nextreg(fs, cc.v)
3496 cc.v.k = "VVOID"
3497 if cc.tostore == luaP.LFIELDS_PER_FLUSH then
3498 luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) -- flush
3499 cc.tostore = 0 -- no more items pending
3500 end
3501end
3502
3503------------------------------------------------------------------------
3504-- emit a set list instruction at the end of parsing list constructor
3505-- * used in constructor()
3506------------------------------------------------------------------------
3507function luaY:lastlistfield(fs, cc)
3508 if cc.tostore == 0 then return end
3509 if self:hasmultret(cc.v.k) then
3510 luaK:setmultret(fs, cc.v)
3511 luaK:setlist(fs, cc.t.info, cc.na, self.LUA_MULTRET)
3512 cc.na = cc.na - 1 -- do not count last expression (unknown number of elements)
3513 else
3514 if cc.v.k ~= "VVOID" then
3515 luaK:exp2nextreg(fs, cc.v)
3516 end
3517 luaK:setlist(fs, cc.t.info, cc.na, cc.tostore)
3518 end
3519end
3520
3521------------------------------------------------------------------------
3522-- parse a table list (array) field
3523-- * used in constructor()
3524------------------------------------------------------------------------
3525function luaY:listfield(ls, cc)
3526 self:expr(ls, cc.v)
3527 self:checklimit(ls.fs, cc.na, self.MAX_INT, "items in a constructor")
3528 cc.na = cc.na + 1
3529 cc.tostore = cc.tostore + 1
3530end
3531
3532------------------------------------------------------------------------
3533-- parse a table constructor
3534-- * used in funcargs(), simpleexp()
3535------------------------------------------------------------------------
3536function luaY:constructor(ls, t)
3537 -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}'
3538 -- field -> recfield | listfield
3539 -- fieldsep -> ',' | ';'
3540 local fs = ls.fs
3541 local line = ls.linenumber
3542 local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0)
3543 local cc = {} -- ConsControl
3544 cc.v = {}
3545 cc.na, cc.nh, cc.tostore = 0, 0, 0
3546 cc.t = t
3547 self:init_exp(t, "VRELOCABLE", pc)
3548 self:init_exp(cc.v, "VVOID", 0) -- no value (yet)
3549 luaK:exp2nextreg(ls.fs, t) -- fix it at stack top (for gc)
3550 self:checknext(ls, "{")
3551 repeat
3552 assert(cc.v.k == "VVOID" or cc.tostore > 0)
3553 if ls.t.token == "}" then break end
3554 self:closelistfield(fs, cc)
3555 local c = ls.t.token
3556
3557 if c == "TK_NAME" then -- may be listfields or recfields
3558 luaX:lookahead(ls)
3559 if ls.lookahead.token ~= "=" then -- expression?
3560 self:listfield(ls, cc)
3561 else
3562 self:recfield(ls, cc)
3563 end
3564 elseif c == "[" then -- constructor_item -> recfield
3565 self:recfield(ls, cc)
3566 else -- constructor_part -> listfield
3567 self:listfield(ls, cc)
3568 end
3569 until not self:testnext(ls, ",") and not self:testnext(ls, ";")
3570 self:check_match(ls, "}", "{", line)
3571 self:lastlistfield(fs, cc)
3572 luaP:SETARG_B(fs.f.code[pc], self:int2fb(cc.na)) -- set initial array size
3573 luaP:SETARG_C(fs.f.code[pc], self:int2fb(cc.nh)) -- set initial table size
3574end
3575
3576-- }======================================================================
3577
3578------------------------------------------------------------------------
3579-- parse the arguments (parameters) of a function declaration
3580-- * used in body()
3581------------------------------------------------------------------------
3582function luaY:parlist(ls)
3583 -- parlist -> [ param { ',' param } ]
3584 local fs = ls.fs
3585 local f = fs.f
3586 local nparams = 0
3587 f.is_vararg = 0
3588 if ls.t.token ~= ")" then -- is 'parlist' not empty?
3589 repeat
3590 local c = ls.t.token
3591 if c == "TK_NAME" then -- param -> NAME
3592 self:new_localvar(ls, self:str_checkname(ls), nparams)
3593 nparams = nparams + 1
3594 elseif c == "TK_DOTS" then -- param -> `...'
3595 luaX:next(ls)
3596-- [[
3597-- #if defined(LUA_COMPAT_VARARG)
3598 -- use `arg' as default name
3599 self:new_localvarliteral(ls, "arg", nparams)
3600 nparams = nparams + 1
3601 f.is_vararg = self.VARARG_HASARG + self.VARARG_NEEDSARG
3602-- #endif
3603--]]
3604 f.is_vararg = f.is_vararg + self.VARARG_ISVARARG
3605 else
3606 luaX:syntaxerror(ls, "<name> or "..self:LUA_QL("...").." expected")
3607 end
3608 until f.is_vararg ~= 0 or not self:testnext(ls, ",")
3609 end--if
3610 self:adjustlocalvars(ls, nparams)
3611 -- NOTE: the following works only when HASARG_MASK is 2!
3612 f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK)
3613 luaK:reserveregs(fs, fs.nactvar) -- reserve register for parameters
3614end
3615
3616------------------------------------------------------------------------
3617-- parse function declaration body
3618-- * used in simpleexp(), localfunc(), funcstat()
3619------------------------------------------------------------------------
3620function luaY:body(ls, e, needself, line)
3621 -- body -> '(' parlist ')' chunk END
3622 local new_fs = {} -- FuncState
3623 new_fs.upvalues = {}
3624 new_fs.actvar = {}
3625 self:open_func(ls, new_fs)
3626 new_fs.f.lineDefined = line
3627 self:checknext(ls, "(")
3628 if needself then
3629 self:new_localvarliteral(ls, "self", 0)
3630 self:adjustlocalvars(ls, 1)
3631 end
3632 self:parlist(ls)
3633 self:checknext(ls, ")")
3634 self:chunk(ls)
3635 new_fs.f.lastlinedefined = ls.linenumber
3636 self:check_match(ls, "TK_END", "TK_FUNCTION", line)
3637 self:close_func(ls)
3638 self:pushclosure(ls, new_fs, e)
3639end
3640
3641------------------------------------------------------------------------
3642-- parse a list of comma-separated expressions
3643-- * used is multiple locations
3644------------------------------------------------------------------------
3645function luaY:explist1(ls, v)
3646 -- explist1 -> expr { ',' expr }
3647 local n = 1 -- at least one expression
3648 self:expr(ls, v)
3649 while self:testnext(ls, ",") do
3650 luaK:exp2nextreg(ls.fs, v)
3651 self:expr(ls, v)
3652 n = n + 1
3653 end
3654 return n
3655end
3656
3657------------------------------------------------------------------------
3658-- parse the parameters of a function call
3659-- * contrast with parlist(), used in function declarations
3660-- * used in primaryexp()
3661------------------------------------------------------------------------
3662function luaY:funcargs(ls, f)
3663 local fs = ls.fs
3664 local args = {} -- expdesc
3665 local nparams
3666 local line = ls.linenumber
3667 local c = ls.t.token
3668 if c == "(" then -- funcargs -> '(' [ explist1 ] ')'
3669 if line ~= ls.lastline then
3670 luaX:syntaxerror(ls, "ambiguous syntax (function call x new statement)")
3671 end
3672 luaX:next(ls)
3673 if ls.t.token == ")" then -- arg list is empty?
3674 args.k = "VVOID"
3675 else
3676 self:explist1(ls, args)
3677 luaK:setmultret(fs, args)
3678 end
3679 self:check_match(ls, ")", "(", line)
3680 elseif c == "{" then -- funcargs -> constructor
3681 self:constructor(ls, args)
3682 elseif c == "TK_STRING" then -- funcargs -> STRING
3683 self:codestring(ls, args, ls.t.seminfo)
3684 luaX:next(ls) -- must use 'seminfo' before 'next'
3685 else
3686 luaX:syntaxerror(ls, "function arguments expected")
3687 return
3688 end
3689 assert(f.k == "VNONRELOC")
3690 local base = f.info -- base register for call
3691 if self:hasmultret(args.k) then
3692 nparams = self.LUA_MULTRET -- open call
3693 else
3694 if args.k ~= "VVOID" then
3695 luaK:exp2nextreg(fs, args) -- close last argument
3696 end
3697 nparams = fs.freereg - (base + 1)
3698 end
3699 self:init_exp(f, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2))
3700 luaK:fixline(fs, line)
3701 fs.freereg = base + 1 -- call remove function and arguments and leaves
3702 -- (unless changed) one result
3703end
3704
3705--[[--------------------------------------------------------------------
3706-- Expression parsing
3707----------------------------------------------------------------------]]
3708
3709------------------------------------------------------------------------
3710-- parses an expression in parentheses or a single variable
3711-- * used in primaryexp()
3712------------------------------------------------------------------------
3713function luaY:prefixexp(ls, v)
3714 -- prefixexp -> NAME | '(' expr ')'
3715 local c = ls.t.token
3716 if c == "(" then
3717 local line = ls.linenumber
3718 luaX:next(ls)
3719 self:expr(ls, v)
3720 self:check_match(ls, ")", "(", line)
3721 luaK:dischargevars(ls.fs, v)
3722 elseif c == "TK_NAME" then
3723 self:singlevar(ls, v)
3724 else
3725 luaX:syntaxerror(ls, "unexpected symbol")
3726 end--if c
3727 return
3728end
3729
3730------------------------------------------------------------------------
3731-- parses a prefixexp (an expression in parentheses or a single variable)
3732-- or a function call specification
3733-- * used in simpleexp(), assignment(), exprstat()
3734------------------------------------------------------------------------
3735function luaY:primaryexp(ls, v)
3736 -- primaryexp ->
3737 -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
3738 local fs = ls.fs
3739 self:prefixexp(ls, v)
3740 while true do
3741 local c = ls.t.token
3742 if c == "." then -- field
3743 self:field(ls, v)
3744 elseif c == "[" then -- '[' exp1 ']'
3745 local key = {} -- expdesc
3746 luaK:exp2anyreg(fs, v)
3747 self:yindex(ls, key)
3748 luaK:indexed(fs, v, key)
3749 elseif c == ":" then -- ':' NAME funcargs
3750 local key = {} -- expdesc
3751 luaX:next(ls)
3752 self:checkname(ls, key)
3753 luaK:_self(fs, v, key)
3754 self:funcargs(ls, v)
3755 elseif c == "(" or c == "TK_STRING" or c == "{" then -- funcargs
3756 luaK:exp2nextreg(fs, v)
3757 self:funcargs(ls, v)
3758 else
3759 return
3760 end--if c
3761 end--while
3762end
3763
3764------------------------------------------------------------------------
3765-- parses general expression types, constants handled here
3766-- * used in subexpr()
3767------------------------------------------------------------------------
3768function luaY:simpleexp(ls, v)
3769 -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
3770 -- constructor | FUNCTION body | primaryexp
3771 local c = ls.t.token
3772 if c == "TK_NUMBER" then
3773 self:init_exp(v, "VKNUM", 0)
3774 v.nval = ls.t.seminfo
3775 elseif c == "TK_STRING" then
3776 self:codestring(ls, v, ls.t.seminfo)
3777 elseif c == "TK_NIL" then
3778 self:init_exp(v, "VNIL", 0)
3779 elseif c == "TK_TRUE" then
3780 self:init_exp(v, "VTRUE", 0)
3781 elseif c == "TK_FALSE" then
3782 self:init_exp(v, "VFALSE", 0)
3783 elseif c == "TK_DOTS" then -- vararg
3784 local fs = ls.fs
3785 self:check_condition(ls, fs.f.is_vararg ~= 0,
3786 "cannot use "..self:LUA_QL("...").." outside a vararg function");
3787 -- NOTE: the following substitutes for a bitop, but is value-specific
3788 local is_vararg = fs.f.is_vararg
3789 if is_vararg >= self.VARARG_NEEDSARG then
3790 fs.f.is_vararg = is_vararg - self.VARARG_NEEDSARG -- don't need 'arg'
3791 end
3792 self:init_exp(v, "VVARARG", luaK:codeABC(fs, "OP_VARARG", 0, 1, 0))
3793 elseif c == "{" then -- constructor
3794 self:constructor(ls, v)
3795 return
3796 elseif c == "TK_FUNCTION" then
3797 luaX:next(ls)
3798 self:body(ls, v, false, ls.linenumber)
3799 return
3800 else
3801 self:primaryexp(ls, v)
3802 return
3803 end--if c
3804 luaX:next(ls)
3805end
3806
3807------------------------------------------------------------------------
3808-- Translates unary operators tokens if found, otherwise returns
3809-- OPR_NOUNOPR. getunopr() and getbinopr() are used in subexpr().
3810-- * used in subexpr()
3811------------------------------------------------------------------------
3812function luaY:getunopr(op)
3813 if op == "TK_NOT" then
3814 return "OPR_NOT"
3815 elseif op == "-" then
3816 return "OPR_MINUS"
3817 elseif op == "#" then
3818 return "OPR_LEN"
3819 else
3820 return "OPR_NOUNOPR"
3821 end
3822end
3823
3824------------------------------------------------------------------------
3825-- Translates binary operator tokens if found, otherwise returns
3826-- OPR_NOBINOPR. Code generation uses OPR_* style tokens.
3827-- * used in subexpr()
3828------------------------------------------------------------------------
3829luaY.getbinopr_table = {
3830 ["+"] = "OPR_ADD",
3831 ["-"] = "OPR_SUB",
3832 ["*"] = "OPR_MUL",
3833 ["/"] = "OPR_DIV",
3834 ["%"] = "OPR_MOD",
3835 ["^"] = "OPR_POW",
3836 ["TK_CONCAT"] = "OPR_CONCAT",
3837 ["TK_NE"] = "OPR_NE",
3838 ["TK_EQ"] = "OPR_EQ",
3839 ["<"] = "OPR_LT",
3840 ["TK_LE"] = "OPR_LE",
3841 [">"] = "OPR_GT",
3842 ["TK_GE"] = "OPR_GE",
3843 ["TK_AND"] = "OPR_AND",
3844 ["TK_OR"] = "OPR_OR",
3845}
3846function luaY:getbinopr(op)
3847 local opr = self.getbinopr_table[op]
3848 if opr then return opr else return "OPR_NOBINOPR" end
3849end
3850
3851------------------------------------------------------------------------
3852-- the following priority table consists of pairs of left/right values
3853-- for binary operators (was a static const struct); grep for ORDER OPR
3854-- * the following struct is replaced:
3855-- static const struct {
3856-- lu_byte left; /* left priority for each binary operator */
3857-- lu_byte right; /* right priority */
3858-- } priority[] = { /* ORDER OPR */
3859------------------------------------------------------------------------
3860luaY.priority = {
3861 {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, -- `+' `-' `/' `%'
3862 {10, 9}, {5, 4}, -- power and concat (right associative)
3863 {3, 3}, {3, 3}, -- equality
3864 {3, 3}, {3, 3}, {3, 3}, {3, 3}, -- order
3865 {2, 2}, {1, 1} -- logical (and/or)
3866}
3867
3868luaY.UNARY_PRIORITY = 8 -- priority for unary operators
3869
3870------------------------------------------------------------------------
3871-- Parse subexpressions. Includes handling of unary operators and binary
3872-- operators. A subexpr is given the rhs priority level of the operator
3873-- immediately left of it, if any (limit is -1 if none,) and if a binop
3874-- is found, limit is compared with the lhs priority level of the binop
3875-- in order to determine which executes first.
3876------------------------------------------------------------------------
3877
3878------------------------------------------------------------------------
3879-- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
3880-- where 'binop' is any binary operator with a priority higher than 'limit'
3881-- * for priority lookups with self.priority[], 1=left and 2=right
3882-- * recursively called
3883-- * used in expr()
3884------------------------------------------------------------------------
3885function luaY:subexpr(ls, v, limit)
3886 self:enterlevel(ls)
3887 local uop = self:getunopr(ls.t.token)
3888 if uop ~= "OPR_NOUNOPR" then
3889 luaX:next(ls)
3890 self:subexpr(ls, v, self.UNARY_PRIORITY)
3891 luaK:prefix(ls.fs, uop, v)
3892 else
3893 self:simpleexp(ls, v)
3894 end
3895 -- expand while operators have priorities higher than 'limit'
3896 local op = self:getbinopr(ls.t.token)
3897 while op ~= "OPR_NOBINOPR" and self.priority[luaK.BinOpr[op] + 1][1] > limit do
3898 local v2 = {} -- expdesc
3899 luaX:next(ls)
3900 luaK:infix(ls.fs, op, v)
3901 -- read sub-expression with higher priority
3902 local nextop = self:subexpr(ls, v2, self.priority[luaK.BinOpr[op] + 1][2])
3903 luaK:posfix(ls.fs, op, v, v2)
3904 op = nextop
3905 end
3906 self:leavelevel(ls)
3907 return op -- return first untreated operator
3908end
3909
3910------------------------------------------------------------------------
3911-- Expression parsing starts here. Function subexpr is entered with the
3912-- left operator (which is non-existent) priority of -1, which is lower
3913-- than all actual operators. Expr information is returned in parm v.
3914-- * used in multiple locations
3915------------------------------------------------------------------------
3916function luaY:expr(ls, v)
3917 self:subexpr(ls, v, 0)
3918end
3919
3920-- }====================================================================
3921
3922--[[--------------------------------------------------------------------
3923-- Rules for Statements
3924----------------------------------------------------------------------]]
3925
3926------------------------------------------------------------------------
3927-- checks next token, used as a look-ahead
3928-- * returns boolean instead of 0|1
3929-- * used in retstat(), chunk()
3930------------------------------------------------------------------------
3931function luaY:block_follow(token)
3932 if token == "TK_ELSE" or token == "TK_ELSEIF" or token == "TK_END"
3933 or token == "TK_UNTIL" or token == "TK_EOS" then
3934 return true
3935 else
3936 return false
3937 end
3938end
3939
3940------------------------------------------------------------------------
3941-- parse a code block or unit
3942-- * used in multiple functions
3943------------------------------------------------------------------------
3944function luaY:block(ls)
3945 -- block -> chunk
3946 local fs = ls.fs
3947 local bl = {} -- BlockCnt
3948 self:enterblock(fs, bl, false)
3949 self:chunk(ls)
3950 assert(bl.breaklist == luaK.NO_JUMP)
3951 self:leaveblock(fs)
3952end
3953
3954------------------------------------------------------------------------
3955-- structure to chain all variables in the left-hand side of an
3956-- assignment
3957-- struct LHS_assign:
3958-- prev -- (table: struct LHS_assign)
3959-- v -- variable (global, local, upvalue, or indexed) (table: expdesc)
3960------------------------------------------------------------------------
3961
3962------------------------------------------------------------------------
3963-- check whether, in an assignment to a local variable, the local variable
3964-- is needed in a previous assignment (to a table). If so, save original
3965-- local value in a safe place and use this safe copy in the previous
3966-- assignment.
3967-- * used in assignment()
3968------------------------------------------------------------------------
3969function luaY:check_conflict(ls, lh, v)
3970 local fs = ls.fs
3971 local extra = fs.freereg -- eventual position to save local variable
3972 local conflict = false
3973 while lh do
3974 if lh.v.k == "VINDEXED" then
3975 if lh.v.info == v.info then -- conflict?
3976 conflict = true
3977 lh.v.info = extra -- previous assignment will use safe copy
3978 end
3979 if lh.v.aux == v.info then -- conflict?
3980 conflict = true
3981 lh.v.aux = extra -- previous assignment will use safe copy
3982 end
3983 end
3984 lh = lh.prev
3985 end
3986 if conflict then
3987 luaK:codeABC(fs, "OP_MOVE", fs.freereg, v.info, 0) -- make copy
3988 luaK:reserveregs(fs, 1)
3989 end
3990end
3991
3992------------------------------------------------------------------------
3993-- parse a variable assignment sequence
3994-- * recursively called
3995-- * used in exprstat()
3996------------------------------------------------------------------------
3997function luaY:assignment(ls, lh, nvars)
3998 local e = {} -- expdesc
3999 -- test was: VLOCAL <= lh->v.k && lh->v.k <= VINDEXED
4000 local c = lh.v.k
4001 self:check_condition(ls, c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL"
4002 or c == "VINDEXED", "syntax error")
4003 if self:testnext(ls, ",") then -- assignment -> ',' primaryexp assignment
4004 local nv = {} -- LHS_assign
4005 nv.v = {}
4006 nv.prev = lh
4007 self:primaryexp(ls, nv.v)
4008 if nv.v.k == "VLOCAL" then
4009 self:check_conflict(ls, lh, nv.v)
4010 end
4011 self:checklimit(ls.fs, nvars, self.LUAI_MAXCCALLS - ls.L.nCcalls,
4012 "variables in assignment")
4013 self:assignment(ls, nv, nvars + 1)
4014 else -- assignment -> '=' explist1
4015 self:checknext(ls, "=")
4016 local nexps = self:explist1(ls, e)
4017 if nexps ~= nvars then
4018 self:adjust_assign(ls, nvars, nexps, e)
4019 if nexps > nvars then
4020 ls.fs.freereg = ls.fs.freereg - (nexps - nvars) -- remove extra values
4021 end
4022 else
4023 luaK:setoneret(ls.fs, e) -- close last expression
4024 luaK:storevar(ls.fs, lh.v, e)
4025 return -- avoid default
4026 end
4027 end
4028 self:init_exp(e, "VNONRELOC", ls.fs.freereg - 1) -- default assignment
4029 luaK:storevar(ls.fs, lh.v, e)
4030end
4031
4032------------------------------------------------------------------------
4033-- parse condition in a repeat statement or an if control structure
4034-- * used in repeatstat(), test_then_block()
4035------------------------------------------------------------------------
4036function luaY:cond(ls)
4037 -- cond -> exp
4038 local v = {} -- expdesc
4039 self:expr(ls, v) -- read condition
4040 if v.k == "VNIL" then v.k = "VFALSE" end -- 'falses' are all equal here
4041 luaK:goiftrue(ls.fs, v)
4042 return v.f
4043end
4044
4045------------------------------------------------------------------------
4046-- parse a break statement
4047-- * used in statements()
4048------------------------------------------------------------------------
4049function luaY:breakstat(ls)
4050 -- stat -> BREAK
4051 local fs = ls.fs
4052 local bl = fs.bl
4053 local upval = false
4054 while bl and not bl.isbreakable do
4055 if bl.upval then upval = true end
4056 bl = bl.previous
4057 end
4058 if not bl then
4059 luaX:syntaxerror(ls, "no loop to break")
4060 end
4061 if upval then
4062 luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
4063 end
4064 bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs))
4065end
4066
4067------------------------------------------------------------------------
4068-- parse a while-do control structure, body processed by block()
4069-- * with dynamic array sizes, MAXEXPWHILE + EXTRAEXP limits imposed by
4070-- the function's implementation can be removed
4071-- * used in statements()
4072------------------------------------------------------------------------
4073function luaY:whilestat(ls, line)
4074 -- whilestat -> WHILE cond DO block END
4075 local fs = ls.fs
4076 local bl = {} -- BlockCnt
4077 luaX:next(ls) -- skip WHILE
4078 local whileinit = luaK:getlabel(fs)
4079 local condexit = self:cond(ls)
4080 self:enterblock(fs, bl, true)
4081 self:checknext(ls, "TK_DO")
4082 self:block(ls)
4083 luaK:patchlist(fs, luaK:jump(fs), whileinit)
4084 self:check_match(ls, "TK_END", "TK_WHILE", line)
4085 self:leaveblock(fs)
4086 luaK:patchtohere(fs, condexit) -- false conditions finish the loop
4087end
4088
4089------------------------------------------------------------------------
4090-- parse a repeat-until control structure, body parsed by chunk()
4091-- * used in statements()
4092------------------------------------------------------------------------
4093function luaY:repeatstat(ls, line)
4094 -- repeatstat -> REPEAT block UNTIL cond
4095 local fs = ls.fs
4096 local repeat_init = luaK:getlabel(fs)
4097 local bl1, bl2 = {}, {} -- BlockCnt
4098 self:enterblock(fs, bl1, true) -- loop block
4099 self:enterblock(fs, bl2, false) -- scope block
4100 luaX:next(ls) -- skip REPEAT
4101 self:chunk(ls)
4102 self:check_match(ls, "TK_UNTIL", "TK_REPEAT", line)
4103 local condexit = self:cond(ls) -- read condition (inside scope block)
4104 if not bl2.upval then -- no upvalues?
4105 self:leaveblock(fs) -- finish scope
4106 luaK:patchlist(ls.fs, condexit, repeat_init) -- close the loop
4107 else -- complete semantics when there are upvalues
4108 self:breakstat(ls) -- if condition then break
4109 luaK:patchtohere(ls.fs, condexit) -- else...
4110 self:leaveblock(fs) -- finish scope...
4111 luaK:patchlist(ls.fs, luaK:jump(fs), repeat_init) -- and repeat
4112 end
4113 self:leaveblock(fs) -- finish loop
4114end
4115
4116------------------------------------------------------------------------
4117-- parse the single expressions needed in numerical for loops
4118-- * used in fornum()
4119------------------------------------------------------------------------
4120function luaY:exp1(ls)
4121 local e = {} -- expdesc
4122 self:expr(ls, e)
4123 local k = e.k
4124 luaK:exp2nextreg(ls.fs, e)
4125 return k
4126end
4127
4128------------------------------------------------------------------------
4129-- parse a for loop body for both versions of the for loop
4130-- * used in fornum(), forlist()
4131------------------------------------------------------------------------
4132function luaY:forbody(ls, base, line, nvars, isnum)
4133 -- forbody -> DO block
4134 local bl = {} -- BlockCnt
4135 local fs = ls.fs
4136 self:adjustlocalvars(ls, 3) -- control variables
4137 self:checknext(ls, "TK_DO")
4138 local prep = isnum and luaK:codeAsBx(fs, "OP_FORPREP", base, luaK.NO_JUMP)
4139 or luaK:jump(fs)
4140 self:enterblock(fs, bl, false) -- scope for declared variables
4141 self:adjustlocalvars(ls, nvars)
4142 luaK:reserveregs(fs, nvars)
4143 self:block(ls)
4144 self:leaveblock(fs) -- end of scope for declared variables
4145 luaK:patchtohere(fs, prep)
4146 local endfor = isnum and luaK:codeAsBx(fs, "OP_FORLOOP", base, luaK.NO_JUMP)
4147 or luaK:codeABC(fs, "OP_TFORLOOP", base, 0, nvars)
4148 luaK:fixline(fs, line) -- pretend that `OP_FOR' starts the loop
4149 luaK:patchlist(fs, isnum and endfor or luaK:jump(fs), prep + 1)
4150end
4151
4152------------------------------------------------------------------------
4153-- parse a numerical for loop, calls forbody()
4154-- * used in forstat()
4155------------------------------------------------------------------------
4156function luaY:fornum(ls, varname, line)
4157 -- fornum -> NAME = exp1,exp1[,exp1] forbody
4158 local fs = ls.fs
4159 local base = fs.freereg
4160 self:new_localvarliteral(ls, "(for index)", 0)
4161 self:new_localvarliteral(ls, "(for limit)", 1)
4162 self:new_localvarliteral(ls, "(for step)", 2)
4163 self:new_localvar(ls, varname, 3)
4164 self:checknext(ls, '=')
4165 self:exp1(ls) -- initial value
4166 self:checknext(ls, ",")
4167 self:exp1(ls) -- limit
4168 if self:testnext(ls, ",") then
4169 self:exp1(ls) -- optional step
4170 else -- default step = 1
4171 luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1))
4172 luaK:reserveregs(fs, 1)
4173 end
4174 self:forbody(ls, base, line, 1, true)
4175end
4176
4177------------------------------------------------------------------------
4178-- parse a generic for loop, calls forbody()
4179-- * used in forstat()
4180------------------------------------------------------------------------
4181function luaY:forlist(ls, indexname)
4182 -- forlist -> NAME {,NAME} IN explist1 forbody
4183 local fs = ls.fs
4184 local e = {} -- expdesc
4185 local nvars = 0
4186 local base = fs.freereg
4187 -- create control variables
4188 self:new_localvarliteral(ls, "(for generator)", nvars)
4189 nvars = nvars + 1
4190 self:new_localvarliteral(ls, "(for state)", nvars)
4191 nvars = nvars + 1
4192 self:new_localvarliteral(ls, "(for control)", nvars)
4193 nvars = nvars + 1
4194 -- create declared variables
4195 self:new_localvar(ls, indexname, nvars)
4196 nvars = nvars + 1
4197 while self:testnext(ls, ",") do
4198 self:new_localvar(ls, self:str_checkname(ls), nvars)
4199 nvars = nvars + 1
4200 end
4201 self:checknext(ls, "TK_IN")
4202 local line = ls.linenumber
4203 self:adjust_assign(ls, 3, self:explist1(ls, e), e)
4204 luaK:checkstack(fs, 3) -- extra space to call generator
4205 self:forbody(ls, base, line, nvars - 3, false)
4206end
4207
4208------------------------------------------------------------------------
4209-- initial parsing for a for loop, calls fornum() or forlist()
4210-- * used in statements()
4211------------------------------------------------------------------------
4212function luaY:forstat(ls, line)
4213 -- forstat -> FOR (fornum | forlist) END
4214 local fs = ls.fs
4215 local bl = {} -- BlockCnt
4216 self:enterblock(fs, bl, true) -- scope for loop and control variables
4217 luaX:next(ls) -- skip `for'
4218 local varname = self:str_checkname(ls) -- first variable name
4219 local c = ls.t.token
4220 if c == "=" then
4221 self:fornum(ls, varname, line)
4222 elseif c == "," or c == "TK_IN" then
4223 self:forlist(ls, varname)
4224 else
4225 luaX:syntaxerror(ls, self:LUA_QL("=").." or "..self:LUA_QL("in").." expected")
4226 end
4227 self:check_match(ls, "TK_END", "TK_FOR", line)
4228 self:leaveblock(fs) -- loop scope (`break' jumps to this point)
4229end
4230
4231------------------------------------------------------------------------
4232-- parse part of an if control structure, including the condition
4233-- * used in ifstat()
4234------------------------------------------------------------------------
4235function luaY:test_then_block(ls)
4236 -- test_then_block -> [IF | ELSEIF] cond THEN block
4237 luaX:next(ls) -- skip IF or ELSEIF
4238 local condexit = self:cond(ls)
4239 self:checknext(ls, "TK_THEN")
4240 self:block(ls) -- `then' part
4241 return condexit
4242end
4243
4244------------------------------------------------------------------------
4245-- parse an if control structure
4246-- * used in statements()
4247------------------------------------------------------------------------
4248function luaY:ifstat(ls, line)
4249 -- ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END
4250 local fs = ls.fs
4251 local escapelist = luaK.NO_JUMP
4252 local flist = self:test_then_block(ls) -- IF cond THEN block
4253 while ls.t.token == "TK_ELSEIF" do
4254 escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
4255 luaK:patchtohere(fs, flist)
4256 flist = self:test_then_block(ls) -- ELSEIF cond THEN block
4257 end
4258 if ls.t.token == "TK_ELSE" then
4259 escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
4260 luaK:patchtohere(fs, flist)
4261 luaX:next(ls) -- skip ELSE (after patch, for correct line info)
4262 self:block(ls) -- 'else' part
4263 else
4264 escapelist = luaK:concat(fs, escapelist, flist)
4265 end
4266 luaK:patchtohere(fs, escapelist)
4267 self:check_match(ls, "TK_END", "TK_IF", line)
4268end
4269
4270------------------------------------------------------------------------
4271-- parse a local function statement
4272-- * used in statements()
4273------------------------------------------------------------------------
4274function luaY:localfunc(ls)
4275 local v, b = {}, {} -- expdesc
4276 local fs = ls.fs
4277 self:new_localvar(ls, self:str_checkname(ls), 0)
4278 self:init_exp(v, "VLOCAL", fs.freereg)
4279 luaK:reserveregs(fs, 1)
4280 self:adjustlocalvars(ls, 1)
4281 self:body(ls, b, false, ls.linenumber)
4282 luaK:storevar(fs, v, b)
4283 -- debug information will only see the variable after this point!
4284 self:getlocvar(fs, fs.nactvar - 1).startpc = fs.pc
4285end
4286
4287------------------------------------------------------------------------
4288-- parse a local variable declaration statement
4289-- * used in statements()
4290------------------------------------------------------------------------
4291function luaY:localstat(ls)
4292 -- stat -> LOCAL NAME {',' NAME} ['=' explist1]
4293 local nvars = 0
4294 local nexps
4295 local e = {} -- expdesc
4296 repeat
4297 self:new_localvar(ls, self:str_checkname(ls), nvars)
4298 nvars = nvars + 1
4299 until not self:testnext(ls, ",")
4300 if self:testnext(ls, "=") then
4301 nexps = self:explist1(ls, e)
4302 else
4303 e.k = "VVOID"
4304 nexps = 0
4305 end
4306 self:adjust_assign(ls, nvars, nexps, e)
4307 self:adjustlocalvars(ls, nvars)
4308end
4309
4310------------------------------------------------------------------------
4311-- parse a function name specification
4312-- * used in funcstat()
4313------------------------------------------------------------------------
4314function luaY:funcname(ls, v)
4315 -- funcname -> NAME {field} [':' NAME]
4316 local needself = false
4317 self:singlevar(ls, v)
4318 while ls.t.token == "." do
4319 self:field(ls, v)
4320 end
4321 if ls.t.token == ":" then
4322 needself = true
4323 self:field(ls, v)
4324 end
4325 return needself
4326end
4327
4328------------------------------------------------------------------------
4329-- parse a function statement
4330-- * used in statements()
4331------------------------------------------------------------------------
4332function luaY:funcstat(ls, line)
4333 -- funcstat -> FUNCTION funcname body
4334 local v, b = {}, {} -- expdesc
4335 luaX:next(ls) -- skip FUNCTION
4336 local needself = self:funcname(ls, v)
4337 self:body(ls, b, needself, line)
4338 luaK:storevar(ls.fs, v, b)
4339 luaK:fixline(ls.fs, line) -- definition 'happens' in the first line
4340end
4341
4342------------------------------------------------------------------------
4343-- parse a function call with no returns or an assignment statement
4344-- * used in statements()
4345------------------------------------------------------------------------
4346function luaY:exprstat(ls)
4347 -- stat -> func | assignment
4348 local fs = ls.fs
4349 local v = {} -- LHS_assign
4350 v.v = {}
4351 self:primaryexp(ls, v.v)
4352 if v.v.k == "VCALL" then -- stat -> func
4353 luaP:SETARG_C(luaK:getcode(fs, v.v), 1) -- call statement uses no results
4354 else -- stat -> assignment
4355 v.prev = nil
4356 self:assignment(ls, v, 1)
4357 end
4358end
4359
4360------------------------------------------------------------------------
4361-- parse a return statement
4362-- * used in statements()
4363------------------------------------------------------------------------
4364function luaY:retstat(ls)
4365 -- stat -> RETURN explist
4366 local fs = ls.fs
4367 local e = {} -- expdesc
4368 local first, nret -- registers with returned values
4369 luaX:next(ls) -- skip RETURN
4370 if self:block_follow(ls.t.token) or ls.t.token == ";" then
4371 first, nret = 0, 0 -- return no values
4372 else
4373 nret = self:explist1(ls, e) -- optional return values
4374 if self:hasmultret(e.k) then
4375 luaK:setmultret(fs, e)
4376 if e.k == "VCALL" and nret == 1 then -- tail call?
4377 luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL")
4378 assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar)
4379 end
4380 first = fs.nactvar
4381 nret = self.LUA_MULTRET -- return all values
4382 else
4383 if nret == 1 then -- only one single value?
4384 first = luaK:exp2anyreg(fs, e)
4385 else
4386 luaK:exp2nextreg(fs, e) -- values must go to the 'stack'
4387 first = fs.nactvar -- return all 'active' values
4388 assert(nret == fs.freereg - first)
4389 end
4390 end--if
4391 end--if
4392 luaK:ret(fs, first, nret)
4393end
4394
4395------------------------------------------------------------------------
4396-- initial parsing for statements, calls a lot of functions
4397-- * returns boolean instead of 0|1
4398-- * used in chunk()
4399------------------------------------------------------------------------
4400function luaY:statement(ls)
4401 local line = ls.linenumber -- may be needed for error messages
4402 local c = ls.t.token
4403 if c == "TK_IF" then -- stat -> ifstat
4404 self:ifstat(ls, line)
4405 return false
4406 elseif c == "TK_WHILE" then -- stat -> whilestat
4407 self:whilestat(ls, line)
4408 return false
4409 elseif c == "TK_DO" then -- stat -> DO block END
4410 luaX:next(ls) -- skip DO
4411 self:block(ls)
4412 self:check_match(ls, "TK_END", "TK_DO", line)
4413 return false
4414 elseif c == "TK_FOR" then -- stat -> forstat
4415 self:forstat(ls, line)
4416 return false
4417 elseif c == "TK_REPEAT" then -- stat -> repeatstat
4418 self:repeatstat(ls, line)
4419 return false
4420 elseif c == "TK_FUNCTION" then -- stat -> funcstat
4421 self:funcstat(ls, line)
4422 return false
4423 elseif c == "TK_LOCAL" then -- stat -> localstat
4424 luaX:next(ls) -- skip LOCAL
4425 if self:testnext(ls, "TK_FUNCTION") then -- local function?
4426 self:localfunc(ls)
4427 else
4428 self:localstat(ls)
4429 end
4430 return false
4431 elseif c == "TK_RETURN" then -- stat -> retstat
4432 self:retstat(ls)
4433 return true -- must be last statement
4434 elseif c == "TK_BREAK" then -- stat -> breakstat
4435 luaX:next(ls) -- skip BREAK
4436 self:breakstat(ls)
4437 return true -- must be last statement
4438 else
4439 self:exprstat(ls)
4440 return false -- to avoid warnings
4441 end--if c
4442end
4443
4444------------------------------------------------------------------------
4445-- parse a chunk, which consists of a bunch of statements
4446-- * used in parser(), body(), block(), repeatstat()
4447------------------------------------------------------------------------
4448function luaY:chunk(ls)
4449 -- chunk -> { stat [';'] }
4450 local islast = false
4451 self:enterlevel(ls)
4452 while not islast and not self:block_follow(ls.t.token) do
4453 islast = self:statement(ls)
4454 self:testnext(ls, ";")
4455 assert(ls.fs.f.maxstacksize >= ls.fs.freereg and
4456 ls.fs.freereg >= ls.fs.nactvar)
4457 ls.fs.freereg = ls.fs.nactvar -- free registers
4458 end
4459 self:leavelevel(ls)
4460end
4461
4462-- }======================================================================
4463return luaY
4464
4465
4466
4467
4468
4469-------------------------------------------------
4470
4471
4472
4473--[[--------------------------------------------------------------------
4474
4475 lzio.lua
4476 Lua buffered streams in Lua
4477 This file is part of Yueliang.
4478
4479 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
4480 The COPYRIGHT file describes the conditions
4481 under which this software may be distributed.
4482
4483 See the ChangeLog for more information.
4484
4485----------------------------------------------------------------------]]
4486
4487--[[--------------------------------------------------------------------
4488-- Notes:
4489-- * EOZ is implemented as a string, "EOZ"
4490-- * Format of z structure (ZIO)
4491-- z.n -- bytes still unread
4492-- z.p -- last read position position in buffer
4493-- z.reader -- chunk reader function
4494-- z.data -- additional data
4495-- * Current position, p, is now last read index instead of a pointer
4496--
4497-- Not implemented:
4498-- * luaZ_lookahead: used only in lapi.c:lua_load to detect binary chunk
4499-- * luaZ_read: used only in lundump.c:ezread to read +1 bytes
4500-- * luaZ_openspace: dropped; let Lua handle buffers as strings (used in
4501-- lundump.c:LoadString & lvm.c:luaV_concat)
4502-- * luaZ buffer macros: dropped; buffers are handled as strings
4503-- * lauxlib.c:getF reader implementation has an extraline flag to
4504-- skip over a shbang (#!) line, this is not implemented here
4505--
4506-- Added:
4507-- (both of the following are vaguely adapted from lauxlib.c)
4508-- * luaZ:make_getS: create Reader from a string
4509-- * luaZ:make_getF: create Reader that reads from a file
4510--
4511-- Changed in 5.1.x:
4512-- * Chunkreader renamed to Reader (ditto with Chunkwriter)
4513-- * Zio struct: no more name string, added Lua state for reader
4514-- (however, Yueliang readers do not require a Lua state)
4515----------------------------------------------------------------------]]
4516
4517local luaZ = {}
4518
4519------------------------------------------------------------------------
4520-- * reader() should return a string, or nil if nothing else to parse.
4521-- Additional data can be set only during stream initialization
4522-- * Readers are handled in lauxlib.c, see luaL_load(file|buffer|string)
4523-- * LUAL_BUFFERSIZE=BUFSIZ=512 in make_getF() (located in luaconf.h)
4524-- * Original Reader typedef:
4525-- const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
4526-- * This Lua chunk reader implementation:
4527-- returns string or nil, no arguments to function
4528------------------------------------------------------------------------
4529
4530------------------------------------------------------------------------
4531-- create a chunk reader from a source string
4532------------------------------------------------------------------------
4533function luaZ:make_getS(buff)
4534 local b = buff
4535 return function() -- chunk reader anonymous function here
4536 if not b then return nil end
4537 local data = b
4538 b = nil
4539 return data
4540 end
4541end
4542
4543------------------------------------------------------------------------
4544-- create a chunk reader from a source file
4545------------------------------------------------------------------------
4546--[[
4547function luaZ:make_getF(filename)
4548 local LUAL_BUFFERSIZE = 512
4549 local h = io.open(filename, "r")
4550 if not h then return nil end
4551 return function() -- chunk reader anonymous function here
4552 if not h or io.type(h) == "closed file" then return nil end
4553 local buff = h:read(LUAL_BUFFERSIZE)
4554 if not buff then h:close(); h = nil end
4555 return buff
4556 end
4557end
4558--]]
4559------------------------------------------------------------------------
4560-- creates a zio input stream
4561-- returns the ZIO structure, z
4562------------------------------------------------------------------------
4563function luaZ:init(reader, data, name)
4564 if not reader then return end
4565 local z = {}
4566 z.reader = reader
4567 z.data = data or ""
4568 z.name = name
4569 -- set up additional data for reading
4570 if not data or data == "" then z.n = 0 else z.n = #data end
4571 z.p = 0
4572 return z
4573end
4574
4575------------------------------------------------------------------------
4576-- fill up input buffer
4577------------------------------------------------------------------------
4578function luaZ:fill(z)
4579 local buff = z.reader()
4580 z.data = buff
4581 if not buff or buff == "" then return "EOZ" end
4582 z.n, z.p = #buff - 1, 1
4583 return string.sub(buff, 1, 1)
4584end
4585
4586------------------------------------------------------------------------
4587-- get next character from the input stream
4588-- * local n, p are used to optimize code generation
4589------------------------------------------------------------------------
4590function luaZ:zgetc(z)
4591 local n, p = z.n, z.p + 1
4592 if n > 0 then
4593 z.n, z.p = n - 1, p
4594 return string.sub(z.data, p, p)
4595 else
4596 return self:fill(z)
4597 end
4598end
4599
4600return luaZ
4601
4602
4603
4604----------------------------------------
4605
4606
4607
4608local Concat = table.concat;
4609local Select = select;
4610local _Byte = string.byte;
4611local Sub = string.sub;
4612local Opcode = { -- Opcode types.
4613 'ABC', 'ABx', 'ABC', 'ABC';
4614 'ABC', 'ABx', 'ABC', 'ABx';
4615 'ABC', 'ABC', 'ABC', 'ABC';
4616 'ABC', 'ABC', 'ABC', 'ABC';
4617 'ABC', 'ABC', 'ABC', 'ABC';
4618 'ABC', 'ABC', 'AsBx', 'ABC';
4619 'ABC', 'ABC', 'ABC', 'ABC';
4620 'ABC', 'ABC', 'ABC', 'AsBx';
4621 'AsBx', 'ABC', 'ABC', 'ABC';
4622 'ABx', 'ABC';
4623};
4624
4625-- rlbi author -> Rerumu
4626
4627--[[
4628 Features;
4629 * Almost complete rework/rewrite
4630 * Fast and performant
4631 * Fixes to upvalues
4632 * C Stack overflow fixes in opcodes
4633 * Fixed missing/broken returns
4634 * Numeric constant 0 is properly handled
4635 * Formatted in a more readable manner
4636 * Tailcalls and stack issues have been fixed
4637 * CLOSE implemented
4638 * SETLIST (extended) implemented
4639 * VARARG fixes
4640--]]
4641
4642local function gBit(Bit, Start, End) -- No tail-calls, yay.
4643 if End then -- Thanks to cntkillme for giving input on this shorter, better approach.
4644 local Res = (Bit / 2 ^ (Start - 1)) % 2 ^ ((End - 1) - (Start - 1) + 1);
4645
4646 return Res - Res % 1;
4647 else
4648 local Plc = 2 ^ (Start - 1);
4649
4650 if (Bit % (Plc + Plc) >= Plc) then
4651 return 1;
4652 else
4653 return 0;
4654 end;
4655 end;
4656end;
4657
4658local function GetMeaning(ByteString)
4659 local Pos = 1;
4660 local gSizet;
4661 local gInt;
4662
4663 local function gBits8() -- Get the next byte in the stream.
4664 local F = _Byte(ByteString, Pos, Pos);
4665
4666 Pos = Pos + 1;
4667
4668 return F;
4669 end;
4670
4671 local function gBits32()
4672 local W, X, Y, Z = _Byte(ByteString, Pos, Pos + 3);
4673
4674 Pos = Pos + 4;
4675
4676 return (Z * 16777216) + (Y * 65536) + (X * 256) + W;
4677 end;
4678
4679 local function gBits64()
4680 return gBits32() * 4294967296 + gBits32();
4681 end;
4682
4683 local function gFloat()
4684 local A, B = gBits32(), gBits32();
4685
4686 if ((A + B) == 0) then
4687 return 0; -- Float 0 tends to be very messy, so this is a temp fix until I figure out what's up.
4688 else
4689 return (-2 * gBit(B, 32) + 1) * (2 ^ (gBit(B, 21, 31) - 1023)) * ((gBit(B, 1, 20) * (2^32) + A) / (2 ^ 52) + 1);
4690 end;
4691 end;
4692
4693 local function gString(Len)
4694 local Str;
4695
4696 if Len then
4697 Str = Sub(ByteString, Pos, Pos + Len - 1);
4698
4699 Pos = Pos + Len;
4700 else
4701 Len = gSizet();
4702
4703 if (Len == 0) then return; end;
4704
4705 Str = Sub(ByteString, Pos, Pos + Len - 1);
4706
4707 Pos = Pos + Len;
4708 end;
4709
4710 return Str;
4711 end;
4712
4713 local function ChunkDecode()
4714 local Instr = {};
4715 local Const = {};
4716 local Proto = {};
4717 local Chunk = {
4718 Instr = Instr; -- Instructions
4719 Const = Const; -- Constants
4720 Proto = Proto; -- Prototypes
4721 Lines = {}; -- Lines
4722 Name = gString(); -- Grab name string.
4723 FirstL = gInt(); -- First line.
4724 LastL = gInt(); -- Last line.
4725 Upvals = gBits8(); -- Upvalue count.
4726 Args = gBits8(); -- Arg count.
4727 Vargs = gBits8(); -- Vararg type.
4728 Stack = gBits8(); -- Stack.
4729 };
4730
4731 if Chunk.Name then
4732 Chunk.Name = Sub(Chunk.Name, 1, -2);
4733 end;
4734
4735 for Idx = 1, gInt() do -- Loading instructions to the chunk.
4736 local Data = gBits32();
4737 local Opco = gBit(Data, 1, 6);
4738 local Type = Opcode[Opco + 1];
4739 local Inst;
4740
4741 if Type then
4742 Inst = {
4743 Enum = Opco;
4744 gBit(Data, 7, 14); -- Register A.
4745 };
4746
4747 if (Type == 'ABC') then -- Most common, basic instruction type.
4748 Inst[2] = gBit(Data, 24, 32);
4749 Inst[3] = gBit(Data, 15, 23);
4750 elseif (Type == 'ABx') then
4751 Inst[2] = gBit(Data, 15, 32);
4752 elseif (Type == 'AsBx') then
4753 Inst[2] = gBit(Data, 15, 32) - 131071;
4754 end;
4755 else
4756 Inst = Data; -- Extended SETLIST
4757 end;
4758
4759 Instr[Idx] = Inst;
4760 end;
4761
4762 for Idx = 1, gInt() do -- Load constants.
4763 local Type = gBits8();
4764 local Cons;
4765
4766 if (Type == 1) then -- Boolean
4767 Cons = (gBits8() ~= 0);
4768 elseif (Type == 3) then -- Float/Double
4769 Cons = gFloat();
4770 elseif (Type == 4) then
4771 Cons = Sub(gString(), 1, -2);
4772 end;
4773
4774 Const[Idx - 1] = Cons;
4775 end;
4776
4777 for Idx = 1, gInt() do -- Nested function prototypes.
4778 Proto[Idx - 1] = ChunkDecode();
4779 end;
4780
4781 do -- Debugging
4782 local Lines = Chunk.Lines;
4783
4784 for Idx = 1, gInt() do
4785 Lines[Idx] = gBits32();
4786 end;
4787
4788 for Idx = 1, gInt() do -- Locals in stack.
4789 gString(); -- Name of local.
4790 gBits32(); -- Starting point.
4791 gBits32(); -- End point.
4792 end;
4793
4794 for Idx = 1, gInt() do -- Upvalues.
4795 gString(); -- Name of upvalue.
4796 end;
4797 end;
4798
4799 return Chunk; -- Finished chunk.
4800 end;
4801
4802 do -- Most of this chunk I was too lazy to reformat or change
4803 assert(gString(4) == "\27Lua", "Lua bytecode expected.");
4804 assert(gBits8() == 0x51, "Only Lua 5.1 is supported.");
4805
4806 gBits8(); -- Probably version control.
4807 gBits8(); -- Is small endians.
4808
4809 local IntSize = gBits8(); -- Int size
4810 local Sizet = gBits8(); -- size_t
4811
4812 if (IntSize == 4) then
4813 gInt = gBits32;
4814 elseif (IntSize == 8) then
4815 gInt = gBits64;
4816 else
4817 error('Integer size not supported', 2);
4818 end;
4819
4820 if (Sizet == 4) then
4821 gSizet = gBits32;
4822 elseif (Sizet == 8) then
4823 gSizet = gBits64;
4824 else
4825 error('Sizet size not supported', 2);
4826 end;
4827
4828 assert(gString(3) == "\4\8\0", "Unsupported bytecode target platform");
4829 end;
4830
4831 return ChunkDecode();
4832end;
4833
4834local function _Returns(...)
4835 return Select('#', ...), {...};
4836end;
4837
4838local function Wrap(Chunk, Env, Upvalues)
4839 local Instr = Chunk.Instr;
4840 local Const = Chunk.Const;
4841 local Proto = Chunk.Proto;
4842
4843 local function OnError(Err, Position) -- Handle your errors in whatever way.
4844 local Name = Chunk.Name or 'Code';
4845 local Line = Chunk.Lines[Position] or '?';
4846 local Err = Err:match'^.+:%s*(.+)' or Err;
4847
4848 error(string.format('%s (%s): %s', Name, Line, Err), 0);
4849 end;
4850
4851 return function(...) -- Returned function to run bytecode chunk (Don't be stupid, you can't setfenv this to work your way).
4852 local Upvalues = Upvalues;
4853 local Instr = Instr;
4854 local Const = Const;
4855 local Proto = Proto;
4856
4857 local InstrPoint, Top = 1, -1;
4858 local Vararg, Varargsz = {}, Select('#', ...) - 1;
4859
4860 local GStack = {};
4861 local Lupvals = {};
4862 local Stack = setmetatable({}, {
4863 __index = GStack;
4864 __newindex = function(_, Key, Value)
4865 if (Key > Top) and Value then
4866 Top = Key;
4867 end;
4868
4869 GStack[Key] = Value;
4870 end;
4871 });
4872
4873 local function Loop()
4874 local Instr = Instr;
4875 local Inst, Enum, A, B;
4876
4877 while true do
4878 Inst = Instr[InstrPoint];
4879 Enum = Inst.Enum;
4880 InstrPoint = InstrPoint + 1;
4881
4882 if (Enum == 0) then -- MOVE
4883 Stack[Inst[1]] = Stack[Inst[2]];
4884 elseif (Enum == 1) then -- LOADK
4885 Stack[Inst[1]] = Const[Inst[2]];
4886 elseif (Enum == 2) then -- LOADBOOL
4887 Stack[Inst[1]] = (Inst[2] ~= 0);
4888
4889 if (Inst[3] ~= 0) then
4890 InstrPoint = InstrPoint + 1;
4891 end;
4892 elseif (Enum == 3) then -- LOADNIL
4893 local Stk = Stack;
4894
4895 for Idx = Inst[1], Inst[2] do
4896 Stk[Idx] = nil;
4897 end;
4898 elseif (Enum == 4) then -- GETUPVAL
4899 Stack[Inst[1]] = Upvalues[Inst[2]];
4900 elseif (Enum == 5) then -- GETGLOBAL
4901 Stack[Inst[1]] = Env[Const[Inst[2]]];
4902 elseif (Enum == 6) then -- GETTABLE
4903 local C = Inst[3];
4904 local Stk = Stack;
4905
4906 if (C > 255) then
4907 C = Const[C - 256];
4908 else
4909 C = Stk[C];
4910 end;
4911
4912 Stk[Inst[1]] = Stk[Inst[2]][C];
4913 elseif (Enum == 7) then -- SETGLOBAL
4914 Env[Const[Inst[2]]] = Stack[Inst[1]];
4915 elseif (Enum == 8) then -- SETUPVAL
4916 Upvalues[Inst[2]] = Stack[Inst[1]];
4917 elseif (Enum == 9) then -- SETTABLE
4918 local B, C = Inst[2], Inst[3];
4919 local Stk = Stack;
4920
4921 if (B > 255) then
4922 B = Const[B - 256];
4923 else
4924 B = Stk[B];
4925 end;
4926
4927 if (C > 255) then
4928 C = Const[C - 256];
4929 else
4930 C = Stk[C];
4931 end;
4932
4933 Stk[Inst[1]][B] = C;
4934 elseif (Enum == 10) then -- NEWTABLE
4935 Stack[Inst[1]] = {};
4936 elseif (Enum == 11) then -- SELF
4937 local A = Inst[1];
4938 local B = Inst[2];
4939 local C = Inst[3];
4940 local Stk = Stack;
4941
4942 B = Stk[B];
4943
4944 if (C > 255) then
4945 C = Const[C - 256];
4946 else
4947 C = Stk[C];
4948 end;
4949
4950 Stk[A + 1] = B;
4951 Stk[A] = B[C];
4952 elseif (Enum == 12) then -- ADD
4953 local B = Inst[2];
4954 local C = Inst[3];
4955 local Stk, Con = Stack, Const;
4956
4957 if (B > 255) then
4958 B = Const[B - 256];
4959 else
4960 B = Stk[B];
4961 end;
4962
4963 if (C > 255) then
4964 C = Const[C - 256];
4965 else
4966 C = Stk[C];
4967 end;
4968
4969 Stk[Inst[1]] = B + C;
4970 elseif (Enum == 13) then -- SUB
4971 local B = Inst[2];
4972 local C = Inst[3];
4973 local Stk, Con = Stack, Const;
4974
4975 if (B > 255) then
4976 B = Const[B - 256];
4977 else
4978 B = Stk[B];
4979 end;
4980
4981 if (C > 255) then
4982 C = Const[C - 256];
4983 else
4984 C = Stk[C];
4985 end;
4986
4987 Stk[Inst[1]] = B - C;
4988 elseif (Enum == 14) then -- MUL
4989 local B = Inst[2];
4990 local C = Inst[3];
4991 local Stk, Con = Stack, Const;
4992
4993 if (B > 255) then
4994 B = Const[B - 256];
4995 else
4996 B = Stk[B];
4997 end;
4998
4999 if (C > 255) then
5000 C = Const[C - 256];
5001 else
5002 C = Stk[C];
5003 end;
5004
5005 Stk[Inst[1]] = B * C;
5006 elseif (Enum == 15) then -- DIV
5007 local B = Inst[2];
5008 local C = Inst[3];
5009 local Stk, Con = Stack, Const;
5010
5011 if (B > 255) then
5012 B = Const[B - 256];
5013 else
5014 B = Stk[B];
5015 end;
5016
5017 if (C > 255) then
5018 C = Const[C - 256];
5019 else
5020 C = Stk[C];
5021 end;
5022
5023 Stk[Inst[1]] = B / C;
5024 elseif (Enum == 16) then -- MOD
5025 local B = Inst[2];
5026 local C = Inst[3];
5027 local Stk, Con = Stack, Const;
5028
5029 if (B > 255) then
5030 B = Const[B - 256];
5031 else
5032 B = Stk[B];
5033 end;
5034
5035 if (C > 255) then
5036 C = Const[C - 256];
5037 else
5038 C = Stk[C];
5039 end;
5040
5041 Stk[Inst[1]] = B % C;
5042 elseif (Enum == 17) then -- POW
5043 local B = Inst[2];
5044 local C = Inst[3];
5045 local Stk, Con = Stack, Const;
5046
5047 if (B > 255) then
5048 B = Const[B - 256];
5049 else
5050 B = Stk[B];
5051 end;
5052
5053 if (C > 255) then
5054 C = Const[C - 256];
5055 else
5056 C = Stk[C];
5057 end;
5058
5059 Stk[Inst[1]] = B ^ C;
5060 elseif (Enum == 18) then -- UNM
5061 Stack[Inst[1]] = -Stack[Inst[2]];
5062 elseif (Enum == 19) then -- NOT
5063 Stack[Inst[1]] = (not Stack[Inst[2]]);
5064 elseif (Enum == 20) then -- LEN
5065 Stack[Inst[1]] = #Stack[Inst[2]];
5066 elseif (Enum == 21) then -- CONCAT
5067 local Stk = Stack;
5068 local B = Inst[2];
5069 local K = {Stack[B]};
5070
5071 for Idx = B + 1, Inst[3] do
5072 K[#K + 1] = Stk[Idx];
5073 end;
5074
5075 Stack[Inst[1]] = Concat(K);
5076 elseif (Enum == 22) then -- JUMP
5077 InstrPoint = InstrPoint + Inst[2];
5078 elseif (Enum == 23) then -- EQ
5079 local A = Inst[1] ~= 0;
5080 local B = Inst[2];
5081 local C = Inst[3];
5082 local Stk, Con = Stack, Const;
5083
5084 if (B > 255) then
5085 B = Const[B - 256];
5086 else
5087 B = Stk[B];
5088 end;
5089
5090 if (C > 255) then
5091 C = Const[C - 256];
5092 else
5093 C = Stk[C];
5094 end;
5095
5096 if (B == C) ~= A then
5097 InstrPoint = InstrPoint + 1;
5098 end;
5099 elseif (Enum == 24) then -- LT
5100 local A = Inst[1] ~= 0;
5101 local B = Inst[2];
5102 local C = Inst[3];
5103 local Stk, Con = Stack, Const;
5104
5105 if (B > 255) then
5106 B = Const[B - 256];
5107 else
5108 B = Stk[B];
5109 end;
5110
5111 if (C > 255) then
5112 C = Const[C - 256];
5113 else
5114 C = Stk[C];
5115 end;
5116
5117 if (B < C) ~= A then
5118 InstrPoint = InstrPoint + 1;
5119 end;
5120 elseif (Enum == 25) then -- LE
5121 local A = Inst[1] ~= 0;
5122 local B = Inst[2];
5123 local C = Inst[3];
5124 local Stk, Con = Stack, Const;
5125
5126 if (B > 255) then
5127 B = Const[B - 256];
5128 else
5129 B = Stk[B];
5130 end;
5131
5132 if (C > 255) then
5133 C = Const[C - 256];
5134 else
5135 C = Stk[C];
5136 end;
5137
5138 if (B <= C) ~= A then
5139 InstrPoint = InstrPoint + 1;
5140 end;
5141 elseif (Enum == 26) then -- TEST
5142 if (not not Stack[Inst[1]]) == (Inst[3] == 0) then
5143 InstrPoint = InstrPoint + 1;
5144 end;
5145 elseif (Enum == 27) then -- TESTSET
5146 local B = Stack[Inst[2]];
5147
5148 if (not not B) == (Inst[3] == 0) then
5149 InstrPoint = InstrPoint + 1;
5150 else
5151 Stack[Inst[1]] = B;
5152 end;
5153 elseif (Enum == 28) then -- CALL
5154 local A = Inst[1];
5155 local B = Inst[2];
5156 local C = Inst[3];
5157 local Stk = Stack;
5158 local Args, Results;
5159 local Limit, Loop;
5160
5161 Args = {};
5162
5163 if (B ~= 1) then
5164 if (B ~= 0) then
5165 Limit = A + B - 1;
5166 else
5167 Limit = Top;
5168 end;
5169
5170 Loop = 0;
5171
5172 for Idx = A + 1, Limit do
5173 Loop = Loop + 1;
5174
5175 Args[Loop] = Stk[Idx];
5176 end;
5177
5178 Limit, Results = _Returns(Stk[A](unpack(Args, 1, Limit - A)));
5179 else
5180 Limit, Results = _Returns(Stk[A]());
5181 end;
5182
5183 Top = A - 1;
5184
5185 if (C ~= 1) then
5186 if (C ~= 0) then
5187 Limit = A + C - 2;
5188 else
5189 Limit = Limit + A;
5190 end;
5191
5192 Loop = 0;
5193
5194 for Idx = A, Limit do
5195 Loop = Loop + 1;
5196
5197 Stk[Idx] = Results[Loop];
5198 end;
5199 end;
5200 elseif (Enum == 29) then -- TAILCALL
5201 local A = Inst[1];
5202 local B = Inst[2];
5203 local C = Inst[3];
5204 local Stk = Stack;
5205 local Args, Results;
5206 local Limit, Loop;
5207
5208 Args = {};
5209
5210 if (B ~= 1) then
5211 if (B ~= 0) then
5212 Limit = A + B - 1;
5213 else
5214 Limit = Top;
5215 end
5216
5217 Loop = 0;
5218
5219 for Idx = A + 1, Limit do
5220 Loop = Loop + 1;
5221
5222 Args[#Args + 1] = Stk[Idx];
5223 end
5224
5225 Results = {Stk[A](unpack(Args, 1, Limit - A))};
5226 else
5227 Results = {Stk[A]()};
5228 end;
5229
5230 return Results;
5231 elseif (Enum == 30) then -- RETURN
5232 local A = Inst[1];
5233 local B = Inst[2];
5234 local Stk = Stack;
5235 local Loop, Output;
5236 local Limit;
5237
5238 if (B == 1) then
5239 return;
5240 elseif (B == 0) then
5241 Limit = Top;
5242 else
5243 Limit = A + B - 2;
5244 end;
5245
5246 Output = {};
5247
5248 local Loop = 0;
5249
5250 for Idx = A, Limit do
5251 Loop = Loop + 1;
5252
5253 Output[Loop] = Stk[Idx];
5254 end;
5255
5256 return Output;
5257 elseif (Enum == 31) then -- FORLOOP
5258 local A = Inst[1];
5259 local Stk = Stack;
5260
5261 local Step = Stk[A + 2];
5262 local Index = Stk[A] + Step;
5263
5264 Stk[A] = Index;
5265
5266 if (Step > 0) then
5267 if Index <= Stk[A + 1] then
5268 InstrPoint = InstrPoint + Inst[2];
5269
5270 Stk[A + 3] = Index;
5271 end;
5272 else
5273 if Index >= Stk[A + 1] then
5274 InstrPoint = InstrPoint + Inst[2];
5275
5276 Stk[A + 3] = Index;
5277 end
5278 end
5279 elseif (Enum == 32) then -- FORPREP
5280 local A = Inst[1];
5281 local Stk = Stack;
5282
5283 Stk[A] = Stk[A] - Stk[A + 2];
5284
5285 InstrPoint = InstrPoint + Inst[2];
5286 elseif (Enum == 33) then -- TFORLOOP
5287 local A = Inst[1];
5288 local B = Inst[2];
5289 local C = Inst[3];
5290 local Stk = Stack;
5291
5292 local Offset = A + 2;
5293 local Result = {Stk[A](Stk[A + 1], Stk[A + 2])};
5294
5295 for Idx = 1, C do
5296 Stack[Offset + Idx] = Result[Idx];
5297 end;
5298
5299 if (Stk[A + 3] ~= nil) then
5300 Stk[A + 2] = Stk[A + 3];
5301 else
5302 InstrPoint = InstrPoint + 1;
5303 end;
5304 elseif (Enum == 34) then -- SETLIST
5305 local A = Inst[1];
5306 local B = Inst[2];
5307 local C = Inst[3];
5308 local Stk = Stack;
5309
5310 if (C == 0) then
5311 InstrPoint = InstrPoint + 1;
5312 C = Instr[InstrPoint]; -- This implementation was ambiguous! Will eventually re-test.
5313 end;
5314
5315 local Offset = (C - 1) * 50;
5316 local T = Stk[A]; -- Assuming T is the newly created table.
5317
5318 if (B == 0) then
5319 B = Top;
5320 end;
5321
5322 for Idx = 1, B do
5323 T[Offset + Idx] = Stk[A + Idx];
5324 end;
5325 elseif (Enum == 35) then -- CLOSE
5326 local A = Inst[1];
5327 local Cls = {}; -- Slight doubts on any issues this may cause
5328
5329 for Idx = 1, #Lupvals do
5330 local List = Lupvals[Idx];
5331
5332 for Idz = 0, #List do
5333 local Upv = List[Idz];
5334 local Stk = Upv[1];
5335 local Pos = Upv[2];
5336
5337 if (Stk == Stack) and (Pos >= A) then
5338 Cls[Pos] = Stk[Pos];
5339 Upv[1] = Cls; -- @memcorrupt credit me for the spoonfeed
5340 end;
5341 end;
5342 end;
5343 elseif (Enum == 36) then -- CLOSURE
5344 local Proto = Proto[Inst[2]];
5345 local Instr = Instr;
5346 local Stk = Stack;
5347
5348 local Indexes;
5349 local NewUvals;
5350
5351 if (Proto.Upvals ~= 0) then
5352 Indexes = {};
5353 NewUvals = setmetatable({}, {
5354 __index = function(_, Key)
5355 local Val = Indexes[Key];
5356
5357 return Val[1][Val[2]];
5358 end,
5359 __newindex = function(_, Key, Value)
5360 local Val = Indexes[Key];
5361
5362 Val[1][Val[2]] = Value;
5363 end;
5364 }
5365 );
5366
5367 for Idx = 1, Proto.Upvals do
5368 local Mvm = Instr[InstrPoint];
5369
5370 if (Mvm.Enum == 0) then -- MOVE
5371 Indexes[Idx - 1] = {Stk, Mvm[2]};
5372 elseif (Mvm.Enum == 4) then -- GETUPVAL
5373 Indexes[Idx - 1] = {Upvalues, Mvm[2]};
5374 end;
5375
5376 InstrPoint = InstrPoint + 1;
5377 end;
5378
5379 Lupvals[#Lupvals + 1] = Indexes;
5380 end;
5381
5382 Stk[Inst[1]] = Wrap(Proto, Env, NewUvals);
5383 elseif (Enum == 37) then -- VARARG
5384 local A = Inst[1];
5385 local B = Inst[2];
5386 local Stk, Vararg = Stack, Vararg;
5387
5388 for Idx = A, A + (B > 0 and B - 1 or Varargsz) do
5389 Stk[Idx] = Vararg[Idx - A];
5390 end;
5391 end;
5392 end;
5393 end;
5394
5395 local Args = {...};
5396
5397 for Idx = 0, Varargsz do
5398 Stack[Idx] = Args[Idx + 1];
5399
5400 if (Idx >= Chunk.Args) then
5401 Vararg[Idx - Chunk.Args] = Args[Idx + 1];
5402 end;
5403 end;
5404
5405 local A, B = pcall(Loop); -- Pcalling to allow yielding
5406
5407 if A then -- We're always expecting this to come out true (because errorless code)
5408 if B then -- So I flipped the conditions.
5409 return unpack(B);
5410 end;
5411
5412 return;
5413 else
5414 OnError(B, InstrPoint - 1); -- Didn't get time to test the `-1` honestly, but I assume it works properly
5415 end;
5416 end;
5417end;
5418
5419return function(BCode, Env) -- lua_function LoadBytecode (string BCode, table Env)
5420 local Buffer = GetMeaning(BCode);
5421
5422 return Wrap(Buffer, Env or getfenv(0)), Buffer;
5423end;