· 5 years ago · Nov 17, 2020, 04:58 PM
1script.Name = "Loadstring"
2do
3 local Dependencies = {
4 'FiOne',
5 'LuaK',
6 'LuaP',
7 'LuaU',
8 'LuaX',
9 'LuaY',
10 'LuaZ',
11 }
12 for i, v in pairs(Dependencies) do
13 Instance.new("ModuleScript", script).Name = v
14 end
15end
16
17local RealScript = script
18function require(module)
19 local func = getfenv()[module.Name]
20 getfenv(func).script = (RealScript.Name == module.Name) and RealScript or RealScript[module.Name]
21 return func()
22end
23
24function Loadstring()
25
26local Dependencies = {
27 'FiOne',
28 'LuaK',
29 'LuaP',
30 'LuaU',
31 'LuaX',
32 'LuaY',
33 'LuaZ',
34}
35
36for _,v in next, Dependencies do script:WaitForChild(v) end
37
38local LuaX = require(script.LuaX)
39local LuaY = require(script.LuaY)
40local LuaZ = require(script.LuaZ)
41local LuaU = require(script.LuaU)
42local FiOne = require(script.FiOne)
43
44LuaX:init()
45
46local LuaState = {}
47
48getfenv().script = nil
49
50return function(str,env)
51 local f,writer,buff,name
52 local env = env or getfenv(2)
53 local name = (env.script and env.script:GetFullName())
54
55 local ran,error = pcall(function()
56
57 local zio = LuaZ:init(LuaZ:make_getS(str), nil)
58 if not zio then return error("Failed to initalize LuaZ") end
59
60 local func = LuaY:parser(LuaState, zio, nil, name or "nil")
61 writer, buff = LuaU:make_setS()
62 LuaU:dump(LuaState, func, writer, buff)
63
64 f = FiOne.wrap_lua(FiOne.stm_lua(buff.data), env)
65 end)
66
67 if ran then
68 return f,buff.data
69 else
70 return nil,error
71 end
72end
73end
74
75function FiOne()
76local bit = bit or bit32 or require('bit')
77local stm_lua_bytecode
78local wrap_lua_func
79local stm_lua_func
80
81-- SETLIST config
82local FIELDS_PER_FLUSH = 50
83
84-- opcode types for getting values
85local opcode_t = {
86 [0] = 'ABC',
87 'ABx',
88 'ABC',
89 'ABC',
90 'ABC',
91 'ABx',
92 'ABC',
93 'ABx',
94 'ABC',
95 'ABC',
96 'ABC',
97 'ABC',
98 'ABC',
99 'ABC',
100 'ABC',
101 'ABC',
102 'ABC',
103 'ABC',
104 'ABC',
105 'ABC',
106 'ABC',
107 'ABC',
108 'AsBx',
109 'ABC',
110 'ABC',
111 'ABC',
112 'ABC',
113 'ABC',
114 'ABC',
115 'ABC',
116 'ABC',
117 'AsBx',
118 'AsBx',
119 'ABC',
120 'ABC',
121 'ABC',
122 'ABx',
123 'ABC',
124}
125
126local opcode_m = {
127 [0] = {b = 'OpArgR', c = 'OpArgN'},
128 {b = 'OpArgK', c = 'OpArgN'},
129 {b = 'OpArgU', c = 'OpArgU'},
130 {b = 'OpArgR', c = 'OpArgN'},
131 {b = 'OpArgU', c = 'OpArgN'},
132 {b = 'OpArgK', c = 'OpArgN'},
133 {b = 'OpArgR', c = 'OpArgK'},
134 {b = 'OpArgK', c = 'OpArgN'},
135 {b = 'OpArgU', c = 'OpArgN'},
136 {b = 'OpArgK', c = 'OpArgK'},
137 {b = 'OpArgU', c = 'OpArgU'},
138 {b = 'OpArgR', c = 'OpArgK'},
139 {b = 'OpArgK', c = 'OpArgK'},
140 {b = 'OpArgK', c = 'OpArgK'},
141 {b = 'OpArgK', c = 'OpArgK'},
142 {b = 'OpArgK', c = 'OpArgK'},
143 {b = 'OpArgK', c = 'OpArgK'},
144 {b = 'OpArgK', c = 'OpArgK'},
145 {b = 'OpArgR', c = 'OpArgN'},
146 {b = 'OpArgR', c = 'OpArgN'},
147 {b = 'OpArgR', c = 'OpArgN'},
148 {b = 'OpArgR', c = 'OpArgR'},
149 {b = 'OpArgR', c = 'OpArgN'},
150 {b = 'OpArgK', c = 'OpArgK'},
151 {b = 'OpArgK', c = 'OpArgK'},
152 {b = 'OpArgK', c = 'OpArgK'},
153 {b = 'OpArgR', c = 'OpArgU'},
154 {b = 'OpArgR', c = 'OpArgU'},
155 {b = 'OpArgU', c = 'OpArgU'},
156 {b = 'OpArgU', c = 'OpArgU'},
157 {b = 'OpArgU', c = 'OpArgN'},
158 {b = 'OpArgR', c = 'OpArgN'},
159 {b = 'OpArgR', c = 'OpArgN'},
160 {b = 'OpArgN', c = 'OpArgU'},
161 {b = 'OpArgU', c = 'OpArgU'},
162 {b = 'OpArgN', c = 'OpArgN'},
163 {b = 'OpArgU', c = 'OpArgN'},
164 {b = 'OpArgU', c = 'OpArgN'},
165}
166
167-- int rd_int_basic(string src, int s, int e, int d)
168-- @src - Source binary string
169-- @s - Start index of a little endian integer
170-- @e - End index of the integer
171-- @d - Direction of the loop
172local function rd_int_basic(src, s, e, d)
173 local num = 0
174
175 -- if bb[l] > 127 then -- signed negative
176 -- num = num - 256 ^ l
177 -- bb[l] = bb[l] - 128
178 -- end
179
180 for i = s, e, d do num = num + src:byte(i, i) * 256 ^ (i - s) end
181
182 return num
183end
184
185-- float rd_flt_basic(byte f1..8)
186-- @f1..4 - The 4 bytes composing a little endian float
187local function rd_flt_basic(f1, f2, f3, f4)
188 local sign = bit.rshift(f4, 7)
189 local exp = bit.rshift(f3, 7) + bit.lshift(bit.band(f4, 0x7F), 1)
190 local frac = f1 + bit.lshift(f2, 8) + bit.lshift(bit.band(f3, 0x7F), 16)
191 local normal = 1
192
193 if exp == 0 then
194 if frac == 0 then
195 return sign * 0
196 else
197 normal = 0
198 exp = 1
199 end
200 elseif exp == 0x7F then
201 if frac == 0 then
202 return sign * (1 / 0)
203 else
204 return sign * (0 / 0)
205 end
206 end
207
208 return (-1) ^ sign * 2 ^ (exp - 127) * (1 + normal / 2 ^ 23)
209end
210
211-- double rd_dbl_basic(byte f1..8)
212-- @f1..8 - The 8 bytes composing a little endian double
213local function rd_dbl_basic(f1, f2, f3, f4, f5, f6, f7, f8)
214 local sign = bit.rshift(f8, 7)
215 local exp = bit.lshift(bit.band(f8, 0x7F), 4) + bit.rshift(f7, 4)
216 local frac = bit.band(f7, 0x0F) * 2 ^ 48
217 local normal = 1
218
219 frac = frac + (f6 * 2 ^ 40) + (f5 * 2 ^ 32) + (f4 * 2 ^ 24) + (f3 * 2 ^ 16) + (f2 * 2 ^ 8) + f1 -- help
220
221 if exp == 0 then
222 if frac == 0 then
223 return sign * 0
224 else
225 normal = 0
226 exp = 1
227 end
228 elseif exp == 0x7FF then
229 if frac == 0 then
230 return sign * (1 / 0)
231 else
232 return sign * (0 / 0)
233 end
234 end
235
236 return (-1) ^ sign * 2 ^ (exp - 1023) * (normal + frac / 2 ^ 52)
237end
238
239-- int rd_int_le(string src, int s, int e)
240-- @src - Source binary string
241-- @s - Start index of a little endian integer
242-- @e - End index of the integer
243local function rd_int_le(src, s, e) return rd_int_basic(src, s, e - 1, 1) end
244
245-- int rd_int_be(string src, int s, int e)
246-- @src - Source binary string
247-- @s - Start index of a big endian integer
248-- @e - End index of the integer
249local function rd_int_be(src, s, e) return rd_int_basic(src, e - 1, s, -1) end
250
251-- float rd_flt_le(string src, int s)
252-- @src - Source binary string
253-- @s - Start index of little endian float
254local function rd_flt_le(src, s) return rd_flt_basic(src:byte(s, s + 3)) end
255
256-- float rd_flt_be(string src, int s)
257-- @src - Source binary string
258-- @s - Start index of big endian float
259local function rd_flt_be(src, s)
260 local f1, f2, f3, f4 = src:byte(s, s + 3)
261 return rd_flt_basic(f4, f3, f2, f1)
262end
263
264-- double rd_dbl_le(string src, int s)
265-- @src - Source binary string
266-- @s - Start index of little endian double
267local function rd_dbl_le(src, s) return rd_dbl_basic(src:byte(s, s + 7)) end
268
269-- double rd_dbl_be(string src, int s)
270-- @src - Source binary string
271-- @s - Start index of big endian double
272local function rd_dbl_be(src, s)
273 local f1, f2, f3, f4, f5, f6, f7, f8 = src:byte(s, s + 7) -- same
274 return rd_dbl_basic(f8, f7, f6, f5, f4, f3, f2, f1)
275end
276
277-- to avoid nested ifs in deserializing
278local float_types = {
279 [4] = {little = rd_flt_le, big = rd_flt_be},
280 [8] = {little = rd_dbl_le, big = rd_dbl_be},
281}
282
283-- byte stm_byte(Stream S)
284-- @S - Stream object to read from
285local function stm_byte(S)
286 local idx = S.index
287 local bt = S.source:byte(idx, idx)
288
289 S.index = idx + 1
290 return bt
291end
292
293-- string stm_string(Stream S, int len)
294-- @S - Stream object to read from
295-- @len - Length of string being read
296local function stm_string(S, len)
297 local pos = S.index + len
298 local str = S.source:sub(S.index, pos - 1)
299
300 S.index = pos
301 return str
302end
303
304-- string stm_lstring(Stream S)
305-- @S - Stream object to read from
306local function stm_lstring(S)
307 local len = S:s_szt()
308 local str
309
310 if len ~= 0 then str = stm_string(S, len):sub(1, -2) end
311
312 return str
313end
314
315-- fn cst_int_rdr(string src, int len, fn func)
316-- @len - Length of type for reader
317-- @func - Reader callback
318local function cst_int_rdr(len, func)
319 return function(S)
320 local pos = S.index + len
321 local int = func(S.source, S.index, pos)
322 S.index = pos
323
324 return int
325 end
326end
327
328-- fn cst_flt_rdr(string src, int len, fn func)
329-- @len - Length of type for reader
330-- @func - Reader callback
331local function cst_flt_rdr(len, func)
332 return function(S)
333 local flt = func(S.source, S.index)
334 S.index = S.index + len
335
336 return flt
337 end
338end
339
340local function stm_instructions(S)
341 local size = S:s_int()
342 local code = {}
343
344 for i = 1, size do
345 local ins = S:s_ins()
346 local op = bit.band(ins, 0x3F)
347 local args = opcode_t[op]
348 local mode = opcode_m[op]
349 local data = {value = ins, op = op, A = bit.band(bit.rshift(ins, 6), 0xFF)}
350
351 if args == 'ABC' then
352 data.B = bit.band(bit.rshift(ins, 23), 0x1FF)
353 data.C = bit.band(bit.rshift(ins, 14), 0x1FF)
354 data.is_KB = mode.b == 'OpArgK' and data.B > 0xFF -- post process optimization
355 data.is_KC = mode.c == 'OpArgK' and data.C > 0xFF
356 elseif args == 'ABx' then
357 data.Bx = bit.band(bit.rshift(ins, 14), 0x3FFFF)
358 data.is_K = mode.b == 'OpArgK'
359 elseif args == 'AsBx' then
360 data.sBx = bit.band(bit.rshift(ins, 14), 0x3FFFF) - 131071
361 end
362
363 code[i] = data
364 end
365
366 return code
367end
368
369local function stm_constants(S)
370 local size = S:s_int()
371 local consts = {}
372
373 for i = 1, size do
374 local tt = stm_byte(S)
375 local k
376
377 if tt == 1 then
378 k = stm_byte(S) ~= 0
379 elseif tt == 3 then
380 k = S:s_num()
381 elseif tt == 4 then
382 k = stm_lstring(S)
383 end
384
385 consts[i] = k -- offset +1 during instruction decode
386 end
387
388 return consts
389end
390
391local function stm_subfuncs(S, src)
392 local size = S:s_int()
393 local sub = {}
394
395 for i = 1, size do
396 sub[i] = stm_lua_func(S, src) -- offset +1 in CLOSURE
397 end
398
399 return sub
400end
401
402local function stm_lineinfo(S)
403 local size = S:s_int()
404 local lines = {}
405
406 for i = 1, size do lines[i] = S:s_int() end
407
408 return lines
409end
410
411local function stm_locvars(S)
412 local size = S:s_int()
413 local locvars = {}
414
415 for i = 1, size do locvars[i] = {varname = stm_lstring(S), startpc = S:s_int(), endpc = S:s_int()} end
416
417 return locvars
418end
419
420local function stm_upvals(S)
421 local size = S:s_int()
422 local upvals = {}
423
424 for i = 1, size do upvals[i] = stm_lstring(S) end
425
426 return upvals
427end
428
429function stm_lua_func(S, psrc)
430 local proto = {}
431 local src = stm_lstring(S) or psrc -- source is propagated
432
433 proto.source = src -- source name
434
435 S:s_int() -- line defined
436 S:s_int() -- last line defined
437
438 proto.numupvals = stm_byte(S) -- num upvalues
439 proto.numparams = stm_byte(S) -- num params
440
441 stm_byte(S) -- vararg flag
442 stm_byte(S) -- max stack size
443
444 proto.code = stm_instructions(S)
445 proto.const = stm_constants(S)
446 proto.subs = stm_subfuncs(S, src)
447 proto.lines = stm_lineinfo(S)
448
449 stm_locvars(S)
450 stm_upvals(S)
451
452 -- post process optimization
453 for _, v in ipairs(proto.code) do
454 if v.is_K then
455 v.const = proto.const[v.Bx + 1] -- offset for 1 based index
456 else
457 if v.is_KB then v.const_B = proto.const[v.B - 0xFF] end
458
459 if v.is_KC then v.const_C = proto.const[v.C - 0xFF] end
460 end
461 end
462
463 return proto
464end
465
466function stm_lua_bytecode(src)
467 -- func reader
468 local rdr_func
469
470 -- header flags
471 local little
472 local size_int
473 local size_szt
474 local size_ins
475 local size_num
476 local flag_int
477
478 -- stream object
479 local stream = {
480 -- data
481 index = 1,
482 source = src,
483 }
484
485 assert(stm_string(stream, 4) == '\27Lua', 'invalid Lua signature')
486 assert(stm_byte(stream) == 0x51, 'invalid Lua version')
487 assert(stm_byte(stream) == 0, 'invalid Lua format')
488
489 little = stm_byte(stream) ~= 0
490 size_int = stm_byte(stream)
491 size_szt = stm_byte(stream)
492 size_ins = stm_byte(stream)
493 size_num = stm_byte(stream)
494 flag_int = stm_byte(stream) ~= 0
495
496 rdr_func = little and rd_int_le or rd_int_be
497 stream.s_int = cst_int_rdr(size_int, rdr_func)
498 stream.s_szt = cst_int_rdr(size_szt, rdr_func)
499 stream.s_ins = cst_int_rdr(size_ins, rdr_func)
500
501 if flag_int then
502 stream.s_num = cst_int_rdr(size_num, rdr_func)
503 elseif float_types[size_num] then
504 stream.s_num = cst_flt_rdr(size_num, float_types[size_num][little and 'little' or 'big'])
505 else
506 error('unsupported float size')
507 end
508
509 return stm_lua_func(stream, '@virtual')
510end
511
512local function close_lua_upvalues(list, index)
513 for i, uv in pairs(list) do
514 if uv.index >= index then
515 uv.value = uv.store[uv.index] -- store value
516 uv.store = uv
517 uv.index = 'value' -- self reference
518 list[i] = nil
519 end
520 end
521end
522
523local function open_lua_upvalue(list, index, stack)
524 local prev = list[index]
525
526 if not prev then
527 prev = {index = index, store = stack}
528 list[index] = prev
529 end
530
531 return prev
532end
533
534local function wrap_lua_variadic(...) return select('#', ...), {...} end
535
536local function on_lua_error(exst, err)
537 local src = exst.source
538 local line = exst.lines[exst.pc - 1]
539 local psrc, pline, pmsg = err:match('^(.-):(%d+):%s+(.+)')
540 local fmt = '%s:%i: [%s:%i] %s'
541
542 line = line or '0'
543 psrc = psrc or '?'
544 pline = pline or '0'
545 pmsg = pmsg or err
546
547 error(string.format(fmt, src, line, psrc, pline, pmsg), 0)
548end
549
550local function exec_lua_func(exst)
551 -- localize for easy lookup
552 local code = exst.code
553 local subs = exst.subs
554 local env = exst.env
555 local upvs = exst.upvals
556 local vargs = exst.varargs
557
558 -- state variables
559 local stktop = -1
560 local openupvs = {}
561 local stack = exst.stack
562 local pc = exst.pc
563
564 while true do
565 local inst = code[pc]
566 local op = inst.op
567 pc = pc + 1
568
569 if op < 19 then
570 if op < 9 then
571 if op < 4 then
572 if op < 2 then
573 if op < 1 then
574 --[[0 MOVE]]
575 stack[inst.A] = stack[inst.B]
576 else
577 --[[1 LOADK]]
578 stack[inst.A] = inst.const
579 end
580 elseif op > 2 then
581 --[[3 LOADNIL]]
582 for i = inst.A, inst.B do stack[i] = nil end
583 else
584 --[[2 LOADBOOL]]
585 stack[inst.A] = inst.B ~= 0
586
587 if inst.C ~= 0 then pc = pc + 1 end
588 end
589 elseif op > 4 then
590 if op < 7 then
591 if op < 6 then
592 --[[5 GETGLOBAL]]
593 stack[inst.A] = env[inst.const]
594 else
595 --[[6 GETTABLE]]
596 local index
597
598 if inst.is_KC then
599 index = inst.const_C
600 else
601 index = stack[inst.C]
602 end
603
604 stack[inst.A] = stack[inst.B][index]
605 end
606 elseif op > 7 then
607 --[[8 SETUPVAL]]
608 local uv = upvs[inst.B]
609
610 uv.store[uv.index] = stack[inst.A]
611 else
612 --[[7 SETGLOBAL]]
613 env[inst.const] = stack[inst.A]
614 end
615 else
616 --[[4 GETUPVAL]]
617 local uv = upvs[inst.B]
618
619 stack[inst.A] = uv.store[uv.index]
620 end
621 elseif op > 9 then
622 if op < 14 then
623 if op < 12 then
624 if op < 11 then
625 --[[10 NEWTABLE]]
626 stack[inst.A] = {}
627 else
628 --[[11 SELF]]
629 local A = inst.A
630 local B = inst.B
631 local index
632
633 if inst.is_KC then
634 index = inst.const_C
635 else
636 index = stack[inst.C]
637 end
638
639 stack[A + 1] = stack[B]
640 stack[A] = stack[B][index]
641 end
642 elseif op > 12 then
643 --[[13 SUB]]
644 local lhs, rhs
645
646 if inst.is_KB then
647 lhs = inst.const_B
648 else
649 lhs = stack[inst.B]
650 end
651
652 if inst.is_KC then
653 rhs = inst.const_C
654 else
655 rhs = stack[inst.C]
656 end
657
658 stack[inst.A] = lhs - rhs
659 else
660 --[[12 ADD]]
661 local lhs, rhs
662
663 if inst.is_KB then
664 lhs = inst.const_B
665 else
666 lhs = stack[inst.B]
667 end
668
669 if inst.is_KC then
670 rhs = inst.const_C
671 else
672 rhs = stack[inst.C]
673 end
674
675 stack[inst.A] = lhs + rhs
676 end
677 elseif op > 14 then
678 if op < 17 then
679 if op < 16 then
680 --[[15 DIV]]
681 local lhs, rhs
682
683 if inst.is_KB then
684 lhs = inst.const_B
685 else
686 lhs = stack[inst.B]
687 end
688
689 if inst.is_KC then
690 rhs = inst.const_C
691 else
692 rhs = stack[inst.C]
693 end
694
695 stack[inst.A] = lhs / rhs
696 else
697 --[[16 MOD]]
698 local lhs, rhs
699
700 if inst.is_KB then
701 lhs = inst.const_B
702 else
703 lhs = stack[inst.B]
704 end
705
706 if inst.is_KC then
707 rhs = inst.const_C
708 else
709 rhs = stack[inst.C]
710 end
711
712 stack[inst.A] = lhs % rhs
713 end
714 elseif op > 17 then
715 --[[18 UNM]]
716 stack[inst.A] = -stack[inst.B]
717 else
718 --[[17 POW]]
719 local lhs, rhs
720
721 if inst.is_KB then
722 lhs = inst.const_B
723 else
724 lhs = stack[inst.B]
725 end
726
727 if inst.is_KC then
728 rhs = inst.const_C
729 else
730 rhs = stack[inst.C]
731 end
732
733 stack[inst.A] = lhs ^ rhs
734 end
735 else
736 --[[14 MUL]]
737 local lhs, rhs
738
739 if inst.is_KB then
740 lhs = inst.const_B
741 else
742 lhs = stack[inst.B]
743 end
744
745 if inst.is_KC then
746 rhs = inst.const_C
747 else
748 rhs = stack[inst.C]
749 end
750
751 stack[inst.A] = lhs * rhs
752 end
753 else
754 --[[9 SETTABLE]]
755 local index, value
756
757 if inst.is_KB then
758 index = inst.const_B
759 else
760 index = stack[inst.B]
761 end
762
763 if inst.is_KC then
764 value = inst.const_C
765 else
766 value = stack[inst.C]
767 end
768
769 stack[inst.A][index] = value
770 end
771 elseif op > 19 then
772 if op < 29 then
773 if op < 24 then
774 if op < 22 then
775 if op < 21 then
776 --[[20 LEN]]
777 stack[inst.A] = #stack[inst.B]
778 else
779 --[[21 CONCAT]]
780 local str = stack[inst.B]
781
782 for i = inst.B + 1, inst.C do str = str .. stack[i] end
783
784 stack[inst.A] = str
785 end
786 elseif op > 22 then
787 --[[23 EQ]]
788 local lhs, rhs
789
790 if inst.is_KB then
791 lhs = inst.const_B
792 else
793 lhs = stack[inst.B]
794 end
795
796 if inst.is_KC then
797 rhs = inst.const_C
798 else
799 rhs = stack[inst.C]
800 end
801
802 if (lhs == rhs) ~= (inst.A ~= 0) then pc = pc + 1 end
803 else
804 --[[22 JMP]]
805 pc = pc + inst.sBx
806 end
807 elseif op > 24 then
808 if op < 27 then
809 if op < 26 then
810 --[[25 LE]]
811 local lhs, rhs
812
813 if inst.is_KB then
814 lhs = inst.const_B
815 else
816 lhs = stack[inst.B]
817 end
818
819 if inst.is_KC then
820 rhs = inst.const_C
821 else
822 rhs = stack[inst.C]
823 end
824
825 if (lhs <= rhs) ~= (inst.A ~= 0) then pc = pc + 1 end
826 else
827 --[[26 TEST]]
828 if (not stack[inst.A]) == (inst.C ~= 0) then pc = pc + 1 end
829 end
830 elseif op > 27 then
831 --[[28 CALL]]
832 local A = inst.A
833 local B = inst.B
834 local C = inst.C
835 local params
836 local sz_vals, l_vals
837
838 if B == 0 then
839 params = stktop - A
840 else
841 params = B - 1
842 end
843
844 sz_vals, l_vals = wrap_lua_variadic(stack[A](unpack(stack, A + 1, A + params)))
845
846 if C == 0 then
847 stktop = A + sz_vals - 1
848 else
849 sz_vals = C - 1
850 end
851
852 for i = 1, sz_vals do stack[A + i - 1] = l_vals[i] end
853 else
854 --[[27 TESTSET]]
855 local A = inst.A
856 local B = inst.B
857
858 if (not stack[B]) == (inst.C ~= 0) then
859 pc = pc + 1
860 else
861 stack[A] = stack[B]
862 end
863 end
864 else
865 --[[24 LT]]
866 local lhs, rhs
867
868 if inst.is_KB then
869 lhs = inst.const_B
870 else
871 lhs = stack[inst.B]
872 end
873
874 if inst.is_KC then
875 rhs = inst.const_C
876 else
877 rhs = stack[inst.C]
878 end
879
880 if (lhs < rhs) ~= (inst.A ~= 0) then pc = pc + 1 end
881 end
882 elseif op > 29 then
883 if op < 34 then
884 if op < 32 then
885 if op < 31 then
886 --[[30 RETURN]]
887 local A = inst.A
888 local B = inst.B
889 local vals = {}
890 local size
891
892 if B == 0 then
893 size = stktop - A + 1
894 else
895 size = B - 1
896 end
897
898 for i = 1, size do vals[i] = stack[A + i - 1] end
899
900 close_lua_upvalues(openupvs, math.huge)
901 return size, vals
902 else
903 --[[31 FORLOOP]]
904 local A = inst.A
905 local step = stack[A + 2]
906 local index = stack[A] + step
907 local limit = stack[A + 1]
908 local loops
909
910 if step == math.abs(step) then
911 loops = index <= limit
912 else
913 loops = index >= limit
914 end
915
916 if loops then
917 stack[inst.A] = index
918 stack[inst.A + 3] = index
919 pc = pc + inst.sBx
920 end
921 end
922 elseif op > 32 then
923 --[[33 TFORLOOP]]
924 local A = inst.A
925 local func = stack[A]
926 local state = stack[A + 1]
927 local index = stack[A + 2]
928 local base = A + 3
929 local vals
930
931 stack[base + 2] = index
932 stack[base + 1] = state
933 stack[base] = func
934
935 vals = {func(state, index)}
936
937 for i = 1, inst.C do stack[base + i - 1] = vals[i] end
938
939 if stack[base] ~= nil then
940 stack[A + 2] = stack[base]
941 else
942 pc = pc + 1
943 end
944 else
945 --[[32 FORPREP]]
946 local A = inst.A
947 local init, limit, step
948
949 init = assert(tonumber(stack[A]), '`for` initial value must be a number')
950 limit = assert(tonumber(stack[A + 1]), '`for` limit must be a number')
951 step = assert(tonumber(stack[A + 2]), '`for` step must be a number')
952
953 stack[A] = init - step
954 stack[A + 1] = limit
955 stack[A + 2] = step
956
957 pc = pc + inst.sBx
958 end
959 elseif op > 34 then
960 if op < 36 then
961 --[[35 CLOSE]]
962 close_lua_upvalues(openupvs, inst.A)
963 elseif op > 36 then
964 --[[37 VARARG]]
965 local A = inst.A
966 local size = inst.B
967
968 if size == 0 then
969 size = vargs.size
970 stktop = A + size - 1
971 end
972
973 for i = 1, size do stack[A + i - 1] = vargs.list[i] end
974 else
975 --[[36 CLOSURE]]
976 local sub = subs[inst.Bx + 1] -- offset for 1 based index
977 local nups = sub.numupvals
978 local uvlist
979
980 if nups ~= 0 then
981 uvlist = {}
982
983 for i = 1, nups do
984 local pseudo = code[pc + i - 1]
985
986 if pseudo.op == 0 then -- @MOVE
987 uvlist[i - 1] = open_lua_upvalue(openupvs, pseudo.B, stack)
988 elseif pseudo.op == 4 then -- @GETUPVAL
989 uvlist[i - 1] = upvs[pseudo.B]
990 end
991 end
992
993 pc = pc + nups
994 end
995
996 stack[inst.A] = wrap_lua_func(sub, env, uvlist)
997 end
998 else
999 --[[34 SETLIST]]
1000 local A = inst.A
1001 local C = inst.C
1002 local size = inst.B
1003 local tab = stack[A]
1004 local offset
1005
1006 if size == 0 then size = stktop - A end
1007
1008 if C == 0 then
1009 C = inst[pc].value
1010 pc = pc + 1
1011 end
1012
1013 offset = (C - 1) * FIELDS_PER_FLUSH
1014
1015 for i = 1, size do tab[i + offset] = stack[A + i] end
1016 end
1017 else
1018 --[[29 TAILCALL]]
1019 local A = inst.A
1020 local B = inst.B
1021 local params
1022
1023 if B == 0 then
1024 params = stktop - A
1025 else
1026 params = B - 1
1027 end
1028
1029 close_lua_upvalues(openupvs, math.huge)
1030 return wrap_lua_variadic(stack[A](unpack(stack, A + 1, A + params)))
1031 end
1032 else
1033 --[[19 NOT]]
1034 stack[inst.A] = not stack[inst.B]
1035 end
1036
1037 exst.pc = pc
1038 end
1039end
1040
1041function wrap_lua_func(state, env, upvals)
1042 local st_code = state.code
1043 local st_subs = state.subs
1044 local st_lines = state.lines
1045 local st_source = state.source
1046 local st_numparams = state.numparams
1047
1048 local function exec_wrap(...)
1049 local stack = {}
1050 local varargs = {}
1051 local sizevarg = 0
1052 local sz_args, l_args = wrap_lua_variadic(...)
1053
1054 local exst
1055 local ok, err, vals
1056
1057 for i = 1, st_numparams do stack[i - 1] = l_args[i] end
1058
1059 if st_numparams < sz_args then
1060 sizevarg = sz_args - st_numparams
1061 for i = 1, sizevarg do varargs[i] = l_args[st_numparams + i] end
1062 end
1063
1064 exst = {
1065 varargs = {list = varargs, size = sizevarg},
1066 code = st_code,
1067 subs = st_subs,
1068 lines = st_lines,
1069 source = st_source,
1070 env = env,
1071 upvals = upvals,
1072 stack = stack,
1073 pc = 1,
1074 }
1075
1076 ok, err, vals = pcall(exec_lua_func, exst, ...)
1077
1078 if ok then
1079 return unpack(vals, 1, err)
1080 else
1081 on_lua_error(exst, err)
1082 end
1083
1084 return -- explicit "return nothing"
1085 end
1086
1087 return exec_wrap
1088end
1089
1090return {stm_lua = stm_lua_bytecode, wrap_lua = wrap_lua_func}
1091end
1092
1093function LuaK()
1094--[[--------------------------------------------------------------------
1095
1096 lcode.lua
1097 Lua 5 code generator in Lua
1098 This file is part of Yueliang.
1099
1100 Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
1101 The COPYRIGHT file describes the conditions
1102 under which this software may be distributed.
1103
1104 See the ChangeLog for more information.
1105
1106----------------------------------------------------------------------]]
1107
1108--[[--------------------------------------------------------------------
1109-- Notes:
1110-- * one function manipulate a pointer argument with a simple data type
1111-- (can't be emulated by a table, ambiguous), now returns that value:
1112-- luaK:concat(fs, l1, l2)
1113-- * luaM_growvector uses the faux luaY:growvector, for limit checking
1114-- * some function parameters changed to boolean, additional code
1115-- translates boolean back to 1/0 for instruction fields
1116--
1117-- Not implemented:
1118-- * NOTE there is a failed assert in luaK:addk, a porting problem
1119--
1120-- Added:
1121-- * constant MAXSTACK from llimits.h
1122-- * luaK:ttisnumber(o) (from lobject.h)
1123-- * luaK:nvalue(o) (from lobject.h)
1124-- * luaK:setnilvalue(o) (from lobject.h)
1125-- * luaK:setnvalue(o, x) (from lobject.h)
1126-- * luaK:setbvalue(o, x) (from lobject.h)
1127-- * luaK:sethvalue(o, x) (from lobject.h), parameter L deleted
1128-- * luaK:setsvalue(o, x) (from lobject.h), parameter L deleted
1129-- * luaK:numadd, luaK:numsub, luaK:nummul, luaK:numdiv, luaK:nummod,
1130-- luaK:numpow, luaK:numunm, luaK:numisnan (from luaconf.h)
1131-- * copyexp(e1, e2) added in luaK:posfix to copy expdesc struct
1132--
1133-- Changed in 5.1.x:
1134-- * enum BinOpr has a new entry, OPR_MOD
1135-- * enum UnOpr has a new entry, OPR_LEN
1136-- * binopistest, unused in 5.0.x, has been deleted
1137-- * macro setmultret is new
1138-- * functions isnumeral, luaK_ret, boolK are new
1139-- * funcion nilK was named nil_constant in 5.0.x
1140-- * function interface changed: need_value, patchtestreg, concat
1141-- * TObject now a TValue
1142-- * functions luaK_setreturns, luaK_setoneret are new
1143-- * function luaK:setcallreturns deleted, to be replaced by:
1144-- luaK:setmultret, luaK:ret, luaK:setreturns, luaK:setoneret
1145-- * functions constfolding, codearith, codecomp are new
1146-- * luaK:codebinop has been deleted
1147-- * function luaK_setlist is new
1148-- * OPR_MULT renamed to OPR_MUL
1149----------------------------------------------------------------------]]
1150
1151-- requires luaP, luaX, luaY
1152local luaK = {}
1153local luaP = require(script.Parent.LuaP)
1154local luaX = require(script.Parent.LuaX)
1155
1156------------------------------------------------------------------------
1157-- constants used by code generator
1158------------------------------------------------------------------------
1159-- maximum stack for a Lua function
1160luaK.MAXSTACK = 250 -- (from llimits.h)
1161
1162--[[--------------------------------------------------------------------
1163-- other functions
1164----------------------------------------------------------------------]]
1165
1166------------------------------------------------------------------------
1167-- emulation of TValue macros (these are from lobject.h)
1168-- * TValue is a table since lcode passes references around
1169-- * tt member field removed, using Lua's type() instead
1170-- * for setsvalue, sethvalue, parameter L (deleted here) in lobject.h
1171-- is used in an assert for testing, see checkliveness(g,obj)
1172------------------------------------------------------------------------
1173function luaK:ttisnumber(o)
1174 if o then return type(o.value) == "number" else return false end
1175end
1176function luaK:nvalue(o) return o.value end
1177function luaK:setnilvalue(o) o.value = nil end
1178function luaK:setsvalue(o, x) o.value = x end
1179luaK.setnvalue = luaK.setsvalue
1180luaK.sethvalue = luaK.setsvalue
1181luaK.setbvalue = luaK.setsvalue
1182
1183------------------------------------------------------------------------
1184-- The luai_num* macros define the primitive operations over numbers.
1185-- * this is not the entire set of primitive operations from luaconf.h
1186-- * used in luaK:constfolding()
1187------------------------------------------------------------------------
1188function luaK:numadd(a, b) return a + b end
1189function luaK:numsub(a, b) return a - b end
1190function luaK:nummul(a, b) return a * b end
1191function luaK:numdiv(a, b) return a / b end
1192function luaK:nummod(a, b) return a % b end
1193 -- ((a) - floor((a)/(b))*(b)) /* actual, for reference */
1194function luaK:numpow(a, b) return a ^ b end
1195function luaK:numunm(a) return -a end
1196function luaK:numisnan(a) return not a == a end
1197 -- a NaN cannot equal another NaN
1198
1199--[[--------------------------------------------------------------------
1200-- code generator functions
1201----------------------------------------------------------------------]]
1202
1203------------------------------------------------------------------------
1204-- Marks the end of a patch list. It is an invalid value both as an absolute
1205-- address, and as a list link (would link an element to itself).
1206------------------------------------------------------------------------
1207luaK.NO_JUMP = -1
1208
1209------------------------------------------------------------------------
1210-- grep "ORDER OPR" if you change these enums
1211------------------------------------------------------------------------
1212luaK.BinOpr = {
1213 OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5,
1214 OPR_CONCAT = 6,
1215 OPR_NE = 7, OPR_EQ = 8,
1216 OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12,
1217 OPR_AND = 13, OPR_OR = 14,
1218 OPR_NOBINOPR = 15,
1219}
1220
1221-- * UnOpr is used by luaK:prefix's op argument, but not directly used
1222-- because the function receives the symbols as strings, e.g. "OPR_NOT"
1223luaK.UnOpr = {
1224 OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3
1225}
1226
1227------------------------------------------------------------------------
1228-- returns the instruction object for given e (expdesc), was a macro
1229------------------------------------------------------------------------
1230function luaK:getcode(fs, e)
1231 return fs.f.code[e.info]
1232end
1233
1234------------------------------------------------------------------------
1235-- codes an instruction with a signed Bx (sBx) field, was a macro
1236-- * used in luaK:jump(), (lparser) luaY:forbody()
1237------------------------------------------------------------------------
1238function luaK:codeAsBx(fs, o, A, sBx)
1239 return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx)
1240end
1241
1242------------------------------------------------------------------------
1243-- set the expdesc e instruction for multiple returns, was a macro
1244------------------------------------------------------------------------
1245function luaK:setmultret(fs, e)
1246 self:setreturns(fs, e, luaY.LUA_MULTRET)
1247end
1248
1249------------------------------------------------------------------------
1250-- there is a jump if patch lists are not identical, was a macro
1251-- * used in luaK:exp2reg(), luaK:exp2anyreg(), luaK:exp2val()
1252------------------------------------------------------------------------
1253function luaK:hasjumps(e)
1254 return e.t ~= e.f
1255end
1256
1257------------------------------------------------------------------------
1258-- true if the expression is a constant number (for constant folding)
1259-- * used in constfolding(), infix()
1260------------------------------------------------------------------------
1261function luaK:isnumeral(e)
1262 return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP
1263end
1264
1265------------------------------------------------------------------------
1266-- codes loading of nil, optimization done if consecutive locations
1267-- * used in luaK:discharge2reg(), (lparser) luaY:adjust_assign()
1268------------------------------------------------------------------------
1269function luaK:_nil(fs, from, n)
1270 if fs.pc > fs.lasttarget then -- no jumps to current position?
1271 if fs.pc == 0 then -- function start?
1272 if from >= fs.nactvar then
1273 return -- positions are already clean
1274 end
1275 else
1276 local previous = fs.f.code[fs.pc - 1]
1277 if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then
1278 local pfrom = luaP:GETARG_A(previous)
1279 local pto = luaP:GETARG_B(previous)
1280 if pfrom <= from and from <= pto + 1 then -- can connect both?
1281 if from + n - 1 > pto then
1282 luaP:SETARG_B(previous, from + n - 1)
1283 end
1284 return
1285 end
1286 end
1287 end
1288 end
1289 self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) -- else no optimization
1290end
1291
1292------------------------------------------------------------------------
1293--
1294-- * used in multiple locations
1295------------------------------------------------------------------------
1296function luaK:jump(fs)
1297 local jpc = fs.jpc -- save list of jumps to here
1298 fs.jpc = self.NO_JUMP
1299 local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP)
1300 j = self:concat(fs, j, jpc) -- keep them on hold
1301 return j
1302end
1303
1304------------------------------------------------------------------------
1305-- codes a RETURN instruction
1306-- * used in luaY:close_func(), luaY:retstat()
1307------------------------------------------------------------------------
1308function luaK:ret(fs, first, nret)
1309 self:codeABC(fs, "OP_RETURN", first, nret + 1, 0)
1310end
1311
1312------------------------------------------------------------------------
1313--
1314-- * used in luaK:jumponcond(), luaK:codecomp()
1315------------------------------------------------------------------------
1316function luaK:condjump(fs, op, A, B, C)
1317 self:codeABC(fs, op, A, B, C)
1318 return self:jump(fs)
1319end
1320
1321------------------------------------------------------------------------
1322--
1323-- * used in luaK:patchlistaux(), luaK:concat()
1324------------------------------------------------------------------------
1325function luaK:fixjump(fs, pc, dest)
1326 local jmp = fs.f.code[pc]
1327 local offset = dest - (pc + 1)
1328 assert(dest ~= self.NO_JUMP)
1329 if math.abs(offset) > luaP.MAXARG_sBx then
1330 luaX:syntaxerror(fs.ls, "control structure too long")
1331 end
1332 luaP:SETARG_sBx(jmp, offset)
1333end
1334
1335------------------------------------------------------------------------
1336-- returns current 'pc' and marks it as a jump target (to avoid wrong
1337-- optimizations with consecutive instructions not in the same basic block).
1338-- * used in multiple locations
1339-- * fs.lasttarget tested only by luaK:_nil() when optimizing OP_LOADNIL
1340------------------------------------------------------------------------
1341function luaK:getlabel(fs)
1342 fs.lasttarget = fs.pc
1343 return fs.pc
1344end
1345
1346------------------------------------------------------------------------
1347--
1348-- * used in luaK:need_value(), luaK:removevalues(), luaK:patchlistaux(),
1349-- luaK:concat()
1350------------------------------------------------------------------------
1351function luaK:getjump(fs, pc)
1352 local offset = luaP:GETARG_sBx(fs.f.code[pc])
1353 if offset == self.NO_JUMP then -- point to itself represents end of list
1354 return self.NO_JUMP -- end of list
1355 else
1356 return (pc + 1) + offset -- turn offset into absolute position
1357 end
1358end
1359
1360------------------------------------------------------------------------
1361--
1362-- * used in luaK:need_value(), luaK:patchtestreg(), luaK:invertjump()
1363------------------------------------------------------------------------
1364function luaK:getjumpcontrol(fs, pc)
1365 local pi = fs.f.code[pc]
1366 local ppi = fs.f.code[pc - 1]
1367 if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then
1368 return ppi
1369 else
1370 return pi
1371 end
1372end
1373
1374------------------------------------------------------------------------
1375-- check whether list has any jump that do not produce a value
1376-- (or produce an inverted value)
1377-- * return value changed to boolean
1378-- * used only in luaK:exp2reg()
1379------------------------------------------------------------------------
1380function luaK:need_value(fs, list)
1381 while list ~= self.NO_JUMP do
1382 local i = self:getjumpcontrol(fs, list)
1383 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then return true end
1384 list = self:getjump(fs, list)
1385 end
1386 return false -- not found
1387end
1388
1389------------------------------------------------------------------------
1390--
1391-- * used in luaK:removevalues(), luaK:patchlistaux()
1392------------------------------------------------------------------------
1393function luaK:patchtestreg(fs, node, reg)
1394 local i = self:getjumpcontrol(fs, node)
1395 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then
1396 return false -- cannot patch other instructions
1397 end
1398 if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then
1399 luaP:SETARG_A(i, reg)
1400 else -- no register to put value or register already has the value
1401 -- due to use of a table as i, i cannot be replaced by another table
1402 -- so the following is required; there is no change to ARG_C
1403 luaP:SET_OPCODE(i, "OP_TEST")
1404 local b = luaP:GETARG_B(i)
1405 luaP:SETARG_A(i, b)
1406 luaP:SETARG_B(i, 0)
1407 -- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); /* C */
1408 end
1409 return true
1410end
1411
1412------------------------------------------------------------------------
1413--
1414-- * used only in luaK:codenot()
1415------------------------------------------------------------------------
1416function luaK:removevalues(fs, list)
1417 while list ~= self.NO_JUMP do
1418 self:patchtestreg(fs, list, luaP.NO_REG)
1419 list = self:getjump(fs, list)
1420 end
1421end
1422
1423------------------------------------------------------------------------
1424--
1425-- * used in luaK:dischargejpc(), luaK:patchlist(), luaK:exp2reg()
1426------------------------------------------------------------------------
1427function luaK:patchlistaux(fs, list, vtarget, reg, dtarget)
1428 while list ~= self.NO_JUMP do
1429 local _next = self:getjump(fs, list)
1430 if self:patchtestreg(fs, list, reg) then
1431 self:fixjump(fs, list, vtarget)
1432 else
1433 self:fixjump(fs, list, dtarget) -- jump to default target
1434 end
1435 list = _next
1436 end
1437end
1438
1439------------------------------------------------------------------------
1440--
1441-- * used only in luaK:code()
1442------------------------------------------------------------------------
1443function luaK:dischargejpc(fs)
1444 self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc)
1445 fs.jpc = self.NO_JUMP
1446end
1447
1448------------------------------------------------------------------------
1449--
1450-- * used in (lparser) luaY:whilestat(), luaY:repeatstat(), luaY:forbody()
1451------------------------------------------------------------------------
1452function luaK:patchlist(fs, list, target)
1453 if target == fs.pc then
1454 self:patchtohere(fs, list)
1455 else
1456 assert(target < fs.pc)
1457 self:patchlistaux(fs, list, target, luaP.NO_REG, target)
1458 end
1459end
1460
1461------------------------------------------------------------------------
1462--
1463-- * used in multiple locations
1464------------------------------------------------------------------------
1465function luaK:patchtohere(fs, list)
1466 self:getlabel(fs)
1467 fs.jpc = self:concat(fs, fs.jpc, list)
1468end
1469
1470------------------------------------------------------------------------
1471-- * l1 was a pointer, now l1 is returned and callee assigns the value
1472-- * used in multiple locations
1473------------------------------------------------------------------------
1474function luaK:concat(fs, l1, l2)
1475 if l2 == self.NO_JUMP then return l1
1476 elseif l1 == self.NO_JUMP then
1477 return l2
1478 else
1479 local list = l1
1480 local _next = self:getjump(fs, list)
1481 while _next ~= self.NO_JUMP do -- find last element
1482 list = _next
1483 _next = self:getjump(fs, list)
1484 end
1485 self:fixjump(fs, list, l2)
1486 end
1487 return l1
1488end
1489
1490------------------------------------------------------------------------
1491--
1492-- * used in luaK:reserveregs(), (lparser) luaY:forlist()
1493------------------------------------------------------------------------
1494function luaK:checkstack(fs, n)
1495 local newstack = fs.freereg + n
1496 if newstack > fs.f.maxstacksize then
1497 if newstack >= self.MAXSTACK then
1498 luaX:syntaxerror(fs.ls, "function or expression too complex")
1499 end
1500 fs.f.maxstacksize = newstack
1501 end
1502end
1503
1504------------------------------------------------------------------------
1505--
1506-- * used in multiple locations
1507------------------------------------------------------------------------
1508function luaK:reserveregs(fs, n)
1509 self:checkstack(fs, n)
1510 fs.freereg = fs.freereg + n
1511end
1512
1513------------------------------------------------------------------------
1514--
1515-- * used in luaK:freeexp(), luaK:dischargevars()
1516------------------------------------------------------------------------
1517function luaK:freereg(fs, reg)
1518 if not luaP:ISK(reg) and reg >= fs.nactvar then
1519 fs.freereg = fs.freereg - 1
1520 assert(reg == fs.freereg)
1521 end
1522end
1523
1524------------------------------------------------------------------------
1525--
1526-- * used in multiple locations
1527------------------------------------------------------------------------
1528function luaK:freeexp(fs, e)
1529 if e.k == "VNONRELOC" then
1530 self:freereg(fs, e.info)
1531 end
1532end
1533
1534------------------------------------------------------------------------
1535-- * TODO NOTE implementation is not 100% correct, since the assert fails
1536-- * luaH_set, setobj deleted; direct table access used instead
1537-- * used in luaK:stringK(), luaK:numberK(), luaK:boolK(), luaK:nilK()
1538------------------------------------------------------------------------
1539function luaK:addk(fs, k, v)
1540 local L = fs.L
1541 local idx = fs.h[k.value]
1542 --TValue *idx = luaH_set(L, fs->h, k); /* C */
1543 local f = fs.f
1544 if self:ttisnumber(idx) then
1545 --TODO this assert currently FAILS (last tested for 5.0.2)
1546 --assert(fs.f.k[self:nvalue(idx)] == v)
1547 --assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); /* C */
1548 return self:nvalue(idx)
1549 else -- constant not found; create a new entry
1550 idx = {}
1551 self:setnvalue(idx, fs.nk)
1552 fs.h[k.value] = idx
1553 -- setnvalue(idx, cast_num(fs->nk)); /* C */
1554 luaY:growvector(L, f.k, fs.nk, f.sizek, nil,
1555 luaP.MAXARG_Bx, "constant table overflow")
1556 -- loop to initialize empty f.k positions not required
1557 f.k[fs.nk] = v
1558 -- setobj(L, &f->k[fs->nk], v); /* C */
1559 -- luaC_barrier(L, f, v); /* GC */
1560 local nk = fs.nk
1561 fs.nk = fs.nk + 1
1562 return nk
1563 end
1564
1565end
1566
1567------------------------------------------------------------------------
1568-- creates and sets a string object
1569-- * used in (lparser) luaY:codestring(), luaY:singlevar()
1570------------------------------------------------------------------------
1571function luaK:stringK(fs, s)
1572 local o = {} -- TValue
1573 self:setsvalue(o, s)
1574 return self:addk(fs, o, o)
1575end
1576
1577------------------------------------------------------------------------
1578-- creates and sets a number object
1579-- * used in luaK:prefix() for negative (or negation of) numbers
1580-- * used in (lparser) luaY:simpleexp(), luaY:fornum()
1581------------------------------------------------------------------------
1582function luaK:numberK(fs, r)
1583 local o = {} -- TValue
1584 self:setnvalue(o, r)
1585 return self:addk(fs, o, o)
1586end
1587
1588------------------------------------------------------------------------
1589-- creates and sets a boolean object
1590-- * used only in luaK:exp2RK()
1591------------------------------------------------------------------------
1592function luaK:boolK(fs, b)
1593 local o = {} -- TValue
1594 self:setbvalue(o, b)
1595 return self:addk(fs, o, o)
1596end
1597
1598------------------------------------------------------------------------
1599-- creates and sets a nil object
1600-- * used only in luaK:exp2RK()
1601------------------------------------------------------------------------
1602function luaK:nilK(fs)
1603 local k, v = {}, {} -- TValue
1604 self:setnilvalue(v)
1605 -- cannot use nil as key; instead use table itself to represent nil
1606 self:sethvalue(k, fs.h)
1607 return self:addk(fs, k, v)
1608end
1609
1610------------------------------------------------------------------------
1611--
1612-- * used in luaK:setmultret(), (lparser) luaY:adjust_assign()
1613------------------------------------------------------------------------
1614function luaK:setreturns(fs, e, nresults)
1615 if e.k == "VCALL" then -- expression is an open function call?
1616 luaP:SETARG_C(self:getcode(fs, e), nresults + 1)
1617 elseif e.k == "VVARARG" then
1618 luaP:SETARG_B(self:getcode(fs, e), nresults + 1);
1619 luaP:SETARG_A(self:getcode(fs, e), fs.freereg);
1620 luaK:reserveregs(fs, 1)
1621 end
1622end
1623
1624------------------------------------------------------------------------
1625--
1626-- * used in luaK:dischargevars(), (lparser) luaY:assignment()
1627------------------------------------------------------------------------
1628function luaK:setoneret(fs, e)
1629 if e.k == "VCALL" then -- expression is an open function call?
1630 e.k = "VNONRELOC"
1631 e.info = luaP:GETARG_A(self:getcode(fs, e))
1632 elseif e.k == "VVARARG" then
1633 luaP:SETARG_B(self:getcode(fs, e), 2)
1634 e.k = "VRELOCABLE" -- can relocate its simple result
1635 end
1636end
1637
1638------------------------------------------------------------------------
1639--
1640-- * used in multiple locations
1641------------------------------------------------------------------------
1642function luaK:dischargevars(fs, e)
1643 local k = e.k
1644 if k == "VLOCAL" then
1645 e.k = "VNONRELOC"
1646 elseif k == "VUPVAL" then
1647 e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0)
1648 e.k = "VRELOCABLE"
1649 elseif k == "VGLOBAL" then
1650 e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info)
1651 e.k = "VRELOCABLE"
1652 elseif k == "VINDEXED" then
1653 self:freereg(fs, e.aux)
1654 self:freereg(fs, e.info)
1655 e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux)
1656 e.k = "VRELOCABLE"
1657 elseif k == "VVARARG" or k == "VCALL" then
1658 self:setoneret(fs, e)
1659 else
1660 -- there is one value available (somewhere)
1661 end
1662end
1663
1664------------------------------------------------------------------------
1665--
1666-- * used only in luaK:exp2reg()
1667------------------------------------------------------------------------
1668function luaK:code_label(fs, A, b, jump)
1669 self:getlabel(fs) -- those instructions may be jump targets
1670 return self:codeABC(fs, "OP_LOADBOOL", A, b, jump)
1671end
1672
1673------------------------------------------------------------------------
1674--
1675-- * used in luaK:discharge2anyreg(), luaK:exp2reg()
1676------------------------------------------------------------------------
1677function luaK:discharge2reg(fs, e, reg)
1678 self:dischargevars(fs, e)
1679 local k = e.k
1680 if k == "VNIL" then
1681 self:_nil(fs, reg, 1)
1682 elseif k == "VFALSE" or k == "VTRUE" then
1683 self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0)
1684 elseif k == "VK" then
1685 self:codeABx(fs, "OP_LOADK", reg, e.info)
1686 elseif k == "VKNUM" then
1687 self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval))
1688 elseif k == "VRELOCABLE" then
1689 local pc = self:getcode(fs, e)
1690 luaP:SETARG_A(pc, reg)
1691 elseif k == "VNONRELOC" then
1692 if reg ~= e.info then
1693 self:codeABC(fs, "OP_MOVE", reg, e.info, 0)
1694 end
1695 else
1696 assert(e.k == "VVOID" or e.k == "VJMP")
1697 return -- nothing to do...
1698 end
1699 e.info = reg
1700 e.k = "VNONRELOC"
1701end
1702
1703------------------------------------------------------------------------
1704--
1705-- * used in luaK:jumponcond(), luaK:codenot()
1706------------------------------------------------------------------------
1707function luaK:discharge2anyreg(fs, e)
1708 if e.k ~= "VNONRELOC" then
1709 self:reserveregs(fs, 1)
1710 self:discharge2reg(fs, e, fs.freereg - 1)
1711 end
1712end
1713
1714------------------------------------------------------------------------
1715--
1716-- * used in luaK:exp2nextreg(), luaK:exp2anyreg(), luaK:storevar()
1717------------------------------------------------------------------------
1718function luaK:exp2reg(fs, e, reg)
1719 self:discharge2reg(fs, e, reg)
1720 if e.k == "VJMP" then
1721 e.t = self:concat(fs, e.t, e.info) -- put this jump in 't' list
1722 end
1723 if self:hasjumps(e) then
1724 local final -- position after whole expression
1725 local p_f = self.NO_JUMP -- position of an eventual LOAD false
1726 local p_t = self.NO_JUMP -- position of an eventual LOAD true
1727 if self:need_value(fs, e.t) or self:need_value(fs, e.f) then
1728 local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs)
1729 p_f = self:code_label(fs, reg, 0, 1)
1730 p_t = self:code_label(fs, reg, 1, 0)
1731 self:patchtohere(fs, fj)
1732 end
1733 final = self:getlabel(fs)
1734 self:patchlistaux(fs, e.f, final, reg, p_f)
1735 self:patchlistaux(fs, e.t, final, reg, p_t)
1736 end
1737 e.f, e.t = self.NO_JUMP, self.NO_JUMP
1738 e.info = reg
1739 e.k = "VNONRELOC"
1740end
1741
1742------------------------------------------------------------------------
1743--
1744-- * used in multiple locations
1745------------------------------------------------------------------------
1746function luaK:exp2nextreg(fs, e)
1747 self:dischargevars(fs, e)
1748 self:freeexp(fs, e)
1749 self:reserveregs(fs, 1)
1750 self:exp2reg(fs, e, fs.freereg - 1)
1751end
1752
1753------------------------------------------------------------------------
1754--
1755-- * used in multiple locations
1756------------------------------------------------------------------------
1757function luaK:exp2anyreg(fs, e)
1758 self:dischargevars(fs, e)
1759 if e.k == "VNONRELOC" then
1760 if not self:hasjumps(e) then -- exp is already in a register
1761 return e.info
1762 end
1763 if e.info >= fs.nactvar then -- reg. is not a local?
1764 self:exp2reg(fs, e, e.info) -- put value on it
1765 return e.info
1766 end
1767 end
1768 self:exp2nextreg(fs, e) -- default
1769 return e.info
1770end
1771
1772------------------------------------------------------------------------
1773--
1774-- * used in luaK:exp2RK(), luaK:prefix(), luaK:posfix()
1775-- * used in (lparser) luaY:yindex()
1776------------------------------------------------------------------------
1777function luaK:exp2val(fs, e)
1778 if self:hasjumps(e) then
1779 self:exp2anyreg(fs, e)
1780 else
1781 self:dischargevars(fs, e)
1782 end
1783end
1784
1785------------------------------------------------------------------------
1786--
1787-- * used in multiple locations
1788------------------------------------------------------------------------
1789function luaK:exp2RK(fs, e)
1790 self:exp2val(fs, e)
1791 local k = e.k
1792 if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then
1793 if fs.nk <= luaP.MAXINDEXRK then -- constant fit in RK operand?
1794 -- converted from a 2-deep ternary operator expression
1795 if e.k == "VNIL" then
1796 e.info = self:nilK(fs)
1797 else
1798 e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval)
1799 or self:boolK(fs, e.k == "VTRUE")
1800 end
1801 e.k = "VK"
1802 return luaP:RKASK(e.info)
1803 end
1804 elseif k == "VK" then
1805 if e.info <= luaP.MAXINDEXRK then -- constant fit in argC?
1806 return luaP:RKASK(e.info)
1807 end
1808 else
1809 -- default
1810 end
1811 -- not a constant in the right range: put it in a register
1812 return self:exp2anyreg(fs, e)
1813end
1814
1815------------------------------------------------------------------------
1816--
1817-- * used in (lparser) luaY:assignment(), luaY:localfunc(), luaY:funcstat()
1818------------------------------------------------------------------------
1819function luaK:storevar(fs, var, ex)
1820 local k = var.k
1821 if k == "VLOCAL" then
1822 self:freeexp(fs, ex)
1823 self:exp2reg(fs, ex, var.info)
1824 return
1825 elseif k == "VUPVAL" then
1826 local e = self:exp2anyreg(fs, ex)
1827 self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0)
1828 elseif k == "VGLOBAL" then
1829 local e = self:exp2anyreg(fs, ex)
1830 self:codeABx(fs, "OP_SETGLOBAL", e, var.info)
1831 elseif k == "VINDEXED" then
1832 local e = self:exp2RK(fs, ex)
1833 self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e)
1834 else
1835 assert(0) -- invalid var kind to store
1836 end
1837 self:freeexp(fs, ex)
1838end
1839
1840------------------------------------------------------------------------
1841--
1842-- * used only in (lparser) luaY:primaryexp()
1843------------------------------------------------------------------------
1844function luaK:_self(fs, e, key)
1845 self:exp2anyreg(fs, e)
1846 self:freeexp(fs, e)
1847 local func = fs.freereg
1848 self:reserveregs(fs, 2)
1849 self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key))
1850 self:freeexp(fs, key)
1851 e.info = func
1852 e.k = "VNONRELOC"
1853end
1854
1855------------------------------------------------------------------------
1856--
1857-- * used in luaK:goiftrue(), luaK:codenot()
1858------------------------------------------------------------------------
1859function luaK:invertjump(fs, e)
1860 local pc = self:getjumpcontrol(fs, e.info)
1861 assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and
1862 luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and
1863 luaP:GET_OPCODE(pc) ~= "OP_TEST")
1864 luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0)
1865end
1866
1867------------------------------------------------------------------------
1868--
1869-- * used in luaK:goiftrue(), luaK:goiffalse()
1870------------------------------------------------------------------------
1871function luaK:jumponcond(fs, e, cond)
1872 if e.k == "VRELOCABLE" then
1873 local ie = self:getcode(fs, e)
1874 if luaP:GET_OPCODE(ie) == "OP_NOT" then
1875 fs.pc = fs.pc - 1 -- remove previous OP_NOT
1876 return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1)
1877 end
1878 -- else go through
1879 end
1880 self:discharge2anyreg(fs, e)
1881 self:freeexp(fs, e)
1882 return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0)
1883end
1884
1885------------------------------------------------------------------------
1886--
1887-- * used in luaK:infix(), (lparser) luaY:cond()
1888------------------------------------------------------------------------
1889function luaK:goiftrue(fs, e)
1890 local pc -- pc of last jump
1891 self:dischargevars(fs, e)
1892 local k = e.k
1893 if k == "VK" or k == "VKNUM" or k == "VTRUE" then
1894 pc = self.NO_JUMP -- always true; do nothing
1895 elseif k == "VFALSE" then
1896 pc = self:jump(fs) -- always jump
1897 elseif k == "VJMP" then
1898 self:invertjump(fs, e)
1899 pc = e.info
1900 else
1901 pc = self:jumponcond(fs, e, false)
1902 end
1903 e.f = self:concat(fs, e.f, pc) -- insert last jump in `f' list
1904 self:patchtohere(fs, e.t)
1905 e.t = self.NO_JUMP
1906end
1907
1908------------------------------------------------------------------------
1909--
1910-- * used in luaK:infix()
1911------------------------------------------------------------------------
1912function luaK:goiffalse(fs, e)
1913 local pc -- pc of last jump
1914 self:dischargevars(fs, e)
1915 local k = e.k
1916 if k == "VNIL" or k == "VFALSE"then
1917 pc = self.NO_JUMP -- always false; do nothing
1918 elseif k == "VTRUE" then
1919 pc = self:jump(fs) -- always jump
1920 elseif k == "VJMP" then
1921 pc = e.info
1922 else
1923 pc = self:jumponcond(fs, e, true)
1924 end
1925 e.t = self:concat(fs, e.t, pc) -- insert last jump in `t' list
1926 self:patchtohere(fs, e.f)
1927 e.f = self.NO_JUMP
1928end
1929
1930------------------------------------------------------------------------
1931--
1932-- * used only in luaK:prefix()
1933------------------------------------------------------------------------
1934function luaK:codenot(fs, e)
1935 self:dischargevars(fs, e)
1936 local k = e.k
1937 if k == "VNIL" or k == "VFALSE" then
1938 e.k = "VTRUE"
1939 elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then
1940 e.k = "VFALSE"
1941 elseif k == "VJMP" then
1942 self:invertjump(fs, e)
1943 elseif k == "VRELOCABLE" or k == "VNONRELOC" then
1944 self:discharge2anyreg(fs, e)
1945 self:freeexp(fs, e)
1946 e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0)
1947 e.k = "VRELOCABLE"
1948 else
1949 assert(0) -- cannot happen
1950 end
1951 -- interchange true and false lists
1952 e.f, e.t = e.t, e.f
1953 self:removevalues(fs, e.f)
1954 self:removevalues(fs, e.t)
1955end
1956
1957------------------------------------------------------------------------
1958--
1959-- * used in (lparser) luaY:field(), luaY:primaryexp()
1960------------------------------------------------------------------------
1961function luaK:indexed(fs, t, k)
1962 t.aux = self:exp2RK(fs, k)
1963 t.k = "VINDEXED"
1964end
1965
1966------------------------------------------------------------------------
1967--
1968-- * used only in luaK:codearith()
1969------------------------------------------------------------------------
1970function luaK:constfolding(op, e1, e2)
1971 local r
1972 if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end
1973 local v1 = e1.nval
1974 local v2 = e2.nval
1975 if op == "OP_ADD" then
1976 r = self:numadd(v1, v2)
1977 elseif op == "OP_SUB" then
1978 r = self:numsub(v1, v2)
1979 elseif op == "OP_MUL" then
1980 r = self:nummul(v1, v2)
1981 elseif op == "OP_DIV" then
1982 if v2 == 0 then return false end -- do not attempt to divide by 0
1983 r = self:numdiv(v1, v2)
1984 elseif op == "OP_MOD" then
1985 if v2 == 0 then return false end -- do not attempt to divide by 0
1986 r = self:nummod(v1, v2)
1987 elseif op == "OP_POW" then
1988 r = self:numpow(v1, v2)
1989 elseif op == "OP_UNM" then
1990 r = self:numunm(v1)
1991 elseif op == "OP_LEN" then
1992 return false -- no constant folding for 'len'
1993 else
1994 assert(0)
1995 r = 0
1996 end
1997 if self:numisnan(r) then return false end -- do not attempt to produce NaN
1998 e1.nval = r
1999 return true
2000end
2001
2002------------------------------------------------------------------------
2003--
2004-- * used in luaK:prefix(), luaK:posfix()
2005------------------------------------------------------------------------
2006function luaK:codearith(fs, op, e1, e2)
2007 if self:constfolding(op, e1, e2) then
2008 return
2009 else
2010 local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0
2011 local o1 = self:exp2RK(fs, e1)
2012 if o1 > o2 then
2013 self:freeexp(fs, e1)
2014 self:freeexp(fs, e2)
2015 else
2016 self:freeexp(fs, e2)
2017 self:freeexp(fs, e1)
2018 end
2019 e1.info = self:codeABC(fs, op, 0, o1, o2)
2020 e1.k = "VRELOCABLE"
2021 end
2022end
2023
2024------------------------------------------------------------------------
2025--
2026-- * used only in luaK:posfix()
2027------------------------------------------------------------------------
2028function luaK:codecomp(fs, op, cond, e1, e2)
2029 local o1 = self:exp2RK(fs, e1)
2030 local o2 = self:exp2RK(fs, e2)
2031 self:freeexp(fs, e2)
2032 self:freeexp(fs, e1)
2033 if cond == 0 and op ~= "OP_EQ" then
2034 -- exchange args to replace by `<' or `<='
2035 o1, o2 = o2, o1 -- o1 <==> o2
2036 cond = 1
2037 end
2038 e1.info = self:condjump(fs, op, cond, o1, o2)
2039 e1.k = "VJMP"
2040end
2041
2042------------------------------------------------------------------------
2043--
2044-- * used only in (lparser) luaY:subexpr()
2045------------------------------------------------------------------------
2046function luaK:prefix(fs, op, e)
2047 local e2 = {} -- expdesc
2048 e2.t, e2.f = self.NO_JUMP, self.NO_JUMP
2049 e2.k = "VKNUM"
2050 e2.nval = 0
2051 if op == "OPR_MINUS" then
2052 if not self:isnumeral(e) then
2053 self:exp2anyreg(fs, e) -- cannot operate on non-numeric constants
2054 end
2055 self:codearith(fs, "OP_UNM", e, e2)
2056 elseif op == "OPR_NOT" then
2057 self:codenot(fs, e)
2058 elseif op == "OPR_LEN" then
2059 self:exp2anyreg(fs, e) -- cannot operate on constants
2060 self:codearith(fs, "OP_LEN", e, e2)
2061 else
2062 assert(0)
2063 end
2064end
2065
2066------------------------------------------------------------------------
2067--
2068-- * used only in (lparser) luaY:subexpr()
2069------------------------------------------------------------------------
2070function luaK:infix(fs, op, v)
2071 if op == "OPR_AND" then
2072 self:goiftrue(fs, v)
2073 elseif op == "OPR_OR" then
2074 self:goiffalse(fs, v)
2075 elseif op == "OPR_CONCAT" then
2076 self:exp2nextreg(fs, v) -- operand must be on the 'stack'
2077 elseif op == "OPR_ADD" or op == "OPR_SUB" or
2078 op == "OPR_MUL" or op == "OPR_DIV" or
2079 op == "OPR_MOD" or op == "OPR_POW" then
2080 if not self:isnumeral(v) then self:exp2RK(fs, v) end
2081 else
2082 self:exp2RK(fs, v)
2083 end
2084end
2085
2086------------------------------------------------------------------------
2087--
2088-- * used only in (lparser) luaY:subexpr()
2089------------------------------------------------------------------------
2090-- table lookups to simplify testing
2091luaK.arith_op = {
2092 OPR_ADD = "OP_ADD", OPR_SUB = "OP_SUB", OPR_MUL = "OP_MUL",
2093 OPR_DIV = "OP_DIV", OPR_MOD = "OP_MOD", OPR_POW = "OP_POW",
2094}
2095luaK.comp_op = {
2096 OPR_EQ = "OP_EQ", OPR_NE = "OP_EQ", OPR_LT = "OP_LT",
2097 OPR_LE = "OP_LE", OPR_GT = "OP_LT", OPR_GE = "OP_LE",
2098}
2099luaK.comp_cond = {
2100 OPR_EQ = 1, OPR_NE = 0, OPR_LT = 1,
2101 OPR_LE = 1, OPR_GT = 0, OPR_GE = 0,
2102}
2103function luaK:posfix(fs, op, e1, e2)
2104 -- needed because e1 = e2 doesn't copy values...
2105 -- * in 5.0.x, only k/info/aux/t/f copied, t for AND, f for OR
2106 -- but here, all elements are copied for completeness' sake
2107 local function copyexp(e1, e2)
2108 e1.k = e2.k
2109 e1.info = e2.info; e1.aux = e2.aux
2110 e1.nval = e2.nval
2111 e1.t = e2.t; e1.f = e2.f
2112 end
2113 if op == "OPR_AND" then
2114 assert(e1.t == self.NO_JUMP) -- list must be closed
2115 self:dischargevars(fs, e2)
2116 e2.f = self:concat(fs, e2.f, e1.f)
2117 copyexp(e1, e2)
2118 elseif op == "OPR_OR" then
2119 assert(e1.f == self.NO_JUMP) -- list must be closed
2120 self:dischargevars(fs, e2)
2121 e2.t = self:concat(fs, e2.t, e1.t)
2122 copyexp(e1, e2)
2123 elseif op == "OPR_CONCAT" then
2124 self:exp2val(fs, e2)
2125 if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then
2126 assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1)
2127 self:freeexp(fs, e1)
2128 luaP:SETARG_B(self:getcode(fs, e2), e1.info)
2129 e1.k = "VRELOCABLE"
2130 e1.info = e2.info
2131 else
2132 self:exp2nextreg(fs, e2) -- operand must be on the 'stack'
2133 self:codearith(fs, "OP_CONCAT", e1, e2)
2134 end
2135 else
2136 -- the following uses a table lookup in place of conditionals
2137 local arith = self.arith_op[op]
2138 if arith then
2139 self:codearith(fs, arith, e1, e2)
2140 else
2141 local comp = self.comp_op[op]
2142 if comp then
2143 self:codecomp(fs, comp, self.comp_cond[op], e1, e2)
2144 else
2145 assert(0)
2146 end
2147 end--if arith
2148 end--if op
2149end
2150
2151------------------------------------------------------------------------
2152-- adjusts debug information for last instruction written, in order to
2153-- change the line where item comes into existence
2154-- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat()
2155------------------------------------------------------------------------
2156function luaK:fixline(fs, line)
2157 fs.f.lineinfo[fs.pc - 1] = line
2158end
2159
2160------------------------------------------------------------------------
2161-- general function to write an instruction into the instruction buffer,
2162-- sets debug information too
2163-- * used in luaK:codeABC(), luaK:codeABx()
2164-- * called directly by (lparser) luaY:whilestat()
2165------------------------------------------------------------------------
2166function luaK:code(fs, i, line)
2167 local f = fs.f
2168 self:dischargejpc(fs) -- 'pc' will change
2169 -- put new instruction in code array
2170 luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil,
2171 luaY.MAX_INT, "code size overflow")
2172 f.code[fs.pc] = i
2173 -- save corresponding line information
2174 luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil,
2175 luaY.MAX_INT, "code size overflow")
2176 f.lineinfo[fs.pc] = line
2177 local pc = fs.pc
2178 fs.pc = fs.pc + 1
2179 return pc
2180end
2181
2182------------------------------------------------------------------------
2183-- writes an instruction of type ABC
2184-- * calls luaK:code()
2185------------------------------------------------------------------------
2186function luaK:codeABC(fs, o, a, b, c)
2187 assert(luaP:getOpMode(o) == luaP.OpMode.iABC)
2188 assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0)
2189 assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0)
2190 return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline)
2191end
2192
2193------------------------------------------------------------------------
2194-- writes an instruction of type ABx
2195-- * calls luaK:code(), called by luaK:codeAsBx()
2196------------------------------------------------------------------------
2197function luaK:codeABx(fs, o, a, bc)
2198 assert(luaP:getOpMode(o) == luaP.OpMode.iABx or
2199 luaP:getOpMode(o) == luaP.OpMode.iAsBx)
2200 assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN)
2201 return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline)
2202end
2203
2204------------------------------------------------------------------------
2205--
2206-- * used in (lparser) luaY:closelistfield(), luaY:lastlistfield()
2207------------------------------------------------------------------------
2208function luaK:setlist(fs, base, nelems, tostore)
2209 local c = math.floor((nelems - 1)/luaP.LFIELDS_PER_FLUSH) + 1
2210 local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore
2211 assert(tostore ~= 0)
2212 if c <= luaP.MAXARG_C then
2213 self:codeABC(fs, "OP_SETLIST", base, b, c)
2214 else
2215 self:codeABC(fs, "OP_SETLIST", base, b, 0)
2216 self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline)
2217 end
2218 fs.freereg = base + 1 -- free registers with list values
2219end
2220
2221return function(a) luaY = a return luaK end
2222end
2223
2224function LuaP()
2225--[[--------------------------------------------------------------------
2226
2227 lopcodes.lua
2228 Lua 5 virtual machine opcodes in Lua
2229 This file is part of Yueliang.
2230
2231 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
2232 The COPYRIGHT file describes the conditions
2233 under which this software may be distributed.
2234
2235 See the ChangeLog for more information.
2236
2237----------------------------------------------------------------------]]
2238
2239--[[--------------------------------------------------------------------
2240-- Notes:
2241-- * an Instruction is a table with OP, A, B, C, Bx elements; this
2242-- makes the code easy to follow and should allow instruction handling
2243-- to work with doubles and ints
2244-- * WARNING luaP:Instruction outputs instructions encoded in little-
2245-- endian form and field size and positions are hard-coded
2246--
2247-- Not implemented:
2248-- *
2249--
2250-- Added:
2251-- * luaP:CREATE_Inst(c): create an inst from a number (for OP_SETLIST)
2252-- * luaP:Instruction(i): convert field elements to a 4-char string
2253-- * luaP:DecodeInst(x): convert 4-char string into field elements
2254--
2255-- Changed in 5.1.x:
2256-- * POS_OP added, instruction field positions changed
2257-- * some symbol names may have changed, e.g. LUAI_BITSINT
2258-- * new operators for RK indices: BITRK, ISK(x), INDEXK(r), RKASK(x)
2259-- * OP_MOD, OP_LEN is new
2260-- * OP_TEST is now OP_TESTSET, OP_TEST is new
2261-- * OP_FORLOOP, OP_TFORLOOP adjusted, OP_FORPREP is new
2262-- * OP_TFORPREP deleted
2263-- * OP_SETLIST and OP_SETLISTO merged and extended
2264-- * OP_VARARG is new
2265-- * many changes to implementation of OpMode data
2266----------------------------------------------------------------------]]
2267
2268local luaP = {}
2269
2270--[[
2271===========================================================================
2272 We assume that instructions are unsigned numbers.
2273 All instructions have an opcode in the first 6 bits.
2274 Instructions can have the following fields:
2275 'A' : 8 bits
2276 'B' : 9 bits
2277 'C' : 9 bits
2278 'Bx' : 18 bits ('B' and 'C' together)
2279 'sBx' : signed Bx
2280
2281 A signed argument is represented in excess K; that is, the number
2282 value is the unsigned value minus K. K is exactly the maximum value
2283 for that argument (so that -max is represented by 0, and +max is
2284 represented by 2*max), which is half the maximum for the corresponding
2285 unsigned argument.
2286===========================================================================
2287--]]
2288
2289luaP.OpMode = { iABC = 0, iABx = 1, iAsBx = 2 } -- basic instruction format
2290
2291------------------------------------------------------------------------
2292-- size and position of opcode arguments.
2293-- * WARNING size and position is hard-coded elsewhere in this script
2294------------------------------------------------------------------------
2295luaP.SIZE_C = 9
2296luaP.SIZE_B = 9
2297luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
2298luaP.SIZE_A = 8
2299
2300luaP.SIZE_OP = 6
2301
2302luaP.POS_OP = 0
2303luaP.POS_A = luaP.POS_OP + luaP.SIZE_OP
2304luaP.POS_C = luaP.POS_A + luaP.SIZE_A
2305luaP.POS_B = luaP.POS_C + luaP.SIZE_C
2306luaP.POS_Bx = luaP.POS_C
2307
2308------------------------------------------------------------------------
2309-- limits for opcode arguments.
2310-- we use (signed) int to manipulate most arguments,
2311-- so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
2312------------------------------------------------------------------------
2313-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
2314-- running on a Lua VM with double or int as LUA_NUMBER
2315
2316luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
2317luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
2318
2319luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
2320luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
2321luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
2322
2323-- creates a mask with 'n' 1 bits at position 'p'
2324-- MASK1(n,p) deleted, not required
2325-- creates a mask with 'n' 0 bits at position 'p'
2326-- MASK0(n,p) deleted, not required
2327
2328--[[--------------------------------------------------------------------
2329 Visual representation for reference:
2330
2331 31 | | | 0 bit position
2332 +-----+-----+-----+----------+
2333 | B | C | A | Opcode | iABC format
2334 +-----+-----+-----+----------+
2335 - 9 - 9 - 8 - 6 - field sizes
2336 +-----+-----+-----+----------+
2337 | [s]Bx | A | Opcode | iABx | iAsBx format
2338 +-----+-----+-----+----------+
2339
2340----------------------------------------------------------------------]]
2341
2342------------------------------------------------------------------------
2343-- the following macros help to manipulate instructions
2344-- * changed to a table object representation, very clean compared to
2345-- the [nightmare] alternatives of using a number or a string
2346-- * Bx is a separate element from B and C, since there is never a need
2347-- to split Bx in the parser or code generator
2348------------------------------------------------------------------------
2349
2350-- these accept or return opcodes in the form of string names
2351function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
2352function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
2353
2354function luaP:GETARG_A(i) return i.A end
2355function luaP:SETARG_A(i, u) i.A = u end
2356
2357function luaP:GETARG_B(i) return i.B end
2358function luaP:SETARG_B(i, b) i.B = b end
2359
2360function luaP:GETARG_C(i) return i.C end
2361function luaP:SETARG_C(i, b) i.C = b end
2362
2363function luaP:GETARG_Bx(i) return i.Bx end
2364function luaP:SETARG_Bx(i, b) i.Bx = b end
2365
2366function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
2367function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
2368
2369function luaP:CREATE_ABC(o,a,b,c)
2370 return {OP = self.OpCode[o], A = a, B = b, C = c}
2371end
2372
2373function luaP:CREATE_ABx(o,a,bc)
2374 return {OP = self.OpCode[o], A = a, Bx = bc}
2375end
2376
2377------------------------------------------------------------------------
2378-- create an instruction from a number (for OP_SETLIST)
2379------------------------------------------------------------------------
2380function luaP:CREATE_Inst(c)
2381 local o = c % 64
2382 c = (c - o) / 64
2383 local a = c % 256
2384 c = (c - a) / 256
2385 return self:CREATE_ABx(o, a, c)
2386end
2387
2388------------------------------------------------------------------------
2389-- returns a 4-char string little-endian encoded form of an instruction
2390------------------------------------------------------------------------
2391function luaP:Instruction(i)
2392 if i.Bx then
2393 -- change to OP/A/B/C format
2394 i.C = i.Bx % 512
2395 i.B = (i.Bx - i.C) / 512
2396 end
2397 local I = i.A * 64 + i.OP
2398 local c0 = I % 256
2399 I = i.C * 64 + (I - c0) / 256 -- 6 bits of A left
2400 local c1 = I % 256
2401 I = i.B * 128 + (I - c1) / 256 -- 7 bits of C left
2402 local c2 = I % 256
2403 local c3 = (I - c2) / 256
2404 return string.char(c0, c1, c2, c3)
2405end
2406
2407------------------------------------------------------------------------
2408-- decodes a 4-char little-endian string into an instruction struct
2409------------------------------------------------------------------------
2410function luaP:DecodeInst(x)
2411 local byte = string.byte
2412 local i = {}
2413 local I = byte(x, 1)
2414 local op = I % 64
2415 i.OP = op
2416 I = byte(x, 2) * 4 + (I - op) / 64 -- 2 bits of c0 left
2417 local a = I % 256
2418 i.A = a
2419 I = byte(x, 3) * 4 + (I - a) / 256 -- 2 bits of c1 left
2420 local c = I % 512
2421 i.C = c
2422 i.B = byte(x, 4) * 2 + (I - c) / 512 -- 1 bits of c2 left
2423 local opmode = self.OpMode[tonumber(string.sub(self.opmodes[op + 1], 7, 7))]
2424 if opmode ~= "iABC" then
2425 i.Bx = i.B * 512 + i.C
2426 end
2427 return i
2428end
2429
2430------------------------------------------------------------------------
2431-- Macros to operate RK indices
2432-- * these use arithmetic instead of bit ops
2433------------------------------------------------------------------------
2434
2435-- this bit 1 means constant (0 means register)
2436luaP.BITRK = math.ldexp(1, luaP.SIZE_B - 1)
2437
2438-- test whether value is a constant
2439function luaP:ISK(x) return x >= self.BITRK end
2440
2441-- gets the index of the constant
2442function luaP:INDEXK(x) return x - self.BITRK end
2443
2444luaP.MAXINDEXRK = luaP.BITRK - 1
2445
2446-- code a constant index as a RK value
2447function luaP:RKASK(x) return x + self.BITRK end
2448
2449------------------------------------------------------------------------
2450-- invalid register that fits in 8 bits
2451------------------------------------------------------------------------
2452luaP.NO_REG = luaP.MAXARG_A
2453
2454------------------------------------------------------------------------
2455-- R(x) - register
2456-- Kst(x) - constant (in constant table)
2457-- RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
2458------------------------------------------------------------------------
2459
2460------------------------------------------------------------------------
2461-- grep "ORDER OP" if you change these enums
2462------------------------------------------------------------------------
2463
2464--[[--------------------------------------------------------------------
2465Lua virtual machine opcodes (enum OpCode):
2466------------------------------------------------------------------------
2467name args description
2468------------------------------------------------------------------------
2469OP_MOVE A B R(A) := R(B)
2470OP_LOADK A Bx R(A) := Kst(Bx)
2471OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++
2472OP_LOADNIL A B R(A) := ... := R(B) := nil
2473OP_GETUPVAL A B R(A) := UpValue[B]
2474OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
2475OP_GETTABLE A B C R(A) := R(B)[RK(C)]
2476OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
2477OP_SETUPVAL A B UpValue[B] := R(A)
2478OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
2479OP_NEWTABLE A B C R(A) := {} (size = B,C)
2480OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
2481OP_ADD A B C R(A) := RK(B) + RK(C)
2482OP_SUB A B C R(A) := RK(B) - RK(C)
2483OP_MUL A B C R(A) := RK(B) * RK(C)
2484OP_DIV A B C R(A) := RK(B) / RK(C)
2485OP_MOD A B C R(A) := RK(B) % RK(C)
2486OP_POW A B C R(A) := RK(B) ^ RK(C)
2487OP_UNM A B R(A) := -R(B)
2488OP_NOT A B R(A) := not R(B)
2489OP_LEN A B R(A) := length of R(B)
2490OP_CONCAT A B C R(A) := R(B).. ... ..R(C)
2491OP_JMP sBx pc+=sBx
2492OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++
2493OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++
2494OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++
2495OP_TEST A C if not (R(A) <=> C) then pc++
2496OP_TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else pc++
2497OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
2498OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1))
2499OP_RETURN A B return R(A), ... ,R(A+B-2) (see note)
2500OP_FORLOOP A sBx R(A)+=R(A+2);
2501 if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
2502OP_FORPREP A sBx R(A)-=R(A+2); pc+=sBx
2503OP_TFORLOOP A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
2504 if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++
2505OP_SETLIST A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
2506OP_CLOSE A close all variables in the stack up to (>=) R(A)
2507OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
2508OP_VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg
2509----------------------------------------------------------------------]]
2510
2511luaP.opnames = {} -- opcode names
2512luaP.OpCode = {} -- lookup name -> number
2513luaP.ROpCode = {} -- lookup number -> name
2514
2515------------------------------------------------------------------------
2516-- ORDER OP
2517------------------------------------------------------------------------
2518local i = 0
2519for v in string.gmatch([[
2520MOVE LOADK LOADBOOL LOADNIL GETUPVAL
2521GETGLOBAL GETTABLE SETGLOBAL SETUPVAL SETTABLE
2522NEWTABLE SELF ADD SUB MUL
2523DIV MOD POW UNM NOT
2524LEN CONCAT JMP EQ LT
2525LE TEST TESTSET CALL TAILCALL
2526RETURN FORLOOP FORPREP TFORLOOP SETLIST
2527CLOSE CLOSURE VARARG
2528]], "%S+") do
2529 local n = "OP_"..v
2530 luaP.opnames[i] = v
2531 luaP.OpCode[n] = i
2532 luaP.ROpCode[i] = n
2533 i = i + 1
2534end
2535luaP.NUM_OPCODES = i
2536
2537--[[
2538===========================================================================
2539 Notes:
2540 (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
2541 and can be 0: OP_CALL then sets 'top' to last_result+1, so
2542 next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
2543 (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
2544 set top (like in OP_CALL with C == 0).
2545 (*) In OP_RETURN, if (B == 0) then return up to 'top'
2546 (*) In OP_SETLIST, if (B == 0) then B = 'top';
2547 if (C == 0) then next 'instruction' is real C
2548 (*) For comparisons, A specifies what condition the test should accept
2549 (true or false).
2550 (*) All 'skips' (pc++) assume that next instruction is a jump
2551===========================================================================
2552--]]
2553
2554--[[--------------------------------------------------------------------
2555 masks for instruction properties. The format is:
2556 bits 0-1: op mode
2557 bits 2-3: C arg mode
2558 bits 4-5: B arg mode
2559 bit 6: instruction set register A
2560 bit 7: operator is a test
2561
2562 for OpArgMask:
2563 OpArgN - argument is not used
2564 OpArgU - argument is used
2565 OpArgR - argument is a register or a jump offset
2566 OpArgK - argument is a constant or register/constant
2567----------------------------------------------------------------------]]
2568
2569-- was enum OpArgMask
2570luaP.OpArgMask = { OpArgN = 0, OpArgU = 1, OpArgR = 2, OpArgK = 3 }
2571
2572------------------------------------------------------------------------
2573-- e.g. to compare with symbols, luaP:getOpMode(...) == luaP.OpCode.iABC
2574-- * accepts opcode parameter as strings, e.g. "OP_MOVE"
2575------------------------------------------------------------------------
2576
2577function luaP:getOpMode(m)
2578 return self.opmodes[self.OpCode[m]] % 4
2579end
2580
2581function luaP:getBMode(m)
2582 return math.floor(self.opmodes[self.OpCode[m]] / 16) % 4
2583end
2584
2585function luaP:getCMode(m)
2586 return math.floor(self.opmodes[self.OpCode[m]] / 4) % 4
2587end
2588
2589function luaP:testAMode(m)
2590 return math.floor(self.opmodes[self.OpCode[m]] / 64) % 2
2591end
2592
2593function luaP:testTMode(m)
2594 return math.floor(self.opmodes[self.OpCode[m]] / 128)
2595end
2596
2597-- luaP_opnames[] is set above, as the luaP.opnames table
2598
2599-- number of list items to accumulate before a SETLIST instruction
2600luaP.LFIELDS_PER_FLUSH = 50
2601
2602------------------------------------------------------------------------
2603-- build instruction properties array
2604-- * deliberately coded to look like the C equivalent
2605------------------------------------------------------------------------
2606local function opmode(t, a, b, c, m)
2607 local luaP = luaP
2608 return t * 128 + a * 64 +
2609 luaP.OpArgMask[b] * 16 + luaP.OpArgMask[c] * 4 + luaP.OpMode[m]
2610end
2611
2612-- ORDER OP
2613luaP.opmodes = {
2614-- T A B C mode opcode
2615 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_LOADK
2616 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_LOADBOOL
2617 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LOADNIL
2618 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_GETUPVAL
2619 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_GETGLOBAL
2620 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_GETTABLE
2621 opmode(0, 0, "OpArgK", "OpArgN", "iABx"), -- OP_SETGLOBAL
2622 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_SETUPVAL
2623 opmode(0, 0, "OpArgK", "OpArgK", "iABC"), -- OP_SETTABLE
2624 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_NEWTABLE
2625 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_SELF
2626 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_ADD
2627 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_SUB
2628 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MUL
2629 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_DIV
2630 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MOD
2631 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_POW
2632 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_UNM
2633 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_NOT
2634 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LEN
2635 opmode(0, 1, "OpArgR", "OpArgR", "iABC"), -- OP_CONCAT
2636 opmode(0, 0, "OpArgR", "OpArgN", "iAsBx"), -- OP_JMP
2637 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_EQ
2638 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LT
2639 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LE
2640 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TEST
2641 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TESTSET
2642 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_CALL
2643 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_TAILCALL
2644 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_RETURN
2645 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORLOOP
2646 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORPREP
2647 opmode(1, 0, "OpArgN", "OpArgU", "iABC"), -- OP_TFORLOOP
2648 opmode(0, 0, "OpArgU", "OpArgU", "iABC"), -- OP_SETLIST
2649 opmode(0, 0, "OpArgN", "OpArgN", "iABC"), -- OP_CLOSE
2650 opmode(0, 1, "OpArgU", "OpArgN", "iABx"), -- OP_CLOSURE
2651 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_VARARG
2652}
2653-- an awkward way to set a zero-indexed table...
2654luaP.opmodes[0] =
2655 opmode(0, 1, "OpArgR", "OpArgN", "iABC") -- OP_MOVE
2656
2657return luaP
2658end
2659
2660function LuaU()
2661--[[--------------------------------------------------------------------
2662
2663 ldump.lua
2664 Save precompiled Lua chunks
2665 This file is part of Yueliang.
2666
2667 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
2668 The COPYRIGHT file describes the conditions
2669 under which this software may be distributed.
2670
2671 See the ChangeLog for more information.
2672
2673----------------------------------------------------------------------]]
2674
2675--[[--------------------------------------------------------------------
2676-- Notes:
2677-- * WARNING! byte order (little endian) and data type sizes for header
2678-- signature values hard-coded; see luaU:header
2679-- * chunk writer generators are included, see below
2680-- * one significant difference is that instructions are still in table
2681-- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
2682-- convert them into 4-char strings
2683--
2684-- Not implemented:
2685-- * DumpVar, DumpMem has been removed
2686-- * DumpVector folded into folded into DumpDebug, DumpCode
2687--
2688-- Added:
2689-- * for convenience, the following two functions have been added:
2690-- luaU:make_setS: create a chunk writer that writes to a string
2691-- luaU:make_setF: create a chunk writer that writes to a file
2692-- (lua.h contains a typedef for lua_Writer/lua_Chunkwriter, and
2693-- a Lua-based implementation exists, writer() in lstrlib.c)
2694-- * luaU:ttype(o) (from lobject.h)
2695-- * for converting number types to its binary equivalent:
2696-- luaU:from_double(x): encode double value for writing
2697-- luaU:from_int(x): encode integer value for writing
2698-- (error checking is limited for these conversion functions)
2699-- (double conversion does not support denormals or NaNs)
2700--
2701-- Changed in 5.1.x:
2702-- * the dumper was mostly rewritten in Lua 5.1.x, so notes on the
2703-- differences between 5.0.x and 5.1.x is limited
2704-- * LUAC_VERSION bumped to 0x51, LUAC_FORMAT added
2705-- * developer is expected to adjust LUAC_FORMAT in order to identify
2706-- non-standard binary chunk formats
2707-- * header signature code is smaller, has been simplified, and is
2708-- tested as a single unit; its logic is shared with the undumper
2709-- * no more endian conversion, invalid endianness mean rejection
2710-- * opcode field sizes are no longer exposed in the header
2711-- * code moved to front of a prototype, followed by constants
2712-- * debug information moved to the end of the binary chunk, and the
2713-- relevant functions folded into a single function
2714-- * luaU:dump returns a writer status code
2715-- * chunk writer now implements status code because dumper uses it
2716-- * luaU:endianness removed
2717----------------------------------------------------------------------]]
2718
2719--requires luaP
2720local luaU = {}
2721local luaP = require(script.Parent.LuaP)
2722
2723-- mark for precompiled code ('<esc>Lua') (from lua.h)
2724luaU.LUA_SIGNATURE = "\27Lua"
2725
2726-- constants used by dumper (from lua.h)
2727luaU.LUA_TNUMBER = 3
2728luaU.LUA_TSTRING = 4
2729luaU.LUA_TNIL = 0
2730luaU.LUA_TBOOLEAN = 1
2731luaU.LUA_TNONE = -1
2732
2733-- constants for header of binary files (from lundump.h)
2734luaU.LUAC_VERSION = 0x51 -- this is Lua 5.1
2735luaU.LUAC_FORMAT = 0 -- this is the official format
2736luaU.LUAC_HEADERSIZE = 12 -- size of header of binary files
2737
2738--[[--------------------------------------------------------------------
2739-- Additional functions to handle chunk writing
2740-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
2741----------------------------------------------------------------------]]
2742
2743------------------------------------------------------------------------
2744-- create a chunk writer that writes to a string
2745-- * returns the writer function and a table containing the string
2746-- * to get the final result, look in buff.data
2747------------------------------------------------------------------------
2748function luaU:make_setS()
2749 local buff = {}
2750 buff.data = ""
2751 local writer =
2752 function(s, buff) -- chunk writer
2753 if not s then return 0 end
2754 buff.data = buff.data..s
2755 return 0
2756 end
2757 return writer, buff
2758end
2759
2760------------------------------------------------------------------------
2761-- create a chunk writer that writes to a file
2762-- * returns the writer function and a table containing the file handle
2763-- * if a nil is passed, then writer should close the open file
2764------------------------------------------------------------------------
2765
2766--[[
2767function luaU:make_setF(filename)
2768 local buff = {}
2769 buff.h = io.open(filename, "wb")
2770 if not buff.h then return nil end
2771 local writer =
2772 function(s, buff) -- chunk writer
2773 if not buff.h then return 0 end
2774 if not s then
2775 if buff.h:close() then return 0 end
2776 else
2777 if buff.h:write(s) then return 0 end
2778 end
2779 return 1
2780 end
2781 return writer, buff
2782end--]]
2783
2784------------------------------------------------------------------------
2785-- works like the lobject.h version except that TObject used in these
2786-- scripts only has a 'value' field, no 'tt' field (native types used)
2787------------------------------------------------------------------------
2788function luaU:ttype(o)
2789 local tt = type(o.value)
2790 if tt == "number" then return self.LUA_TNUMBER
2791 elseif tt == "string" then return self.LUA_TSTRING
2792 elseif tt == "nil" then return self.LUA_TNIL
2793 elseif tt == "boolean" then return self.LUA_TBOOLEAN
2794 else
2795 return self.LUA_TNONE -- the rest should not appear
2796 end
2797end
2798
2799-----------------------------------------------------------------------
2800-- converts a IEEE754 double number to an 8-byte little-endian string
2801-- * luaU:from_double() and luaU:from_int() are adapted from ChunkBake
2802-- * supports +/- Infinity, but not denormals or NaNs
2803-----------------------------------------------------------------------
2804function luaU:from_double(x)
2805 local function grab_byte(v)
2806 local c = v % 256
2807 return (v - c) / 256, string.char(c)
2808 end
2809 local sign = 0
2810 if x < 0 then sign = 1; x = -x end
2811 local mantissa, exponent = math.frexp(x)
2812 if x == 0 then -- zero
2813 mantissa, exponent = 0, 0
2814 elseif x == 1/0 then
2815 mantissa, exponent = 0, 2047
2816 else
2817 mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
2818 exponent = exponent + 1022
2819 end
2820 local v, byte = "" -- convert to bytes
2821 x = math.floor(mantissa)
2822 for i = 1,6 do
2823 x, byte = grab_byte(x); v = v..byte -- 47:0
2824 end
2825 x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
2826 x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
2827 return v
2828end
2829
2830-----------------------------------------------------------------------
2831-- converts a number to a little-endian 32-bit integer string
2832-- * input value assumed to not overflow, can be signed/unsigned
2833-----------------------------------------------------------------------
2834function luaU:from_int(x)
2835 local v = ""
2836 x = math.floor(x)
2837 if x < 0 then x = 4294967296 + x end -- ULONG_MAX+1
2838 for i = 1, 4 do
2839 local c = x % 256
2840 v = v..string.char(c); x = math.floor(x / 256)
2841 end
2842 return v
2843end
2844
2845--[[--------------------------------------------------------------------
2846-- Functions to make a binary chunk
2847-- * many functions have the size parameter removed, since output is
2848-- in the form of a string and some sizes are implicit or hard-coded
2849----------------------------------------------------------------------]]
2850
2851--[[--------------------------------------------------------------------
2852-- struct DumpState:
2853-- L -- lua_State (not used in this script)
2854-- writer -- lua_Writer (chunk writer function)
2855-- data -- void* (chunk writer context or data already written)
2856-- strip -- if true, don't write any debug information
2857-- status -- if non-zero, an error has occured
2858----------------------------------------------------------------------]]
2859
2860------------------------------------------------------------------------
2861-- dumps a block of bytes
2862-- * lua_unlock(D.L), lua_lock(D.L) unused
2863------------------------------------------------------------------------
2864function luaU:DumpBlock(b, D)
2865 if D.status == 0 then
2866 -- lua_unlock(D->L);
2867 D.status = D.write(b, D.data)
2868 -- lua_lock(D->L);
2869 end
2870end
2871
2872------------------------------------------------------------------------
2873-- dumps a char
2874------------------------------------------------------------------------
2875function luaU:DumpChar(y, D)
2876 self:DumpBlock(string.char(y), D)
2877end
2878
2879------------------------------------------------------------------------
2880-- dumps a 32-bit signed or unsigned integer (for int) (hard-coded)
2881------------------------------------------------------------------------
2882function luaU:DumpInt(x, D)
2883 self:DumpBlock(self:from_int(x), D)
2884end
2885
2886------------------------------------------------------------------------
2887-- dumps a lua_Number (hard-coded as a double)
2888------------------------------------------------------------------------
2889function luaU:DumpNumber(x, D)
2890 self:DumpBlock(self:from_double(x), D)
2891end
2892
2893------------------------------------------------------------------------
2894-- dumps a Lua string (size type is hard-coded)
2895------------------------------------------------------------------------
2896function luaU:DumpString(s, D)
2897 if s == nil then
2898 self:DumpInt(0, D)
2899 else
2900 s = s.."\0" -- include trailing '\0'
2901 self:DumpInt(#s, D)
2902 self:DumpBlock(s, D)
2903 end
2904end
2905
2906------------------------------------------------------------------------
2907-- dumps instruction block from function prototype
2908------------------------------------------------------------------------
2909function luaU:DumpCode(f, D)
2910 local n = f.sizecode
2911 --was DumpVector
2912 self:DumpInt(n, D)
2913 for i = 0, n - 1 do
2914 self:DumpBlock(luaP:Instruction(f.code[i]), D)
2915 end
2916end
2917
2918------------------------------------------------------------------------
2919-- dump constant pool from function prototype
2920-- * bvalue(o), nvalue(o) and rawtsvalue(o) macros removed
2921------------------------------------------------------------------------
2922function luaU:DumpConstants(f, D)
2923 local n = f.sizek
2924 self:DumpInt(n, D)
2925 for i = 0, n - 1 do
2926 local o = f.k[i] -- TValue
2927 local tt = self:ttype(o)
2928 self:DumpChar(tt, D)
2929 if tt == self.LUA_TNIL then
2930 elseif tt == self.LUA_TBOOLEAN then
2931 self:DumpChar(o.value and 1 or 0, D)
2932 elseif tt == self.LUA_TNUMBER then
2933 self:DumpNumber(o.value, D)
2934 elseif tt == self.LUA_TSTRING then
2935 self:DumpString(o.value, D)
2936 else
2937 --lua_assert(0) -- cannot happen
2938 end
2939 end
2940 n = f.sizep
2941 self:DumpInt(n, D)
2942 for i = 0, n - 1 do
2943 self:DumpFunction(f.p[i], f.source, D)
2944 end
2945end
2946
2947------------------------------------------------------------------------
2948-- dump debug information
2949------------------------------------------------------------------------
2950function luaU:DumpDebug(f, D)
2951 local n
2952 n = D.strip and 0 or f.sizelineinfo -- dump line information
2953 --was DumpVector
2954 self:DumpInt(n, D)
2955 for i = 0, n - 1 do
2956 self:DumpInt(f.lineinfo[i], D)
2957 end
2958 n = D.strip and 0 or f.sizelocvars -- dump local information
2959 self:DumpInt(n, D)
2960 for i = 0, n - 1 do
2961 self:DumpString(f.locvars[i].varname, D)
2962 self:DumpInt(f.locvars[i].startpc, D)
2963 self:DumpInt(f.locvars[i].endpc, D)
2964 end
2965 n = D.strip and 0 or f.sizeupvalues -- dump upvalue information
2966 self:DumpInt(n, D)
2967 for i = 0, n - 1 do
2968 self:DumpString(f.upvalues[i], D)
2969 end
2970end
2971
2972------------------------------------------------------------------------
2973-- dump child function prototypes from function prototype
2974------------------------------------------------------------------------
2975function luaU:DumpFunction(f, p, D)
2976 local source = f.source
2977 if source == p or D.strip then source = nil end
2978 self:DumpString(source, D)
2979 self:DumpInt(f.lineDefined, D)
2980 self:DumpInt(f.lastlinedefined, D)
2981 self:DumpChar(f.nups, D)
2982 self:DumpChar(f.numparams, D)
2983 self:DumpChar(f.is_vararg, D)
2984 self:DumpChar(f.maxstacksize, D)
2985 self:DumpCode(f, D)
2986 self:DumpConstants(f, D)
2987 self:DumpDebug(f, D)
2988end
2989
2990------------------------------------------------------------------------
2991-- dump Lua header section (some sizes hard-coded)
2992------------------------------------------------------------------------
2993function luaU:DumpHeader(D)
2994 local h = self:header()
2995 assert(#h == self.LUAC_HEADERSIZE) -- fixed buffer now an assert
2996 self:DumpBlock(h, D)
2997end
2998
2999------------------------------------------------------------------------
3000-- make header (from lundump.c)
3001-- returns the header string
3002------------------------------------------------------------------------
3003function luaU:header()
3004 local x = 1
3005 return self.LUA_SIGNATURE..
3006 string.char(
3007 self.LUAC_VERSION,
3008 self.LUAC_FORMAT,
3009 x, -- endianness (1=little)
3010 4, -- sizeof(int)
3011 4, -- sizeof(size_t)
3012 4, -- sizeof(Instruction)
3013 8, -- sizeof(lua_Number)
3014 0) -- is lua_Number integral?
3015end
3016
3017------------------------------------------------------------------------
3018-- dump Lua function as precompiled chunk
3019-- (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
3020-- * w, data are created from make_setS, make_setF
3021------------------------------------------------------------------------
3022function luaU:dump(L, f, w, data, strip)
3023 local D = {} -- DumpState
3024 D.L = L
3025 D.write = w
3026 D.data = data
3027 D.strip = strip
3028 D.status = 0
3029 self:DumpHeader(D)
3030 self:DumpFunction(f, nil, D)
3031 -- added: for a chunk writer writing to a file, this final call with
3032 -- nil data is to indicate to the writer to close the file
3033 D.write(nil, D.data)
3034 return D.status
3035end
3036
3037return luaU
3038end
3039
3040function LuaX()
3041--[[--------------------------------------------------------------------
3042
3043 llex.lua
3044 Lua lexical analyzer in Lua
3045 This file is part of Yueliang.
3046
3047 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
3048 The COPYRIGHT file describes the conditions
3049 under which this software may be distributed.
3050
3051 See the ChangeLog for more information.
3052
3053----------------------------------------------------------------------]]
3054
3055--[[--------------------------------------------------------------------
3056-- Notes:
3057-- * intended to 'imitate' llex.c code; performance is not a concern
3058-- * tokens are strings; code structure largely retained
3059-- * deleted stuff (compared to llex.c) are noted, comments retained
3060-- * nextc() returns the currently read character to simplify coding
3061-- here; next() in llex.c does not return anything
3062-- * compatibility code is marked with "--#" comments
3063--
3064-- Added:
3065-- * luaX:chunkid (function luaO_chunkid from lobject.c)
3066-- * luaX:str2d (function luaO_str2d from lobject.c)
3067-- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
3068-- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
3069-- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
3070--
3071-- To use the lexer:
3072-- (1) luaX:init() to initialize the lexer
3073-- (2) luaX:setinput() to set the input stream to lex
3074-- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
3075-- until "TK_EOS": luaX:next()
3076-- * since EOZ is returned as a string, be careful when regexp testing
3077--
3078-- Not implemented:
3079-- * luaX_newstring: not required by this Lua implementation
3080-- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
3081-- in the interest of performance
3082-- * locale-aware number handling is largely redundant as Lua's
3083-- tonumber() function is already capable of this
3084--
3085-- Changed in 5.1.x:
3086-- * TK_NAME token order moved down
3087-- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
3088-- * token struct renamed to lower case (LS -> ls)
3089-- * LexState struct: removed nestlevel, added decpoint
3090-- * error message functions have been greatly simplified
3091-- * token2string renamed to luaX_tokens, exposed in llex.h
3092-- * lexer now handles all kinds of newlines, including CRLF
3093-- * shbang first line handling removed from luaX:setinput;
3094-- it is now done in lauxlib.c (luaL_loadfile)
3095-- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
3096-- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
3097-- * checkbuffer(ls, len) macro deleted
3098-- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
3099-- luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
3100-- * luaX:read_numeral is now more promiscuous in slurping characters;
3101-- hexadecimal numbers was added, locale-aware decimal points too
3102-- * luaX:skip_sep is new; used by luaX:read_long_string
3103-- * luaX:read_long_string handles new-style long blocks, with some
3104-- optional compatibility code
3105-- * luaX:llex: parts changed to support new-style long blocks
3106-- * luaX:llex: readname functionality has been folded in
3107-- * luaX:llex: removed test for control characters
3108--
3109--------------------------------------------------------------------]]
3110
3111local luaZ = require(script.Parent.LuaZ)
3112
3113local luaX = {}
3114
3115-- FIRST_RESERVED is not required as tokens are manipulated as strings
3116-- TOKEN_LEN deleted; maximum length of a reserved word not needed
3117
3118------------------------------------------------------------------------
3119-- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
3120------------------------------------------------------------------------
3121
3122-- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
3123-- other terminal symbols: TK_NAME to TK_EOS
3124luaX.RESERVED = [[
3125TK_AND and
3126TK_BREAK break
3127TK_DO do
3128TK_ELSE else
3129TK_ELSEIF elseif
3130TK_END end
3131TK_FALSE false
3132TK_FOR for
3133TK_FUNCTION function
3134TK_IF if
3135TK_IN in
3136TK_LOCAL local
3137TK_NIL nil
3138TK_NOT not
3139TK_OR or
3140TK_REPEAT repeat
3141TK_RETURN return
3142TK_THEN then
3143TK_TRUE true
3144TK_UNTIL until
3145TK_WHILE while
3146TK_CONCAT ..
3147TK_DOTS ...
3148TK_EQ ==
3149TK_GE >=
3150TK_LE <=
3151TK_NE ~=
3152TK_NAME <name>
3153TK_NUMBER <number>
3154TK_STRING <string>
3155TK_EOS <eof>]]
3156
3157-- NUM_RESERVED is not required; number of reserved words
3158
3159--[[--------------------------------------------------------------------
3160-- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
3161-- so that lexer functions can use its table element, ls.t.seminfo
3162--
3163-- SemInfo (struct no longer needed, a mixed-type value is used)
3164--
3165-- Token (struct of ls.t and ls.lookahead):
3166-- token -- token symbol
3167-- seminfo -- semantics information
3168--
3169-- LexState (struct of ls; ls is initialized by luaX:setinput):
3170-- current -- current character (charint)
3171-- linenumber -- input line counter
3172-- lastline -- line of last token 'consumed'
3173-- t -- current token (table: struct Token)
3174-- lookahead -- look ahead token (table: struct Token)
3175-- fs -- 'FuncState' is private to the parser
3176-- L -- LuaState
3177-- z -- input stream
3178-- buff -- buffer for tokens
3179-- source -- current source name
3180-- decpoint -- locale decimal point
3181-- nestlevel -- level of nested non-terminals
3182----------------------------------------------------------------------]]
3183
3184-- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init
3185
3186luaX.MAXSRC = 80
3187luaX.MAX_INT = 2147483645 -- constants from elsewhere (see above)
3188luaX.LUA_QS = "'%s'"
3189luaX.LUA_COMPAT_LSTR = 1
3190--luaX.MAX_SIZET = 4294967293
3191
3192------------------------------------------------------------------------
3193-- initialize lexer
3194-- * original luaX_init has code to create and register token strings
3195-- * luaX.tokens: TK_* -> token
3196-- * luaX.enums: token -> TK_* (used in luaX:llex)
3197------------------------------------------------------------------------
3198function luaX:init()
3199 local tokens, enums = {}, {}
3200 for v in string.gmatch(self.RESERVED, "[^\n]+") do
3201 local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
3202 tokens[tok] = str
3203 enums[str] = tok
3204 end
3205 self.tokens = tokens
3206 self.enums = enums
3207end
3208
3209------------------------------------------------------------------------
3210-- returns a suitably-formatted chunk name or id
3211-- * from lobject.c, used in llex.c and ldebug.c
3212-- * the result, out, is returned (was first argument)
3213------------------------------------------------------------------------
3214function luaX:chunkid(source, bufflen)
3215 local out
3216 local first = string.sub(source, 1, 1)
3217 if first == "=" then
3218 out = string.sub(source, 2, bufflen) -- remove first char
3219 else -- out = "source", or "...source"
3220 if first == "@" then
3221 source = string.sub(source, 2) -- skip the '@'
3222 bufflen = bufflen - #" '...' "
3223 local l = #source
3224 out = ""
3225 if l > bufflen then
3226 source = string.sub(source, 1 + l - bufflen) -- get last part of file name
3227 out = out.."..."
3228 end
3229 out = out..source
3230 else -- out = [string "string"]
3231 local len = string.find(source, "[\n\r]") -- stop at first newline
3232 len = len and (len - 1) or #source
3233 bufflen = bufflen - #(" [string \"...\"] ")
3234 if len > bufflen then len = bufflen end
3235 out = "[string \""
3236 if len < #source then -- must truncate?
3237 out = out..string.sub(source, 1, len).."..."
3238 else
3239 out = out..source
3240 end
3241 out = out.."\"]"
3242 end
3243 end
3244 return out
3245end
3246
3247--[[--------------------------------------------------------------------
3248-- Support functions for lexer
3249-- * all lexer errors eventually reaches lexerror:
3250 syntaxerror -> lexerror
3251----------------------------------------------------------------------]]
3252
3253------------------------------------------------------------------------
3254-- look up token and return keyword if found (also called by parser)
3255------------------------------------------------------------------------
3256function luaX:token2str(ls, token)
3257 if string.sub(token, 1, 3) ~= "TK_" then
3258 if string.find(token, "%c") then
3259 return string.format("char(%d)", string.byte(token))
3260 end
3261 return token
3262 else
3263 end
3264 return self.tokens[token]
3265end
3266
3267------------------------------------------------------------------------
3268-- throws a lexer error
3269-- * txtToken has been made local to luaX:lexerror
3270-- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
3271------------------------------------------------------------------------
3272function luaX:lexerror(ls, msg, token)
3273 local function txtToken(ls, token)
3274 if token == "TK_NAME" or
3275 token == "TK_STRING" or
3276 token == "TK_NUMBER" then
3277 return ls.buff
3278 else
3279 return self:token2str(ls, token)
3280 end
3281 end
3282 local buff = self:chunkid(ls.source, self.MAXSRC)
3283 local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
3284 if token then
3285 msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
3286 end
3287 -- luaD_throw(ls->L, LUA_ERRSYNTAX)
3288 error(msg)
3289end
3290
3291------------------------------------------------------------------------
3292-- throws a syntax error (mainly called by parser)
3293-- * ls.t.token has to be set by the function calling luaX:llex
3294-- (see luaX:next and luaX:lookahead elsewhere in this file)
3295------------------------------------------------------------------------
3296function luaX:syntaxerror(ls, msg)
3297 self:lexerror(ls, msg, ls.t.token)
3298end
3299
3300------------------------------------------------------------------------
3301-- move on to next line
3302------------------------------------------------------------------------
3303function luaX:currIsNewline(ls)
3304 return ls.current == "\n" or ls.current == "\r"
3305end
3306
3307function luaX:inclinenumber(ls)
3308 local old = ls.current
3309 -- lua_assert(currIsNewline(ls))
3310 self:nextc(ls) -- skip '\n' or '\r'
3311 if self:currIsNewline(ls) and ls.current ~= old then
3312 self:nextc(ls) -- skip '\n\r' or '\r\n'
3313 end
3314 ls.linenumber = ls.linenumber + 1
3315 if ls.linenumber >= self.MAX_INT then
3316 self:syntaxerror(ls, "chunk has too many lines")
3317 end
3318end
3319
3320------------------------------------------------------------------------
3321-- initializes an input stream for lexing
3322-- * if ls (the lexer state) is passed as a table, then it is filled in,
3323-- otherwise it has to be retrieved as a return value
3324-- * LUA_MINBUFFER not used; buffer handling not required any more
3325------------------------------------------------------------------------
3326function luaX:setinput(L, ls, z, source)
3327 if not ls then ls = {} end -- create struct
3328 if not ls.lookahead then ls.lookahead = {} end
3329 if not ls.t then ls.t = {} end
3330 ls.decpoint = "."
3331 ls.L = L
3332 ls.lookahead.token = "TK_EOS" -- no look-ahead token
3333 ls.z = z
3334 ls.fs = nil
3335 ls.linenumber = 1
3336 ls.lastline = 1
3337 ls.source = source
3338 self:nextc(ls) -- read first char
3339end
3340
3341--[[--------------------------------------------------------------------
3342-- LEXICAL ANALYZER
3343----------------------------------------------------------------------]]
3344
3345------------------------------------------------------------------------
3346-- checks if current character read is found in the set 'set'
3347------------------------------------------------------------------------
3348function luaX:check_next(ls, set)
3349 if not string.find(set, ls.current, 1, 1) then
3350 return false
3351 end
3352 self:save_and_next(ls)
3353 return true
3354end
3355
3356------------------------------------------------------------------------
3357-- retrieve next token, checking the lookahead buffer if necessary
3358-- * note that the macro next(ls) in llex.c is now luaX:nextc
3359-- * utilized used in lparser.c (various places)
3360------------------------------------------------------------------------
3361function luaX:next(ls)
3362 ls.lastline = ls.linenumber
3363 if ls.lookahead.token ~= "TK_EOS" then -- is there a look-ahead token?
3364 -- this must be copy-by-value
3365 ls.t.seminfo = ls.lookahead.seminfo -- use this one
3366 ls.t.token = ls.lookahead.token
3367 ls.lookahead.token = "TK_EOS" -- and discharge it
3368 else
3369 ls.t.token = self:llex(ls, ls.t) -- read next token
3370 end
3371end
3372
3373------------------------------------------------------------------------
3374-- fill in the lookahead buffer
3375-- * utilized used in lparser.c:constructor
3376------------------------------------------------------------------------
3377function luaX:lookahead(ls)
3378 -- lua_assert(ls.lookahead.token == "TK_EOS")
3379 ls.lookahead.token = self:llex(ls, ls.lookahead)
3380end
3381
3382------------------------------------------------------------------------
3383-- gets the next character and returns it
3384-- * this is the next() macro in llex.c; see notes at the beginning
3385------------------------------------------------------------------------
3386function luaX:nextc(ls)
3387 local c = luaZ:zgetc(ls.z)
3388 ls.current = c
3389 return c
3390end
3391
3392------------------------------------------------------------------------
3393-- saves the given character into the token buffer
3394-- * buffer handling code removed, not used in this implementation
3395-- * test for maximum token buffer length not used, makes things faster
3396------------------------------------------------------------------------
3397
3398function luaX:save(ls, c)
3399 local buff = ls.buff
3400 -- if you want to use this, please uncomment luaX.MAX_SIZET further up
3401 --if #buff > self.MAX_SIZET then
3402 -- self:lexerror(ls, "lexical element too long")
3403 --end
3404 ls.buff = buff..c
3405end
3406
3407------------------------------------------------------------------------
3408-- save current character into token buffer, grabs next character
3409-- * like luaX:nextc, returns the character read for convenience
3410------------------------------------------------------------------------
3411function luaX:save_and_next(ls)
3412 self:save(ls, ls.current)
3413 return self:nextc(ls)
3414end
3415
3416------------------------------------------------------------------------
3417-- LUA_NUMBER
3418-- * luaX:read_numeral is the main lexer function to read a number
3419-- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
3420------------------------------------------------------------------------
3421
3422------------------------------------------------------------------------
3423-- string to number converter (was luaO_str2d from lobject.c)
3424-- * returns the number, nil if fails (originally returns a boolean)
3425-- * conversion function originally lua_str2number(s,p), a macro which
3426-- maps to the strtod() function by default (from luaconf.h)
3427------------------------------------------------------------------------
3428function luaX:str2d(s)
3429 local result = tonumber(s)
3430 if result then return result end
3431 -- conversion failed
3432 if string.lower(string.sub(s, 1, 2)) == "0x" then -- maybe an hexadecimal constant?
3433 result = tonumber(s, 16)
3434 if result then return result end -- most common case
3435 -- Was: invalid trailing characters?
3436 -- In C, this function then skips over trailing spaces.
3437 -- true is returned if nothing else is found except for spaces.
3438 -- If there is still something else, then it returns a false.
3439 -- All this is not necessary using Lua's tonumber.
3440 end
3441 return nil
3442end
3443
3444------------------------------------------------------------------------
3445-- single-character replacement, for locale-aware decimal points
3446------------------------------------------------------------------------
3447function luaX:buffreplace(ls, from, to)
3448 local result, buff = "", ls.buff
3449 for p = 1, #buff do
3450 local c = string.sub(buff, p, p)
3451 if c == from then c = to end
3452 result = result..c
3453 end
3454 ls.buff = result
3455end
3456
3457------------------------------------------------------------------------
3458-- Attempt to convert a number by translating '.' decimal points to
3459-- the decimal point character used by the current locale. This is not
3460-- needed in Yueliang as Lua's tonumber() is already locale-aware.
3461-- Instead, the code is here in case the user implements localeconv().
3462------------------------------------------------------------------------
3463function luaX:trydecpoint(ls, Token)
3464 -- format error: try to update decimal point separator
3465 local old = ls.decpoint
3466 -- translate the following to Lua if you implement localeconv():
3467 -- struct lconv *cv = localeconv();
3468 -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
3469 self:buffreplace(ls, old, ls.decpoint) -- try updated decimal separator
3470 local seminfo = self:str2d(ls.buff)
3471 Token.seminfo = seminfo
3472 if not seminfo then
3473 -- format error with correct decimal point: no more options
3474 self:buffreplace(ls, ls.decpoint, ".") -- undo change (for error message)
3475 self:lexerror(ls, "malformed number", "TK_NUMBER")
3476 end
3477end
3478
3479------------------------------------------------------------------------
3480-- main number conversion function
3481-- * "^%w$" needed in the scan in order to detect "EOZ"
3482------------------------------------------------------------------------
3483function luaX:read_numeral(ls, Token)
3484 -- lua_assert(string.find(ls.current, "%d"))
3485 repeat
3486 self:save_and_next(ls)
3487 until string.find(ls.current, "%D") and ls.current ~= "."
3488 if self:check_next(ls, "Ee") then -- 'E'?
3489 self:check_next(ls, "+-") -- optional exponent sign
3490 end
3491 while string.find(ls.current, "^%w$") or ls.current == "_" do
3492 self:save_and_next(ls)
3493 end
3494 self:buffreplace(ls, ".", ls.decpoint) -- follow locale for decimal point
3495 local seminfo = self:str2d(ls.buff)
3496 Token.seminfo = seminfo
3497 if not seminfo then -- format error?
3498 self:trydecpoint(ls, Token) -- try to update decimal point separator
3499 end
3500end
3501
3502------------------------------------------------------------------------
3503-- count separators ("=") in a long string delimiter
3504-- * used by luaX:read_long_string
3505------------------------------------------------------------------------
3506function luaX:skip_sep(ls)
3507 local count = 0
3508 local s = ls.current
3509 -- lua_assert(s == "[" or s == "]")
3510 self:save_and_next(ls)
3511 while ls.current == "=" do
3512 self:save_and_next(ls)
3513 count = count + 1
3514 end
3515 return (ls.current == s) and count or (-count) - 1
3516end
3517
3518------------------------------------------------------------------------
3519-- reads a long string or long comment
3520------------------------------------------------------------------------
3521function luaX:read_long_string(ls, Token, sep)
3522 local cont = 0
3523 self:save_and_next(ls) -- skip 2nd '['
3524 if self:currIsNewline(ls) then -- string starts with a newline?
3525 self:inclinenumber(ls) -- skip it
3526 end
3527 while true do
3528 local c = ls.current
3529 if c == "EOZ" then
3530 self:lexerror(ls, Token and "unfinished long string" or
3531 "unfinished long comment", "TK_EOS")
3532 elseif c == "[" then
3533 --# compatibility code start
3534 if self.LUA_COMPAT_LSTR then
3535 if self:skip_sep(ls) == sep then
3536 self:save_and_next(ls) -- skip 2nd '['
3537 cont = cont + 1
3538 --# compatibility code start
3539 if self.LUA_COMPAT_LSTR == 1 then
3540 if sep == 0 then
3541 self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
3542 end
3543 end
3544 --# compatibility code end
3545 end
3546 end
3547 --# compatibility code end
3548 elseif c == "]" then
3549 if self:skip_sep(ls) == sep then
3550 self:save_and_next(ls) -- skip 2nd ']'
3551 --# compatibility code start
3552 if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
3553 cont = cont - 1
3554 if sep == 0 and cont >= 0 then break end
3555 end
3556 --# compatibility code end
3557 break
3558 end
3559 elseif self:currIsNewline(ls) then
3560 self:save(ls, "\n")
3561 self:inclinenumber(ls)
3562 if not Token then ls.buff = "" end -- avoid wasting space
3563 else -- default
3564 if Token then
3565 self:save_and_next(ls)
3566 else
3567 self:nextc(ls)
3568 end
3569 end--if c
3570 end--while
3571 if Token then
3572 local p = 3 + sep
3573 Token.seminfo = string.sub(ls.buff, p, -p)
3574 end
3575end
3576
3577------------------------------------------------------------------------
3578-- reads a string
3579-- * has been restructured significantly compared to the original C code
3580------------------------------------------------------------------------
3581
3582function luaX:read_string(ls, del, Token)
3583 self:save_and_next(ls)
3584 while ls.current ~= del do
3585 local c = ls.current
3586 if c == "EOZ" then
3587 self:lexerror(ls, "unfinished string", "TK_EOS")
3588 elseif self:currIsNewline(ls) then
3589 self:lexerror(ls, "unfinished string", "TK_STRING")
3590 elseif c == "\\" then
3591 c = self:nextc(ls) -- do not save the '\'
3592 if self:currIsNewline(ls) then -- go through
3593 self:save(ls, "\n")
3594 self:inclinenumber(ls)
3595 elseif c ~= "EOZ" then -- will raise an error next loop
3596 -- escapes handling greatly simplified here:
3597 local i = string.find("abfnrtv", c, 1, 1)
3598 if i then
3599 self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
3600 self:nextc(ls)
3601 elseif not string.find(c, "%d") then
3602 self:save_and_next(ls) -- handles \\, \", \', and \?
3603 else -- \xxx
3604 c, i = 0, 0
3605 repeat
3606 c = 10 * c + ls.current
3607 self:nextc(ls)
3608 i = i + 1
3609 until i >= 3 or not string.find(ls.current, "%d")
3610 if c > 255 then -- UCHAR_MAX
3611 self:lexerror(ls, "escape sequence too large", "TK_STRING")
3612 end
3613 self:save(ls, string.char(c))
3614 end
3615 end
3616 else
3617 self:save_and_next(ls)
3618 end--if c
3619 end--while
3620 self:save_and_next(ls) -- skip delimiter
3621 Token.seminfo = string.sub(ls.buff, 2, -2)
3622end
3623
3624------------------------------------------------------------------------
3625-- main lexer function
3626------------------------------------------------------------------------
3627function luaX:llex(ls, Token)
3628 ls.buff = ""
3629 while true do
3630 local c = ls.current
3631 ----------------------------------------------------------------
3632 if self:currIsNewline(ls) then
3633 self:inclinenumber(ls)
3634 ----------------------------------------------------------------
3635 elseif c == "-" then
3636 c = self:nextc(ls)
3637 if c ~= "-" then return "-" end
3638 -- else is a comment
3639 local sep = -1
3640 if self:nextc(ls) == '[' then
3641 sep = self:skip_sep(ls)
3642 ls.buff = "" -- 'skip_sep' may dirty the buffer
3643 end
3644 if sep >= 0 then
3645 self:read_long_string(ls, nil, sep) -- long comment
3646 ls.buff = ""
3647 else -- else short comment
3648 while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
3649 self:nextc(ls)
3650 end
3651 end
3652 ----------------------------------------------------------------
3653 elseif c == "[" then
3654 local sep = self:skip_sep(ls)
3655 if sep >= 0 then
3656 self:read_long_string(ls, Token, sep)
3657 return "TK_STRING"
3658 elseif sep == -1 then
3659 return "["
3660 else
3661 self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
3662 end
3663 ----------------------------------------------------------------
3664 elseif c == "=" then
3665 c = self:nextc(ls)
3666 if c ~= "=" then return "="
3667 else self:nextc(ls); return "TK_EQ" end
3668 ----------------------------------------------------------------
3669 elseif c == "<" then
3670 c = self:nextc(ls)
3671 if c ~= "=" then return "<"
3672 else self:nextc(ls); return "TK_LE" end
3673 ----------------------------------------------------------------
3674 elseif c == ">" then
3675 c = self:nextc(ls)
3676 if c ~= "=" then return ">"
3677 else self:nextc(ls); return "TK_GE" end
3678 ----------------------------------------------------------------
3679 elseif c == "~" then
3680 c = self:nextc(ls)
3681 if c ~= "=" then return "~"
3682 else self:nextc(ls); return "TK_NE" end
3683 ----------------------------------------------------------------
3684 elseif c == "\"" or c == "'" then
3685 self:read_string(ls, c, Token)
3686 return "TK_STRING"
3687 ----------------------------------------------------------------
3688 elseif c == "." then
3689 c = self:save_and_next(ls)
3690 if self:check_next(ls, ".") then
3691 if self:check_next(ls, ".") then
3692 return "TK_DOTS" -- ...
3693 else return "TK_CONCAT" -- ..
3694 end
3695 elseif not string.find(c, "%d") then
3696 return "."
3697 else
3698 self:read_numeral(ls, Token)
3699 return "TK_NUMBER"
3700 end
3701 ----------------------------------------------------------------
3702 elseif c == "EOZ" then
3703 return "TK_EOS"
3704 ----------------------------------------------------------------
3705 else -- default
3706 if string.find(c, "%s") then
3707 -- lua_assert(self:currIsNewline(ls))
3708 self:nextc(ls)
3709 elseif string.find(c, "%d") then
3710 self:read_numeral(ls, Token)
3711 return "TK_NUMBER"
3712 elseif string.find(c, "[_%a]") then
3713 -- identifier or reserved word
3714 repeat
3715 c = self:save_and_next(ls)
3716 until c == "EOZ" or not string.find(c, "[_%w]")
3717 local ts = ls.buff
3718 local tok = self.enums[ts]
3719 if tok then return tok end -- reserved word?
3720 Token.seminfo = ts
3721 return "TK_NAME"
3722 else
3723 self:nextc(ls)
3724 return c -- single-char tokens (+ - / ...)
3725 end
3726 ----------------------------------------------------------------
3727 end--if c
3728 end--while
3729end
3730
3731return luaX
3732end
3733
3734function LuaY()
3735--[[--------------------------------------------------------------------
3736
3737 llex.lua
3738 Lua lexical analyzer in Lua
3739 This file is part of Yueliang.
3740
3741 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
3742 The COPYRIGHT file describes the conditions
3743 under which this software may be distributed.
3744
3745 See the ChangeLog for more information.
3746
3747----------------------------------------------------------------------]]
3748
3749--[[--------------------------------------------------------------------
3750-- Notes:
3751-- * intended to 'imitate' llex.c code; performance is not a concern
3752-- * tokens are strings; code structure largely retained
3753-- * deleted stuff (compared to llex.c) are noted, comments retained
3754-- * nextc() returns the currently read character to simplify coding
3755-- here; next() in llex.c does not return anything
3756-- * compatibility code is marked with "--#" comments
3757--
3758-- Added:
3759-- * luaX:chunkid (function luaO_chunkid from lobject.c)
3760-- * luaX:str2d (function luaO_str2d from lobject.c)
3761-- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
3762-- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
3763-- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
3764--
3765-- To use the lexer:
3766-- (1) luaX:init() to initialize the lexer
3767-- (2) luaX:setinput() to set the input stream to lex
3768-- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
3769-- until "TK_EOS": luaX:next()
3770-- * since EOZ is returned as a string, be careful when regexp testing
3771--
3772-- Not implemented:
3773-- * luaX_newstring: not required by this Lua implementation
3774-- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
3775-- in the interest of performance
3776-- * locale-aware number handling is largely redundant as Lua's
3777-- tonumber() function is already capable of this
3778--
3779-- Changed in 5.1.x:
3780-- * TK_NAME token order moved down
3781-- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
3782-- * token struct renamed to lower case (LS -> ls)
3783-- * LexState struct: removed nestlevel, added decpoint
3784-- * error message functions have been greatly simplified
3785-- * token2string renamed to luaX_tokens, exposed in llex.h
3786-- * lexer now handles all kinds of newlines, including CRLF
3787-- * shbang first line handling removed from luaX:setinput;
3788-- it is now done in lauxlib.c (luaL_loadfile)
3789-- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
3790-- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
3791-- * checkbuffer(ls, len) macro deleted
3792-- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
3793-- luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
3794-- * luaX:read_numeral is now more promiscuous in slurping characters;
3795-- hexadecimal numbers was added, locale-aware decimal points too
3796-- * luaX:skip_sep is new; used by luaX:read_long_string
3797-- * luaX:read_long_string handles new-style long blocks, with some
3798-- optional compatibility code
3799-- * luaX:llex: parts changed to support new-style long blocks
3800-- * luaX:llex: readname functionality has been folded in
3801-- * luaX:llex: removed test for control characters
3802--
3803--------------------------------------------------------------------]]
3804
3805local luaZ = require(script.Parent.LuaZ)
3806
3807local luaX = {}
3808
3809-- FIRST_RESERVED is not required as tokens are manipulated as strings
3810-- TOKEN_LEN deleted; maximum length of a reserved word not needed
3811
3812------------------------------------------------------------------------
3813-- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
3814------------------------------------------------------------------------
3815
3816-- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
3817-- other terminal symbols: TK_NAME to TK_EOS
3818luaX.RESERVED = [[
3819TK_AND and
3820TK_BREAK break
3821TK_DO do
3822TK_ELSE else
3823TK_ELSEIF elseif
3824TK_END end
3825TK_FALSE false
3826TK_FOR for
3827TK_FUNCTION function
3828TK_IF if
3829TK_IN in
3830TK_LOCAL local
3831TK_NIL nil
3832TK_NOT not
3833TK_OR or
3834TK_REPEAT repeat
3835TK_RETURN return
3836TK_THEN then
3837TK_TRUE true
3838TK_UNTIL until
3839TK_WHILE while
3840TK_CONCAT ..
3841TK_DOTS ...
3842TK_EQ ==
3843TK_GE >=
3844TK_LE <=
3845TK_NE ~=
3846TK_NAME <name>
3847TK_NUMBER <number>
3848TK_STRING <string>
3849TK_EOS <eof>]]
3850
3851-- NUM_RESERVED is not required; number of reserved words
3852
3853--[[--------------------------------------------------------------------
3854-- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
3855-- so that lexer functions can use its table element, ls.t.seminfo
3856--
3857-- SemInfo (struct no longer needed, a mixed-type value is used)
3858--
3859-- Token (struct of ls.t and ls.lookahead):
3860-- token -- token symbol
3861-- seminfo -- semantics information
3862--
3863-- LexState (struct of ls; ls is initialized by luaX:setinput):
3864-- current -- current character (charint)
3865-- linenumber -- input line counter
3866-- lastline -- line of last token 'consumed'
3867-- t -- current token (table: struct Token)
3868-- lookahead -- look ahead token (table: struct Token)
3869-- fs -- 'FuncState' is private to the parser
3870-- L -- LuaState
3871-- z -- input stream
3872-- buff -- buffer for tokens
3873-- source -- current source name
3874-- decpoint -- locale decimal point
3875-- nestlevel -- level of nested non-terminals
3876----------------------------------------------------------------------]]
3877
3878-- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init
3879
3880luaX.MAXSRC = 80
3881luaX.MAX_INT = 2147483645 -- constants from elsewhere (see above)
3882luaX.LUA_QS = "'%s'"
3883luaX.LUA_COMPAT_LSTR = 1
3884--luaX.MAX_SIZET = 4294967293
3885
3886------------------------------------------------------------------------
3887-- initialize lexer
3888-- * original luaX_init has code to create and register token strings
3889-- * luaX.tokens: TK_* -> token
3890-- * luaX.enums: token -> TK_* (used in luaX:llex)
3891------------------------------------------------------------------------
3892function luaX:init()
3893 local tokens, enums = {}, {}
3894 for v in string.gmatch(self.RESERVED, "[^\n]+") do
3895 local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
3896 tokens[tok] = str
3897 enums[str] = tok
3898 end
3899 self.tokens = tokens
3900 self.enums = enums
3901end
3902
3903------------------------------------------------------------------------
3904-- returns a suitably-formatted chunk name or id
3905-- * from lobject.c, used in llex.c and ldebug.c
3906-- * the result, out, is returned (was first argument)
3907------------------------------------------------------------------------
3908function luaX:chunkid(source, bufflen)
3909 local out
3910 local first = string.sub(source, 1, 1)
3911 if first == "=" then
3912 out = string.sub(source, 2, bufflen) -- remove first char
3913 else -- out = "source", or "...source"
3914 if first == "@" then
3915 source = string.sub(source, 2) -- skip the '@'
3916 bufflen = bufflen - #" '...' "
3917 local l = #source
3918 out = ""
3919 if l > bufflen then
3920 source = string.sub(source, 1 + l - bufflen) -- get last part of file name
3921 out = out.."..."
3922 end
3923 out = out..source
3924 else -- out = [string "string"]
3925 local len = string.find(source, "[\n\r]") -- stop at first newline
3926 len = len and (len - 1) or #source
3927 bufflen = bufflen - #(" [string \"...\"] ")
3928 if len > bufflen then len = bufflen end
3929 out = "[string \""
3930 if len < #source then -- must truncate?
3931 out = out..string.sub(source, 1, len).."..."
3932 else
3933 out = out..source
3934 end
3935 out = out.."\"]"
3936 end
3937 end
3938 return out
3939end
3940
3941--[[--------------------------------------------------------------------
3942-- Support functions for lexer
3943-- * all lexer errors eventually reaches lexerror:
3944 syntaxerror -> lexerror
3945----------------------------------------------------------------------]]
3946
3947------------------------------------------------------------------------
3948-- look up token and return keyword if found (also called by parser)
3949------------------------------------------------------------------------
3950function luaX:token2str(ls, token)
3951 if string.sub(token, 1, 3) ~= "TK_" then
3952 if string.find(token, "%c") then
3953 return string.format("char(%d)", string.byte(token))
3954 end
3955 return token
3956 else
3957 end
3958 return self.tokens[token]
3959end
3960
3961------------------------------------------------------------------------
3962-- throws a lexer error
3963-- * txtToken has been made local to luaX:lexerror
3964-- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
3965------------------------------------------------------------------------
3966function luaX:lexerror(ls, msg, token)
3967 local function txtToken(ls, token)
3968 if token == "TK_NAME" or
3969 token == "TK_STRING" or
3970 token == "TK_NUMBER" then
3971 return ls.buff
3972 else
3973 return self:token2str(ls, token)
3974 end
3975 end
3976 local buff = self:chunkid(ls.source, self.MAXSRC)
3977 local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
3978 if token then
3979 msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
3980 end
3981 -- luaD_throw(ls->L, LUA_ERRSYNTAX)
3982 error(msg)
3983end
3984
3985------------------------------------------------------------------------
3986-- throws a syntax error (mainly called by parser)
3987-- * ls.t.token has to be set by the function calling luaX:llex
3988-- (see luaX:next and luaX:lookahead elsewhere in this file)
3989------------------------------------------------------------------------
3990function luaX:syntaxerror(ls, msg)
3991 self:lexerror(ls, msg, ls.t.token)
3992end
3993
3994------------------------------------------------------------------------
3995-- move on to next line
3996------------------------------------------------------------------------
3997function luaX:currIsNewline(ls)
3998 return ls.current == "\n" or ls.current == "\r"
3999end
4000
4001function luaX:inclinenumber(ls)
4002 local old = ls.current
4003 -- lua_assert(currIsNewline(ls))
4004 self:nextc(ls) -- skip '\n' or '\r'
4005 if self:currIsNewline(ls) and ls.current ~= old then
4006 self:nextc(ls) -- skip '\n\r' or '\r\n'
4007 end
4008 ls.linenumber = ls.linenumber + 1
4009 if ls.linenumber >= self.MAX_INT then
4010 self:syntaxerror(ls, "chunk has too many lines")
4011 end
4012end
4013
4014------------------------------------------------------------------------
4015-- initializes an input stream for lexing
4016-- * if ls (the lexer state) is passed as a table, then it is filled in,
4017-- otherwise it has to be retrieved as a return value
4018-- * LUA_MINBUFFER not used; buffer handling not required any more
4019------------------------------------------------------------------------
4020function luaX:setinput(L, ls, z, source)
4021 if not ls then ls = {} end -- create struct
4022 if not ls.lookahead then ls.lookahead = {} end
4023 if not ls.t then ls.t = {} end
4024 ls.decpoint = "."
4025 ls.L = L
4026 ls.lookahead.token = "TK_EOS" -- no look-ahead token
4027 ls.z = z
4028 ls.fs = nil
4029 ls.linenumber = 1
4030 ls.lastline = 1
4031 ls.source = source
4032 self:nextc(ls) -- read first char
4033end
4034
4035--[[--------------------------------------------------------------------
4036-- LEXICAL ANALYZER
4037----------------------------------------------------------------------]]
4038
4039------------------------------------------------------------------------
4040-- checks if current character read is found in the set 'set'
4041------------------------------------------------------------------------
4042function luaX:check_next(ls, set)
4043 if not string.find(set, ls.current, 1, 1) then
4044 return false
4045 end
4046 self:save_and_next(ls)
4047 return true
4048end
4049
4050------------------------------------------------------------------------
4051-- retrieve next token, checking the lookahead buffer if necessary
4052-- * note that the macro next(ls) in llex.c is now luaX:nextc
4053-- * utilized used in lparser.c (various places)
4054------------------------------------------------------------------------
4055function luaX:next(ls)
4056 ls.lastline = ls.linenumber
4057 if ls.lookahead.token ~= "TK_EOS" then -- is there a look-ahead token?
4058 -- this must be copy-by-value
4059 ls.t.seminfo = ls.lookahead.seminfo -- use this one
4060 ls.t.token = ls.lookahead.token
4061 ls.lookahead.token = "TK_EOS" -- and discharge it
4062 else
4063 ls.t.token = self:llex(ls, ls.t) -- read next token
4064 end
4065end
4066
4067------------------------------------------------------------------------
4068-- fill in the lookahead buffer
4069-- * utilized used in lparser.c:constructor
4070------------------------------------------------------------------------
4071function luaX:lookahead(ls)
4072 -- lua_assert(ls.lookahead.token == "TK_EOS")
4073 ls.lookahead.token = self:llex(ls, ls.lookahead)
4074end
4075
4076------------------------------------------------------------------------
4077-- gets the next character and returns it
4078-- * this is the next() macro in llex.c; see notes at the beginning
4079------------------------------------------------------------------------
4080function luaX:nextc(ls)
4081 local c = luaZ:zgetc(ls.z)
4082 ls.current = c
4083 return c
4084end
4085
4086------------------------------------------------------------------------
4087-- saves the given character into the token buffer
4088-- * buffer handling code removed, not used in this implementation
4089-- * test for maximum token buffer length not used, makes things faster
4090------------------------------------------------------------------------
4091
4092function luaX:save(ls, c)
4093 local buff = ls.buff
4094 -- if you want to use this, please uncomment luaX.MAX_SIZET further up
4095 --if #buff > self.MAX_SIZET then
4096 -- self:lexerror(ls, "lexical element too long")
4097 --end
4098 ls.buff = buff..c
4099end
4100
4101------------------------------------------------------------------------
4102-- save current character into token buffer, grabs next character
4103-- * like luaX:nextc, returns the character read for convenience
4104------------------------------------------------------------------------
4105function luaX:save_and_next(ls)
4106 self:save(ls, ls.current)
4107 return self:nextc(ls)
4108end
4109
4110------------------------------------------------------------------------
4111-- LUA_NUMBER
4112-- * luaX:read_numeral is the main lexer function to read a number
4113-- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
4114------------------------------------------------------------------------
4115
4116------------------------------------------------------------------------
4117-- string to number converter (was luaO_str2d from lobject.c)
4118-- * returns the number, nil if fails (originally returns a boolean)
4119-- * conversion function originally lua_str2number(s,p), a macro which
4120-- maps to the strtod() function by default (from luaconf.h)
4121------------------------------------------------------------------------
4122function luaX:str2d(s)
4123 local result = tonumber(s)
4124 if result then return result end
4125 -- conversion failed
4126 if string.lower(string.sub(s, 1, 2)) == "0x" then -- maybe an hexadecimal constant?
4127 result = tonumber(s, 16)
4128 if result then return result end -- most common case
4129 -- Was: invalid trailing characters?
4130 -- In C, this function then skips over trailing spaces.
4131 -- true is returned if nothing else is found except for spaces.
4132 -- If there is still something else, then it returns a false.
4133 -- All this is not necessary using Lua's tonumber.
4134 end
4135 return nil
4136end
4137
4138------------------------------------------------------------------------
4139-- single-character replacement, for locale-aware decimal points
4140------------------------------------------------------------------------
4141function luaX:buffreplace(ls, from, to)
4142 local result, buff = "", ls.buff
4143 for p = 1, #buff do
4144 local c = string.sub(buff, p, p)
4145 if c == from then c = to end
4146 result = result..c
4147 end
4148 ls.buff = result
4149end
4150
4151------------------------------------------------------------------------
4152-- Attempt to convert a number by translating '.' decimal points to
4153-- the decimal point character used by the current locale. This is not
4154-- needed in Yueliang as Lua's tonumber() is already locale-aware.
4155-- Instead, the code is here in case the user implements localeconv().
4156------------------------------------------------------------------------
4157function luaX:trydecpoint(ls, Token)
4158 -- format error: try to update decimal point separator
4159 local old = ls.decpoint
4160 -- translate the following to Lua if you implement localeconv():
4161 -- struct lconv *cv = localeconv();
4162 -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
4163 self:buffreplace(ls, old, ls.decpoint) -- try updated decimal separator
4164 local seminfo = self:str2d(ls.buff)
4165 Token.seminfo = seminfo
4166 if not seminfo then
4167 -- format error with correct decimal point: no more options
4168 self:buffreplace(ls, ls.decpoint, ".") -- undo change (for error message)
4169 self:lexerror(ls, "malformed number", "TK_NUMBER")
4170 end
4171end
4172
4173------------------------------------------------------------------------
4174-- main number conversion function
4175-- * "^%w$" needed in the scan in order to detect "EOZ"
4176------------------------------------------------------------------------
4177function luaX:read_numeral(ls, Token)
4178 -- lua_assert(string.find(ls.current, "%d"))
4179 repeat
4180 self:save_and_next(ls)
4181 until string.find(ls.current, "%D") and ls.current ~= "."
4182 if self:check_next(ls, "Ee") then -- 'E'?
4183 self:check_next(ls, "+-") -- optional exponent sign
4184 end
4185 while string.find(ls.current, "^%w$") or ls.current == "_" do
4186 self:save_and_next(ls)
4187 end
4188 self:buffreplace(ls, ".", ls.decpoint) -- follow locale for decimal point
4189 local seminfo = self:str2d(ls.buff)
4190 Token.seminfo = seminfo
4191 if not seminfo then -- format error?
4192 self:trydecpoint(ls, Token) -- try to update decimal point separator
4193 end
4194end
4195
4196------------------------------------------------------------------------
4197-- count separators ("=") in a long string delimiter
4198-- * used by luaX:read_long_string
4199------------------------------------------------------------------------
4200function luaX:skip_sep(ls)
4201 local count = 0
4202 local s = ls.current
4203 -- lua_assert(s == "[" or s == "]")
4204 self:save_and_next(ls)
4205 while ls.current == "=" do
4206 self:save_and_next(ls)
4207 count = count + 1
4208 end
4209 return (ls.current == s) and count or (-count) - 1
4210end
4211
4212------------------------------------------------------------------------
4213-- reads a long string or long comment
4214------------------------------------------------------------------------
4215function luaX:read_long_string(ls, Token, sep)
4216 local cont = 0
4217 self:save_and_next(ls) -- skip 2nd '['
4218 if self:currIsNewline(ls) then -- string starts with a newline?
4219 self:inclinenumber(ls) -- skip it
4220 end
4221 while true do
4222 local c = ls.current
4223 if c == "EOZ" then
4224 self:lexerror(ls, Token and "unfinished long string" or
4225 "unfinished long comment", "TK_EOS")
4226 elseif c == "[" then
4227 --# compatibility code start
4228 if self.LUA_COMPAT_LSTR then
4229 if self:skip_sep(ls) == sep then
4230 self:save_and_next(ls) -- skip 2nd '['
4231 cont = cont + 1
4232 --# compatibility code start
4233 if self.LUA_COMPAT_LSTR == 1 then
4234 if sep == 0 then
4235 self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
4236 end
4237 end
4238 --# compatibility code end
4239 end
4240 end
4241 --# compatibility code end
4242 elseif c == "]" then
4243 if self:skip_sep(ls) == sep then
4244 self:save_and_next(ls) -- skip 2nd ']'
4245 --# compatibility code start
4246 if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
4247 cont = cont - 1
4248 if sep == 0 and cont >= 0 then break end
4249 end
4250 --# compatibility code end
4251 break
4252 end
4253 elseif self:currIsNewline(ls) then
4254 self:save(ls, "\n")
4255 self:inclinenumber(ls)
4256 if not Token then ls.buff = "" end -- avoid wasting space
4257 else -- default
4258 if Token then
4259 self:save_and_next(ls)
4260 else
4261 self:nextc(ls)
4262 end
4263 end--if c
4264 end--while
4265 if Token then
4266 local p = 3 + sep
4267 Token.seminfo = string.sub(ls.buff, p, -p)
4268 end
4269end
4270
4271------------------------------------------------------------------------
4272-- reads a string
4273-- * has been restructured significantly compared to the original C code
4274------------------------------------------------------------------------
4275
4276function luaX:read_string(ls, del, Token)
4277 self:save_and_next(ls)
4278 while ls.current ~= del do
4279 local c = ls.current
4280 if c == "EOZ" then
4281 self:lexerror(ls, "unfinished string", "TK_EOS")
4282 elseif self:currIsNewline(ls) then
4283 self:lexerror(ls, "unfinished string", "TK_STRING")
4284 elseif c == "\\" then
4285 c = self:nextc(ls) -- do not save the '\'
4286 if self:currIsNewline(ls) then -- go through
4287 self:save(ls, "\n")
4288 self:inclinenumber(ls)
4289 elseif c ~= "EOZ" then -- will raise an error next loop
4290 -- escapes handling greatly simplified here:
4291 local i = string.find("abfnrtv", c, 1, 1)
4292 if i then
4293 self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
4294 self:nextc(ls)
4295 elseif not string.find(c, "%d") then
4296 self:save_and_next(ls) -- handles \\, \", \', and \?
4297 else -- \xxx
4298 c, i = 0, 0
4299 repeat
4300 c = 10 * c + ls.current
4301 self:nextc(ls)
4302 i = i + 1
4303 until i >= 3 or not string.find(ls.current, "%d")
4304 if c > 255 then -- UCHAR_MAX
4305 self:lexerror(ls, "escape sequence too large", "TK_STRING")
4306 end
4307 self:save(ls, string.char(c))
4308 end
4309 end
4310 else
4311 self:save_and_next(ls)
4312 end--if c
4313 end--while
4314 self:save_and_next(ls) -- skip delimiter
4315 Token.seminfo = string.sub(ls.buff, 2, -2)
4316end
4317
4318------------------------------------------------------------------------
4319-- main lexer function
4320------------------------------------------------------------------------
4321function luaX:llex(ls, Token)
4322 ls.buff = ""
4323 while true do
4324 local c = ls.current
4325 ----------------------------------------------------------------
4326 if self:currIsNewline(ls) then
4327 self:inclinenumber(ls)
4328 ----------------------------------------------------------------
4329 elseif c == "-" then
4330 c = self:nextc(ls)
4331 if c ~= "-" then return "-" end
4332 -- else is a comment
4333 local sep = -1
4334 if self:nextc(ls) == '[' then
4335 sep = self:skip_sep(ls)
4336 ls.buff = "" -- 'skip_sep' may dirty the buffer
4337 end
4338 if sep >= 0 then
4339 self:read_long_string(ls, nil, sep) -- long comment
4340 ls.buff = ""
4341 else -- else short comment
4342 while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
4343 self:nextc(ls)
4344 end
4345 end
4346 ----------------------------------------------------------------
4347 elseif c == "[" then
4348 local sep = self:skip_sep(ls)
4349 if sep >= 0 then
4350 self:read_long_string(ls, Token, sep)
4351 return "TK_STRING"
4352 elseif sep == -1 then
4353 return "["
4354 else
4355 self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
4356 end
4357 ----------------------------------------------------------------
4358 elseif c == "=" then
4359 c = self:nextc(ls)
4360 if c ~= "=" then return "="
4361 else self:nextc(ls); return "TK_EQ" end
4362 ----------------------------------------------------------------
4363 elseif c == "<" then
4364 c = self:nextc(ls)
4365 if c ~= "=" then return "<"
4366 else self:nextc(ls); return "TK_LE" end
4367 ----------------------------------------------------------------
4368 elseif c == ">" then
4369 c = self:nextc(ls)
4370 if c ~= "=" then return ">"
4371 else self:nextc(ls); return "TK_GE" end
4372 ----------------------------------------------------------------
4373 elseif c == "~" then
4374 c = self:nextc(ls)
4375 if c ~= "=" then return "~"
4376 else self:nextc(ls); return "TK_NE" end
4377 ----------------------------------------------------------------
4378 elseif c == "\"" or c == "'" then
4379 self:read_string(ls, c, Token)
4380 return "TK_STRING"
4381 ----------------------------------------------------------------
4382 elseif c == "." then
4383 c = self:save_and_next(ls)
4384 if self:check_next(ls, ".") then
4385 if self:check_next(ls, ".") then
4386 return "TK_DOTS" -- ...
4387 else return "TK_CONCAT" -- ..
4388 end
4389 elseif not string.find(c, "%d") then
4390 return "."
4391 else
4392 self:read_numeral(ls, Token)
4393 return "TK_NUMBER"
4394 end
4395 ----------------------------------------------------------------
4396 elseif c == "EOZ" then
4397 return "TK_EOS"
4398 ----------------------------------------------------------------
4399 else -- default
4400 if string.find(c, "%s") then
4401 -- lua_assert(self:currIsNewline(ls))
4402 self:nextc(ls)
4403 elseif string.find(c, "%d") then
4404 self:read_numeral(ls, Token)
4405 return "TK_NUMBER"
4406 elseif string.find(c, "[_%a]") then
4407 -- identifier or reserved word
4408 repeat
4409 c = self:save_and_next(ls)
4410 until c == "EOZ" or not string.find(c, "[_%w]")
4411 local ts = ls.buff
4412 local tok = self.enums[ts]
4413 if tok then return tok end -- reserved word?
4414 Token.seminfo = ts
4415 return "TK_NAME"
4416 else
4417 self:nextc(ls)
4418 return c -- single-char tokens (+ - / ...)
4419 end
4420 ----------------------------------------------------------------
4421 end--if c
4422 end--while
4423end
4424
4425return luaY
4426end
4427
4428function LuaZ()
4429--[[--------------------------------------------------------------------
4430
4431 lzio.lua
4432 Lua buffered streams in Lua
4433 This file is part of Yueliang.
4434
4435 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
4436 The COPYRIGHT file describes the conditions
4437 under which this software may be distributed.
4438
4439 See the ChangeLog for more information.
4440
4441----------------------------------------------------------------------]]
4442
4443--[[--------------------------------------------------------------------
4444-- Notes:
4445-- * EOZ is implemented as a string, "EOZ"
4446-- * Format of z structure (ZIO)
4447-- z.n -- bytes still unread
4448-- z.p -- last read position position in buffer
4449-- z.reader -- chunk reader function
4450-- z.data -- additional data
4451-- * Current position, p, is now last read index instead of a pointer
4452--
4453-- Not implemented:
4454-- * luaZ_lookahead: used only in lapi.c:lua_load to detect binary chunk
4455-- * luaZ_read: used only in lundump.c:ezread to read +1 bytes
4456-- * luaZ_openspace: dropped; let Lua handle buffers as strings (used in
4457-- lundump.c:LoadString & lvm.c:luaV_concat)
4458-- * luaZ buffer macros: dropped; buffers are handled as strings
4459-- * lauxlib.c:getF reader implementation has an extraline flag to
4460-- skip over a shbang (#!) line, this is not implemented here
4461--
4462-- Added:
4463-- (both of the following are vaguely adapted from lauxlib.c)
4464-- * luaZ:make_getS: create Reader from a string
4465-- * luaZ:make_getF: create Reader that reads from a file
4466--
4467-- Changed in 5.1.x:
4468-- * Chunkreader renamed to Reader (ditto with Chunkwriter)
4469-- * Zio struct: no more name string, added Lua state for reader
4470-- (however, Yueliang readers do not require a Lua state)
4471----------------------------------------------------------------------]]
4472
4473local luaZ = {}
4474
4475------------------------------------------------------------------------
4476-- * reader() should return a string, or nil if nothing else to parse.
4477-- Additional data can be set only during stream initialization
4478-- * Readers are handled in lauxlib.c, see luaL_load(file|buffer|string)
4479-- * LUAL_BUFFERSIZE=BUFSIZ=512 in make_getF() (located in luaconf.h)
4480-- * Original Reader typedef:
4481-- const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
4482-- * This Lua chunk reader implementation:
4483-- returns string or nil, no arguments to function
4484------------------------------------------------------------------------
4485
4486------------------------------------------------------------------------
4487-- create a chunk reader from a source string
4488------------------------------------------------------------------------
4489function luaZ:make_getS(buff)
4490 local b = buff
4491 return function() -- chunk reader anonymous function here
4492 if not b then return nil end
4493 local data = b
4494 b = nil
4495 return data
4496 end
4497end
4498
4499------------------------------------------------------------------------
4500-- create a chunk reader from a source file
4501------------------------------------------------------------------------
4502--[[
4503function luaZ:make_getF(filename)
4504 local LUAL_BUFFERSIZE = 512
4505 local h = io.open(filename, "r")
4506 if not h then return nil end
4507 return function() -- chunk reader anonymous function here
4508 if not h or io.type(h) == "closed file" then return nil end
4509 local buff = h:read(LUAL_BUFFERSIZE)
4510 if not buff then h:close(); h = nil end
4511 return buff
4512 end
4513end
4514--]]
4515------------------------------------------------------------------------
4516-- creates a zio input stream
4517-- returns the ZIO structure, z
4518------------------------------------------------------------------------
4519function luaZ:init(reader, data, name)
4520 if not reader then return end
4521 local z = {}
4522 z.reader = reader
4523 z.data = data or ""
4524 z.name = name
4525 -- set up additional data for reading
4526 if not data or data == "" then z.n = 0 else z.n = #data end
4527 z.p = 0
4528 return z
4529end
4530
4531------------------------------------------------------------------------
4532-- fill up input buffer
4533------------------------------------------------------------------------
4534function luaZ:fill(z)
4535 local buff = z.reader()
4536 z.data = buff
4537 if not buff or buff == "" then return "EOZ" end
4538 z.n, z.p = #buff - 1, 1
4539 return string.sub(buff, 1, 1)
4540end
4541
4542------------------------------------------------------------------------
4543-- get next character from the input stream
4544-- * local n, p are used to optimize code generation
4545------------------------------------------------------------------------
4546function luaZ:zgetc(z)
4547 local n, p = z.n, z.p + 1
4548 if n > 0 then
4549 z.n, z.p = n - 1, p
4550 return string.sub(z.data, p, p)
4551 else
4552 return self:fill(z)
4553 end
4554end
4555
4556return luaZ
4557end
4558
4559print(Loadstring([[print("HELLO")]]))