1use lua_types::{AbsLineInfo, GcRef, LuaError, LuaString, LuaValue, LuaProto, UpvalDesc, LocalVar};
24
25pub type TokenKind = i32;
33pub const TK_AND: TokenKind = 257;
34pub const TK_BREAK: TokenKind = 258;
35pub const TK_DO: TokenKind = 259;
36pub const TK_ELSE: TokenKind = 260;
37pub const TK_ELSEIF: TokenKind = 261;
38pub const TK_END: TokenKind = 262;
39pub const TK_FALSE: TokenKind = 263;
40pub const TK_FOR: TokenKind = 264;
41pub const TK_FUNCTION: TokenKind = 265;
42pub const TK_GOTO: TokenKind = 266;
43pub const TK_IF: TokenKind = 267;
44pub const TK_IN: TokenKind = 268;
45pub const TK_LOCAL: TokenKind = 269;
46pub const TK_NIL: TokenKind = 270;
47pub const TK_NOT: TokenKind = 271;
48pub const TK_OR: TokenKind = 272;
49pub const TK_REPEAT: TokenKind = 273;
50pub const TK_RETURN: TokenKind = 274;
51pub const TK_THEN: TokenKind = 275;
52pub const TK_TRUE: TokenKind = 276;
53pub const TK_UNTIL: TokenKind = 277;
54pub const TK_WHILE: TokenKind = 278;
55pub const TK_IDIV: TokenKind = 279;
56pub const TK_CONCAT: TokenKind = 280;
57pub const TK_DOTS: TokenKind = 281;
58pub const TK_EQ: TokenKind = 282;
59pub const TK_GE: TokenKind = 283;
60pub const TK_LE: TokenKind = 284;
61pub const TK_NE: TokenKind = 285;
62pub const TK_SHL: TokenKind = 286;
63pub const TK_SHR: TokenKind = 287;
64pub const TK_DBCOLON: TokenKind = 288;
65pub const TK_EOS: TokenKind = 289;
66pub const TK_FLT: TokenKind = 290;
67pub const TK_INT: TokenKind = 291;
68pub const TK_NAME: TokenKind = 292;
69pub const TK_STRING: TokenKind = 293;
70
71const MAX_VARS: i32 = 200;
74
75const NO_JUMP: i32 = -1;
76
77const UNARY_PRIORITY: i32 = 12;
78
79const LUA_MULTRET: i32 = -1;
80
81const MAX_UPVAL: u8 = 255;
82
83const MAXARG_BX: i32 = (1 << 17) - 1;
85
86const LFIELDS_PER_FLUSH: i32 = 50;
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92#[repr(u8)]
93pub enum VarKind {
94 Reg = 0,
95 Const = 1,
96 ToBeClosed = 2,
97 CompileTimeConst = 3,
98}
99
100impl VarKind {
101 pub fn from_u8(v: u8) -> Self {
102 match v {
103 0 => VarKind::Reg,
104 1 => VarKind::Const,
105 2 => VarKind::ToBeClosed,
106 3 => VarKind::CompileTimeConst,
107 _ => VarKind::Reg,
108 }
109 }
110 pub fn as_u8(self) -> u8 { self as u8 }
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum ExprKind {
118 Void, Nil, True, False, K, KFlt, KInt, KStr, NonReloc, Local, UpVal, Const, Indexed, IndexUp, IndexI, IndexStr, Jmp, Reloc, Call, VarArg, }
139
140impl ExprKind {
141 #[inline]
142 pub fn has_mult_ret(self) -> bool {
143 matches!(self, ExprKind::Call | ExprKind::VarArg)
144 }
145
146 #[inline]
147 pub fn is_var(self) -> bool {
148 matches!(
149 self,
150 ExprKind::Local
151 | ExprKind::UpVal
152 | ExprKind::Const
153 | ExprKind::Indexed
154 | ExprKind::IndexUp
155 | ExprKind::IndexI
156 | ExprKind::IndexStr
157 )
158 }
159
160 #[inline]
161 pub fn is_indexed(self) -> bool {
162 matches!(
163 self,
164 ExprKind::Indexed | ExprKind::IndexUp | ExprKind::IndexI | ExprKind::IndexStr
165 )
166 }
167}
168
169#[derive(Debug, Clone, Default)]
174pub struct ExprPayload {
175 pub ival: i64,
176 pub nval: f64,
177 pub strval: Option<GcRef<LuaString>>,
178 pub info: i32,
179 pub ind_idx: i16,
180 pub ind_t: u8,
181 pub var_ridx: u8,
182 pub var_vidx: u16,
183}
184
185#[derive(Debug, Clone)]
189pub struct ExprDesc {
190 pub k: ExprKind,
191 pub u: ExprPayload,
192 pub t: i32,
193 pub f: i32,
194}
195
196impl Default for ExprDesc {
197 fn default() -> Self {
198 ExprDesc { k: ExprKind::Void, u: ExprPayload::default(), t: NO_JUMP, f: NO_JUMP }
199 }
200}
201
202#[derive(Debug, Clone)]
208pub struct VarDesc {
209 pub kind: VarKind,
210 pub ridx: u8,
211 pub pidx: i16,
212 pub name: Option<GcRef<LuaString>>,
213 pub const_val: LuaValue,
214}
215
216impl Default for VarDesc {
217 fn default() -> Self {
218 VarDesc {
219 kind: VarKind::Reg,
220 ridx: 0,
221 pidx: 0,
222 name: None,
223 const_val: LuaValue::Nil,
224 }
225 }
226}
227
228#[derive(Debug, Clone)]
231pub struct LabelDesc {
232 pub name: Option<GcRef<LuaString>>,
233 pub pc: i32,
234 pub line: i32,
235 pub nactvar: u8,
236 pub close: bool,
237}
238
239#[derive(Debug, Default)]
243pub struct DynData {
244 pub actvar: Vec<VarDesc>,
245 pub gt: Vec<LabelDesc>,
246 pub label: Vec<LabelDesc>,
247}
248
249#[derive(Debug)]
254pub struct BlockCnt {
255 pub previous: Option<Box<BlockCnt>>,
256 pub firstlabel: i32,
257 pub firstgoto: i32,
258 pub nactvar: u8,
259 pub upval: bool,
260 pub isloop: bool,
261 pub insidetbc: bool,
262}
263
264#[derive(Debug)]
269pub struct FuncState {
270 pub f: Box<LuaProto>,
274 pub prev: Option<Box<FuncState>>,
275 pub bl: Option<Box<BlockCnt>>,
276 pub pc: i32,
277 pub lasttarget: i32,
278 pub previousline: i32,
279 pub nk: i32,
280 pub np: i32,
281 pub nabslineinfo: i32,
282 pub firstlocal: i32,
283 pub firstlabel: i32,
284 pub ndebugvars: i16,
285 pub nactvar: u8,
286 pub nups: u8,
287 pub freereg: u8,
288 pub iwthabs: u8,
289 pub needclose: bool,
290 pub last_token_line: i32,
296}
297
298#[derive(Debug)]
304pub struct ConsControl {
305 pub v: ExprDesc,
306 pub t: ExprDesc,
307 pub nh: i32,
308 pub na: i32,
309 pub tostore: i32,
310}
311
312#[derive(Debug)]
316pub struct LhsAssign {
317 pub prev: Option<Box<LhsAssign>>,
318 pub v: ExprDesc,
319}
320
321#[derive(Debug, Clone, Copy, PartialEq, Eq)]
325pub enum UnOpr {
326 Minus, BNot, Not, Len, NoUnOpr, }
332
333#[derive(Debug, Clone, Copy, PartialEq, Eq)]
334pub enum BinOpr {
335 Add, Sub, Mul, Mod, Pow, Div, IDiv, BAnd, BOr, BXor, Shl, Shr, Concat, Eq, Lt, Le, Ne, Gt, Ge, And, Or, NoBinOpr, }
358
359const PRIORITY: [(u8, u8); 21] = [
361 (10, 10), (10, 10), (11, 11), (11, 11), (14, 13), (11, 11), (11, 11), (6, 6), (4, 4), (5, 5), (7, 7), (7, 7), (9, 8), (3, 3), (3, 3), (3, 3), (3, 3), (3, 3), (3, 3), (2, 2), (1, 1), ];
372
373pub use lua_code::opcodes::OpCode;
375
376#[derive(Debug, Clone, Default)]
383pub struct TokenValue {
384 pub r: f64,
385 pub i: i64,
386 pub ts: Option<GcRef<LuaString>>,
387}
388
389#[derive(Debug, Clone, Default)]
390pub struct LexToken {
391 pub token: TokenKind,
392 pub seminfo: TokenValue,
393}
394
395pub struct LexState {
400 pub current: i32,
401 pub linenumber: i32,
402 pub lastline: i32,
403 pub t: LexToken,
404 pub lookahead: LexToken,
405 pub fs: Option<Box<FuncState>>,
406 pub dyd: DynData,
407 pub source: Option<GcRef<LuaString>>,
408 pub envn: Option<GcRef<LuaString>>,
409 pub lex: lua_lex::LexState,
414 pub recursion_depth: u32,
416}
417
418const PARSER_MAX_C_CALLS: u32 = 200;
419
420fn enter_level(ls: &mut LexState) -> Result<(), LuaError> {
421 ls.recursion_depth += 1;
422 if ls.recursion_depth >= PARSER_MAX_C_CALLS {
423 Err(LuaError::syntax(format_args!("C stack overflow")))
424 } else {
425 Ok(())
426 }
427}
428
429fn leave_level(ls: &mut LexState) {
430 ls.recursion_depth = ls.recursion_depth.saturating_sub(1);
431}
432
433fn lex_next(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
437 lua_lex::next(state, &mut ls.lex)?;
438 sync_from_lex(ls);
439 Ok(())
440}
441
442fn lex_lookahead(ls: &mut LexState, state: &mut LuaState) -> Result<TokenKind, LuaError> {
445 let kind = lua_lex::lookahead(state, &mut ls.lex)?;
446 sync_from_lex(ls);
447 Ok(kind)
448}
449
450fn sync_from_lex(ls: &mut LexState) {
453 ls.current = ls.lex.current;
454 ls.linenumber = ls.lex.linenumber;
455 ls.lastline = ls.lex.lastline;
456 ls.t = LexToken {
457 token: ls.lex.t.kind,
458 seminfo: local_token_value(&ls.lex.t.value),
459 };
460 ls.lookahead = LexToken {
461 token: ls.lex.lookahead.kind,
462 seminfo: local_token_value(&ls.lex.lookahead.value),
463 };
464 if let Some(fs) = ls.fs.as_mut() {
468 fs.last_token_line = ls.lastline;
469 }
470}
471
472pub use lua_vm::state::LuaState;
474
475fn emit_inst(fs: &mut FuncState, line: i32, inst: lua_code::opcodes::Instruction) -> i32 {
491 const MAX_IWTH_ABS: i32 = 128;
492 const LIM_LINE_DIFF: i32 = 0x80;
493 const ABS_LINE_INFO: i8 = -0x80i8;
494 let pc = fs.pc as usize;
495 if fs.f.code.len() <= pc {
496 fs.f.code.resize(pc + 1, lua_types::opcode::Instruction::default());
497 }
498 fs.f.code[pc] = lua_types::opcode::Instruction::new(inst.0);
499 if fs.f.lineinfo.len() <= pc {
500 fs.f.lineinfo.resize(pc + 1, 0i8);
501 }
502 let linedif_raw = line - fs.previousline;
503 let need_abs = linedif_raw.abs() >= LIM_LINE_DIFF || {
504 let over = fs.iwthabs as i32 >= MAX_IWTH_ABS;
505 if !over { fs.iwthabs += 1; }
506 over
507 };
508 if need_abs {
509 fs.f.abslineinfo.push(AbsLineInfo { pc: pc as i32, line });
510 fs.nabslineinfo += 1;
511 fs.f.lineinfo[pc] = ABS_LINE_INFO;
512 fs.iwthabs = 1;
513 } else {
514 fs.f.lineinfo[pc] = linedif_raw as i8;
515 }
516 fs.previousline = line;
517 let result = fs.pc;
518 fs.pc += 1;
519 result
520}
521
522fn add_k_value(fs: &mut FuncState, v: LuaValue) -> i32 {
523 let idx = fs.nk;
524 if (fs.f.k.len() as i32) <= idx {
525 fs.f.k.resize((idx + 1) as usize, LuaValue::Nil);
526 }
527 fs.f.k[idx as usize] = v;
528 fs.nk += 1;
529 idx
530}
531
532fn add_k_string(fs: &mut FuncState, s: GcRef<LuaString>) -> i32 {
533 for (i, k) in fs.f.k.iter().take(fs.nk as usize).enumerate() {
534 if let LuaValue::Str(existing) = k {
535 if GcRef::ptr_eq(existing, &s) {
536 return i as i32;
537 }
538 }
539 }
540 add_k_value(fs, LuaValue::Str(s))
541}
542
543fn bump_maxstack(fs: &mut FuncState, n: u8) {
544 if fs.f.maxstacksize < n {
545 fs.f.maxstacksize = n;
546 }
547}
548
549fn reserve_reg(fs: &mut FuncState) -> Result<u8, LuaError> {
550 if fs.freereg == u8::MAX {
551 return Err(LuaError::syntax(format_args!(
552 "function or expression needs too many registers"
553 )));
554 }
555 let r = fs.freereg;
556 fs.freereg += 1;
557 bump_maxstack(fs, fs.freereg);
558 Ok(r)
559}
560
561fn reserve_regs(fs: &mut FuncState, n: i32) -> Result<(), LuaError> {
562 let newstack = fs.freereg as i32 + n;
563 if newstack >= 255 {
564 return Err(LuaError::syntax(format_args!(
565 "function or expression needs too many registers"
566 )));
567 }
568 fs.freereg = newstack as u8;
569 bump_maxstack(fs, fs.freereg);
570 Ok(())
571}
572
573fn cg_free_reg(fs: &mut FuncState, reg: i32) {
579 if reg >= fs.nactvar as i32 {
580 debug_assert_eq!(reg, fs.freereg as i32 - 1);
581 fs.freereg = fs.freereg.saturating_sub(1);
582 }
583}
584
585fn cg_free_exp(fs: &mut FuncState, e: &ExprDesc) {
590 if e.k == ExprKind::NonReloc {
591 cg_free_reg(fs, e.u.info);
592 }
593}
594
595fn cg_free_exps(fs: &mut FuncState, e1: &ExprDesc, e2: &ExprDesc) {
600 let r1 = if e1.k == ExprKind::NonReloc { e1.u.info } else { -1 };
601 let r2 = if e2.k == ExprKind::NonReloc { e2.u.info } else { -1 };
602 if r1 > r2 {
603 cg_free_reg(fs, r1);
604 cg_free_reg(fs, r2);
605 } else {
606 cg_free_reg(fs, r2);
607 cg_free_reg(fs, r1);
608 }
609}
610
611fn cg_posfix_fold(
622 fs: &mut FuncState,
623 op: BinOpr,
624 e1: &mut ExprDesc,
625 e2: &mut ExprDesc,
626 line: i32,
627) -> Result<(), LuaError> {
628 let rhs_line = fs.last_token_line;
634 cg_discharge_vars(fs, rhs_line, e2)?;
635
636 let promote = |k: ExprKind, u: &ExprPayload| -> Option<f64> {
637 match k {
638 ExprKind::KInt => Some(u.ival as f64),
639 ExprKind::KFlt => Some(u.nval),
640 _ => None,
641 }
642 };
643
644 let foldable = e1.t == NO_JUMP && e1.f == NO_JUMP
645 && e2.t == NO_JUMP && e2.f == NO_JUMP;
646
647 if foldable {
648 if let (ExprKind::KInt, ExprKind::KInt) = (e1.k, e2.k) {
649 let a = e1.u.ival;
650 let b = e2.u.ival;
651 let r: Option<i64> = match op {
652 BinOpr::Add => Some(a.wrapping_add(b)),
653 BinOpr::Sub => Some(a.wrapping_sub(b)),
654 BinOpr::Mul => Some(a.wrapping_mul(b)),
655 BinOpr::Mod if b != 0 => Some(a.rem_euclid(b)),
656 BinOpr::IDiv if b != 0 => Some(a.div_euclid(b)),
657 BinOpr::BAnd => Some(a & b),
658 BinOpr::BOr => Some(a | b),
659 BinOpr::BXor => Some(a ^ b),
660 _ => None,
661 };
662 if let Some(v) = r {
663 e1.k = ExprKind::KInt;
664 e1.u.ival = v;
665 return Ok(());
666 }
667 }
668 if let (Some(a), Some(b)) = (promote(e1.k, &e1.u), promote(e2.k, &e2.u)) {
669 let r: Option<f64> = match op {
670 BinOpr::Add => Some(a + b),
671 BinOpr::Sub => Some(a - b),
672 BinOpr::Mul => Some(a * b),
673 BinOpr::Div => Some(a / b),
674 BinOpr::Pow => Some(a.powf(b)),
675 _ => None,
676 };
677 if let Some(v) = r {
678 if v.is_finite() {
679 e1.k = ExprKind::KFlt;
680 e1.u.nval = v;
681 return Ok(());
682 }
683 }
684 }
685 }
686
687 if matches!(op, BinOpr::Lt | BinOpr::Le) {
688 return cg_emit_order(fs, op, e1, e2, line);
689 }
690
691 if matches!(op, BinOpr::Gt | BinOpr::Ge) {
692 let swap_op = if matches!(op, BinOpr::Gt) { BinOpr::Lt } else { BinOpr::Le };
693 std::mem::swap(e1, e2);
694 return cg_emit_order(fs, swap_op, e1, e2, line);
695 }
696
697 if matches!(op, BinOpr::Eq | BinOpr::Ne) {
698 return cg_emit_eq(fs, op, e1, e2, line);
699 }
700
701 if matches!(op, BinOpr::And) {
702 debug_assert_eq!(e1.t, NO_JUMP);
703 cg_concat(fs, &mut e2.f, e1.f)?;
704 *e1 = e2.clone();
705 return Ok(());
706 }
707
708 if matches!(op, BinOpr::Or) {
709 debug_assert_eq!(e1.f, NO_JUMP);
710 cg_concat(fs, &mut e2.t, e1.t)?;
711 *e1 = e2.clone();
712 return Ok(());
713 }
714
715 if matches!(op, BinOpr::Concat) {
716 return cg_emit_concat(fs, e1, e2, line);
717 }
718
719 let (opcode, event) = match op {
720 BinOpr::Add => (lua_code::opcodes::OpCode::Add, lua_types::tagmethod::TagMethod::Add),
721 BinOpr::Sub => (lua_code::opcodes::OpCode::Sub, lua_types::tagmethod::TagMethod::Sub),
722 BinOpr::Mul => (lua_code::opcodes::OpCode::Mul, lua_types::tagmethod::TagMethod::Mul),
723 BinOpr::Mod => (lua_code::opcodes::OpCode::Mod, lua_types::tagmethod::TagMethod::Mod),
724 BinOpr::Pow => (lua_code::opcodes::OpCode::Pow, lua_types::tagmethod::TagMethod::Pow),
725 BinOpr::Div => (lua_code::opcodes::OpCode::Div, lua_types::tagmethod::TagMethod::Div),
726 BinOpr::IDiv => (lua_code::opcodes::OpCode::IDiv, lua_types::tagmethod::TagMethod::Idiv),
727 BinOpr::BAnd => (lua_code::opcodes::OpCode::BAnd, lua_types::tagmethod::TagMethod::Band),
728 BinOpr::BOr => (lua_code::opcodes::OpCode::BOr, lua_types::tagmethod::TagMethod::Bor),
729 BinOpr::BXor => (lua_code::opcodes::OpCode::BXor, lua_types::tagmethod::TagMethod::Bxor),
730 BinOpr::Shl => (lua_code::opcodes::OpCode::Shl, lua_types::tagmethod::TagMethod::Shl),
731 BinOpr::Shr => (lua_code::opcodes::OpCode::Shr, lua_types::tagmethod::TagMethod::Shr),
732 _ => todo!(
733 "phase-b: cg_posfix_fold non-foldable binop {:?} ({:?} {:?})",
734 op, e1.k, e2.k
735 ),
736 };
737
738 cg_discharge_vars(fs, line, e1)?;
739 cg_discharge_vars(fs, line, e2)?;
740 let v2 = cg_exp_to_any_reg(fs, line, e2)?;
741 let v1 = cg_exp_to_any_reg(fs, line, e1)?;
742
743 let inst = lua_code::opcodes::Instruction::abck(opcode, 0, v1 as u32, v2 as u32, 0);
744 let pc = emit_inst(fs, line, inst);
745 cg_free_exps(fs, e1, e2);
746 e1.u.info = pc;
747 e1.k = ExprKind::Reloc;
748
749 let mm_inst = lua_code::opcodes::Instruction::abck(
750 lua_code::opcodes::OpCode::MmBin,
751 v1 as u32,
752 v2 as u32,
753 event as u32,
754 0,
755 );
756 emit_inst(fs, line, mm_inst);
757 Ok(())
758}
759
760fn cg_emit_order(
769 fs: &mut FuncState,
770 op: BinOpr,
771 e1: &mut ExprDesc,
772 e2: &mut ExprDesc,
773 line: i32,
774) -> Result<(), LuaError> {
775 debug_assert!(matches!(op, BinOpr::Lt | BinOpr::Le));
776 let is_le = matches!(op, BinOpr::Le);
777 let (op_imm_e2, op_imm_e1, op_reg) = if is_le {
778 (
779 lua_code::opcodes::OpCode::LeI,
780 lua_code::opcodes::OpCode::GeI,
781 lua_code::opcodes::OpCode::Le,
782 )
783 } else {
784 (
785 lua_code::opcodes::OpCode::LtI,
786 lua_code::opcodes::OpCode::GtI,
787 lua_code::opcodes::OpCode::Lt,
788 )
789 };
790 let (r1, r2, cmp_op) = if let Some(im) = cg_sc_int(e2) {
791 let r1 = cg_exp_to_any_reg(fs, line, e1)?;
792 (r1, im, op_imm_e2)
793 } else if let Some(im) = cg_sc_int(e1) {
794 let r1 = cg_exp_to_any_reg(fs, line, e2)?;
795 (r1, im, op_imm_e1)
796 } else {
797 let r2 = cg_exp_to_any_reg(fs, line, e2)?;
798 let r1 = cg_exp_to_any_reg(fs, line, e1)?;
799 (r1, r2, op_reg)
800 };
801 cg_free_exps(fs, e1, e2);
802 let cmp = lua_code::opcodes::Instruction::abck(
803 cmp_op,
804 r1 as u32,
805 r2 as u32,
806 0,
807 1,
808 );
809 emit_inst(fs, line, cmp);
810 let jmp_arg = (NO_JUMP + lua_code::opcodes::OFFSET_S_J) as u32;
811 let jmp = lua_code::opcodes::Instruction::sj(
812 lua_code::opcodes::OpCode::Jmp,
813 jmp_arg,
814 0,
815 );
816 let jmp_pc = emit_inst(fs, line, jmp);
817 e1.u.info = jmp_pc;
818 e1.k = ExprKind::Jmp;
819 Ok(())
820}
821
822fn cg_emit_eq(
832 fs: &mut FuncState,
833 op: BinOpr,
834 e1: &mut ExprDesc,
835 e2: &mut ExprDesc,
836 line: i32,
837) -> Result<(), LuaError> {
838 debug_assert!(matches!(op, BinOpr::Eq | BinOpr::Ne));
839 if e1.k != ExprKind::NonReloc {
840 std::mem::swap(e1, e2);
841 }
842 let r1 = cg_exp_to_any_reg(fs, line, e1)?;
843 let (r2, cmp_op) = if let Some(im) = cg_sc_int(e2) {
844 (im, lua_code::opcodes::OpCode::EqI)
845 } else {
846 let r = cg_exp_to_any_reg(fs, line, e2)?;
847 (r, lua_code::opcodes::OpCode::Eq)
848 };
849 cg_free_exps(fs, e1, e2);
850 let k_bit = if matches!(op, BinOpr::Eq) { 1 } else { 0 };
851 let cmp = lua_code::opcodes::Instruction::abck(
852 cmp_op,
853 r1 as u32,
854 r2 as u32,
855 0,
856 k_bit,
857 );
858 emit_inst(fs, line, cmp);
859 let jmp_pc = cg_jump(fs, line);
860 e1.u.info = jmp_pc;
861 e1.k = ExprKind::Jmp;
862 Ok(())
863}
864
865fn previous_instruction_idx(fs: &FuncState) -> Option<usize> {
870 if fs.pc > fs.lasttarget {
871 Some((fs.pc - 1) as usize)
872 } else {
873 None
874 }
875}
876
877fn cg_emit_concat(
886 fs: &mut FuncState,
887 e1: &mut ExprDesc,
888 e2: &mut ExprDesc,
889 line: i32,
890) -> Result<(), LuaError> {
891 cg_exp_to_next_reg(fs, line, e2)?;
892
893 if let Some(prev_idx) = previous_instruction_idx(fs) {
894 let prev = lua_code::opcodes::Instruction(fs.f.code[prev_idx].0);
895 if prev.opcode() == Some(lua_code::opcodes::OpCode::Concat) {
896 let n = prev.arg_b();
897 debug_assert_eq!(e1.u.info + 1, prev.arg_a() as i32);
898 cg_free_exp(fs, e2);
899 let mut updated = prev;
900 updated.set_arg_a(e1.u.info as u32);
901 updated.set_arg_b(n + 1);
902 fs.f.code[prev_idx] = lua_types::opcode::Instruction::new(updated.0);
903 return Ok(());
904 }
905 }
906
907 let inst = lua_code::opcodes::Instruction::abck(
908 lua_code::opcodes::OpCode::Concat,
909 e1.u.info as u32,
910 2,
911 0,
912 0,
913 );
914 emit_inst(fs, line, inst);
915 cg_free_exp(fs, e2);
916 Ok(())
917}
918
919fn cg_prefix(
928 fs: &mut FuncState,
929 op: UnOpr,
930 e: &mut ExprDesc,
931 line: i32,
932) -> Result<(), LuaError> {
933 cg_discharge_vars(fs, line, e)?;
934 let opcode = match op {
935 UnOpr::Minus => lua_code::opcodes::OpCode::Unm,
936 UnOpr::BNot => lua_code::opcodes::OpCode::BNot,
937 UnOpr::Len => lua_code::opcodes::OpCode::Len,
938 UnOpr::Not => return cg_codenot(fs, line, e),
939 UnOpr::NoUnOpr => return Ok(()),
940 };
941 let r = cg_exp_to_any_reg(fs, line, e)?;
942 cg_free_exp(fs, e);
943 let inst = lua_code::opcodes::Instruction::abck(opcode, 0, r as u32, 0, 0);
944 let pc = emit_inst(fs, line, inst);
945 e.u.info = pc;
946 e.k = ExprKind::Reloc;
947 Ok(())
948}
949
950fn cg_get_jump_control(fs: &FuncState, pc: i32) -> i32 {
957 if pc >= 1 {
958 let prev = cg_inst_at(fs, pc - 1);
959 if let Some(op) = prev.opcode() {
960 if lua_code::opcodes::test_t_mode(op) {
961 return pc - 1;
962 }
963 }
964 }
965 pc
966}
967
968fn cg_patch_test_reg(fs: &mut FuncState, node: i32, reg: u32) -> bool {
976 let ctrl_pc = cg_get_jump_control(fs, node);
977 let mut inst = cg_inst_at(fs, ctrl_pc);
978 if inst.opcode() != Some(lua_code::opcodes::OpCode::TestSet) {
979 return false;
980 }
981 let b = inst.arg_b();
982 let k = inst.arg_k();
983 if reg != lua_code::opcodes::NO_REG && reg != b {
984 inst.set_arg_a(reg);
985 cg_set_inst_at(fs, ctrl_pc, inst);
986 } else {
987 let test = lua_code::opcodes::Instruction::abck(
988 lua_code::opcodes::OpCode::Test,
989 b,
990 0,
991 0,
992 k,
993 );
994 cg_set_inst_at(fs, ctrl_pc, test);
995 }
996 true
997}
998
999fn cg_remove_values(fs: &mut FuncState, list: i32) {
1006 let mut list = list;
1007 while list != NO_JUMP {
1008 let next = cg_get_jump(fs, list);
1009 cg_patch_test_reg(fs, list, lua_code::opcodes::NO_REG);
1010 list = next;
1011 }
1012}
1013
1014fn cg_codenot(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
1022 match e.k {
1023 ExprKind::Nil | ExprKind::False => {
1024 e.k = ExprKind::True;
1025 }
1026 ExprKind::K
1027 | ExprKind::KFlt
1028 | ExprKind::KInt
1029 | ExprKind::KStr
1030 | ExprKind::True => {
1031 e.k = ExprKind::False;
1032 }
1033 ExprKind::Jmp => {
1034 cg_negate_condition(fs, e);
1035 }
1036 ExprKind::Reloc | ExprKind::NonReloc => {
1037 let reg = cg_exp_to_any_reg(fs, line, e)?;
1038 cg_free_exp(fs, e);
1039 let inst = lua_code::opcodes::Instruction::abck(
1040 lua_code::opcodes::OpCode::Not,
1041 0,
1042 reg as u32,
1043 0,
1044 0,
1045 );
1046 let pc = emit_inst(fs, line, inst);
1047 e.u.info = pc;
1048 e.k = ExprKind::Reloc;
1049 }
1050 _ => debug_assert!(false, "cg_codenot: unexpected ExprKind {:?}", e.k),
1051 }
1052 std::mem::swap(&mut e.f, &mut e.t);
1053 cg_remove_values(fs, e.f);
1054 cg_remove_values(fs, e.t);
1055 Ok(())
1056}
1057
1058fn cg_jump(fs: &mut FuncState, line: i32) -> i32 {
1062 let jmp_arg = (NO_JUMP + lua_code::opcodes::OFFSET_S_J) as u32;
1063 let jmp = lua_code::opcodes::Instruction::sj(
1064 lua_code::opcodes::OpCode::Jmp,
1065 jmp_arg,
1066 0,
1067 );
1068 emit_inst(fs, line, jmp)
1069}
1070
1071fn cg_inst_at(fs: &FuncState, pc: i32) -> lua_code::opcodes::Instruction {
1074 lua_code::opcodes::Instruction(fs.f.code[pc as usize].0)
1075}
1076
1077fn cg_set_inst_at(fs: &mut FuncState, pc: i32, inst: lua_code::opcodes::Instruction) {
1080 fs.f.code[pc as usize] = lua_types::opcode::Instruction::new(inst.0);
1081}
1082
1083fn cg_get_jump(fs: &FuncState, pc: i32) -> i32 {
1088 let offset = cg_inst_at(fs, pc).arg_s_j();
1089 if offset == NO_JUMP { NO_JUMP } else { (pc + 1) + offset }
1090}
1091
1092fn cg_fix_jump(fs: &mut FuncState, pc: i32, dest: i32) -> Result<(), LuaError> {
1096 debug_assert!(dest != NO_JUMP);
1097 let offset = dest - (pc + 1);
1098 let max = lua_code::opcodes::MAXARG_S_J as i32 - lua_code::opcodes::OFFSET_S_J;
1099 let min = -lua_code::opcodes::OFFSET_S_J;
1100 if offset < min || offset > max {
1101 return Err(LuaError::syntax(format_args!("control structure too long")));
1102 }
1103 let mut inst = cg_inst_at(fs, pc);
1104 inst.set_arg_s_j(offset);
1105 cg_set_inst_at(fs, pc, inst);
1106 Ok(())
1107}
1108
1109fn cg_get_label(fs: &mut FuncState) -> i32 {
1113 fs.lasttarget = fs.pc;
1114 fs.pc
1115}
1116
1117fn cg_concat(fs: &mut FuncState, l1: &mut i32, l2: i32) -> Result<(), LuaError> {
1121 if l2 == NO_JUMP { return Ok(()); }
1122 if *l1 == NO_JUMP { *l1 = l2; return Ok(()); }
1123 let mut list = *l1;
1124 loop {
1125 let next = cg_get_jump(fs, list);
1126 if next == NO_JUMP { break; }
1127 list = next;
1128 }
1129 cg_fix_jump(fs, list, l2)
1130}
1131
1132fn cg_patch_list(fs: &mut FuncState, list: i32, target: i32) -> Result<(), LuaError> {
1141 cg_patch_list_aux(fs, list, target, lua_code::opcodes::NO_REG, target)
1142}
1143
1144fn cg_patch_to_here(fs: &mut FuncState, list: i32) -> Result<(), LuaError> {
1148 let target = cg_get_label(fs);
1149 cg_patch_list(fs, list, target)
1150}
1151
1152fn cg_negate_condition(fs: &mut FuncState, e: &ExprDesc) {
1158 let pc = e.u.info - 1;
1159 let mut inst = cg_inst_at(fs, pc);
1160 let k = inst.arg_k();
1161 inst.set_arg_k(k ^ 1);
1162 cg_set_inst_at(fs, pc, inst);
1163}
1164
1165fn cg_go_if_true(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
1174 cg_discharge_vars(fs, line, e)?;
1175 let pc: i32 = match e.k {
1176 ExprKind::Jmp => {
1177 cg_negate_condition(fs, e);
1178 e.u.info
1179 }
1180 ExprKind::K | ExprKind::KFlt | ExprKind::KInt | ExprKind::KStr | ExprKind::True => {
1181 NO_JUMP
1182 }
1183 _ => cg_jump_on_cond(fs, line, e, 0)?,
1184 };
1185 cg_concat(fs, &mut e.f, pc)?;
1186 cg_patch_to_here(fs, e.t)?;
1187 e.t = NO_JUMP;
1188 Ok(())
1189}
1190
1191fn cg_go_if_false(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
1198 cg_discharge_vars(fs, line, e)?;
1199 let pc: i32 = match e.k {
1200 ExprKind::Jmp => e.u.info,
1201 ExprKind::Nil | ExprKind::False => NO_JUMP,
1202 _ => cg_jump_on_cond(fs, line, e, 1)?,
1203 };
1204 cg_concat(fs, &mut e.t, pc)?;
1205 cg_patch_to_here(fs, e.f)?;
1206 e.f = NO_JUMP;
1207 Ok(())
1208}
1209
1210fn cg_jump_on_cond(
1220 fs: &mut FuncState,
1221 line: i32,
1222 e: &mut ExprDesc,
1223 cond: u8,
1224) -> Result<i32, LuaError> {
1225 let reg = cg_exp_to_any_reg(fs, line, e)?;
1226 cg_free_exp(fs, e);
1227 let test = lua_code::opcodes::Instruction::abck(
1228 lua_code::opcodes::OpCode::TestSet,
1229 lua_code::opcodes::NO_REG,
1230 reg as u32,
1231 0,
1232 cond as u32,
1233 );
1234 emit_inst(fs, line, test);
1235 Ok(cg_jump(fs, line))
1236}
1237
1238fn cg_infix(
1251 fs: &mut FuncState,
1252 op: BinOpr,
1253 v: &mut ExprDesc,
1254 line: i32,
1255) -> Result<(), LuaError> {
1256 match op {
1257 BinOpr::And => cg_go_if_true(fs, line, v),
1258 BinOpr::Or => cg_go_if_false(fs, line, v),
1259 BinOpr::Concat => cg_exp_to_next_reg(fs, line, v),
1260 BinOpr::Add | BinOpr::Sub | BinOpr::Mul | BinOpr::Div | BinOpr::IDiv
1261 | BinOpr::Mod | BinOpr::Pow
1262 | BinOpr::BAnd | BinOpr::BOr | BinOpr::BXor
1263 | BinOpr::Shl | BinOpr::Shr
1264 | BinOpr::Eq | BinOpr::Ne
1265 | BinOpr::Lt | BinOpr::Le | BinOpr::Gt | BinOpr::Ge => {
1266 if matches!(v.k, ExprKind::KInt | ExprKind::KFlt)
1267 && v.t == NO_JUMP && v.f == NO_JUMP
1268 {
1269 cg_discharge_vars(fs, line, v)
1270 } else {
1271 cg_exp_to_any_reg(fs, line, v).map(|_| ())
1272 }
1273 }
1274 _ => cg_discharge_vars(fs, line, v),
1275 }
1276}
1277
1278fn cg_sc_int(e: &ExprDesc) -> Option<u8> {
1284 if !matches!(e.k, ExprKind::KInt) {
1285 return None;
1286 }
1287 if e.t != NO_JUMP || e.f != NO_JUMP {
1288 return None;
1289 }
1290 let biased = (e.u.ival as u64).wrapping_add(lua_code::opcodes::OFFSET_S_C as u64);
1291 if biased <= lua_code::opcodes::MAXARG_C as u64 {
1292 Some(biased as u8)
1293 } else {
1294 None
1295 }
1296}
1297
1298fn cg_exp_to_any_reg(
1302 fs: &mut FuncState,
1303 line: i32,
1304 e: &mut ExprDesc,
1305) -> Result<u8, LuaError> {
1306 cg_discharge_vars(fs, line, e)?;
1307 if e.k == ExprKind::NonReloc {
1308 if e.t == NO_JUMP && e.f == NO_JUMP {
1309 return Ok(e.u.info as u8);
1310 }
1311 if e.u.info >= fs.nactvar as i32 {
1312 cg_exp_to_reg(fs, line, e, e.u.info as u8)?;
1313 return Ok(e.u.info as u8);
1314 }
1315 }
1316 cg_exp_to_next_reg(fs, line, e)?;
1317 Ok(e.u.info as u8)
1318}
1319
1320fn cg_discharge_vars(
1324 fs: &mut FuncState,
1325 line: i32,
1326 e: &mut ExprDesc,
1327) -> Result<(), LuaError> {
1328 match e.k {
1329 ExprKind::Local => {
1330 e.u.info = e.u.var_ridx as i32;
1331 e.k = ExprKind::NonReloc;
1332 }
1333 ExprKind::UpVal => {
1334 let inst = lua_code::opcodes::Instruction::abck(
1335 lua_code::opcodes::OpCode::GetUpVal,
1336 0,
1337 e.u.info as u32,
1338 0,
1339 0,
1340 );
1341 let pc = emit_inst(fs, line, inst);
1342 e.u.info = pc;
1343 e.k = ExprKind::Reloc;
1344 }
1345 ExprKind::IndexUp => {
1346 let inst = lua_code::opcodes::Instruction::abck(
1347 lua_code::opcodes::OpCode::GetTabUp,
1348 0,
1349 e.u.ind_t as u32,
1350 e.u.ind_idx as u32,
1351 0,
1352 );
1353 let pc = emit_inst(fs, line, inst);
1354 e.u.info = pc;
1355 e.k = ExprKind::Reloc;
1356 }
1357 ExprKind::IndexI => {
1358 cg_free_reg_if_temp(fs, e.u.ind_t as i32);
1359 let inst = lua_code::opcodes::Instruction::abck(
1360 lua_code::opcodes::OpCode::GetI,
1361 0,
1362 e.u.ind_t as u32,
1363 e.u.ind_idx as u32,
1364 0,
1365 );
1366 let pc = emit_inst(fs, line, inst);
1367 e.u.info = pc;
1368 e.k = ExprKind::Reloc;
1369 }
1370 ExprKind::IndexStr => {
1371 cg_free_reg_if_temp(fs, e.u.ind_t as i32);
1372 let inst = lua_code::opcodes::Instruction::abck(
1373 lua_code::opcodes::OpCode::GetField,
1374 0,
1375 e.u.ind_t as u32,
1376 e.u.ind_idx as u32,
1377 0,
1378 );
1379 let pc = emit_inst(fs, line, inst);
1380 e.u.info = pc;
1381 e.k = ExprKind::Reloc;
1382 }
1383 ExprKind::Indexed => {
1384 let t_reg = e.u.ind_t as i32;
1385 let idx_reg = e.u.ind_idx as i32;
1386 if idx_reg > t_reg {
1387 cg_free_reg_if_temp(fs, idx_reg);
1388 cg_free_reg_if_temp(fs, t_reg);
1389 } else {
1390 cg_free_reg_if_temp(fs, t_reg);
1391 cg_free_reg_if_temp(fs, idx_reg);
1392 }
1393 let inst = lua_code::opcodes::Instruction::abck(
1394 lua_code::opcodes::OpCode::GetTable,
1395 0,
1396 e.u.ind_t as u32,
1397 e.u.ind_idx as u32,
1398 0,
1399 );
1400 let pc = emit_inst(fs, line, inst);
1401 e.u.info = pc;
1402 e.k = ExprKind::Reloc;
1403 }
1404 ExprKind::VarArg | ExprKind::Call => {
1405 cg_set_one_ret(fs, e);
1406 }
1407 _ => {}
1408 }
1409 Ok(())
1410}
1411
1412fn cg_set_one_ret(fs: &mut FuncState, e: &mut ExprDesc) {
1418 if e.k == ExprKind::Call {
1419 let pc_idx = e.u.info as usize;
1420 let lc = lua_code::opcodes::Instruction(fs.f.code[pc_idx].0);
1421 debug_assert_eq!(lc.arg_c(), 2);
1422 e.u.info = lc.arg_a() as i32;
1423 e.k = ExprKind::NonReloc;
1424 } else if e.k == ExprKind::VarArg {
1425 let pc_idx = e.u.info as usize;
1426 let mut lc = lua_code::opcodes::Instruction(fs.f.code[pc_idx].0);
1427 lc.set_arg_c(2);
1428 fs.f.code[pc_idx] = lua_types::opcode::Instruction::new(lc.0);
1429 e.k = ExprKind::Reloc;
1430 }
1431}
1432
1433fn cg_storevar(
1436 fs: &mut FuncState,
1437 line: i32,
1438 var: &ExprDesc,
1439 ex: &mut ExprDesc,
1440) -> Result<(), LuaError> {
1441 match var.k {
1442 ExprKind::Local => {
1443 cg_free_exp(fs, ex);
1444 cg_exp_to_reg(fs, line, ex, var.u.var_ridx as u8)?;
1445 return Ok(());
1446 }
1447 ExprKind::UpVal => {
1448 let e_reg = cg_exp_to_any_reg(fs, line, ex)?;
1449 let inst = lua_code::opcodes::Instruction::abck(
1450 lua_code::opcodes::OpCode::SetUpVal,
1451 e_reg as u32,
1452 var.u.info as u32,
1453 0,
1454 0,
1455 );
1456 emit_inst(fs, line, inst);
1457 }
1458 ExprKind::IndexUp => {
1459 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetTabUp,
1460 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1461 }
1462 ExprKind::IndexI => {
1463 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetI,
1464 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1465 }
1466 ExprKind::IndexStr => {
1467 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetField,
1468 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1469 }
1470 ExprKind::Indexed => {
1471 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetTable,
1472 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1473 }
1474 _ => {
1475 return Err(LuaError::syntax(format_args!(
1476 "internal: cg_storevar: invalid var kind {:?}", var.k
1477 )));
1478 }
1479 }
1480 cg_free_exp(fs, ex);
1481 Ok(())
1482}
1483
1484fn cg_store_abrk(
1488 fs: &mut FuncState,
1489 line: i32,
1490 op: lua_code::opcodes::OpCode,
1491 a: u32,
1492 b: u32,
1493 ex: &mut ExprDesc,
1494) -> Result<(), LuaError> {
1495 let c_reg = cg_exp_to_any_reg(fs, line, ex)?;
1496 let inst = lua_code::opcodes::Instruction::abck(op, a, b, c_reg as u32, 0);
1497 emit_inst(fs, line, inst);
1498 Ok(())
1499}
1500
1501fn cg_discharge_to_reg(
1506 fs: &mut FuncState,
1507 line: i32,
1508 e: &mut ExprDesc,
1509 reg: u8,
1510) -> Result<(), LuaError> {
1511 cg_discharge_vars(fs, line, e)?;
1512 match e.k {
1513 ExprKind::Jmp => {
1514 return Ok(());
1515 }
1516 ExprKind::NonReloc => {
1517 if e.u.info as u8 != reg {
1518 let inst = lua_code::opcodes::Instruction::abck(
1519 lua_code::opcodes::OpCode::Move,
1520 reg as u32,
1521 e.u.info as u32,
1522 0, 0,
1523 );
1524 emit_inst(fs, line, inst);
1525 }
1526 }
1527 ExprKind::Reloc => {
1528 let pc = e.u.info as usize;
1529 let mut lc = lua_code::opcodes::Instruction(fs.f.code[pc].0);
1530 lc.set_arg_a(reg as u32);
1531 fs.f.code[pc] = lua_types::opcode::Instruction::new(lc.0);
1532 }
1533 ExprKind::Nil => {
1534 let inst = lua_code::opcodes::Instruction::abck(
1535 lua_code::opcodes::OpCode::LoadNil, reg as u32, 0, 0, 0,
1536 );
1537 emit_inst(fs, line, inst);
1538 }
1539 ExprKind::True => {
1540 let inst = lua_code::opcodes::Instruction::abck(
1541 lua_code::opcodes::OpCode::LoadTrue, reg as u32, 0, 0, 0,
1542 );
1543 emit_inst(fs, line, inst);
1544 }
1545 ExprKind::False => {
1546 let inst = lua_code::opcodes::Instruction::abck(
1547 lua_code::opcodes::OpCode::LoadFalse, reg as u32, 0, 0, 0,
1548 );
1549 emit_inst(fs, line, inst);
1550 }
1551 ExprKind::KInt => {
1552 let i = e.u.ival;
1553 let max = lua_code::opcodes::MAXARG_BX as i64 - lua_code::opcodes::OFFSET_S_BX as i64;
1554 let min = -(lua_code::opcodes::OFFSET_S_BX as i64);
1555 if i >= min && i <= max {
1556 let bx = (i as i32 + lua_code::opcodes::OFFSET_S_BX) as u32;
1557 let inst = lua_code::opcodes::Instruction::abx(
1558 lua_code::opcodes::OpCode::LoadI, reg as u32, bx,
1559 );
1560 emit_inst(fs, line, inst);
1561 } else {
1562 let k_idx = add_k_value(fs, LuaValue::Int(i));
1563 let inst = lua_code::opcodes::Instruction::abx(
1564 lua_code::opcodes::OpCode::LoadK, reg as u32, k_idx as u32,
1565 );
1566 emit_inst(fs, line, inst);
1567 }
1568 }
1569 ExprKind::KFlt => {
1570 let f = e.u.nval;
1571 let max = lua_code::opcodes::MAXARG_BX as i64 - lua_code::opcodes::OFFSET_S_BX as i64;
1572 let min = -(lua_code::opcodes::OFFSET_S_BX as i64);
1573 let fi_opt: Option<i64> = if f.fract() == 0.0 && f.abs() < i64::MAX as f64 {
1574 Some(f as i64)
1575 } else {
1576 None
1577 };
1578 if let Some(fi) = fi_opt.filter(|fi| *fi >= min && *fi <= max) {
1579 let bx = (fi as i32 + lua_code::opcodes::OFFSET_S_BX) as u32;
1580 let inst = lua_code::opcodes::Instruction::abx(
1581 lua_code::opcodes::OpCode::LoadF, reg as u32, bx,
1582 );
1583 emit_inst(fs, line, inst);
1584 } else {
1585 let k_idx = add_k_value(fs, LuaValue::Float(f));
1586 let inst = lua_code::opcodes::Instruction::abx(
1587 lua_code::opcodes::OpCode::LoadK, reg as u32, k_idx as u32,
1588 );
1589 emit_inst(fs, line, inst);
1590 }
1591 }
1592 ExprKind::KStr => {
1593 let s = e.u.strval.clone()
1594 .ok_or_else(|| LuaError::syntax(format_args!("internal: VKStr with no strval")))?;
1595 let k_idx = add_k_string(fs, s);
1596 let inst = lua_code::opcodes::Instruction::abx(
1597 lua_code::opcodes::OpCode::LoadK,
1598 reg as u32,
1599 k_idx as u32,
1600 );
1601 emit_inst(fs, line, inst);
1602 }
1603 ExprKind::K => {
1604 let inst = lua_code::opcodes::Instruction::abx(
1605 lua_code::opcodes::OpCode::LoadK,
1606 reg as u32,
1607 e.u.info as u32,
1608 );
1609 emit_inst(fs, line, inst);
1610 }
1611 _ => {
1612 return Err(LuaError::syntax(format_args!(
1613 "internal: cg_discharge_to_reg cannot discharge {:?}", e.k
1614 )));
1615 }
1616 }
1617 e.u.info = reg as i32;
1618 e.k = ExprKind::NonReloc;
1619 Ok(())
1620}
1621
1622fn cg_need_value(fs: &FuncState, list: i32) -> bool {
1627 let mut list = list;
1628 while list != NO_JUMP {
1629 let ctrl_pc = cg_get_jump_control(fs, list);
1630 let ctrl = cg_inst_at(fs, ctrl_pc);
1631 if ctrl.opcode() != Some(lua_code::opcodes::OpCode::TestSet) {
1632 return true;
1633 }
1634 list = cg_get_jump(fs, list);
1635 }
1636 false
1637}
1638
1639fn cg_code_loadbool(fs: &mut FuncState, line: i32, reg: i32, op: lua_code::opcodes::OpCode) -> i32 {
1643 cg_get_label(fs);
1644 let inst = lua_code::opcodes::Instruction::abck(op, reg as u32, 0, 0, 0);
1645 emit_inst(fs, line, inst)
1646}
1647
1648fn cg_patch_list_aux(
1652 fs: &mut FuncState,
1653 list: i32,
1654 vtarget: i32,
1655 reg: u32,
1656 dtarget: i32,
1657) -> Result<(), LuaError> {
1658 let mut list = list;
1659 while list != NO_JUMP {
1660 let next = cg_get_jump(fs, list);
1661 if cg_patch_test_reg(fs, list, reg) {
1662 cg_fix_jump(fs, list, vtarget)?;
1663 } else {
1664 cg_fix_jump(fs, list, dtarget)?;
1665 }
1666 list = next;
1667 }
1668 Ok(())
1669}
1670
1671fn cg_exp_to_reg(
1678 fs: &mut FuncState,
1679 line: i32,
1680 e: &mut ExprDesc,
1681 reg: u8,
1682) -> Result<(), LuaError> {
1683 cg_discharge_to_reg(fs, line, e, reg)?;
1684 if e.k == ExprKind::Jmp {
1685 let info = e.u.info;
1686 cg_concat(fs, &mut e.t, info)?;
1687 }
1688 if e.t != e.f {
1689 let mut p_f = NO_JUMP;
1690 let mut p_t = NO_JUMP;
1691 if cg_need_value(fs, e.t) || cg_need_value(fs, e.f) {
1692 let fj = if e.k == ExprKind::Jmp {
1693 NO_JUMP
1694 } else {
1695 cg_jump(fs, line)
1696 };
1697 p_f = cg_code_loadbool(fs, line, reg as i32, lua_code::opcodes::OpCode::LFalseSkip);
1698 p_t = cg_code_loadbool(fs, line, reg as i32, lua_code::opcodes::OpCode::LoadTrue);
1699 cg_patch_to_here(fs, fj)?;
1700 }
1701 let final_pc = cg_get_label(fs);
1702 cg_patch_list_aux(fs, e.f, final_pc, reg as u32, p_f)?;
1703 cg_patch_list_aux(fs, e.t, final_pc, reg as u32, p_t)?;
1704 }
1705 e.f = NO_JUMP;
1706 e.t = NO_JUMP;
1707 e.u.info = reg as i32;
1708 e.k = ExprKind::NonReloc;
1709 Ok(())
1710}
1711
1712fn cg_free_reg_if_temp(fs: &mut FuncState, reg: i32) {
1716 if reg >= fs.nactvar as i32 {
1717 debug_assert!(reg < fs.freereg as i32);
1718 if reg == fs.freereg as i32 - 1 {
1719 fs.freereg -= 1;
1720 }
1721 }
1722}
1723
1724fn cg_exp_to_next_reg(
1729 fs: &mut FuncState,
1730 line: i32,
1731 e: &mut ExprDesc,
1732) -> Result<(), LuaError> {
1733 cg_discharge_vars(fs, line, e)?;
1734 cg_free_exp(fs, e);
1735 let reg = reserve_reg(fs)?;
1736 cg_exp_to_reg(fs, line, e, reg)
1737}
1738
1739fn cg_set_returns(fs: &mut FuncState, e: &mut ExprDesc, nresults: i32) {
1741 let pc_idx = e.u.info as usize;
1742 let mut lc = lua_code::opcodes::Instruction(fs.f.code[pc_idx].0);
1743 if e.k == ExprKind::Call {
1744 lc.set_arg_c((nresults + 1) as u32);
1745 } else {
1746 debug_assert_eq!(e.k, ExprKind::VarArg);
1747 lc.set_arg_c((nresults + 1) as u32);
1748 lc.set_arg_a(fs.freereg as u32);
1749 fs.freereg += 1;
1750 }
1751 fs.f.code[pc_idx] = lua_types::opcode::Instruction::new(lc.0);
1752}
1753
1754fn cg_final_target(fs: &FuncState, mut i: i32) -> i32 {
1757 for _ in 0..100 {
1758 let inst = cg_inst_at(fs, i);
1759 if inst.opcode() != Some(lua_code::opcodes::OpCode::Jmp) {
1760 break;
1761 }
1762 i += inst.arg_s_j() + 1;
1763 }
1764 i
1765}
1766
1767fn cg_finish(fs: &mut FuncState) {
1773 use lua_code::opcodes::OpCode;
1774 let needclose = fs.needclose;
1775 let is_vararg = fs.f.is_vararg;
1776 let numparams = fs.f.numparams as u32;
1777 let pc_end = fs.pc;
1778 for i in 0..pc_end {
1779 let mut inst = cg_inst_at(fs, i);
1780 match inst.opcode() {
1781 Some(OpCode::Return0) | Some(OpCode::Return1) => {
1782 if !(needclose || is_vararg) {
1783 continue;
1784 }
1785 inst.set_opcode(OpCode::Return);
1786 if needclose {
1787 inst.set_arg_k(1);
1788 }
1789 if is_vararg {
1790 inst.set_arg_c(numparams + 1);
1791 }
1792 cg_set_inst_at(fs, i, inst);
1793 }
1794 Some(OpCode::Return) | Some(OpCode::TailCall) => {
1795 if needclose {
1796 inst.set_arg_k(1);
1797 }
1798 if is_vararg {
1799 inst.set_arg_c(numparams + 1);
1800 }
1801 cg_set_inst_at(fs, i, inst);
1802 }
1803 Some(OpCode::Jmp) => {
1804 let target = cg_final_target(fs, i);
1805 let _ = cg_fix_jump(fs, i, target);
1806 }
1807 _ => {}
1808 }
1809 }
1810}
1811
1812fn cg_emit_return(fs: &mut FuncState, line: i32, first: i32, nret: i32) {
1815 let op = match nret {
1816 0 => lua_code::opcodes::OpCode::Return0,
1817 1 => lua_code::opcodes::OpCode::Return1,
1818 _ => lua_code::opcodes::OpCode::Return,
1819 };
1820 let inst = lua_code::opcodes::Instruction::abck(
1821 op,
1822 first as u32,
1823 (nret + 1) as u32,
1824 0,
1825 0,
1826 );
1827 emit_inst(fs, line, inst);
1828}
1829
1830fn error_expected(ls: &mut LexState, token: TokenKind) -> LuaError {
1840 let tok_str = lua_lex::token2str(&ls.lex, token);
1841 let mut msg: Vec<u8> = Vec::with_capacity(tok_str.len() + 10);
1842 msg.extend_from_slice(&tok_str);
1843 msg.extend_from_slice(b" expected");
1844 lua_lex::syntax_error(&mut ls.lex, &msg)
1845}
1846
1847fn error_limit(fs: &FuncState, limit: i32, what: &str) -> LuaError {
1849 let line = fs.f.linedefined;
1850 if line == 0 {
1851 LuaError::syntax(format_args!(
1852 "too many {} (limit is {}) in main function", what, limit
1853 ))
1854 } else {
1855 LuaError::syntax(format_args!(
1856 "too many {} (limit is {}) in function at line {}", what, limit, line
1857 ))
1858 }
1859}
1860
1861fn check_limit(fs: &FuncState, v: i32, l: i32, what: &str) -> Result<(), LuaError> {
1862 if v > l {
1863 return Err(error_limit(fs, l, what));
1864 }
1865 Ok(())
1866}
1867
1868fn test_next(ls: &mut LexState, state: &mut LuaState, c: TokenKind) -> Result<bool, LuaError> {
1872 if ls.t.token == c {
1873 lex_next(ls, state)?;
1874 Ok(true)
1875 } else {
1876 Ok(false)
1877 }
1878}
1879
1880fn check(ls: &mut LexState, c: TokenKind) -> Result<(), LuaError> {
1881 if ls.t.token != c {
1882 return Err(error_expected(ls, c));
1883 }
1884 Ok(())
1885}
1886
1887fn check_next(ls: &mut LexState, state: &mut LuaState, c: TokenKind) -> Result<(), LuaError> {
1888 check(ls, c)?;
1889 lex_next(ls, state)?;
1890 Ok(())
1891}
1892
1893fn str_check_name(ls: &mut LexState, state: &mut LuaState) -> Result<GcRef<LuaString>, LuaError> {
1895 check(ls, TK_NAME)?;
1896 let ts = ls.t.seminfo.ts.clone()
1897 .ok_or_else(|| LuaError::syntax(format_args!("name expected")))?;
1898 lex_next(ls, state)?;
1899 Ok(ts)
1900}
1901
1902fn init_exp(e: &mut ExprDesc, k: ExprKind, i: i32) {
1903 e.f = NO_JUMP;
1904 e.t = NO_JUMP;
1905 e.k = k;
1906 e.u.info = i;
1907}
1908
1909fn codestring(e: &mut ExprDesc, s: GcRef<LuaString>) {
1910 e.f = NO_JUMP;
1911 e.t = NO_JUMP;
1912 e.k = ExprKind::KStr;
1913 e.u.strval = Some(s);
1914}
1915
1916fn codename(ls: &mut LexState, state: &mut LuaState, e: &mut ExprDesc) -> Result<(), LuaError> {
1917 let name = str_check_name(ls, state)?;
1918 codestring(e, name);
1919 Ok(())
1920}
1921
1922fn register_local_var(
1927 ls: &mut LexState,
1928 state: &mut LuaState,
1929 fs: &mut FuncState,
1930 varname: GcRef<LuaString>,
1931) -> Result<i32, LuaError> {
1932 let idx = fs.ndebugvars as usize;
1934 while fs.f.locvars.len() <= idx {
1935 fs.f.locvars.push(LocalVar {
1936 varname: varname.clone(), startpc: 0,
1938 endpc: 0,
1939 });
1940 }
1941 fs.f.locvars[idx].varname = varname;
1942 fs.f.locvars[idx].startpc = fs.pc;
1943 let result = fs.ndebugvars as i32;
1944 fs.ndebugvars += 1;
1945 Ok(result)
1946}
1947
1948fn new_local_var(
1951 ls: &mut LexState,
1952 state: &mut LuaState,
1953 name: GcRef<LuaString>,
1954) -> Result<i32, LuaError> {
1955 let fs = ls.fs.as_ref().unwrap();
1956 let n = ls.dyd.actvar.len() as i32;
1957 let first_local = fs.firstlocal;
1958 check_limit(fs, n + 1 - first_local, MAX_VARS, "local variables")?;
1959
1960 let mut var = VarDesc::default();
1961 var.kind = VarKind::Reg;
1962 var.name = Some(name);
1963 ls.dyd.actvar.push(var);
1964 let result = ls.dyd.actvar.len() as i32 - 1 - first_local;
1965 Ok(result)
1966}
1967
1968fn get_local_var_desc<'a>(ls: &'a LexState, fs: &FuncState, vidx: i32) -> &'a VarDesc {
1970 &ls.dyd.actvar[(fs.firstlocal + vidx) as usize]
1971}
1972
1973fn get_local_var_desc_mut(ls: &mut LexState, first_local: i32, vidx: i32) -> &mut VarDesc {
1974 &mut ls.dyd.actvar[(first_local + vidx) as usize]
1975}
1976
1977fn reg_level(ls: &LexState, fs: &FuncState, nvar: i32) -> i32 {
1979 let mut nvar = nvar;
1980 while nvar > 0 {
1981 nvar -= 1;
1982 let vd = get_local_var_desc(ls, fs, nvar);
1983 if vd.kind != VarKind::CompileTimeConst {
1984 return vd.ridx as i32 + 1;
1985 }
1986 }
1987 0
1988}
1989
1990pub fn nvarstack(ls: &LexState, fs: &FuncState) -> i32 {
1993 reg_level(ls, fs, fs.nactvar as i32)
1994}
1995
1996fn local_debug_info<'a>(ls: &LexState, fs: &'a mut FuncState, vidx: i32) -> Option<&'a mut LocalVar> {
1999 let vd = get_local_var_desc(ls, fs, vidx);
2000 if vd.kind == VarKind::CompileTimeConst {
2001 return None;
2002 }
2003 let idx = vd.pidx as usize;
2004 debug_assert!((idx as i16) < fs.ndebugvars);
2005 Some(&mut fs.f.locvars[idx])
2007}
2008
2009fn init_var(ls: &LexState, fs: &FuncState, e: &mut ExprDesc, vidx: i32) {
2010 e.f = NO_JUMP;
2011 e.t = NO_JUMP;
2012 e.k = ExprKind::Local;
2013 e.u.var_vidx = vidx as u16;
2014 e.u.var_ridx = get_local_var_desc(ls, fs, vidx).ridx;
2015}
2016
2017fn check_readonly(ls: &mut LexState, state: &mut LuaState, e: &ExprDesc) -> Result<(), LuaError> {
2019 let varname: Option<GcRef<LuaString>> = {
2020 let fs = ls.fs.as_ref().unwrap();
2021 match e.k {
2022 ExprKind::Const => {
2023 ls.dyd.actvar[e.u.info as usize].name.clone()
2024 }
2025 ExprKind::Local => {
2026 let vd = get_local_var_desc(ls, fs, e.u.var_vidx as i32);
2027 if vd.kind != VarKind::Reg {
2028 vd.name.clone()
2029 } else {
2030 None
2031 }
2032 }
2033 ExprKind::UpVal => {
2034 let up = &fs.f.upvalues[e.u.info as usize];
2035 if VarKind::from_u8(up.kind) != VarKind::Reg {
2036 up.name.clone()
2037 } else {
2038 None
2039 }
2040 }
2041 _ => None,
2042 }
2043 };
2044 if let Some(vname) = varname {
2045 let _ = state;
2048 let msg = format!(
2049 "attempt to assign to const variable '{}'",
2050 String::from_utf8_lossy(vname.as_bytes())
2051 );
2052 return Err(lua_lex::syntax_error(&mut ls.lex, msg.as_bytes()));
2053 }
2054 Ok(())
2055}
2056
2057fn adjust_local_vars(ls: &mut LexState, state: &mut LuaState, nvars: i32) -> Result<(), LuaError> {
2059 let first_local = ls.fs.as_ref().unwrap().firstlocal;
2061 let nactvar_start = ls.fs.as_ref().unwrap().nactvar as i32;
2062 let mut reglevel_val = {
2063 let fs = ls.fs.as_ref().unwrap();
2064 reg_level(ls, fs, fs.nactvar as i32)
2065 };
2066
2067 for i in 0..nvars {
2068 let vidx = nactvar_start + i;
2069 ls.fs.as_mut().unwrap().nactvar += 1;
2070 let var_name = ls.dyd.actvar[(first_local + vidx) as usize].name.clone();
2071 ls.dyd.actvar[(first_local + vidx) as usize].ridx = reglevel_val as u8;
2072 reglevel_val += 1;
2073 if let Some(vn) = var_name {
2074 let mut fs_box = ls.fs.take().unwrap();
2075 let pidx_result = register_local_var(ls, state, &mut fs_box, vn);
2076 ls.fs = Some(fs_box);
2077 let pidx = pidx_result?;
2078 ls.dyd.actvar[(first_local + vidx) as usize].pidx = pidx as i16;
2079 } else {
2080 }
2082 }
2083 Ok(())
2084}
2085
2086fn remove_vars(ls: &mut LexState, fs: &mut FuncState, tolevel: i32) {
2088 let delta = fs.nactvar as i32 - tolevel;
2096 while fs.nactvar as i32 > tolevel {
2097 fs.nactvar -= 1;
2098 let nactvar = fs.nactvar as i32;
2099 let vd_kind = {
2100 let first_local = fs.firstlocal;
2101 ls.dyd.actvar.get((first_local + nactvar) as usize)
2102 .map(|v| v.kind)
2103 .unwrap_or(VarKind::Reg)
2104 };
2105 if vd_kind != VarKind::CompileTimeConst {
2106 let vd_pidx = {
2107 let first_local = fs.firstlocal;
2108 ls.dyd.actvar.get((first_local + nactvar) as usize)
2109 .map(|v| v.pidx)
2110 .unwrap_or(0)
2111 };
2112 if let Some(lv) = fs.f.locvars.get_mut(vd_pidx as usize) {
2113 lv.endpc = fs.pc;
2114 }
2115 }
2116 }
2117 if delta > 0 {
2118 let new_len = ls.dyd.actvar.len().saturating_sub(delta as usize);
2119 ls.dyd.actvar.truncate(new_len);
2120 }
2121}
2122
2123fn search_upvalue(fs: &FuncState, name: &GcRef<LuaString>) -> i32 {
2127 for (i, up) in fs.f.upvalues.iter().enumerate() {
2128 if up.name.as_ref().map_or(false, |n| GcRef::ptr_eq(n, name)) {
2129 return i as i32;
2130 }
2131 }
2132 -1
2133}
2134
2135fn alloc_upvalue(fs: &mut FuncState) -> Result<usize, LuaError> {
2137 if fs.nups as i32 + 1 > MAX_UPVAL as i32 {
2138 return Err(error_limit(fs, MAX_UPVAL as i32, "upvalues"));
2139 }
2140 let idx = fs.nups as usize;
2141 while fs.f.upvalues.len() <= idx {
2142 fs.f.upvalues.push(UpvalDesc { name: None, instack: false, idx: 0, kind: 0 });
2143 }
2144 fs.nups += 1;
2145 Ok(idx)
2146}
2147
2148fn new_upvalue(
2150 ls: &LexState,
2151 fs: &mut FuncState,
2152 name: GcRef<LuaString>,
2153 v: &ExprDesc,
2154) -> Result<i32, LuaError> {
2155 let idx = alloc_upvalue(fs)?;
2156 let kind: u8 = if v.k == ExprKind::Local {
2157 let prev = fs.prev.as_deref().expect("upvalue capture requires enclosing FuncState");
2158 get_local_var_desc(ls, prev, v.u.var_vidx as i32).kind.as_u8()
2159 } else {
2160 let prev = fs.prev.as_deref().expect("upvalue chain requires enclosing FuncState");
2161 prev.f.upvalues[v.u.info as usize].kind
2162 };
2163 let up = &mut fs.f.upvalues[idx];
2164 if v.k == ExprKind::Local {
2165 up.instack = true;
2166 up.idx = v.u.var_ridx;
2167 } else {
2168 up.instack = false;
2169 up.idx = v.u.info as u8;
2170 }
2171 up.kind = kind;
2172 up.name = Some(name);
2173 Ok(fs.nups as i32 - 1)
2174}
2175
2176fn searchvar(
2178 ls: &LexState,
2179 fs: &FuncState,
2180 n: &GcRef<LuaString>,
2181 var: &mut ExprDesc,
2182) -> i32 {
2183 let mut i = fs.nactvar as i32 - 1;
2184 while i >= 0 {
2185 let vd = get_local_var_desc(ls, fs, i);
2186 if vd.name.as_ref().map_or(false, |nm| GcRef::ptr_eq(nm, n)) {
2187 if vd.kind == VarKind::CompileTimeConst {
2188 init_exp(var, ExprKind::Const, fs.firstlocal + i);
2189 } else {
2190 init_var(ls, fs, var, i);
2191 }
2192 return var.k as i32; }
2194 i -= 1;
2195 }
2196 -1
2197}
2198
2199fn markupval(fs: &mut FuncState, level: i32) {
2201 let mut current = fs.bl.as_deref_mut();
2202 while let Some(b) = current {
2203 if (b.nactvar as i32) <= level {
2204 b.upval = true;
2205 break;
2206 }
2207 current = b.previous.as_deref_mut();
2208 }
2209 fs.needclose = true;
2210}
2211
2212fn marktobeclosed(fs: &mut FuncState) {
2213 if let Some(bl) = fs.bl.as_mut() {
2214 bl.upval = true;
2215 bl.insidetbc = true;
2216 }
2217 fs.needclose = true;
2218}
2219
2220fn singlevaraux(
2225 ls: &LexState,
2226 fs: Option<&mut FuncState>,
2227 n: &GcRef<LuaString>,
2228 var: &mut ExprDesc,
2229 base: bool,
2230) -> Result<(), LuaError> {
2231 match fs {
2232 None => {
2233 init_exp(var, ExprKind::Void, 0);
2234 }
2235 Some(fs) => {
2236 let v = searchvar(ls, fs, n, var);
2237 if v >= 0 {
2238 if v == ExprKind::Local as i32 && !base {
2239 markupval(fs, var.u.var_vidx as i32);
2240 }
2241 } else {
2242 let idx = search_upvalue(fs, n);
2243 let final_idx = if idx < 0 {
2244 singlevaraux(ls, fs.prev.as_deref_mut(), n, var, false)?;
2245 if var.k == ExprKind::Local || var.k == ExprKind::UpVal {
2246 new_upvalue(ls, fs, n.clone(), var)?
2247 } else {
2248 return Ok(());
2249 }
2250 } else {
2251 idx
2252 };
2253 init_exp(var, ExprKind::UpVal, final_idx);
2254 }
2255 }
2256 }
2257 Ok(())
2258}
2259
2260fn singlevar(ls: &mut LexState, state: &mut LuaState, var: &mut ExprDesc) -> Result<(), LuaError> {
2262 let varname = str_check_name(ls, state)?;
2263 let mut fs_box = ls.fs.take();
2264 let recurse_result = singlevaraux(ls, fs_box.as_deref_mut(), &varname, var, true);
2265 ls.fs = fs_box;
2266 recurse_result?;
2267 if var.k == ExprKind::Void {
2268 let envn = ls.envn.clone().expect("envn must be set when resolving globals");
2269 let mut env_var = ExprDesc::default();
2270 let mut fs_box = ls.fs.take();
2271 let r = singlevaraux(ls, fs_box.as_deref_mut(), &envn, &mut env_var, true);
2272 ls.fs = fs_box;
2273 r?;
2274 debug_assert!(env_var.k != ExprKind::Void, "_ENV must resolve");
2275 let line = ls.lastline;
2276 let fs = ls.fs.as_mut().unwrap();
2277 cg_exp_to_any_reg_up(fs, line, &mut env_var)?;
2278 let mut key = ExprDesc::default();
2279 codestring(&mut key, varname);
2280 cg_indexed(fs, line, &mut env_var, &mut key)?;
2281 *var = env_var;
2282 }
2283 Ok(())
2284}
2285
2286fn adjust_assign(
2287 ls: &mut LexState,
2288 state: &mut LuaState,
2289 nvars: i32,
2290 nexps: i32,
2291 e: &mut ExprDesc,
2292) -> Result<(), LuaError> {
2293 let needed = nvars - nexps;
2294 let line = ls.lastline;
2295 let fs = ls.fs.as_mut().unwrap();
2296 if e.k.has_mult_ret() {
2297 let extra = if needed + 1 < 0 { 0 } else { needed + 1 };
2298 cg_set_returns(fs, e, extra);
2299 } else {
2300 if e.k != ExprKind::Void {
2301 cg_exp_to_next_reg(fs, line, e)?;
2302 }
2303 if needed > 0 {
2304 let from = fs.freereg as i32;
2305 cg_emit_nil(fs, line, from, needed);
2306 }
2307 }
2308 if needed > 0 {
2309 for _ in 0..needed {
2310 reserve_reg(fs)?;
2311 }
2312 } else {
2313 fs.freereg = (fs.freereg as i32 + needed) as u8;
2314 }
2315 Ok(())
2316}
2317
2318fn cg_emit_newtable(fs: &mut FuncState, line: i32) -> i32 {
2322 let newtable = lua_code::opcodes::Instruction::abck(
2323 lua_code::opcodes::OpCode::NewTable, 0, 0, 0, 0,
2324 );
2325 let pc = emit_inst(fs, line, newtable);
2326 let extra = lua_code::opcodes::Instruction::ax(
2327 lua_code::opcodes::OpCode::ExtraArg, 0,
2328 );
2329 emit_inst(fs, line, extra);
2330 pc
2331}
2332
2333fn cg_settablesize(fs: &mut FuncState, pc: i32, ra: i32, asize: i32, hsize: i32) {
2337 let rb = if hsize != 0 {
2338 (hsize as u32).next_power_of_two().trailing_zeros() as i32 + 1
2339 } else {
2340 0
2341 };
2342 let maxc = lua_code::opcodes::MAXARG_C as i32 + 1;
2343 let extra = asize / maxc;
2344 let rc = asize % maxc;
2345 let k = if extra > 0 { 1u32 } else { 0u32 };
2346 let newtable = lua_code::opcodes::Instruction::abck(
2347 lua_code::opcodes::OpCode::NewTable,
2348 ra as u32, rb as u32, rc as u32, k,
2349 );
2350 fs.f.code[pc as usize] = lua_types::opcode::Instruction::new(newtable.0);
2351 let extra_inst = lua_code::opcodes::Instruction::ax(
2352 lua_code::opcodes::OpCode::ExtraArg, extra as u32,
2353 );
2354 fs.f.code[pc as usize + 1] = lua_types::opcode::Instruction::new(extra_inst.0);
2355}
2356
2357fn cg_setlist(fs: &mut FuncState, line: i32, base: i32, nelems: i32, tostore: i32) {
2362 let maxc = lua_code::opcodes::MAXARG_C as i32;
2363 let tostore_arg = if tostore == LUA_MULTRET { 0 } else { tostore };
2364 if nelems <= maxc {
2365 let inst = lua_code::opcodes::Instruction::abck(
2366 lua_code::opcodes::OpCode::SetList,
2367 base as u32, tostore_arg as u32, nelems as u32, 0,
2368 );
2369 emit_inst(fs, line, inst);
2370 } else {
2371 let extra = nelems / (maxc + 1);
2372 let nelems_lo = nelems % (maxc + 1);
2373 let inst = lua_code::opcodes::Instruction::abck(
2374 lua_code::opcodes::OpCode::SetList,
2375 base as u32, tostore_arg as u32, nelems_lo as u32, 1,
2376 );
2377 emit_inst(fs, line, inst);
2378 let extra_inst = lua_code::opcodes::Instruction::ax(
2379 lua_code::opcodes::OpCode::ExtraArg, extra as u32,
2380 );
2381 emit_inst(fs, line, extra_inst);
2382 }
2383 fs.freereg = (base + 1) as u8;
2384}
2385
2386fn cg_indexed(fs: &mut FuncState, line: i32, t: &mut ExprDesc, k: &mut ExprDesc) -> Result<(), LuaError> {
2391 if k.k == ExprKind::KStr {
2392 let s = k.u.strval.clone()
2393 .ok_or_else(|| LuaError::syntax(format_args!("internal: VKStr with no strval")))?;
2394 let k_idx = add_k_string(fs, s);
2395 k.u.info = k_idx;
2396 k.k = ExprKind::K;
2397 }
2398 let k_is_kstr = k.k == ExprKind::K
2399 && k.u.info >= 0
2400 && (k.u.info as u32) <= lua_code::opcodes::MAXARG_B;
2401 if t.k == ExprKind::UpVal && !k_is_kstr {
2402 cg_exp_to_any_reg(fs, line, t)?;
2403 }
2404 if t.k == ExprKind::UpVal {
2405 let temp = t.u.info as u8;
2406 t.u.ind_t = temp;
2407 t.u.ind_idx = k.u.info as i16;
2408 t.k = ExprKind::IndexUp;
2409 return Ok(());
2410 }
2411 let t_reg = match t.k {
2412 ExprKind::Local => t.u.var_ridx,
2413 ExprKind::NonReloc => t.u.info as u8,
2414 _ => return Err(LuaError::syntax(format_args!(
2415 "internal: cg_indexed on non-register table kind {:?}", t.k
2416 ))),
2417 };
2418 t.u.ind_t = t_reg;
2419 if k.k == ExprKind::K && k_is_kstr {
2420 t.u.ind_idx = k.u.info as i16;
2421 t.k = ExprKind::IndexStr;
2422 } else if k.k == ExprKind::KInt && cg_fits_int_key(k.u.ival) {
2423 t.u.ind_idx = k.u.ival as i16;
2424 t.k = ExprKind::IndexI;
2425 } else {
2426 cg_exp_to_any_reg(fs, line, k)?;
2427 t.u.ind_idx = k.u.info as i16;
2428 t.k = ExprKind::Indexed;
2429 }
2430 Ok(())
2431}
2432
2433fn cg_fits_int_key(i: i64) -> bool {
2434 i >= 0 && (i as u32) <= lua_code::opcodes::MAXARG_C
2435}
2436
2437fn cg_self(
2441 fs: &mut FuncState,
2442 line: i32,
2443 e: &mut ExprDesc,
2444 key: &mut ExprDesc,
2445) -> Result<(), LuaError> {
2446 cg_exp_to_any_reg(fs, line, e)?;
2447 let ereg = e.u.info;
2448 cg_free_exp(fs, e);
2449 let base = fs.freereg as i32;
2450 e.u.info = base;
2451 e.k = ExprKind::NonReloc;
2452 reserve_regs(fs, 2)?;
2453 let key_str = key.u.strval.clone()
2454 .ok_or_else(|| LuaError::syntax(format_args!(
2455 "internal: cg_self expected VKStr key, got {:?}", key.k
2456 )))?;
2457 let k_idx = add_k_string(fs, key_str);
2458 let (c_arg, k_flag) = if (k_idx as u32) <= lua_code::opcodes::MAXINDEXRK {
2459 (k_idx as u32, 1u32)
2460 } else {
2461 key.k = ExprKind::K;
2462 key.u.info = k_idx;
2463 cg_exp_to_any_reg(fs, line, key)?;
2464 (key.u.info as u32, 0u32)
2465 };
2466 let inst = lua_code::opcodes::Instruction::abck(
2467 lua_code::opcodes::OpCode::Self_,
2468 base as u32,
2469 ereg as u32,
2470 c_arg,
2471 k_flag,
2472 );
2473 emit_inst(fs, line, inst);
2474 cg_free_exp(fs, key);
2475 Ok(())
2476}
2477
2478fn cg_exp_to_any_reg_up(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
2481 if matches!(e.k, ExprKind::UpVal | ExprKind::K) {
2482 return Ok(());
2483 }
2484 cg_exp_to_any_reg(fs, line, e)?;
2485 Ok(())
2486}
2487
2488fn cg_emit_nil(fs: &mut FuncState, line: i32, from: i32, n: i32) {
2492 let inst = lua_code::opcodes::Instruction::abck(
2493 lua_code::opcodes::OpCode::LoadNil,
2494 from as u32,
2495 (n - 1) as u32,
2496 0,
2497 0,
2498 );
2499 emit_inst(fs, line, inst);
2500}
2501
2502fn jumpscopeerror(ls: &LexState, gt_idx: usize) -> LuaError {
2505 let gt = &ls.dyd.gt[gt_idx];
2506 let line = gt.line;
2507 let gt_name_bytes: &[u8] = gt.name.as_ref().map(|n| n.as_bytes()).unwrap_or(b"");
2508 let gt_name = String::from_utf8_lossy(gt_name_bytes);
2509 let varname_bytes: &[u8] = ls.fs.as_ref()
2510 .and_then(|fs| {
2511 let vidx = gt.nactvar as i32;
2512 if (fs.firstlocal + vidx) >= 0 && ((fs.firstlocal + vidx) as usize) < ls.dyd.actvar.len() {
2513 let vd = get_local_var_desc(ls, fs, vidx);
2514 vd.name.as_ref().map(|n| n.as_bytes())
2515 } else {
2516 None
2517 }
2518 })
2519 .unwrap_or(b"");
2520 let varname = String::from_utf8_lossy(varname_bytes);
2521 LuaError::syntax(format_args!(
2522 "<goto {}> at line {} jumps into the scope of local '{}'", gt_name, line, varname
2523 ))
2524}
2525
2526fn solvegoto(
2528 ls: &mut LexState,
2529 state: &mut LuaState,
2530 g: usize,
2531 label_pc: i32,
2532 label_nactvar: u8,
2533) -> Result<(), LuaError> {
2534 if ls.dyd.gt[g].nactvar < label_nactvar {
2535 return Err(jumpscopeerror(ls, g));
2536 }
2537 let gt_pc = ls.dyd.gt[g].pc;
2538 cg_patch_list(ls.fs.as_mut().unwrap(), gt_pc, label_pc)?;
2539 ls.dyd.gt.remove(g);
2540 Ok(())
2541}
2542
2543fn findlabel(ls: &LexState, name: &GcRef<LuaString>) -> Option<usize> {
2545 let first = ls.fs.as_ref().unwrap().firstlabel as usize;
2546 for i in first..ls.dyd.label.len() {
2547 let lb = &ls.dyd.label[i];
2548 if lb.name.as_ref().map_or(false, |n| GcRef::ptr_eq(n, name)) {
2549 return Some(i);
2550 }
2551 }
2552 None
2553}
2554
2555fn new_label_entry(
2557 ls: &mut LexState,
2558 state: &mut LuaState,
2559 is_goto: bool,
2560 name: GcRef<LuaString>,
2561 line: i32,
2562 pc: i32,
2563) -> Result<usize, LuaError> {
2564 let nactvar = ls.fs.as_ref().unwrap().nactvar;
2565 let entry = LabelDesc { name: Some(name), pc, line, nactvar, close: false };
2566 let list = if is_goto { &mut ls.dyd.gt } else { &mut ls.dyd.label };
2567 let n = list.len();
2568 list.push(entry);
2569 Ok(n)
2570}
2571
2572fn new_goto_entry(
2573 ls: &mut LexState,
2574 state: &mut LuaState,
2575 name: GcRef<LuaString>,
2576 line: i32,
2577 pc: i32,
2578) -> Result<usize, LuaError> {
2579 new_label_entry(ls, state, true, name, line, pc)
2580}
2581
2582fn solvegotos(ls: &mut LexState, state: &mut LuaState, lb_idx: usize) -> Result<bool, LuaError> {
2585 let lb_name = ls.dyd.label[lb_idx].name.clone();
2586 let lb_pc = ls.dyd.label[lb_idx].pc;
2587 let lb_nactvar = ls.dyd.label[lb_idx].nactvar;
2588 let first_goto = ls.fs.as_ref().unwrap().bl.as_ref().map_or(0, |b| b.firstgoto) as usize;
2589
2590 let mut i = first_goto;
2591 let mut needs_close = false;
2592 while i < ls.dyd.gt.len() {
2593 let gt_name = ls.dyd.gt[i].name.clone();
2594 let names_match = lb_name.as_ref().and_then(|ln| gt_name.as_ref().map(|gn| GcRef::ptr_eq(ln, gn))).unwrap_or(false);
2595 if names_match {
2596 needs_close |= ls.dyd.gt[i].close;
2597 solvegoto(ls, state, i, lb_pc, lb_nactvar)?;
2599 } else {
2600 i += 1;
2601 }
2602 }
2603 Ok(needs_close)
2604}
2605
2606fn createlabel(
2608 ls: &mut LexState,
2609 state: &mut LuaState,
2610 name: GcRef<LuaString>,
2611 line: i32,
2612 last: bool,
2613) -> Result<bool, LuaError> {
2614 let label_pc = cg_get_label(ls.fs.as_mut().unwrap());
2615 let l = new_label_entry(ls, state, false, name, line, label_pc)?;
2616 if last {
2617 let bl_nactvar = ls.fs.as_ref().unwrap().bl.as_ref().map_or(0, |b| b.nactvar);
2618 ls.dyd.label[l].nactvar = bl_nactvar;
2619 }
2620 let needs_close = solvegotos(ls, state, l)?;
2621 if needs_close {
2622 let nstack = nvarstack(ls, ls.fs.as_ref().unwrap()) as u32;
2623 let inst = lua_code::opcodes::Instruction::abck(
2624 lua_code::opcodes::OpCode::Close,
2625 nstack,
2626 0,
2627 0,
2628 0,
2629 );
2630 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
2631 return Ok(true);
2632 }
2633 Ok(false)
2634}
2635
2636fn movegotosout(ls: &mut LexState, bl_firstgoto: usize, bl_nactvar: u8, bl_upval: bool) {
2638 let fs = ls.fs.as_ref().unwrap();
2639 let first_goto = bl_firstgoto;
2640 let n_gt = ls.dyd.gt.len();
2641 drop(fs); for i in first_goto..ls.dyd.gt.len() {
2644 let gt_nactvar = ls.dyd.gt[i].nactvar;
2645 if bl_upval {
2647 ls.dyd.gt[i].close = true;
2648 }
2649 ls.dyd.gt[i].nactvar = bl_nactvar;
2650 }
2651}
2652
2653fn enter_block(ls: &mut LexState, isloop: bool) {
2655 let firstlabel = ls.dyd.label.len() as i32;
2656 let firstgoto = ls.dyd.gt.len() as i32;
2657 let insidetbc = ls.fs.as_ref()
2658 .and_then(|f| f.bl.as_ref())
2659 .map_or(false, |b| b.insidetbc);
2660 let fs = ls.fs.as_mut().unwrap();
2661 let nactvar = fs.nactvar;
2662 let new_bl = Box::new(BlockCnt {
2663 previous: fs.bl.take(),
2664 firstlabel,
2665 firstgoto,
2666 nactvar,
2667 upval: false,
2668 isloop,
2669 insidetbc,
2670 });
2671 fs.bl = Some(new_bl);
2672 debug_assert!(fs.freereg as i32 == {
2673 fs.freereg as i32 });
2676}
2677
2678fn undef_goto(ls: &LexState, gt_idx: usize) -> LuaError {
2679 let gt = &ls.dyd.gt[gt_idx];
2680 let line = gt.line;
2681 let name_bytes: &[u8] = gt.name.as_ref().map(|n| n.as_bytes()).unwrap_or(b"");
2682 if name_bytes == b"break" {
2683 LuaError::syntax(format_args!("break outside loop at line {}", line))
2684 } else {
2685 let name_str = String::from_utf8_lossy(name_bytes);
2686 LuaError::syntax(format_args!("no visible label '{}' for <goto> at line {}", name_str, line))
2687 }
2688}
2689
2690fn leave_block(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
2692 let (bl_nactvar, bl_isloop, bl_upval, bl_firstgoto, bl_firstlabel) = {
2696 let bl = ls
2697 .fs
2698 .as_ref()
2699 .unwrap()
2700 .bl
2701 .as_ref()
2702 .expect("leave_block: no current block");
2703 (bl.nactvar, bl.isloop, bl.upval, bl.firstgoto, bl.firstlabel)
2704 };
2705
2706 let stklevel = reg_level(ls, ls.fs.as_ref().unwrap(), bl_nactvar as i32);
2707 let mut fs_box = ls.fs.take().unwrap();
2708 remove_vars(ls, &mut fs_box, bl_nactvar as i32);
2709 debug_assert!(bl_nactvar == fs_box.nactvar);
2710 ls.fs = Some(fs_box);
2711
2712 let hasclose = if bl_isloop {
2713 let break_str = state.intern_str(b"break")?;
2714 createlabel(ls, state, break_str, 0, false)?
2715 } else {
2716 false
2717 };
2718
2719 let mut bl_box = ls.fs.as_mut().unwrap().bl.take().unwrap();
2721 let previous = bl_box.previous.take();
2722 ls.fs.as_mut().unwrap().bl = previous;
2723
2724 let has_prev_block = ls.fs.as_ref().unwrap().bl.is_some();
2725 if !hasclose && has_prev_block && bl_upval {
2726 let line = ls.lastline;
2730 let inst = lua_code::opcodes::Instruction::abck(
2731 lua_code::opcodes::OpCode::Close,
2732 stklevel as u32,
2733 0,
2734 0,
2735 0,
2736 );
2737 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
2738 }
2739 ls.fs.as_mut().unwrap().freereg = stklevel as u8;
2740
2741 ls.dyd.label.truncate(bl_firstlabel as usize);
2742
2743 if has_prev_block {
2744 movegotosout(ls, bl_firstgoto as usize, bl_nactvar, bl_upval);
2745 } else {
2746 if (bl_firstgoto as usize) < ls.dyd.gt.len() {
2747 return Err(undef_goto(ls, bl_firstgoto as usize));
2748 }
2749 }
2750 Ok(())
2751}
2752
2753fn add_prototype(ls: &mut LexState, state: &mut LuaState) -> Result<Box<LuaProto>, LuaError> {
2758 let np = ls.fs.as_ref().unwrap().np as usize;
2759 let new_proto = Box::new(LuaProto::placeholder());
2761 while ls.fs.as_ref().unwrap().f.p.len() <= np {
2762 ls.fs
2763 .as_mut()
2764 .unwrap()
2765 .f
2766 .p
2767 .push(GcRef::new(LuaProto::placeholder()));
2768 }
2769 ls.fs.as_mut().unwrap().np += 1;
2770 Ok(new_proto)
2771}
2772
2773fn codeclosure(ls: &mut LexState, _state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
2775 let line = ls.lastline;
2776 let mut child = ls.fs.take().expect("codeclosure: no current FuncState");
2777 let result = (|| -> Result<(), LuaError> {
2778 let parent = child.prev.as_mut().expect(
2779 "codeclosure: child FuncState has no parent (called outside body()?)",
2780 );
2781 let bx = (parent.np - 1) as u32;
2782 let inst = lua_code::opcodes::Instruction::abx(
2783 lua_code::opcodes::OpCode::Closure,
2784 0,
2785 bx,
2786 );
2787 let pc = emit_inst(parent, line, inst);
2788 init_exp(v, ExprKind::Reloc, pc);
2789 cg_exp_to_next_reg(parent, line, v)
2790 })();
2791 ls.fs = Some(child);
2792 result
2793}
2794
2795fn open_func(ls: &mut LexState, state: &mut LuaState, mut new_fs: FuncState) -> Result<(), LuaError> {
2797 new_fs.prev = ls.fs.take();
2798
2799 let f = &mut new_fs.f;
2800 new_fs.pc = 0;
2801 new_fs.previousline = f.linedefined;
2802 new_fs.iwthabs = 0;
2803 new_fs.lasttarget = 0;
2804 new_fs.freereg = 0;
2805 new_fs.nk = 0;
2806 new_fs.nabslineinfo = 0;
2807 new_fs.np = 0;
2808 new_fs.nups = 0;
2809 new_fs.ndebugvars = 0;
2810 new_fs.nactvar = 0;
2811 new_fs.needclose = false;
2812
2813 new_fs.firstlocal = ls.dyd.actvar.len() as i32;
2814 new_fs.firstlabel = ls.dyd.label.len() as i32;
2815 new_fs.bl = None;
2816
2817 new_fs.f.source = ls.source.clone();
2818 new_fs.f.maxstacksize = 2;
2819
2820
2821 ls.fs = Some(Box::new(new_fs));
2822
2823 enter_block(ls, false);
2824 Ok(())
2825}
2826
2827fn close_func(ls: &mut LexState, state: &mut LuaState) -> Result<Box<LuaProto>, LuaError> {
2830 {
2831 let first = {
2832 let fs = ls.fs.as_ref().unwrap();
2833 nvarstack(ls, fs)
2834 };
2835 let line = ls.lastline;
2836 let fs = ls.fs.as_mut().unwrap();
2837 let inst = lua_code::opcodes::Instruction::abck(
2838 lua_code::opcodes::OpCode::Return0,
2839 first as u32,
2840 1,
2841 0,
2842 0,
2843 );
2844 emit_inst(fs, line, inst);
2845 }
2846 leave_block(ls, state)?;
2847 debug_assert!(ls.fs.as_ref().unwrap().bl.is_none());
2848
2849 cg_finish(ls.fs.as_mut().unwrap());
2851
2852 {
2853 let fs = ls.fs.as_mut().unwrap();
2854 let pc = fs.pc as usize;
2855 let nabslineinfo = fs.nabslineinfo as usize;
2856 let nk = fs.nk as usize;
2857 let np = fs.np as usize;
2858 let ndebugvars = fs.ndebugvars as usize;
2859 let nups = fs.nups as usize;
2860 fs.f.code.truncate(pc);
2861 fs.f.lineinfo.truncate(pc);
2862 fs.f.abslineinfo.truncate(nabslineinfo);
2863 fs.f.k.truncate(nk);
2864 fs.f.p.truncate(np);
2865 fs.f.locvars.truncate(ndebugvars);
2866 fs.f.upvalues.truncate(nups);
2867 }
2868
2869 let mut fs_box = ls.fs.take().unwrap();
2870 ls.fs = fs_box.prev.take();
2871
2872 Ok(fs_box.f)
2873}
2874
2875fn block_follow(ls: &LexState, withuntil: bool) -> bool {
2879 match ls.t.token {
2880 TK_ELSE | TK_ELSEIF | TK_END | TK_EOS => true,
2881 TK_UNTIL => withuntil,
2882 _ => false,
2883 }
2884}
2885
2886fn statlist(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
2887 while !block_follow(ls, true) {
2888 if ls.t.token == TK_RETURN {
2889 statement(ls, state)?;
2890 return Ok(());
2891 }
2892 statement(ls, state)?;
2893 }
2894 Ok(())
2895}
2896
2897fn fieldsel(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
2899 let line = ls.lastline;
2900 cg_exp_to_any_reg_up(ls.fs.as_mut().unwrap(), line, v)?;
2901 lex_next(ls, state)?; let mut key = ExprDesc::default();
2903 codename(ls, state, &mut key)?;
2904 cg_indexed(ls.fs.as_mut().unwrap(), line, v, &mut key)?;
2905 Ok(())
2906}
2907
2908fn yindex(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
2910 lex_next(ls, state)?;
2911 expr(ls, state, v)?;
2912 check_next(ls, state, b']' as TokenKind)?;
2914 Ok(())
2915}
2916
2917fn recfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
2920 let reg = ls.fs.as_ref().unwrap().freereg as i32;
2921 let mut key = ExprDesc::default();
2922 let mut val = ExprDesc::default();
2923 if ls.t.token == TK_NAME {
2924 let fs = ls.fs.as_ref().unwrap();
2925 check_limit(fs, cc.nh, i32::MAX, "items in a constructor")?;
2926 codename(ls, state, &mut key)?;
2927 } else {
2928 yindex(ls, state, &mut key)?;
2929 }
2930 cc.nh += 1;
2931 check_next(ls, state, b'=' as TokenKind)?;
2932 let mut tab = cc.t.clone();
2933 let line = ls.lastline;
2934 cg_indexed(ls.fs.as_mut().unwrap(), line, &mut tab, &mut key)?;
2935 expr(ls, state, &mut val)?;
2936 cg_storevar(ls.fs.as_mut().unwrap(), line, &tab, &mut val)?;
2937 ls.fs.as_mut().unwrap().freereg = reg as u8;
2938 Ok(())
2939}
2940
2941fn closelistfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
2942 let _ = state;
2943 if cc.v.k == ExprKind::Void {
2944 return Ok(());
2945 }
2946 let line = ls.lastline;
2947 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut cc.v)?;
2948 cc.v.k = ExprKind::Void;
2949 if cc.tostore == LFIELDS_PER_FLUSH {
2950 let t_info = cc.t.u.info;
2951 cg_setlist(ls.fs.as_mut().unwrap(), line, t_info, cc.na, cc.tostore);
2952 cc.na += cc.tostore;
2953 cc.tostore = 0;
2954 }
2955 Ok(())
2956}
2957
2958fn lastlistfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
2959 let _ = state;
2960 if cc.tostore == 0 {
2961 return Ok(());
2962 }
2963 let t_info = cc.t.u.info;
2964 let line = ls.lastline;
2965 if cc.v.k.has_mult_ret() {
2966 cg_set_returns(ls.fs.as_mut().unwrap(), &mut cc.v, LUA_MULTRET);
2967 cg_setlist(ls.fs.as_mut().unwrap(), line, t_info, cc.na, LUA_MULTRET);
2968 cc.na -= 1;
2969 } else {
2970 if cc.v.k != ExprKind::Void {
2971 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut cc.v)?;
2972 }
2973 cg_setlist(ls.fs.as_mut().unwrap(), line, t_info, cc.na, cc.tostore);
2974 }
2975 cc.na += cc.tostore;
2976 Ok(())
2977}
2978
2979fn listfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
2980 expr(ls, state, &mut cc.v)?;
2981 cc.tostore += 1;
2982 Ok(())
2983}
2984
2985fn field(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
2986 match ls.t.token {
2987 TK_NAME => {
2988 let next_is_eq = lex_lookahead(ls, state)? == b'=' as TokenKind;
2989 if !next_is_eq {
2990 listfield(ls, state, cc)?;
2991 } else {
2992 recfield(ls, state, cc)?;
2993 }
2994 }
2995 c if c == b'[' as TokenKind => {
2996 recfield(ls, state, cc)?;
2997 }
2998 _ => {
2999 listfield(ls, state, cc)?;
3000 }
3001 }
3002 Ok(())
3003}
3004
3005fn constructor(ls: &mut LexState, state: &mut LuaState, t: &mut ExprDesc) -> Result<(), LuaError> {
3006 let line = ls.lastline;
3007 let pc = cg_emit_newtable(ls.fs.as_mut().unwrap(), line);
3008
3009 let freereg = ls.fs.as_ref().unwrap().freereg as i32;
3010 init_exp(t, ExprKind::NonReloc, freereg);
3011 reserve_regs(ls.fs.as_mut().unwrap(), 1)?;
3012
3013 let mut cc = ConsControl {
3014 v: ExprDesc::default(),
3015 t: t.clone(),
3016 nh: 0,
3017 na: 0,
3018 tostore: 0,
3019 };
3020
3021 check_next(ls, state, b'{' as TokenKind)?;
3022 loop {
3023 debug_assert!(cc.v.k == ExprKind::Void || cc.tostore > 0);
3024 if ls.t.token == b'}' as TokenKind {
3025 break;
3026 }
3027 closelistfield(ls, state, &mut cc)?;
3028 field(ls, state, &mut cc)?;
3029 if !test_next(ls, state, b',' as TokenKind)?
3030 && !test_next(ls, state, b';' as TokenKind)?
3031 {
3032 break;
3033 }
3034 }
3035 check_match(ls, state, b'}' as TokenKind, b'{' as TokenKind, line)?;
3036 lastlistfield(ls, state, &mut cc)?;
3037
3038 let t_info = t.u.info;
3039 cg_settablesize(ls.fs.as_mut().unwrap(), pc, t_info, cc.na, cc.nh);
3040 Ok(())
3041}
3042
3043fn setvararg(fs: &mut FuncState, _state: &mut LuaState, nparams: i32) -> Result<(), LuaError> {
3046 fs.f.is_vararg = true;
3047 let inst = lua_code::opcodes::Instruction::abck(
3048 lua_code::opcodes::OpCode::VarArgPrep,
3049 nparams as u32,
3050 0, 0, 0,
3051 );
3052 let line = fs.previousline;
3053 emit_inst(fs, line, inst);
3054 Ok(())
3055}
3056
3057fn parlist(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3058 let mut nparams: i32 = 0;
3059 let mut isvararg = false;
3060 if ls.t.token != b')' as TokenKind {
3061 loop {
3062 match ls.t.token {
3063 TK_NAME => {
3064 let name = str_check_name(ls, state)?;
3065 new_local_var(ls, state, name)?;
3066 nparams += 1;
3067 }
3068 TK_DOTS => {
3069 lex_next(ls, state)?;
3070 isvararg = true;
3071 }
3072 _ => {
3073 return Err(LuaError::syntax(format_args!("<name> or '...' expected")));
3074 }
3075 }
3076 if isvararg || !test_next(ls, state, b',' as TokenKind)? {
3077 break;
3078 }
3079 }
3080 }
3081 adjust_local_vars(ls, state, nparams)?;
3082 let numparams = ls.fs.as_ref().unwrap().nactvar;
3083 ls.fs.as_mut().unwrap().f.numparams = numparams;
3084 if isvararg {
3085 setvararg(ls.fs.as_mut().unwrap(), state, numparams as i32)?;
3086 }
3087 let nactvar = ls.fs.as_ref().unwrap().nactvar as i32;
3088 reserve_regs(ls.fs.as_mut().unwrap(), nactvar)?;
3089 Ok(())
3090}
3091
3092fn check_match(
3093 ls: &mut LexState,
3094 state: &mut LuaState,
3095 what: TokenKind,
3096 who: TokenKind,
3097 where_line: i32,
3098) -> Result<(), LuaError> {
3099 if !test_next(ls, state, what)? {
3100 if where_line == ls.linenumber {
3101 return Err(error_expected(ls, what));
3102 } else {
3103 let what_str = lua_lex::token2str(&ls.lex, what);
3104 let who_str = lua_lex::token2str(&ls.lex, who);
3105 let mut msg: Vec<u8> = Vec::new();
3106 msg.extend_from_slice(&what_str);
3107 msg.extend_from_slice(b" expected (to close ");
3108 msg.extend_from_slice(&who_str);
3109 use std::io::Write as _;
3110 let _ = write!(msg, " at line {})", where_line);
3111 return Err(lua_lex::syntax_error(&mut ls.lex, &msg));
3112 }
3113 }
3114 Ok(())
3115}
3116
3117fn body(
3118 ls: &mut LexState,
3119 state: &mut LuaState,
3120 e: &mut ExprDesc,
3121 ismethod: bool,
3122 line: i32,
3123) -> Result<(), LuaError> {
3124 let new_proto = add_prototype(ls, state)?;
3125 let mut new_fs = FuncState {
3126 f: new_proto,
3127 prev: None,
3128 bl: None,
3129 pc: 0,
3130 lasttarget: 0,
3131 previousline: line,
3132 nk: 0,
3133 np: 0,
3134 nabslineinfo: 0,
3135 firstlocal: 0,
3136 firstlabel: 0,
3137 ndebugvars: 0,
3138 nactvar: 0,
3139 nups: 0,
3140 freereg: 0,
3141 iwthabs: 0,
3142 needclose: false,
3143 last_token_line: ls.lastline,
3144 };
3145 new_fs.f.linedefined = line;
3146 open_func(ls, state, new_fs)?;
3147
3148 check_next(ls, state, b'(' as TokenKind)?;
3149 if ismethod {
3150 let self_str = state.intern_str(b"self")?;
3151 new_local_var(ls, state, self_str)?;
3152 adjust_local_vars(ls, state, 1)?;
3153 }
3154 parlist(ls, state)?;
3155 check_next(ls, state, b')' as TokenKind)?;
3156 statlist(ls, state)?;
3157 ls.fs.as_mut().unwrap().f.lastlinedefined = ls.linenumber;
3158 check_match(ls, state, TK_END, TK_FUNCTION, line)?;
3159 codeclosure(ls, state, e)?;
3160 let inner_proto = close_func(ls, state)?;
3161 let parent = ls.fs.as_mut().expect("body: close_func left no parent FuncState");
3162 let slot = (parent.np - 1) as usize;
3163 if parent.f.p.len() <= slot {
3164 parent.f.p.resize_with(slot + 1, || GcRef::new(LuaProto::placeholder()));
3165 }
3166 parent.f.p[slot] = GcRef::new(*inner_proto);
3167 Ok(())
3168}
3169
3170fn explist(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<i32, LuaError> {
3173 let mut n = 1;
3174 expr(ls, state, v)?;
3175 while test_next(ls, state, b',' as TokenKind)? {
3176 let line = ls.lastline;
3177 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, v)?;
3178 expr(ls, state, v)?;
3179 n += 1;
3180 }
3181 Ok(n)
3182}
3183
3184fn funcargs(ls: &mut LexState, state: &mut LuaState, f: &mut ExprDesc) -> Result<(), LuaError> {
3185 let mut args = ExprDesc::default();
3186 let line = ls.linenumber;
3189 match ls.t.token {
3190 c if c == b'(' as TokenKind => {
3191 lex_next(ls, state)?; if ls.t.token == b')' as TokenKind {
3193 args.k = ExprKind::Void;
3194 } else {
3195 explist(ls, state, &mut args)?;
3196 if args.k.has_mult_ret() {
3197 cg_set_returns(ls.fs.as_mut().unwrap(), &mut args, LUA_MULTRET);
3200 }
3201 }
3202 check_match(ls, state, b')' as TokenKind, b'(' as TokenKind, line)?;
3203 }
3204 c if c == b'{' as TokenKind => {
3205 constructor(ls, state, &mut args)?;
3206 }
3207 TK_STRING => {
3208 let s = ls.t.seminfo.ts.clone()
3209 .ok_or_else(|| LuaError::syntax(format_args!("string expected")))?;
3210 codestring(&mut args, s);
3211 lex_next(ls, state)?;
3212 }
3213 _ => {
3214 return Err(LuaError::syntax(format_args!("function arguments expected")));
3215 }
3216 }
3217 debug_assert!(f.k == ExprKind::NonReloc);
3218 let base = f.u.info;
3219 let nparams: i32 = if args.k.has_mult_ret() {
3220 LUA_MULTRET
3223 } else {
3224 if args.k != ExprKind::Void {
3225 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut args)?;
3226 }
3227 ls.fs.as_ref().unwrap().freereg as i32 - (base + 1)
3228 };
3229 let call_inst = lua_code::opcodes::Instruction::abck(
3230 lua_code::opcodes::OpCode::Call,
3231 base as u32,
3232 (nparams + 1) as u32,
3233 2,
3234 0,
3235 );
3236 let call_pc = emit_inst(ls.fs.as_mut().unwrap(), line, call_inst);
3237 init_exp(f, ExprKind::Call, call_pc);
3238 ls.fs.as_mut().unwrap().freereg = base as u8 + 1;
3239 Ok(())
3240}
3241
3242fn primaryexp(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3245 match ls.t.token {
3246 c if c == b'(' as TokenKind => {
3247 let line = ls.lastline;
3248 lex_next(ls, state)?;
3249 expr(ls, state, v)?;
3250 check_match(ls, state, b')' as TokenKind, b'(' as TokenKind, line)?;
3251 cg_discharge_vars(ls.fs.as_mut().unwrap(), line, v)?;
3252 }
3253 TK_NAME => {
3254 singlevar(ls, state, v)?;
3255 }
3256 _ => {
3257 return Err(lua_lex::syntax_error(&mut ls.lex, b"unexpected symbol"));
3258 }
3259 }
3260 Ok(())
3261}
3262
3263fn suffixedexp(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3264 primaryexp(ls, state, v)?;
3265 loop {
3266 match ls.t.token {
3267 c if c == b'.' as TokenKind => {
3268 fieldsel(ls, state, v)?;
3269 }
3270 c if c == b'[' as TokenKind => {
3271 let mut key = ExprDesc::default();
3272 let line = ls.lastline;
3273 cg_exp_to_any_reg_up(ls.fs.as_mut().unwrap(), line, v)?;
3274 yindex(ls, state, &mut key)?;
3275 cg_indexed(ls.fs.as_mut().unwrap(), line, v, &mut key)?;
3276 }
3277 c if c == b':' as TokenKind => {
3278 let mut key = ExprDesc::default();
3279 lex_next(ls, state)?;
3280 codename(ls, state, &mut key)?;
3281 let line = ls.lastline;
3282 cg_self(ls.fs.as_mut().unwrap(), line, v, &mut key)?;
3283 funcargs(ls, state, v)?;
3284 }
3285 c if c == b'(' as TokenKind || c == TK_STRING || c == b'{' as TokenKind => {
3286 let line = ls.lastline;
3287 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, v)?;
3288 funcargs(ls, state, v)?;
3289 }
3290 _ => return Ok(()),
3291 }
3292 }
3293}
3294
3295fn simpleexp(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3296 match ls.t.token {
3297 TK_FLT => {
3298 init_exp(v, ExprKind::KFlt, 0);
3299 v.u.nval = ls.t.seminfo.r;
3300 }
3301 TK_INT => {
3302 init_exp(v, ExprKind::KInt, 0);
3303 v.u.ival = ls.t.seminfo.i;
3304 }
3305 TK_STRING => {
3306 let s = ls.t.seminfo.ts.clone()
3307 .ok_or_else(|| LuaError::syntax(format_args!("string value missing")))?;
3308 codestring(v, s);
3309 }
3310 TK_NIL => {
3311 init_exp(v, ExprKind::Nil, 0);
3312 }
3313 TK_TRUE => {
3314 init_exp(v, ExprKind::True, 0);
3315 }
3316 TK_FALSE => {
3317 init_exp(v, ExprKind::False, 0);
3318 }
3319 TK_DOTS => {
3320 let is_vararg = ls.fs.as_ref().unwrap().f.is_vararg;
3321 if !is_vararg {
3322 return Err(LuaError::syntax(format_args!(
3323 "cannot use '...' outside a vararg function"
3324 )));
3325 }
3326 let line = ls.lastline;
3327 let inst = lua_code::opcodes::Instruction::abck(
3328 lua_code::opcodes::OpCode::VarArg,
3329 0,
3330 0,
3331 1,
3332 0,
3333 );
3334 let pc = emit_inst(ls.fs.as_mut().unwrap(), line, inst);
3335 init_exp(v, ExprKind::VarArg, pc);
3336 }
3337 c if c == b'{' as TokenKind => {
3338 constructor(ls, state, v)?;
3339 return Ok(());
3340 }
3341 TK_FUNCTION => {
3342 lex_next(ls, state)?;
3343 let line = ls.lastline;
3344 body(ls, state, v, false, line)?;
3345 return Ok(());
3346 }
3347 _ => {
3348 suffixedexp(ls, state, v)?;
3349 return Ok(());
3350 }
3351 }
3352 lex_next(ls, state)?;
3353 Ok(())
3354}
3355
3356fn getunopr(op: TokenKind) -> UnOpr {
3357 match op {
3358 TK_NOT => UnOpr::Not,
3359 c if c == b'-' as TokenKind => UnOpr::Minus,
3360 c if c == b'~' as TokenKind => UnOpr::BNot,
3361 c if c == b'#' as TokenKind => UnOpr::Len,
3362 _ => UnOpr::NoUnOpr,
3363 }
3364}
3365
3366fn getbinopr(op: TokenKind) -> BinOpr {
3367 match op {
3368 c if c == b'+' as TokenKind => BinOpr::Add,
3369 c if c == b'-' as TokenKind => BinOpr::Sub,
3370 c if c == b'*' as TokenKind => BinOpr::Mul,
3371 c if c == b'%' as TokenKind => BinOpr::Mod,
3372 c if c == b'^' as TokenKind => BinOpr::Pow,
3373 c if c == b'/' as TokenKind => BinOpr::Div,
3374 TK_IDIV => BinOpr::IDiv,
3375 c if c == b'&' as TokenKind => BinOpr::BAnd,
3376 c if c == b'|' as TokenKind => BinOpr::BOr,
3377 c if c == b'~' as TokenKind => BinOpr::BXor,
3378 TK_SHL => BinOpr::Shl,
3379 TK_SHR => BinOpr::Shr,
3380 TK_CONCAT => BinOpr::Concat,
3381 TK_NE => BinOpr::Ne,
3382 TK_EQ => BinOpr::Eq,
3383 c if c == b'<' as TokenKind => BinOpr::Lt,
3384 TK_LE => BinOpr::Le,
3385 c if c == b'>' as TokenKind => BinOpr::Gt,
3386 TK_GE => BinOpr::Ge,
3387 TK_AND => BinOpr::And,
3388 TK_OR => BinOpr::Or,
3389 _ => BinOpr::NoBinOpr,
3390 }
3391}
3392
3393fn subexpr(
3396 ls: &mut LexState,
3397 state: &mut LuaState,
3398 v: &mut ExprDesc,
3399 limit: i32,
3400) -> Result<BinOpr, LuaError> {
3401 enter_level(ls)?;
3402
3403 let uop = getunopr(ls.t.token);
3404 if uop != UnOpr::NoUnOpr {
3405 let line = ls.linenumber;
3407 lex_next(ls, state)?; subexpr(ls, state, v, UNARY_PRIORITY)?;
3409 cg_prefix(ls.fs.as_mut().unwrap(), uop, v, line)?;
3410 } else {
3411 simpleexp(ls, state, v)?;
3412 }
3413
3414 let mut op = getbinopr(ls.t.token);
3415 while op != BinOpr::NoBinOpr && PRIORITY[op as usize].0 as i32 > limit {
3416 let mut v2 = ExprDesc::default();
3417 let line = ls.linenumber;
3420 lex_next(ls, state)?;
3421 cg_infix(ls.fs.as_mut().unwrap(), op, v, line)?;
3422 let nextop = subexpr(ls, state, &mut v2, PRIORITY[op as usize].1 as i32)?;
3423 cg_posfix_fold(ls.fs.as_mut().unwrap(), op, v, &mut v2, line)?;
3424 op = nextop;
3425 }
3426
3427 leave_level(ls);
3428 Ok(op)
3429}
3430
3431fn expr(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3432 subexpr(ls, state, v, 0)?;
3433 Ok(())
3434}
3435
3436fn block(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3439 enter_block(ls, false);
3440 statlist(ls, state)?;
3441 leave_block(ls, state)?;
3442 Ok(())
3443}
3444
3445fn check_conflict(
3453 ls: &mut LexState,
3454 _state: &mut LuaState,
3455 lh: &mut LhsAssign,
3456 v: &ExprDesc,
3457) -> Result<(), LuaError> {
3458 let extra = ls.fs.as_ref().unwrap().freereg as i32;
3459 let line = ls.lastline;
3460 let mut conflict = false;
3461
3462 conflict |= check_one_lhs_entry(&mut lh.v, v, extra);
3463 let mut prev = lh.prev.as_deref_mut();
3464 while let Some(node) = prev {
3465 conflict |= check_one_lhs_entry(&mut node.v, v, extra);
3466 prev = node.prev.as_deref_mut();
3467 }
3468
3469 if conflict {
3470 let fs = ls.fs.as_mut().unwrap();
3471 let inst = if v.k == ExprKind::Local {
3472 lua_code::opcodes::Instruction::abck(
3473 lua_code::opcodes::OpCode::Move,
3474 extra as u32, v.u.var_ridx as u32, 0, 0,
3475 )
3476 } else {
3477 lua_code::opcodes::Instruction::abck(
3478 lua_code::opcodes::OpCode::GetUpVal,
3479 extra as u32, v.u.info as u32, 0, 0,
3480 )
3481 };
3482 emit_inst(fs, line, inst);
3483 reserve_regs(fs, 1)?;
3484 }
3485 Ok(())
3486}
3487
3488fn check_one_lhs_entry(entry: &mut ExprDesc, v: &ExprDesc, extra: i32) -> bool {
3489 if !entry.k.is_indexed() {
3490 return false;
3491 }
3492 let mut found = false;
3493 if entry.k == ExprKind::IndexUp {
3494 if v.k == ExprKind::UpVal && entry.u.ind_t == v.u.info as u8 {
3495 found = true;
3496 entry.k = ExprKind::IndexStr;
3497 entry.u.ind_t = extra as u8;
3498 }
3499 } else {
3500 if v.k == ExprKind::Local && entry.u.ind_t == v.u.var_ridx {
3501 found = true;
3502 entry.u.ind_t = extra as u8;
3503 }
3504 if entry.k == ExprKind::Indexed
3505 && v.k == ExprKind::Local
3506 && entry.u.ind_idx == v.u.var_ridx as i16
3507 {
3508 found = true;
3509 entry.u.ind_idx = extra as i16;
3510 }
3511 }
3512 found
3513}
3514
3515fn restassign(
3516 ls: &mut LexState,
3517 state: &mut LuaState,
3518 lh: &mut LhsAssign,
3519 nvars: i32,
3520) -> Result<(), LuaError> {
3521 if !lh.v.k.is_var() {
3522 return Err(lua_lex::syntax_error(&mut ls.lex, b"syntax error"));
3523 }
3524 check_readonly(ls, state, &lh.v.clone())?;
3525
3526 if test_next(ls, state, b',' as TokenKind)? {
3527 let mut nv_assign = LhsAssign {
3528 prev: None, v: ExprDesc::default(),
3530 };
3531 suffixedexp(ls, state, &mut nv_assign.v)?;
3532 if !nv_assign.v.k.is_indexed() {
3533 check_conflict(ls, state, lh, &nv_assign.v.clone())?;
3534 }
3535 enter_level(ls)?;
3536 restassign(ls, state, &mut nv_assign, nvars + 1)?;
3537 leave_level(ls);
3538 } else {
3539 let mut e = ExprDesc::default();
3540 check_next(ls, state, b'=' as TokenKind)?;
3541 let nexps = explist(ls, state, &mut e)?;
3542 if nexps != nvars {
3543 adjust_assign(ls, state, nvars, nexps, &mut e)?;
3544 } else {
3545 let line = ls.lastline;
3546 let fs = ls.fs.as_mut().unwrap();
3547 cg_set_one_ret(fs, &mut e);
3548 cg_storevar(fs, line, &lh.v, &mut e)?;
3549 return Ok(());
3550 }
3551 }
3552 let line = ls.lastline;
3553 let fs = ls.fs.as_mut().unwrap();
3554 let freereg = fs.freereg as i32 - 1;
3555 let mut e = ExprDesc::default();
3556 init_exp(&mut e, ExprKind::NonReloc, freereg);
3557 cg_storevar(fs, line, &lh.v, &mut e)?;
3558 Ok(())
3559}
3560
3561fn cond(ls: &mut LexState, state: &mut LuaState) -> Result<i32, LuaError> {
3563 let mut v = ExprDesc::default();
3564 expr(ls, state, &mut v)?;
3565 if v.k == ExprKind::Nil {
3566 v.k = ExprKind::False;
3567 }
3568 let line = ls.lastline;
3569 cg_go_if_true(ls.fs.as_mut().unwrap(), line, &mut v)?;
3570 Ok(v.f)
3571}
3572
3573fn gotostat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3574 let line = ls.lastline;
3575 let name = str_check_name(ls, state)?;
3576 let lb = findlabel(ls, &name);
3577 if lb.is_none() {
3578 let pc = cg_jump(ls.fs.as_mut().unwrap(), line);
3579 new_goto_entry(ls, state, name, line, pc)?;
3580 } else {
3581 let lb_idx = lb.unwrap();
3582 let lb_pc = ls.dyd.label[lb_idx].pc;
3583 let lb_nactvar = ls.dyd.label[lb_idx].nactvar;
3584 let lblevel = reg_level(ls, ls.fs.as_ref().unwrap(), lb_nactvar as i32);
3585 let cur_nvarstack = {
3586 let fs = ls.fs.as_ref().unwrap();
3587 nvarstack(ls, fs)
3588 };
3589 if cur_nvarstack > lblevel {
3590 let inst = lua_code::opcodes::Instruction::abck(
3591 lua_code::opcodes::OpCode::Close,
3592 lblevel as u32,
3593 0,
3594 0,
3595 0,
3596 );
3597 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
3598 }
3599 let jpc = cg_jump(ls.fs.as_mut().unwrap(), line);
3600 cg_patch_list(ls.fs.as_mut().unwrap(), jpc, lb_pc)?;
3601 }
3602 Ok(())
3603}
3604
3605fn breakstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3606 let line = ls.lastline;
3607 lex_next(ls, state)?;
3608 let break_str = state.intern_str(b"break")?;
3609 let pc = cg_jump(ls.fs.as_mut().unwrap(), line);
3610 new_goto_entry(ls, state, break_str, line, pc)?;
3611 Ok(())
3612}
3613
3614fn checkrepeated(ls: &LexState, name: &GcRef<LuaString>) -> Result<(), LuaError> {
3615 if let Some(lb_idx) = findlabel(ls, name) {
3616 let name_str = String::from_utf8_lossy(name.as_bytes());
3617 let line = ls.dyd.label[lb_idx].line;
3618 return Err(LuaError::syntax(format_args!(
3619 "label '{}' already defined on line {}", name_str, line
3620 )));
3621 }
3622 Ok(())
3623}
3624
3625fn labelstat(
3626 ls: &mut LexState,
3627 state: &mut LuaState,
3628 name: GcRef<LuaString>,
3629 line: i32,
3630) -> Result<(), LuaError> {
3631 check_next(ls, state, TK_DBCOLON)?;
3632 while ls.t.token == b';' as TokenKind || ls.t.token == TK_DBCOLON {
3633 statement(ls, state)?;
3634 }
3635 checkrepeated(ls, &name)?;
3636 let is_last = block_follow(ls, false);
3637 createlabel(ls, state, name, line, is_last)?;
3638 Ok(())
3639}
3640
3641fn whilestat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
3642 lex_next(ls, state)?;
3643 let whileinit = cg_get_label(ls.fs.as_mut().unwrap());
3644 let condexit = cond(ls, state)?;
3645 enter_block(ls, true);
3646 check_next(ls, state, TK_DO)?;
3647 block(ls, state)?;
3648 let back = cg_jump(ls.fs.as_mut().unwrap(), ls.lastline);
3653 cg_patch_list(ls.fs.as_mut().unwrap(), back, whileinit)?;
3654 check_match(ls, state, TK_END, TK_WHILE, line)?;
3655 leave_block(ls, state)?;
3656 cg_patch_to_here(ls.fs.as_mut().unwrap(), condexit)?;
3657 Ok(())
3658}
3659
3660fn repeatstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
3661 let repeat_init = cg_get_label(ls.fs.as_mut().unwrap());
3662 enter_block(ls, true);
3663 enter_block(ls, false);
3664 lex_next(ls, state)?;
3665 statlist(ls, state)?;
3666 check_match(ls, state, TK_UNTIL, TK_REPEAT, line)?;
3667 let condexit = cond(ls, state)?;
3668
3669 let bl2_upval = ls.fs.as_ref().unwrap().bl.as_ref().unwrap().upval;
3670 let bl2_nactvar = ls.fs.as_ref().unwrap().bl.as_ref().unwrap().nactvar as i32;
3671 leave_block(ls, state)?;
3672
3673 let mut condexit = condexit;
3674 if bl2_upval {
3675 let exit = cg_jump(ls.fs.as_mut().unwrap(), line);
3676 cg_patch_to_here(ls.fs.as_mut().unwrap(), condexit)?;
3677 let close_level = reg_level(ls, ls.fs.as_ref().unwrap(), bl2_nactvar) as u32;
3678 let close_inst = lua_code::opcodes::Instruction::abck(
3679 lua_code::opcodes::OpCode::Close,
3680 close_level,
3681 0,
3682 0,
3683 0,
3684 );
3685 emit_inst(ls.fs.as_mut().unwrap(), line, close_inst);
3686 condexit = cg_jump(ls.fs.as_mut().unwrap(), line);
3687 cg_patch_to_here(ls.fs.as_mut().unwrap(), exit)?;
3688 }
3689 cg_patch_list(ls.fs.as_mut().unwrap(), condexit, repeat_init)?;
3690 leave_block(ls, state)?;
3691 Ok(())
3692}
3693
3694fn exp1(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3696 let mut e = ExprDesc::default();
3697 expr(ls, state, &mut e)?;
3698 let line = ls.lastline;
3699 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut e)?;
3700 debug_assert!(e.k == ExprKind::NonReloc);
3701 Ok(())
3702}
3703
3704fn fixforjump(fs: &mut FuncState, pc: i32, dest: i32, back: bool) -> Result<(), LuaError> {
3705 let mut offset = dest - (pc + 1);
3706 if back {
3707 offset = -offset;
3708 }
3709 if offset > MAXARG_BX {
3710 return Err(LuaError::syntax(format_args!("control structure too long")));
3711 }
3712 let raw = fs.f.code[pc as usize].0;
3713 let mut inst = lua_code::opcodes::Instruction(raw);
3714 inst.set_arg_bx(offset as u32);
3715 fs.f.code[pc as usize] = lua_types::opcode::Instruction::new(inst.0);
3716 Ok(())
3717}
3718
3719fn forbody(
3720 ls: &mut LexState,
3721 state: &mut LuaState,
3722 base: i32,
3723 line: i32,
3724 nvars: i32,
3725 isgen: bool,
3726) -> Result<(), LuaError> {
3727 check_next(ls, state, TK_DO)?;
3728 let prep_op = if isgen { OpCode::TForPrep } else { OpCode::ForPrep };
3729 let prep = {
3730 let fs = ls.fs.as_mut().unwrap();
3731 let inst = lua_code::opcodes::Instruction::abx(prep_op, base as u32, 0);
3732 emit_inst(fs, line, inst)
3733 };
3734
3735 enter_block(ls, false);
3736 adjust_local_vars(ls, state, nvars)?;
3737 reserve_regs(ls.fs.as_mut().unwrap(), nvars)?;
3738 block(ls, state)?;
3739 leave_block(ls, state)?;
3740
3741 let label_pc = ls.fs.as_ref().unwrap().pc;
3742 fixforjump(ls.fs.as_mut().unwrap(), prep, label_pc, false)?;
3743
3744 if isgen {
3745 let fs = ls.fs.as_mut().unwrap();
3746 let inst = lua_code::opcodes::Instruction::abck(
3747 OpCode::TForCall, base as u32, 0, nvars as u32, 0,
3748 );
3749 emit_inst(fs, line, inst);
3750 }
3751 let loop_op = if isgen { OpCode::TForLoop } else { OpCode::ForLoop };
3752 let endfor = {
3753 let fs = ls.fs.as_mut().unwrap();
3754 let inst = lua_code::opcodes::Instruction::abx(loop_op, base as u32, 0);
3755 emit_inst(fs, line, inst)
3756 };
3757 fixforjump(ls.fs.as_mut().unwrap(), endfor, prep + 1, true)?;
3758 Ok(())
3759}
3760
3761fn fornum(
3762 ls: &mut LexState,
3763 state: &mut LuaState,
3764 varname: GcRef<LuaString>,
3765 line: i32,
3766) -> Result<(), LuaError> {
3767 let base = ls.fs.as_ref().unwrap().freereg as i32;
3768 let for_state_str = state.intern_str(b"(for state)")?;
3769 new_local_var(ls, state, for_state_str.clone())?;
3770 new_local_var(ls, state, for_state_str.clone())?;
3771 new_local_var(ls, state, for_state_str)?;
3772 new_local_var(ls, state, varname)?;
3773 check_next(ls, state, b'=' as TokenKind)?;
3774 exp1(ls, state)?; check_next(ls, state, b',' as TokenKind)?;
3776 exp1(ls, state)?; if test_next(ls, state, b',' as TokenKind)? {
3778 exp1(ls, state)?; } else {
3780 let fs = ls.fs.as_mut().unwrap();
3781 let reg = fs.freereg as u32;
3782 let bx = (1i32 + lua_code::opcodes::OFFSET_S_BX) as u32;
3783 let inst = lua_code::opcodes::Instruction::abx(
3784 lua_code::opcodes::OpCode::LoadI, reg, bx,
3785 );
3786 emit_inst(fs, line, inst);
3787 reserve_regs(fs, 1)?;
3788 }
3789 adjust_local_vars(ls, state, 3)?; forbody(ls, state, base, line, 1, false)?;
3791 Ok(())
3792}
3793
3794fn forlist(
3795 ls: &mut LexState,
3796 state: &mut LuaState,
3797 indexname: GcRef<LuaString>,
3798) -> Result<(), LuaError> {
3799 let mut nvars: i32 = 5; let base = ls.fs.as_ref().unwrap().freereg as i32;
3801 let for_state_str = state.intern_str(b"(for state)")?;
3802 new_local_var(ls, state, for_state_str.clone())?;
3803 new_local_var(ls, state, for_state_str.clone())?;
3804 new_local_var(ls, state, for_state_str.clone())?;
3805 new_local_var(ls, state, for_state_str)?;
3806 new_local_var(ls, state, indexname)?;
3807 while test_next(ls, state, b',' as TokenKind)? {
3808 let extra_name = str_check_name(ls, state)?;
3809 new_local_var(ls, state, extra_name)?;
3810 nvars += 1;
3811 }
3812 check_next(ls, state, TK_IN)?;
3813 let line = ls.linenumber;
3817 let mut e = ExprDesc::default();
3818 let nexps = explist(ls, state, &mut e)?;
3819 adjust_assign(ls, state, 4, nexps, &mut e)?;
3820 adjust_local_vars(ls, state, 4)?;
3821 marktobeclosed(ls.fs.as_mut().unwrap()); forbody(ls, state, base, line, nvars - 4, true)?;
3824 Ok(())
3825}
3826
3827fn forstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
3828 enter_block(ls, true); lex_next(ls, state)?;
3830 let varname = str_check_name(ls, state)?;
3831 match ls.t.token {
3832 c if c == b'=' as TokenKind => fornum(ls, state, varname, line)?,
3833 c if c == b',' as TokenKind || c == TK_IN => forlist(ls, state, varname)?,
3834 _ => {
3835 return Err(LuaError::syntax(format_args!("'=' or 'in' expected")));
3836 }
3837 }
3838 check_match(ls, state, TK_END, TK_FOR, line)?;
3839 leave_block(ls, state)?; Ok(())
3841}
3842
3843fn test_then_block(
3844 ls: &mut LexState,
3845 state: &mut LuaState,
3846 escapelist: &mut i32,
3847) -> Result<(), LuaError> {
3848 lex_next(ls, state)?;
3849 let mut v = ExprDesc::default();
3850 expr(ls, state, &mut v)?;
3851 check_next(ls, state, TK_THEN)?;
3852
3853 let jf: i32;
3854 if ls.t.token == TK_BREAK {
3855 let line = ls.lastline;
3856 cg_go_if_false(ls.fs.as_mut().unwrap(), line, &mut v)?;
3857 lex_next(ls, state)?; enter_block(ls, false);
3859 let break_str = state.intern_str(b"break")?;
3860 new_goto_entry(ls, state, break_str, line, v.t)?;
3861 while test_next(ls, state, b';' as TokenKind)? {}
3862 if block_follow(ls, false) {
3863 leave_block(ls, state)?;
3864 return Ok(());
3865 } else {
3866 jf = cg_jump(ls.fs.as_mut().unwrap(), ls.linenumber);
3867 }
3868 } else {
3869 let line = ls.lastline;
3870 cg_go_if_true(ls.fs.as_mut().unwrap(), line, &mut v)?;
3871 enter_block(ls, false);
3872 jf = v.f;
3873 }
3874
3875 statlist(ls, state)?;
3876 leave_block(ls, state)?;
3877
3878 if ls.t.token == TK_ELSE || ls.t.token == TK_ELSEIF {
3879 let line = ls.lastline;
3880 let j = cg_jump(ls.fs.as_mut().unwrap(), line);
3881 cg_concat(ls.fs.as_mut().unwrap(), escapelist, j)?;
3882 }
3883 cg_patch_to_here(ls.fs.as_mut().unwrap(), jf)?;
3884 Ok(())
3885}
3886
3887fn ifstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
3888 let mut escapelist = NO_JUMP;
3889 test_then_block(ls, state, &mut escapelist)?; while ls.t.token == TK_ELSEIF {
3891 test_then_block(ls, state, &mut escapelist)?;
3892 }
3893 if test_next(ls, state, TK_ELSE)? {
3894 block(ls, state)?;
3895 }
3896 check_match(ls, state, TK_END, TK_IF, line)?;
3897 cg_patch_to_here(ls.fs.as_mut().unwrap(), escapelist)?;
3898 Ok(())
3899}
3900
3901fn localfunc(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3902 let mut b = ExprDesc::default();
3903 let fvar = ls.fs.as_ref().unwrap().nactvar as i32;
3904 let name = str_check_name(ls, state)?;
3905 new_local_var(ls, state, name)?;
3906 adjust_local_vars(ls, state, 1)?; let line = ls.lastline;
3908 body(ls, state, &mut b, false, line)?;
3909 let pc = ls.fs.as_ref().unwrap().pc;
3910 Ok(())
3912}
3913
3914fn getlocalattribute(ls: &mut LexState, state: &mut LuaState) -> Result<VarKind, LuaError> {
3916 if test_next(ls, state, b'<' as TokenKind)? {
3917 let attr_name = str_check_name(ls, state)?;
3918 check_next(ls, state, b'>' as TokenKind)?;
3919 let bytes = attr_name.as_bytes();
3920 if bytes == b"const" {
3921 return Ok(VarKind::Const);
3922 } else if bytes == b"close" {
3923 return Ok(VarKind::ToBeClosed);
3924 } else {
3925 let name_str = String::from_utf8_lossy(bytes);
3926 return Err(LuaError::syntax(format_args!(
3927 "unknown attribute '{}'", name_str
3928 )));
3929 }
3930 }
3931 Ok(VarKind::Reg)
3932}
3933
3934fn checktoclose(ls: &mut LexState, state: &mut LuaState, level: i32) -> Result<(), LuaError> {
3935 if level != -1 {
3936 marktobeclosed(ls.fs.as_mut().unwrap());
3937 let rl = reg_level(ls, ls.fs.as_ref().unwrap(), level);
3938 let line = ls.lastline;
3939 let inst = lua_code::opcodes::Instruction::abck(
3940 lua_code::opcodes::OpCode::Tbc,
3941 rl as u32,
3942 0,
3943 0,
3944 0,
3945 );
3946 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
3947 }
3948 Ok(())
3949}
3950
3951fn localstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3952 let mut toclose: i32 = -1;
3953 let mut nvars: i32 = 0;
3954 let mut vidx = 0i32;
3955 loop {
3956 let name = str_check_name(ls, state)?;
3957 vidx = new_local_var(ls, state, name)?;
3958 let kind = getlocalattribute(ls, state)?;
3959 get_local_var_desc_mut(ls, ls.fs.as_ref().unwrap().firstlocal, vidx).kind = kind;
3960 if kind == VarKind::ToBeClosed {
3961 if toclose != -1 {
3962 return Err(LuaError::syntax(format_args!(
3963 "multiple to-be-closed variables in local list"
3964 )));
3965 }
3966 toclose = ls.fs.as_ref().unwrap().nactvar as i32 + nvars;
3967 }
3968 nvars += 1;
3969 if !test_next(ls, state, b',' as TokenKind)? {
3970 break;
3971 }
3972 }
3973 let nexps: i32;
3974 let mut e = ExprDesc::default();
3975 if test_next(ls, state, b'=' as TokenKind)? {
3976 nexps = explist(ls, state, &mut e)?;
3977 } else {
3978 e.k = ExprKind::Void;
3979 nexps = 0;
3980 }
3981 let first_local = ls.fs.as_ref().unwrap().firstlocal;
3982 let last_vd_kind = ls.dyd.actvar[(first_local + vidx) as usize].kind;
3983 if nvars == nexps
3984 && last_vd_kind == VarKind::Const
3985 {
3986 let is_const = false; if is_const {
3989 ls.dyd.actvar[(first_local + vidx) as usize].kind = VarKind::CompileTimeConst;
3990 adjust_local_vars(ls, state, nvars - 1)?;
3991 ls.fs.as_mut().unwrap().nactvar += 1;
3992 } else {
3993 adjust_assign(ls, state, nvars, nexps, &mut e)?;
3994 adjust_local_vars(ls, state, nvars)?;
3995 }
3996 } else {
3997 adjust_assign(ls, state, nvars, nexps, &mut e)?;
3998 adjust_local_vars(ls, state, nvars)?;
3999 }
4000 checktoclose(ls, state, toclose)?;
4001 Ok(())
4002}
4003
4004fn funcname(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<bool, LuaError> {
4006 let mut ismethod = false;
4007 singlevar(ls, state, v)?;
4008 while ls.t.token == b'.' as TokenKind {
4009 fieldsel(ls, state, v)?;
4010 }
4011 if ls.t.token == b':' as TokenKind {
4012 ismethod = true;
4013 fieldsel(ls, state, v)?;
4014 }
4015 Ok(ismethod)
4016}
4017
4018fn funcstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
4019 lex_next(ls, state)?;
4020 let mut v = ExprDesc::default();
4021 let mut b = ExprDesc::default();
4022 let ismethod = funcname(ls, state, &mut v)?;
4023 body(ls, state, &mut b, ismethod, line)?;
4024 check_readonly(ls, state, &v.clone())?;
4025 let fs = ls.fs.as_mut().unwrap();
4026 cg_storevar(fs, line, &v, &mut b)?;
4027 Ok(())
4029}
4030
4031fn exprstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4032 let mut v_assign = LhsAssign { prev: None, v: ExprDesc::default() };
4033 suffixedexp(ls, state, &mut v_assign.v)?;
4034 if ls.t.token == b'=' as TokenKind || ls.t.token == b',' as TokenKind {
4035 restassign(ls, state, &mut v_assign, 1)?;
4036 } else {
4037 if v_assign.v.k != ExprKind::Call {
4038 return Err(lua_lex::syntax_error(&mut ls.lex, b"syntax error"));
4039 }
4040 let info = v_assign.v.u.info as usize;
4041 let fs = ls.fs.as_mut().unwrap();
4042 let mut lc = lua_code::opcodes::Instruction(fs.f.code[info].0);
4043 lc.set_arg_c(1);
4044 fs.f.code[info] = lua_types::opcode::Instruction::new(lc.0);
4045 }
4046 Ok(())
4047}
4048
4049fn retstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4050 let mut first = {
4051 let fs = ls.fs.as_ref().unwrap();
4052 nvarstack(ls, fs)
4053 };
4054 let mut nret: i32;
4055 if block_follow(ls, true) || ls.t.token == b';' as TokenKind {
4056 nret = 0;
4057 } else {
4058 let mut e = ExprDesc::default();
4059 nret = explist(ls, state, &mut e)?;
4060 if e.k.has_mult_ret() {
4061 cg_set_returns(ls.fs.as_mut().unwrap(), &mut e, LUA_MULTRET);
4062 if e.k == ExprKind::Call && nret == 1 {
4063 let insidetbc = ls.fs.as_ref().unwrap().bl.as_ref().map_or(false, |b| b.insidetbc);
4064 if !insidetbc {
4065 let fs = ls.fs.as_mut().unwrap();
4066 let info = e.u.info as usize;
4067 let mut lc = lua_code::opcodes::Instruction(fs.f.code[info].0);
4068 lc.set_opcode(lua_code::opcodes::OpCode::TailCall);
4069 fs.f.code[info] = lua_types::opcode::Instruction::new(lc.0);
4070 }
4071 }
4072 nret = LUA_MULTRET;
4073 } else {
4074 let line = ls.lastline;
4075 if nret == 1 {
4076 first = cg_exp_to_any_reg(ls.fs.as_mut().unwrap(), line, &mut e)? as i32;
4077 } else {
4078 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut e)?;
4079 }
4080 }
4081 }
4082 let line = ls.lastline;
4083 cg_emit_return(ls.fs.as_mut().unwrap(), line, first, nret);
4084 test_next(ls, state, b';' as TokenKind)?;
4085 Ok(())
4086}
4087
4088fn statement(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4090 let line = ls.linenumber;
4095 enter_level(ls)?;
4096 match ls.t.token {
4097 c if c == b';' as TokenKind => {
4098 lex_next(ls, state)?;
4099 }
4100 TK_IF => {
4101 ifstat(ls, state, line)?;
4102 }
4103 TK_WHILE => {
4104 whilestat(ls, state, line)?;
4105 }
4106 TK_DO => {
4107 lex_next(ls, state)?; block(ls, state)?;
4109 check_match(ls, state, TK_END, TK_DO, line)?;
4110 }
4111 TK_FOR => {
4112 forstat(ls, state, line)?;
4113 }
4114 TK_REPEAT => {
4115 repeatstat(ls, state, line)?;
4116 }
4117 TK_FUNCTION => {
4118 funcstat(ls, state, line)?;
4119 }
4120 TK_LOCAL => {
4121 lex_next(ls, state)?; if test_next(ls, state, TK_FUNCTION)? {
4123 localfunc(ls, state)?;
4124 } else {
4125 localstat(ls, state)?;
4126 }
4127 }
4128 TK_DBCOLON => {
4129 lex_next(ls, state)?; let name = str_check_name(ls, state)?;
4131 labelstat(ls, state, name, line)?;
4132 }
4133 TK_RETURN => {
4134 lex_next(ls, state)?; retstat(ls, state)?;
4136 }
4137 TK_BREAK => {
4138 breakstat(ls, state)?;
4139 }
4140 TK_GOTO => {
4141 lex_next(ls, state)?; gotostat(ls, state)?;
4143 }
4144 _ => {
4145 exprstat(ls, state)?;
4146 }
4147 }
4148 debug_assert!(
4149 ls.fs.as_ref().unwrap().f.maxstacksize >= ls.fs.as_ref().unwrap().freereg
4150 && ls.fs.as_ref().unwrap().freereg as i32
4151 >= nvarstack(ls, ls.fs.as_ref().unwrap())
4152 );
4153 let nv = nvarstack(ls, ls.fs.as_ref().unwrap());
4154 ls.fs.as_mut().unwrap().freereg = nv as u8;
4155 leave_level(ls);
4156 Ok(())
4157}
4158
4159fn mainfunc(ls: &mut LexState, state: &mut LuaState, main_fs: FuncState) -> Result<Box<LuaProto>, LuaError> {
4163 open_func(ls, state, main_fs)?;
4164
4165 setvararg(ls.fs.as_mut().unwrap(), state, 0)?;
4166
4167 let env_name = ls.envn.clone();
4168 {
4169 let idx = alloc_upvalue(ls.fs.as_mut().unwrap())?;
4170 let up = &mut ls.fs.as_mut().unwrap().f.upvalues[idx];
4171 up.instack = true;
4172 up.idx = 0;
4173 up.kind = VarKind::Reg.as_u8();
4174 up.name = env_name.clone();
4175 }
4176
4177 lex_next(ls, state)?;
4178
4179 statlist(ls, state)?;
4180
4181 check(ls, TK_EOS)?;
4182
4183 close_func(ls, state)
4184}
4185
4186pub fn parse(
4194 state: &mut LuaState,
4195 dyd: DynData,
4196 source: &[u8],
4197 name: &[u8],
4198 firstchar: i32,
4199) -> Result<Box<LuaProto>, LuaError> {
4200 let source_str = state.intern_str(name)?;
4201 let envn_str = state.intern_str(lua_lex::LUA_ENV)?;
4202
4203 let rest_bytes: Vec<u8> = source.iter().skip(1).copied().collect();
4204 let z = lua_lex::ZIO::from_bytes(rest_bytes);
4205
4206 let lex_ls = lua_lex::LexState {
4207 current: firstchar,
4208 linenumber: 1,
4209 lastline: 1,
4210 t: lua_lex::Token::eos(),
4211 lookahead: lua_lex::Token::eos(),
4212 fs: None,
4213 z,
4214 buff: lua_lex::LexBuffer::new(),
4215 h: None,
4216 long_str_anchor: std::collections::HashMap::new(),
4217 dyd: None,
4218 source: source_str.clone(),
4219 envn: envn_str.clone(),
4220 };
4221
4222 let mut lexstate = LexState {
4223 current: lex_ls.current,
4224 linenumber: lex_ls.linenumber,
4225 lastline: lex_ls.lastline,
4226 t: LexToken::default(),
4227 lookahead: LexToken::default(),
4228 fs: None,
4229 dyd,
4230 source: Some(source_str.clone()),
4231 envn: Some(lex_ls.envn.clone()),
4232 lex: lex_ls,
4233 recursion_depth: 0,
4234 };
4235 let mut main_proto = Box::new(LuaProto::placeholder());
4240 main_proto.source = Some(source_str);
4241 main_proto.is_vararg = true;
4242 let main_fs = FuncState {
4243 f: main_proto,
4244 prev: None,
4245 bl: None,
4246 pc: 0,
4247 lasttarget: 0,
4248 previousline: 0,
4249 nk: 0,
4250 np: 0,
4251 nabslineinfo: 0,
4252 firstlocal: 0,
4253 firstlabel: 0,
4254 ndebugvars: 0,
4255 nactvar: 0,
4256 nups: 0,
4257 freereg: 0,
4258 iwthabs: 0,
4259 needclose: false,
4260 last_token_line: 0,
4261 };
4262
4263 mainfunc(&mut lexstate, state, main_fs)
4264}
4265
4266fn local_token_value(v: &lua_lex::TokenValue) -> TokenValue {
4271 match v {
4272 lua_lex::TokenValue::None => TokenValue::default(),
4273 lua_lex::TokenValue::Float(r) => TokenValue { r: *r, i: 0, ts: None },
4274 lua_lex::TokenValue::Int(i) => TokenValue { r: 0.0, i: *i, ts: None },
4275 lua_lex::TokenValue::Str(s) => TokenValue { r: 0.0, i: 0, ts: Some(s.clone()) },
4276 }
4277}
4278
4279