1use lua_types::{AbsLineInfo, GcRef, LuaError, LuaString, LuaValue, LuaProto, UpvalDesc, LocalVar};
24
25pub type TokenKind = i32;
34pub const TK_AND: TokenKind = 257;
35pub const TK_BREAK: TokenKind = 258;
36pub const TK_DO: TokenKind = 259;
37pub const TK_ELSE: TokenKind = 260;
38pub const TK_ELSEIF: TokenKind = 261;
39pub const TK_END: TokenKind = 262;
40pub const TK_FALSE: TokenKind = 263;
41pub const TK_FOR: TokenKind = 264;
42pub const TK_FUNCTION: TokenKind = 265;
43pub const TK_GOTO: TokenKind = 266;
44pub const TK_IF: TokenKind = 267;
45pub const TK_IN: TokenKind = 268;
46pub const TK_LOCAL: TokenKind = 269;
47pub const TK_NIL: TokenKind = 270;
48pub const TK_NOT: TokenKind = 271;
49pub const TK_OR: TokenKind = 272;
50pub const TK_REPEAT: TokenKind = 273;
51pub const TK_RETURN: TokenKind = 274;
52pub const TK_THEN: TokenKind = 275;
53pub const TK_TRUE: TokenKind = 276;
54pub const TK_UNTIL: TokenKind = 277;
55pub const TK_WHILE: TokenKind = 278;
56pub const TK_IDIV: TokenKind = 279;
57pub const TK_CONCAT: TokenKind = 280;
58pub const TK_DOTS: TokenKind = 281;
59pub const TK_EQ: TokenKind = 282;
60pub const TK_GE: TokenKind = 283;
61pub const TK_LE: TokenKind = 284;
62pub const TK_NE: TokenKind = 285;
63pub const TK_SHL: TokenKind = 286;
64pub const TK_SHR: TokenKind = 287;
65pub const TK_DBCOLON: TokenKind = 288;
66pub const TK_EOS: TokenKind = 289;
67pub const TK_FLT: TokenKind = 290;
68pub const TK_INT: TokenKind = 291;
69pub const TK_NAME: TokenKind = 292;
70pub const TK_STRING: TokenKind = 293;
71
72const MAX_VARS: i32 = 200;
76
77const NO_JUMP: i32 = -1;
79
80const UNARY_PRIORITY: i32 = 12;
82
83const LUA_MULTRET: i32 = -1;
85
86const MAX_UPVAL: u8 = 255;
88
89const MAXARG_BX: i32 = (1 << 17) - 1;
92
93const LFIELDS_PER_FLUSH: i32 = 50;
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101#[repr(u8)]
102pub enum VarKind {
103 Reg = 0,
105 Const = 1,
107 ToBeClosed = 2,
109 CompileTimeConst = 3,
111}
112
113impl VarKind {
114 pub fn from_u8(v: u8) -> Self {
115 match v {
116 0 => VarKind::Reg,
117 1 => VarKind::Const,
118 2 => VarKind::ToBeClosed,
119 3 => VarKind::CompileTimeConst,
120 _ => VarKind::Reg,
121 }
122 }
123 pub fn as_u8(self) -> u8 { self as u8 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub enum ExprKind {
132 Void, Nil, True, False, K, KFlt, KInt, KStr, NonReloc, Local, UpVal, Const, Indexed, IndexUp, IndexI, IndexStr, Jmp, Reloc, Call, VarArg, }
153
154impl ExprKind {
155 #[inline]
157 pub fn has_mult_ret(self) -> bool {
158 matches!(self, ExprKind::Call | ExprKind::VarArg)
159 }
160
161 #[inline]
163 pub fn is_var(self) -> bool {
164 matches!(
165 self,
166 ExprKind::Local
167 | ExprKind::UpVal
168 | ExprKind::Const
169 | ExprKind::Indexed
170 | ExprKind::IndexUp
171 | ExprKind::IndexI
172 | ExprKind::IndexStr
173 )
174 }
175
176 #[inline]
178 pub fn is_indexed(self) -> bool {
179 matches!(
180 self,
181 ExprKind::Indexed | ExprKind::IndexUp | ExprKind::IndexI | ExprKind::IndexStr
182 )
183 }
184}
185
186#[derive(Debug, Clone, Default)]
192pub struct ExprPayload {
193 pub ival: i64,
195 pub nval: f64,
197 pub strval: Option<GcRef<LuaString>>,
199 pub info: i32,
201 pub ind_idx: i16,
203 pub ind_t: u8,
205 pub var_ridx: u8,
207 pub var_vidx: u16,
209}
210
211#[derive(Debug, Clone)]
216pub struct ExprDesc {
217 pub k: ExprKind,
218 pub u: ExprPayload,
219 pub t: i32,
221 pub f: i32,
223}
224
225impl Default for ExprDesc {
226 fn default() -> Self {
227 ExprDesc { k: ExprKind::Void, u: ExprPayload::default(), t: NO_JUMP, f: NO_JUMP }
228 }
229}
230
231#[derive(Debug, Clone)]
238pub struct VarDesc {
239 pub kind: VarKind,
241 pub ridx: u8,
243 pub pidx: i16,
245 pub name: Option<GcRef<LuaString>>,
247 pub const_val: LuaValue,
249}
250
251impl Default for VarDesc {
252 fn default() -> Self {
253 VarDesc {
254 kind: VarKind::Reg,
255 ridx: 0,
256 pidx: 0,
257 name: None,
258 const_val: LuaValue::Nil,
259 }
260 }
261}
262
263#[derive(Debug, Clone)]
267pub struct LabelDesc {
268 pub name: Option<GcRef<LuaString>>,
270 pub pc: i32,
272 pub line: i32,
274 pub nactvar: u8,
276 pub close: bool,
278}
279
280#[derive(Debug, Default)]
285pub struct DynData {
286 pub actvar: Vec<VarDesc>,
288 pub gt: Vec<LabelDesc>,
290 pub label: Vec<LabelDesc>,
292}
293
294#[derive(Debug)]
300pub struct BlockCnt {
301 pub previous: Option<Box<BlockCnt>>,
303 pub firstlabel: i32,
305 pub firstgoto: i32,
307 pub nactvar: u8,
309 pub upval: bool,
311 pub isloop: bool,
313 pub insidetbc: bool,
315}
316
317#[derive(Debug)]
323pub struct FuncState {
324 pub f: Box<LuaProto>,
329 pub prev: Option<Box<FuncState>>,
331 pub bl: Option<Box<BlockCnt>>,
333 pub pc: i32,
335 pub lasttarget: i32,
337 pub previousline: i32,
339 pub nk: i32,
341 pub np: i32,
343 pub nabslineinfo: i32,
345 pub firstlocal: i32,
347 pub firstlabel: i32,
349 pub ndebugvars: i16,
351 pub nactvar: u8,
353 pub nups: u8,
355 pub freereg: u8,
357 pub iwthabs: u8,
359 pub needclose: bool,
361 pub last_token_line: i32,
367}
368
369#[derive(Debug)]
376pub struct ConsControl {
377 pub v: ExprDesc,
379 pub t: ExprDesc,
381 pub nh: i32,
383 pub na: i32,
385 pub tostore: i32,
387}
388
389#[derive(Debug)]
394pub struct LhsAssign {
395 pub prev: Option<Box<LhsAssign>>,
397 pub v: ExprDesc,
399}
400
401#[derive(Debug, Clone, Copy, PartialEq, Eq)]
407pub enum UnOpr {
408 Minus, BNot, Not, Len, NoUnOpr, }
414
415#[derive(Debug, Clone, Copy, PartialEq, Eq)]
417pub enum BinOpr {
418 Add, Sub, Mul, Mod, Pow, Div, IDiv, BAnd, BOr, BXor, Shl, Shr, Concat, Eq, Lt, Le, Ne, Gt, Ge, And, Or, NoBinOpr, }
441
442const PRIORITY: [(u8, u8); 21] = [
445 (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), ];
456
457pub use lua_code::opcodes::OpCode;
459
460#[derive(Debug, Clone, Default)]
468pub struct TokenValue {
469 pub r: f64,
471 pub i: i64,
473 pub ts: Option<GcRef<LuaString>>,
475}
476
477#[derive(Debug, Clone, Default)]
479pub struct LexToken {
480 pub token: TokenKind,
481 pub seminfo: TokenValue,
482}
483
484pub struct LexState {
490 pub current: i32,
492 pub linenumber: i32,
494 pub lastline: i32,
496 pub t: LexToken,
498 pub lookahead: LexToken,
500 pub fs: Option<Box<FuncState>>,
502 pub dyd: DynData,
504 pub source: Option<GcRef<LuaString>>,
506 pub envn: Option<GcRef<LuaString>>,
508 pub lex: lua_lex::LexState,
513 pub recursion_depth: u32,
515}
516
517const PARSER_MAX_C_CALLS: u32 = 200;
518
519fn enter_level(ls: &mut LexState) -> Result<(), LuaError> {
520 ls.recursion_depth += 1;
521 if ls.recursion_depth >= PARSER_MAX_C_CALLS {
522 Err(LuaError::syntax(format_args!("C stack overflow")))
523 } else {
524 Ok(())
525 }
526}
527
528fn leave_level(ls: &mut LexState) {
529 ls.recursion_depth = ls.recursion_depth.saturating_sub(1);
530}
531
532fn lex_next(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
536 lua_lex::next(state, &mut ls.lex)?;
537 sync_from_lex(ls);
538 Ok(())
539}
540
541fn lex_lookahead(ls: &mut LexState, state: &mut LuaState) -> Result<TokenKind, LuaError> {
544 let kind = lua_lex::lookahead(state, &mut ls.lex)?;
545 sync_from_lex(ls);
546 Ok(kind)
547}
548
549fn sync_from_lex(ls: &mut LexState) {
552 ls.current = ls.lex.current;
553 ls.linenumber = ls.lex.linenumber;
554 ls.lastline = ls.lex.lastline;
555 ls.t = LexToken {
556 token: ls.lex.t.kind,
557 seminfo: local_token_value(&ls.lex.t.value),
558 };
559 ls.lookahead = LexToken {
560 token: ls.lex.lookahead.kind,
561 seminfo: local_token_value(&ls.lex.lookahead.value),
562 };
563 if let Some(fs) = ls.fs.as_mut() {
567 fs.last_token_line = ls.lastline;
568 }
569}
570
571pub use lua_vm::state::LuaState;
573
574fn emit_inst(fs: &mut FuncState, line: i32, inst: lua_code::opcodes::Instruction) -> i32 {
590 const MAX_IWTH_ABS: i32 = 128;
591 const LIM_LINE_DIFF: i32 = 0x80;
592 const ABS_LINE_INFO: i8 = -0x80i8;
593 let pc = fs.pc as usize;
594 if fs.f.code.len() <= pc {
595 fs.f.code.resize(pc + 1, lua_types::opcode::Instruction::default());
596 }
597 fs.f.code[pc] = lua_types::opcode::Instruction::new(inst.0);
598 if fs.f.lineinfo.len() <= pc {
599 fs.f.lineinfo.resize(pc + 1, 0i8);
600 }
601 let linedif_raw = line - fs.previousline;
602 let need_abs = linedif_raw.abs() >= LIM_LINE_DIFF || {
603 let over = fs.iwthabs as i32 >= MAX_IWTH_ABS;
604 if !over { fs.iwthabs += 1; }
605 over
606 };
607 if need_abs {
608 fs.f.abslineinfo.push(AbsLineInfo { pc: pc as i32, line });
609 fs.nabslineinfo += 1;
610 fs.f.lineinfo[pc] = ABS_LINE_INFO;
611 fs.iwthabs = 1;
612 } else {
613 fs.f.lineinfo[pc] = linedif_raw as i8;
614 }
615 fs.previousline = line;
616 let result = fs.pc;
617 fs.pc += 1;
618 result
619}
620
621fn add_k_value(fs: &mut FuncState, v: LuaValue) -> i32 {
622 let idx = fs.nk;
623 if (fs.f.k.len() as i32) <= idx {
624 fs.f.k.resize((idx + 1) as usize, LuaValue::Nil);
625 }
626 fs.f.k[idx as usize] = v;
627 fs.nk += 1;
628 idx
629}
630
631fn add_k_string(fs: &mut FuncState, s: GcRef<LuaString>) -> i32 {
632 for (i, k) in fs.f.k.iter().take(fs.nk as usize).enumerate() {
633 if let LuaValue::Str(existing) = k {
634 if GcRef::ptr_eq(existing, &s) {
635 return i as i32;
636 }
637 }
638 }
639 add_k_value(fs, LuaValue::Str(s))
640}
641
642fn bump_maxstack(fs: &mut FuncState, n: u8) {
643 if fs.f.maxstacksize < n {
644 fs.f.maxstacksize = n;
645 }
646}
647
648fn reserve_reg(fs: &mut FuncState) -> Result<u8, LuaError> {
649 if fs.freereg == u8::MAX {
650 return Err(LuaError::syntax(format_args!(
651 "function or expression needs too many registers"
652 )));
653 }
654 let r = fs.freereg;
655 fs.freereg += 1;
656 bump_maxstack(fs, fs.freereg);
657 Ok(r)
658}
659
660fn reserve_regs(fs: &mut FuncState, n: i32) -> Result<(), LuaError> {
661 let newstack = fs.freereg as i32 + n;
662 if newstack >= 255 {
663 return Err(LuaError::syntax(format_args!(
664 "function or expression needs too many registers"
665 )));
666 }
667 fs.freereg = newstack as u8;
668 bump_maxstack(fs, fs.freereg);
669 Ok(())
670}
671
672fn cg_free_reg(fs: &mut FuncState, reg: i32) {
678 if reg >= fs.nactvar as i32 {
679 debug_assert_eq!(reg, fs.freereg as i32 - 1);
680 fs.freereg = fs.freereg.saturating_sub(1);
681 }
682}
683
684fn cg_free_exp(fs: &mut FuncState, e: &ExprDesc) {
689 if e.k == ExprKind::NonReloc {
690 cg_free_reg(fs, e.u.info);
691 }
692}
693
694fn cg_free_exps(fs: &mut FuncState, e1: &ExprDesc, e2: &ExprDesc) {
699 let r1 = if e1.k == ExprKind::NonReloc { e1.u.info } else { -1 };
700 let r2 = if e2.k == ExprKind::NonReloc { e2.u.info } else { -1 };
701 if r1 > r2 {
702 cg_free_reg(fs, r1);
703 cg_free_reg(fs, r2);
704 } else {
705 cg_free_reg(fs, r2);
706 cg_free_reg(fs, r1);
707 }
708}
709
710fn cg_posfix_fold(
721 fs: &mut FuncState,
722 op: BinOpr,
723 e1: &mut ExprDesc,
724 e2: &mut ExprDesc,
725 line: i32,
726) -> Result<(), LuaError> {
727 let rhs_line = fs.last_token_line;
733 cg_discharge_vars(fs, rhs_line, e2)?;
734
735 let promote = |k: ExprKind, u: &ExprPayload| -> Option<f64> {
736 match k {
737 ExprKind::KInt => Some(u.ival as f64),
738 ExprKind::KFlt => Some(u.nval),
739 _ => None,
740 }
741 };
742
743 let foldable = e1.t == NO_JUMP && e1.f == NO_JUMP
744 && e2.t == NO_JUMP && e2.f == NO_JUMP;
745
746 if foldable {
747 if let (ExprKind::KInt, ExprKind::KInt) = (e1.k, e2.k) {
748 let a = e1.u.ival;
749 let b = e2.u.ival;
750 let r: Option<i64> = match op {
751 BinOpr::Add => Some(a.wrapping_add(b)),
752 BinOpr::Sub => Some(a.wrapping_sub(b)),
753 BinOpr::Mul => Some(a.wrapping_mul(b)),
754 BinOpr::Mod if b != 0 => Some(a.rem_euclid(b)),
755 BinOpr::IDiv if b != 0 => Some(a.div_euclid(b)),
756 BinOpr::BAnd => Some(a & b),
757 BinOpr::BOr => Some(a | b),
758 BinOpr::BXor => Some(a ^ b),
759 _ => None,
760 };
761 if let Some(v) = r {
762 e1.k = ExprKind::KInt;
763 e1.u.ival = v;
764 return Ok(());
765 }
766 }
767 if let (Some(a), Some(b)) = (promote(e1.k, &e1.u), promote(e2.k, &e2.u)) {
768 let r: Option<f64> = match op {
769 BinOpr::Add => Some(a + b),
770 BinOpr::Sub => Some(a - b),
771 BinOpr::Mul => Some(a * b),
772 BinOpr::Div => Some(a / b),
773 BinOpr::Pow => Some(a.powf(b)),
774 _ => None,
775 };
776 if let Some(v) = r {
777 if v.is_finite() {
778 e1.k = ExprKind::KFlt;
779 e1.u.nval = v;
780 return Ok(());
781 }
782 }
783 }
784 }
785
786 if matches!(op, BinOpr::Lt | BinOpr::Le) {
787 return cg_emit_order(fs, op, e1, e2, line);
788 }
789
790 if matches!(op, BinOpr::Gt | BinOpr::Ge) {
791 let swap_op = if matches!(op, BinOpr::Gt) { BinOpr::Lt } else { BinOpr::Le };
792 std::mem::swap(e1, e2);
793 return cg_emit_order(fs, swap_op, e1, e2, line);
794 }
795
796 if matches!(op, BinOpr::Eq | BinOpr::Ne) {
797 return cg_emit_eq(fs, op, e1, e2, line);
798 }
799
800 if matches!(op, BinOpr::And) {
801 debug_assert_eq!(e1.t, NO_JUMP);
802 cg_concat(fs, &mut e2.f, e1.f)?;
803 *e1 = e2.clone();
804 return Ok(());
805 }
806
807 if matches!(op, BinOpr::Or) {
808 debug_assert_eq!(e1.f, NO_JUMP);
809 cg_concat(fs, &mut e2.t, e1.t)?;
810 *e1 = e2.clone();
811 return Ok(());
812 }
813
814 if matches!(op, BinOpr::Concat) {
815 return cg_emit_concat(fs, e1, e2, line);
816 }
817
818 let (opcode, event) = match op {
819 BinOpr::Add => (lua_code::opcodes::OpCode::Add, lua_types::tagmethod::TagMethod::Add),
820 BinOpr::Sub => (lua_code::opcodes::OpCode::Sub, lua_types::tagmethod::TagMethod::Sub),
821 BinOpr::Mul => (lua_code::opcodes::OpCode::Mul, lua_types::tagmethod::TagMethod::Mul),
822 BinOpr::Mod => (lua_code::opcodes::OpCode::Mod, lua_types::tagmethod::TagMethod::Mod),
823 BinOpr::Pow => (lua_code::opcodes::OpCode::Pow, lua_types::tagmethod::TagMethod::Pow),
824 BinOpr::Div => (lua_code::opcodes::OpCode::Div, lua_types::tagmethod::TagMethod::Div),
825 BinOpr::IDiv => (lua_code::opcodes::OpCode::IDiv, lua_types::tagmethod::TagMethod::Idiv),
826 BinOpr::BAnd => (lua_code::opcodes::OpCode::BAnd, lua_types::tagmethod::TagMethod::Band),
827 BinOpr::BOr => (lua_code::opcodes::OpCode::BOr, lua_types::tagmethod::TagMethod::Bor),
828 BinOpr::BXor => (lua_code::opcodes::OpCode::BXor, lua_types::tagmethod::TagMethod::Bxor),
829 BinOpr::Shl => (lua_code::opcodes::OpCode::Shl, lua_types::tagmethod::TagMethod::Shl),
830 BinOpr::Shr => (lua_code::opcodes::OpCode::Shr, lua_types::tagmethod::TagMethod::Shr),
831 _ => todo!(
832 "phase-b: cg_posfix_fold non-foldable binop {:?} ({:?} {:?})",
833 op, e1.k, e2.k
834 ),
835 };
836
837 cg_discharge_vars(fs, line, e1)?;
838 cg_discharge_vars(fs, line, e2)?;
839 let v2 = cg_exp_to_any_reg(fs, line, e2)?;
840 let v1 = cg_exp_to_any_reg(fs, line, e1)?;
841
842 let inst = lua_code::opcodes::Instruction::abck(opcode, 0, v1 as u32, v2 as u32, 0);
843 let pc = emit_inst(fs, line, inst);
844 cg_free_exps(fs, e1, e2);
845 e1.u.info = pc;
846 e1.k = ExprKind::Reloc;
847
848 let mm_inst = lua_code::opcodes::Instruction::abck(
849 lua_code::opcodes::OpCode::MmBin,
850 v1 as u32,
851 v2 as u32,
852 event as u32,
853 0,
854 );
855 emit_inst(fs, line, mm_inst);
856 Ok(())
857}
858
859fn cg_emit_order(
868 fs: &mut FuncState,
869 op: BinOpr,
870 e1: &mut ExprDesc,
871 e2: &mut ExprDesc,
872 line: i32,
873) -> Result<(), LuaError> {
874 debug_assert!(matches!(op, BinOpr::Lt | BinOpr::Le));
875 let is_le = matches!(op, BinOpr::Le);
876 let (op_imm_e2, op_imm_e1, op_reg) = if is_le {
877 (
878 lua_code::opcodes::OpCode::LeI,
879 lua_code::opcodes::OpCode::GeI,
880 lua_code::opcodes::OpCode::Le,
881 )
882 } else {
883 (
884 lua_code::opcodes::OpCode::LtI,
885 lua_code::opcodes::OpCode::GtI,
886 lua_code::opcodes::OpCode::Lt,
887 )
888 };
889 let (r1, r2, cmp_op) = if let Some(im) = cg_sc_int(e2) {
890 let r1 = cg_exp_to_any_reg(fs, line, e1)?;
891 (r1, im, op_imm_e2)
892 } else if let Some(im) = cg_sc_int(e1) {
893 let r1 = cg_exp_to_any_reg(fs, line, e2)?;
894 (r1, im, op_imm_e1)
895 } else {
896 let r2 = cg_exp_to_any_reg(fs, line, e2)?;
897 let r1 = cg_exp_to_any_reg(fs, line, e1)?;
898 (r1, r2, op_reg)
899 };
900 cg_free_exps(fs, e1, e2);
901 let cmp = lua_code::opcodes::Instruction::abck(
902 cmp_op,
903 r1 as u32,
904 r2 as u32,
905 0,
906 1,
907 );
908 emit_inst(fs, line, cmp);
909 let jmp_arg = (NO_JUMP + lua_code::opcodes::OFFSET_S_J) as u32;
910 let jmp = lua_code::opcodes::Instruction::sj(
911 lua_code::opcodes::OpCode::Jmp,
912 jmp_arg,
913 0,
914 );
915 let jmp_pc = emit_inst(fs, line, jmp);
916 e1.u.info = jmp_pc;
917 e1.k = ExprKind::Jmp;
918 Ok(())
919}
920
921fn cg_emit_eq(
931 fs: &mut FuncState,
932 op: BinOpr,
933 e1: &mut ExprDesc,
934 e2: &mut ExprDesc,
935 line: i32,
936) -> Result<(), LuaError> {
937 debug_assert!(matches!(op, BinOpr::Eq | BinOpr::Ne));
938 if e1.k != ExprKind::NonReloc {
939 std::mem::swap(e1, e2);
940 }
941 let r1 = cg_exp_to_any_reg(fs, line, e1)?;
942 let (r2, cmp_op) = if let Some(im) = cg_sc_int(e2) {
943 (im, lua_code::opcodes::OpCode::EqI)
944 } else {
945 let r = cg_exp_to_any_reg(fs, line, e2)?;
946 (r, lua_code::opcodes::OpCode::Eq)
947 };
948 cg_free_exps(fs, e1, e2);
949 let k_bit = if matches!(op, BinOpr::Eq) { 1 } else { 0 };
950 let cmp = lua_code::opcodes::Instruction::abck(
951 cmp_op,
952 r1 as u32,
953 r2 as u32,
954 0,
955 k_bit,
956 );
957 emit_inst(fs, line, cmp);
958 let jmp_pc = cg_jump(fs, line);
959 e1.u.info = jmp_pc;
960 e1.k = ExprKind::Jmp;
961 Ok(())
962}
963
964fn previous_instruction_idx(fs: &FuncState) -> Option<usize> {
969 if fs.pc > fs.lasttarget {
970 Some((fs.pc - 1) as usize)
971 } else {
972 None
973 }
974}
975
976fn cg_emit_concat(
985 fs: &mut FuncState,
986 e1: &mut ExprDesc,
987 e2: &mut ExprDesc,
988 line: i32,
989) -> Result<(), LuaError> {
990 cg_exp_to_next_reg(fs, line, e2)?;
991
992 if let Some(prev_idx) = previous_instruction_idx(fs) {
993 let prev = lua_code::opcodes::Instruction(fs.f.code[prev_idx].0);
994 if prev.opcode() == Some(lua_code::opcodes::OpCode::Concat) {
995 let n = prev.arg_b();
996 debug_assert_eq!(e1.u.info + 1, prev.arg_a() as i32);
997 cg_free_exp(fs, e2);
998 let mut updated = prev;
999 updated.set_arg_a(e1.u.info as u32);
1000 updated.set_arg_b(n + 1);
1001 fs.f.code[prev_idx] = lua_types::opcode::Instruction::new(updated.0);
1002 return Ok(());
1003 }
1004 }
1005
1006 let inst = lua_code::opcodes::Instruction::abck(
1007 lua_code::opcodes::OpCode::Concat,
1008 e1.u.info as u32,
1009 2,
1010 0,
1011 0,
1012 );
1013 emit_inst(fs, line, inst);
1014 cg_free_exp(fs, e2);
1015 Ok(())
1016}
1017
1018fn cg_prefix(
1027 fs: &mut FuncState,
1028 op: UnOpr,
1029 e: &mut ExprDesc,
1030 line: i32,
1031) -> Result<(), LuaError> {
1032 cg_discharge_vars(fs, line, e)?;
1033 let opcode = match op {
1034 UnOpr::Minus => lua_code::opcodes::OpCode::Unm,
1035 UnOpr::BNot => lua_code::opcodes::OpCode::BNot,
1036 UnOpr::Len => lua_code::opcodes::OpCode::Len,
1037 UnOpr::Not => return cg_codenot(fs, line, e),
1038 UnOpr::NoUnOpr => return Ok(()),
1039 };
1040 let r = cg_exp_to_any_reg(fs, line, e)?;
1041 cg_free_exp(fs, e);
1042 let inst = lua_code::opcodes::Instruction::abck(opcode, 0, r as u32, 0, 0);
1043 let pc = emit_inst(fs, line, inst);
1044 e.u.info = pc;
1045 e.k = ExprKind::Reloc;
1046 Ok(())
1047}
1048
1049fn cg_get_jump_control(fs: &FuncState, pc: i32) -> i32 {
1056 if pc >= 1 {
1057 let prev = cg_inst_at(fs, pc - 1);
1058 if let Some(op) = prev.opcode() {
1059 if lua_code::opcodes::test_t_mode(op) {
1060 return pc - 1;
1061 }
1062 }
1063 }
1064 pc
1065}
1066
1067fn cg_patch_test_reg(fs: &mut FuncState, node: i32, reg: u32) -> bool {
1075 let ctrl_pc = cg_get_jump_control(fs, node);
1076 let mut inst = cg_inst_at(fs, ctrl_pc);
1077 if inst.opcode() != Some(lua_code::opcodes::OpCode::TestSet) {
1078 return false;
1079 }
1080 let b = inst.arg_b();
1081 let k = inst.arg_k();
1082 if reg != lua_code::opcodes::NO_REG && reg != b {
1083 inst.set_arg_a(reg);
1084 cg_set_inst_at(fs, ctrl_pc, inst);
1085 } else {
1086 let test = lua_code::opcodes::Instruction::abck(
1087 lua_code::opcodes::OpCode::Test,
1088 b,
1089 0,
1090 0,
1091 k,
1092 );
1093 cg_set_inst_at(fs, ctrl_pc, test);
1094 }
1095 true
1096}
1097
1098fn cg_remove_values(fs: &mut FuncState, list: i32) {
1105 let mut list = list;
1106 while list != NO_JUMP {
1107 let next = cg_get_jump(fs, list);
1108 cg_patch_test_reg(fs, list, lua_code::opcodes::NO_REG);
1109 list = next;
1110 }
1111}
1112
1113fn cg_codenot(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
1121 match e.k {
1122 ExprKind::Nil | ExprKind::False => {
1123 e.k = ExprKind::True;
1124 }
1125 ExprKind::K
1126 | ExprKind::KFlt
1127 | ExprKind::KInt
1128 | ExprKind::KStr
1129 | ExprKind::True => {
1130 e.k = ExprKind::False;
1131 }
1132 ExprKind::Jmp => {
1133 cg_negate_condition(fs, e);
1134 }
1135 ExprKind::Reloc | ExprKind::NonReloc => {
1136 let reg = cg_exp_to_any_reg(fs, line, e)?;
1137 cg_free_exp(fs, e);
1138 let inst = lua_code::opcodes::Instruction::abck(
1139 lua_code::opcodes::OpCode::Not,
1140 0,
1141 reg as u32,
1142 0,
1143 0,
1144 );
1145 let pc = emit_inst(fs, line, inst);
1146 e.u.info = pc;
1147 e.k = ExprKind::Reloc;
1148 }
1149 _ => debug_assert!(false, "cg_codenot: unexpected ExprKind {:?}", e.k),
1150 }
1151 std::mem::swap(&mut e.f, &mut e.t);
1152 cg_remove_values(fs, e.f);
1153 cg_remove_values(fs, e.t);
1154 Ok(())
1155}
1156
1157fn cg_jump(fs: &mut FuncState, line: i32) -> i32 {
1161 let jmp_arg = (NO_JUMP + lua_code::opcodes::OFFSET_S_J) as u32;
1162 let jmp = lua_code::opcodes::Instruction::sj(
1163 lua_code::opcodes::OpCode::Jmp,
1164 jmp_arg,
1165 0,
1166 );
1167 emit_inst(fs, line, jmp)
1168}
1169
1170fn cg_inst_at(fs: &FuncState, pc: i32) -> lua_code::opcodes::Instruction {
1173 lua_code::opcodes::Instruction(fs.f.code[pc as usize].0)
1174}
1175
1176fn cg_set_inst_at(fs: &mut FuncState, pc: i32, inst: lua_code::opcodes::Instruction) {
1179 fs.f.code[pc as usize] = lua_types::opcode::Instruction::new(inst.0);
1180}
1181
1182fn cg_get_jump(fs: &FuncState, pc: i32) -> i32 {
1187 let offset = cg_inst_at(fs, pc).arg_s_j();
1188 if offset == NO_JUMP { NO_JUMP } else { (pc + 1) + offset }
1189}
1190
1191fn cg_fix_jump(fs: &mut FuncState, pc: i32, dest: i32) -> Result<(), LuaError> {
1195 debug_assert!(dest != NO_JUMP);
1196 let offset = dest - (pc + 1);
1197 let max = lua_code::opcodes::MAXARG_S_J as i32 - lua_code::opcodes::OFFSET_S_J;
1198 let min = -lua_code::opcodes::OFFSET_S_J;
1199 if offset < min || offset > max {
1200 return Err(LuaError::syntax(format_args!("control structure too long")));
1201 }
1202 let mut inst = cg_inst_at(fs, pc);
1203 inst.set_arg_s_j(offset);
1204 cg_set_inst_at(fs, pc, inst);
1205 Ok(())
1206}
1207
1208fn cg_get_label(fs: &mut FuncState) -> i32 {
1212 fs.lasttarget = fs.pc;
1213 fs.pc
1214}
1215
1216fn cg_concat(fs: &mut FuncState, l1: &mut i32, l2: i32) -> Result<(), LuaError> {
1220 if l2 == NO_JUMP { return Ok(()); }
1221 if *l1 == NO_JUMP { *l1 = l2; return Ok(()); }
1222 let mut list = *l1;
1223 loop {
1224 let next = cg_get_jump(fs, list);
1225 if next == NO_JUMP { break; }
1226 list = next;
1227 }
1228 cg_fix_jump(fs, list, l2)
1229}
1230
1231fn cg_patch_list(fs: &mut FuncState, list: i32, target: i32) -> Result<(), LuaError> {
1240 cg_patch_list_aux(fs, list, target, lua_code::opcodes::NO_REG, target)
1241}
1242
1243fn cg_patch_to_here(fs: &mut FuncState, list: i32) -> Result<(), LuaError> {
1247 let target = cg_get_label(fs);
1248 cg_patch_list(fs, list, target)
1249}
1250
1251fn cg_negate_condition(fs: &mut FuncState, e: &ExprDesc) {
1257 let pc = e.u.info - 1;
1258 let mut inst = cg_inst_at(fs, pc);
1259 let k = inst.arg_k();
1260 inst.set_arg_k(k ^ 1);
1261 cg_set_inst_at(fs, pc, inst);
1262}
1263
1264fn cg_go_if_true(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
1273 cg_discharge_vars(fs, line, e)?;
1274 let pc: i32 = match e.k {
1275 ExprKind::Jmp => {
1276 cg_negate_condition(fs, e);
1277 e.u.info
1278 }
1279 ExprKind::K | ExprKind::KFlt | ExprKind::KInt | ExprKind::KStr | ExprKind::True => {
1280 NO_JUMP
1281 }
1282 _ => cg_jump_on_cond(fs, line, e, 0)?,
1283 };
1284 cg_concat(fs, &mut e.f, pc)?;
1285 cg_patch_to_here(fs, e.t)?;
1286 e.t = NO_JUMP;
1287 Ok(())
1288}
1289
1290fn cg_go_if_false(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
1297 cg_discharge_vars(fs, line, e)?;
1298 let pc: i32 = match e.k {
1299 ExprKind::Jmp => e.u.info,
1300 ExprKind::Nil | ExprKind::False => NO_JUMP,
1301 _ => cg_jump_on_cond(fs, line, e, 1)?,
1302 };
1303 cg_concat(fs, &mut e.t, pc)?;
1304 cg_patch_to_here(fs, e.f)?;
1305 e.f = NO_JUMP;
1306 Ok(())
1307}
1308
1309fn cg_jump_on_cond(
1319 fs: &mut FuncState,
1320 line: i32,
1321 e: &mut ExprDesc,
1322 cond: u8,
1323) -> Result<i32, LuaError> {
1324 let reg = cg_exp_to_any_reg(fs, line, e)?;
1325 cg_free_exp(fs, e);
1326 let test = lua_code::opcodes::Instruction::abck(
1327 lua_code::opcodes::OpCode::TestSet,
1328 lua_code::opcodes::NO_REG,
1329 reg as u32,
1330 0,
1331 cond as u32,
1332 );
1333 emit_inst(fs, line, test);
1334 Ok(cg_jump(fs, line))
1335}
1336
1337fn cg_infix(
1350 fs: &mut FuncState,
1351 op: BinOpr,
1352 v: &mut ExprDesc,
1353 line: i32,
1354) -> Result<(), LuaError> {
1355 match op {
1356 BinOpr::And => cg_go_if_true(fs, line, v),
1357 BinOpr::Or => cg_go_if_false(fs, line, v),
1358 BinOpr::Concat => cg_exp_to_next_reg(fs, line, v),
1359 BinOpr::Add | BinOpr::Sub | BinOpr::Mul | BinOpr::Div | BinOpr::IDiv
1360 | BinOpr::Mod | BinOpr::Pow
1361 | BinOpr::BAnd | BinOpr::BOr | BinOpr::BXor
1362 | BinOpr::Shl | BinOpr::Shr
1363 | BinOpr::Eq | BinOpr::Ne
1364 | BinOpr::Lt | BinOpr::Le | BinOpr::Gt | BinOpr::Ge => {
1365 if matches!(v.k, ExprKind::KInt | ExprKind::KFlt)
1366 && v.t == NO_JUMP && v.f == NO_JUMP
1367 {
1368 cg_discharge_vars(fs, line, v)
1369 } else {
1370 cg_exp_to_any_reg(fs, line, v).map(|_| ())
1371 }
1372 }
1373 _ => cg_discharge_vars(fs, line, v),
1374 }
1375}
1376
1377fn cg_sc_int(e: &ExprDesc) -> Option<u8> {
1383 if !matches!(e.k, ExprKind::KInt) {
1384 return None;
1385 }
1386 if e.t != NO_JUMP || e.f != NO_JUMP {
1387 return None;
1388 }
1389 let biased = (e.u.ival as u64).wrapping_add(lua_code::opcodes::OFFSET_S_C as u64);
1390 if biased <= lua_code::opcodes::MAXARG_C as u64 {
1391 Some(biased as u8)
1392 } else {
1393 None
1394 }
1395}
1396
1397fn cg_exp_to_any_reg(
1401 fs: &mut FuncState,
1402 line: i32,
1403 e: &mut ExprDesc,
1404) -> Result<u8, LuaError> {
1405 cg_discharge_vars(fs, line, e)?;
1406 if e.k == ExprKind::NonReloc {
1407 if e.t == NO_JUMP && e.f == NO_JUMP {
1408 return Ok(e.u.info as u8);
1409 }
1410 if e.u.info >= fs.nactvar as i32 {
1411 cg_exp_to_reg(fs, line, e, e.u.info as u8)?;
1412 return Ok(e.u.info as u8);
1413 }
1414 }
1415 cg_exp_to_next_reg(fs, line, e)?;
1416 Ok(e.u.info as u8)
1417}
1418
1419fn cg_discharge_vars(
1423 fs: &mut FuncState,
1424 line: i32,
1425 e: &mut ExprDesc,
1426) -> Result<(), LuaError> {
1427 match e.k {
1428 ExprKind::Local => {
1429 e.u.info = e.u.var_ridx as i32;
1430 e.k = ExprKind::NonReloc;
1431 }
1432 ExprKind::UpVal => {
1433 let inst = lua_code::opcodes::Instruction::abck(
1434 lua_code::opcodes::OpCode::GetUpVal,
1435 0,
1436 e.u.info as u32,
1437 0,
1438 0,
1439 );
1440 let pc = emit_inst(fs, line, inst);
1441 e.u.info = pc;
1442 e.k = ExprKind::Reloc;
1443 }
1444 ExprKind::IndexUp => {
1445 let inst = lua_code::opcodes::Instruction::abck(
1446 lua_code::opcodes::OpCode::GetTabUp,
1447 0,
1448 e.u.ind_t as u32,
1449 e.u.ind_idx as u32,
1450 0,
1451 );
1452 let pc = emit_inst(fs, line, inst);
1453 e.u.info = pc;
1454 e.k = ExprKind::Reloc;
1455 }
1456 ExprKind::IndexI => {
1457 cg_free_reg_if_temp(fs, e.u.ind_t as i32);
1458 let inst = lua_code::opcodes::Instruction::abck(
1459 lua_code::opcodes::OpCode::GetI,
1460 0,
1461 e.u.ind_t as u32,
1462 e.u.ind_idx as u32,
1463 0,
1464 );
1465 let pc = emit_inst(fs, line, inst);
1466 e.u.info = pc;
1467 e.k = ExprKind::Reloc;
1468 }
1469 ExprKind::IndexStr => {
1470 cg_free_reg_if_temp(fs, e.u.ind_t as i32);
1471 let inst = lua_code::opcodes::Instruction::abck(
1472 lua_code::opcodes::OpCode::GetField,
1473 0,
1474 e.u.ind_t as u32,
1475 e.u.ind_idx as u32,
1476 0,
1477 );
1478 let pc = emit_inst(fs, line, inst);
1479 e.u.info = pc;
1480 e.k = ExprKind::Reloc;
1481 }
1482 ExprKind::Indexed => {
1483 let t_reg = e.u.ind_t as i32;
1484 let idx_reg = e.u.ind_idx as i32;
1485 if idx_reg > t_reg {
1486 cg_free_reg_if_temp(fs, idx_reg);
1487 cg_free_reg_if_temp(fs, t_reg);
1488 } else {
1489 cg_free_reg_if_temp(fs, t_reg);
1490 cg_free_reg_if_temp(fs, idx_reg);
1491 }
1492 let inst = lua_code::opcodes::Instruction::abck(
1493 lua_code::opcodes::OpCode::GetTable,
1494 0,
1495 e.u.ind_t as u32,
1496 e.u.ind_idx as u32,
1497 0,
1498 );
1499 let pc = emit_inst(fs, line, inst);
1500 e.u.info = pc;
1501 e.k = ExprKind::Reloc;
1502 }
1503 ExprKind::VarArg | ExprKind::Call => {
1504 cg_set_one_ret(fs, e);
1505 }
1506 _ => {}
1507 }
1508 Ok(())
1509}
1510
1511fn cg_set_one_ret(fs: &mut FuncState, e: &mut ExprDesc) {
1518 if e.k == ExprKind::Call {
1519 let pc_idx = e.u.info as usize;
1520 let lc = lua_code::opcodes::Instruction(fs.f.code[pc_idx].0);
1521 debug_assert_eq!(lc.arg_c(), 2);
1522 e.u.info = lc.arg_a() as i32;
1523 e.k = ExprKind::NonReloc;
1524 } else if e.k == ExprKind::VarArg {
1525 let pc_idx = e.u.info as usize;
1526 let mut lc = lua_code::opcodes::Instruction(fs.f.code[pc_idx].0);
1527 lc.set_arg_c(2);
1528 fs.f.code[pc_idx] = lua_types::opcode::Instruction::new(lc.0);
1529 e.k = ExprKind::Reloc;
1530 }
1531}
1532
1533fn cg_storevar(
1537 fs: &mut FuncState,
1538 line: i32,
1539 var: &ExprDesc,
1540 ex: &mut ExprDesc,
1541) -> Result<(), LuaError> {
1542 match var.k {
1543 ExprKind::Local => {
1544 cg_free_exp(fs, ex);
1545 cg_exp_to_reg(fs, line, ex, var.u.var_ridx as u8)?;
1546 return Ok(());
1547 }
1548 ExprKind::UpVal => {
1549 let e_reg = cg_exp_to_any_reg(fs, line, ex)?;
1550 let inst = lua_code::opcodes::Instruction::abck(
1551 lua_code::opcodes::OpCode::SetUpVal,
1552 e_reg as u32,
1553 var.u.info as u32,
1554 0,
1555 0,
1556 );
1557 emit_inst(fs, line, inst);
1558 }
1559 ExprKind::IndexUp => {
1560 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetTabUp,
1561 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1562 }
1563 ExprKind::IndexI => {
1564 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetI,
1565 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1566 }
1567 ExprKind::IndexStr => {
1568 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetField,
1569 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1570 }
1571 ExprKind::Indexed => {
1572 cg_store_abrk(fs, line, lua_code::opcodes::OpCode::SetTable,
1573 var.u.ind_t as u32, var.u.ind_idx as u32, ex)?;
1574 }
1575 _ => {
1576 return Err(LuaError::syntax(format_args!(
1577 "internal: cg_storevar: invalid var kind {:?}", var.k
1578 )));
1579 }
1580 }
1581 cg_free_exp(fs, ex);
1582 Ok(())
1583}
1584
1585fn cg_store_abrk(
1589 fs: &mut FuncState,
1590 line: i32,
1591 op: lua_code::opcodes::OpCode,
1592 a: u32,
1593 b: u32,
1594 ex: &mut ExprDesc,
1595) -> Result<(), LuaError> {
1596 let c_reg = cg_exp_to_any_reg(fs, line, ex)?;
1597 let inst = lua_code::opcodes::Instruction::abck(op, a, b, c_reg as u32, 0);
1598 emit_inst(fs, line, inst);
1599 Ok(())
1600}
1601
1602fn cg_discharge_to_reg(
1607 fs: &mut FuncState,
1608 line: i32,
1609 e: &mut ExprDesc,
1610 reg: u8,
1611) -> Result<(), LuaError> {
1612 cg_discharge_vars(fs, line, e)?;
1613 match e.k {
1614 ExprKind::Jmp => {
1615 return Ok(());
1616 }
1617 ExprKind::NonReloc => {
1618 if e.u.info as u8 != reg {
1619 let inst = lua_code::opcodes::Instruction::abck(
1620 lua_code::opcodes::OpCode::Move,
1621 reg as u32,
1622 e.u.info as u32,
1623 0, 0,
1624 );
1625 emit_inst(fs, line, inst);
1626 }
1627 }
1628 ExprKind::Reloc => {
1629 let pc = e.u.info as usize;
1630 let mut lc = lua_code::opcodes::Instruction(fs.f.code[pc].0);
1631 lc.set_arg_a(reg as u32);
1632 fs.f.code[pc] = lua_types::opcode::Instruction::new(lc.0);
1633 }
1634 ExprKind::Nil => {
1635 let inst = lua_code::opcodes::Instruction::abck(
1636 lua_code::opcodes::OpCode::LoadNil, reg as u32, 0, 0, 0,
1637 );
1638 emit_inst(fs, line, inst);
1639 }
1640 ExprKind::True => {
1641 let inst = lua_code::opcodes::Instruction::abck(
1642 lua_code::opcodes::OpCode::LoadTrue, reg as u32, 0, 0, 0,
1643 );
1644 emit_inst(fs, line, inst);
1645 }
1646 ExprKind::False => {
1647 let inst = lua_code::opcodes::Instruction::abck(
1648 lua_code::opcodes::OpCode::LoadFalse, reg as u32, 0, 0, 0,
1649 );
1650 emit_inst(fs, line, inst);
1651 }
1652 ExprKind::KInt => {
1653 let i = e.u.ival;
1654 let max = lua_code::opcodes::MAXARG_BX as i64 - lua_code::opcodes::OFFSET_S_BX as i64;
1655 let min = -(lua_code::opcodes::OFFSET_S_BX as i64);
1656 if i >= min && i <= max {
1657 let bx = (i as i32 + lua_code::opcodes::OFFSET_S_BX) as u32;
1658 let inst = lua_code::opcodes::Instruction::abx(
1659 lua_code::opcodes::OpCode::LoadI, reg as u32, bx,
1660 );
1661 emit_inst(fs, line, inst);
1662 } else {
1663 let k_idx = add_k_value(fs, LuaValue::Int(i));
1664 let inst = lua_code::opcodes::Instruction::abx(
1665 lua_code::opcodes::OpCode::LoadK, reg as u32, k_idx as u32,
1666 );
1667 emit_inst(fs, line, inst);
1668 }
1669 }
1670 ExprKind::KFlt => {
1671 let f = e.u.nval;
1672 let max = lua_code::opcodes::MAXARG_BX as i64 - lua_code::opcodes::OFFSET_S_BX as i64;
1673 let min = -(lua_code::opcodes::OFFSET_S_BX as i64);
1674 let fi_opt: Option<i64> = if f.fract() == 0.0 && f.abs() < i64::MAX as f64 {
1675 Some(f as i64)
1676 } else {
1677 None
1678 };
1679 if let Some(fi) = fi_opt.filter(|fi| *fi >= min && *fi <= max) {
1680 let bx = (fi as i32 + lua_code::opcodes::OFFSET_S_BX) as u32;
1681 let inst = lua_code::opcodes::Instruction::abx(
1682 lua_code::opcodes::OpCode::LoadF, reg as u32, bx,
1683 );
1684 emit_inst(fs, line, inst);
1685 } else {
1686 let k_idx = add_k_value(fs, LuaValue::Float(f));
1687 let inst = lua_code::opcodes::Instruction::abx(
1688 lua_code::opcodes::OpCode::LoadK, reg as u32, k_idx as u32,
1689 );
1690 emit_inst(fs, line, inst);
1691 }
1692 }
1693 ExprKind::KStr => {
1694 let s = e.u.strval.clone()
1695 .ok_or_else(|| LuaError::syntax(format_args!("internal: VKStr with no strval")))?;
1696 let k_idx = add_k_string(fs, s);
1697 let inst = lua_code::opcodes::Instruction::abx(
1698 lua_code::opcodes::OpCode::LoadK,
1699 reg as u32,
1700 k_idx as u32,
1701 );
1702 emit_inst(fs, line, inst);
1703 }
1704 ExprKind::K => {
1705 let inst = lua_code::opcodes::Instruction::abx(
1706 lua_code::opcodes::OpCode::LoadK,
1707 reg as u32,
1708 e.u.info as u32,
1709 );
1710 emit_inst(fs, line, inst);
1711 }
1712 _ => {
1713 return Err(LuaError::syntax(format_args!(
1714 "internal: cg_discharge_to_reg cannot discharge {:?}", e.k
1715 )));
1716 }
1717 }
1718 e.u.info = reg as i32;
1719 e.k = ExprKind::NonReloc;
1720 Ok(())
1721}
1722
1723fn cg_need_value(fs: &FuncState, list: i32) -> bool {
1728 let mut list = list;
1729 while list != NO_JUMP {
1730 let ctrl_pc = cg_get_jump_control(fs, list);
1731 let ctrl = cg_inst_at(fs, ctrl_pc);
1732 if ctrl.opcode() != Some(lua_code::opcodes::OpCode::TestSet) {
1733 return true;
1734 }
1735 list = cg_get_jump(fs, list);
1736 }
1737 false
1738}
1739
1740fn cg_code_loadbool(fs: &mut FuncState, line: i32, reg: i32, op: lua_code::opcodes::OpCode) -> i32 {
1744 cg_get_label(fs);
1745 let inst = lua_code::opcodes::Instruction::abck(op, reg as u32, 0, 0, 0);
1746 emit_inst(fs, line, inst)
1747}
1748
1749fn cg_patch_list_aux(
1753 fs: &mut FuncState,
1754 list: i32,
1755 vtarget: i32,
1756 reg: u32,
1757 dtarget: i32,
1758) -> Result<(), LuaError> {
1759 let mut list = list;
1760 while list != NO_JUMP {
1761 let next = cg_get_jump(fs, list);
1762 if cg_patch_test_reg(fs, list, reg) {
1763 cg_fix_jump(fs, list, vtarget)?;
1764 } else {
1765 cg_fix_jump(fs, list, dtarget)?;
1766 }
1767 list = next;
1768 }
1769 Ok(())
1770}
1771
1772fn cg_exp_to_reg(
1779 fs: &mut FuncState,
1780 line: i32,
1781 e: &mut ExprDesc,
1782 reg: u8,
1783) -> Result<(), LuaError> {
1784 cg_discharge_to_reg(fs, line, e, reg)?;
1785 if e.k == ExprKind::Jmp {
1786 let info = e.u.info;
1787 cg_concat(fs, &mut e.t, info)?;
1788 }
1789 if e.t != e.f {
1790 let mut p_f = NO_JUMP;
1791 let mut p_t = NO_JUMP;
1792 if cg_need_value(fs, e.t) || cg_need_value(fs, e.f) {
1793 let fj = if e.k == ExprKind::Jmp {
1794 NO_JUMP
1795 } else {
1796 cg_jump(fs, line)
1797 };
1798 p_f = cg_code_loadbool(fs, line, reg as i32, lua_code::opcodes::OpCode::LFalseSkip);
1799 p_t = cg_code_loadbool(fs, line, reg as i32, lua_code::opcodes::OpCode::LoadTrue);
1800 cg_patch_to_here(fs, fj)?;
1801 }
1802 let final_pc = cg_get_label(fs);
1803 cg_patch_list_aux(fs, e.f, final_pc, reg as u32, p_f)?;
1804 cg_patch_list_aux(fs, e.t, final_pc, reg as u32, p_t)?;
1805 }
1806 e.f = NO_JUMP;
1807 e.t = NO_JUMP;
1808 e.u.info = reg as i32;
1809 e.k = ExprKind::NonReloc;
1810 Ok(())
1811}
1812
1813fn cg_free_reg_if_temp(fs: &mut FuncState, reg: i32) {
1817 if reg >= fs.nactvar as i32 {
1818 debug_assert!(reg < fs.freereg as i32);
1819 if reg == fs.freereg as i32 - 1 {
1820 fs.freereg -= 1;
1821 }
1822 }
1823}
1824
1825fn cg_exp_to_next_reg(
1830 fs: &mut FuncState,
1831 line: i32,
1832 e: &mut ExprDesc,
1833) -> Result<(), LuaError> {
1834 cg_discharge_vars(fs, line, e)?;
1835 cg_free_exp(fs, e);
1836 let reg = reserve_reg(fs)?;
1837 cg_exp_to_reg(fs, line, e, reg)
1838}
1839
1840fn cg_set_returns(fs: &mut FuncState, e: &mut ExprDesc, nresults: i32) {
1843 let pc_idx = e.u.info as usize;
1844 let mut lc = lua_code::opcodes::Instruction(fs.f.code[pc_idx].0);
1845 if e.k == ExprKind::Call {
1846 lc.set_arg_c((nresults + 1) as u32);
1847 } else {
1848 debug_assert_eq!(e.k, ExprKind::VarArg);
1849 lc.set_arg_c((nresults + 1) as u32);
1850 lc.set_arg_a(fs.freereg as u32);
1851 fs.freereg += 1;
1852 }
1853 fs.f.code[pc_idx] = lua_types::opcode::Instruction::new(lc.0);
1854}
1855
1856fn cg_final_target(fs: &FuncState, mut i: i32) -> i32 {
1860 for _ in 0..100 {
1861 let inst = cg_inst_at(fs, i);
1862 if inst.opcode() != Some(lua_code::opcodes::OpCode::Jmp) {
1863 break;
1864 }
1865 i += inst.arg_s_j() + 1;
1866 }
1867 i
1868}
1869
1870fn cg_finish(fs: &mut FuncState) {
1877 use lua_code::opcodes::OpCode;
1878 let needclose = fs.needclose;
1879 let is_vararg = fs.f.is_vararg;
1880 let numparams = fs.f.numparams as u32;
1881 let pc_end = fs.pc;
1882 for i in 0..pc_end {
1883 let mut inst = cg_inst_at(fs, i);
1884 match inst.opcode() {
1885 Some(OpCode::Return0) | Some(OpCode::Return1) => {
1886 if !(needclose || is_vararg) {
1887 continue;
1888 }
1889 inst.set_opcode(OpCode::Return);
1890 if needclose {
1891 inst.set_arg_k(1);
1892 }
1893 if is_vararg {
1894 inst.set_arg_c(numparams + 1);
1895 }
1896 cg_set_inst_at(fs, i, inst);
1897 }
1898 Some(OpCode::Return) | Some(OpCode::TailCall) => {
1899 if needclose {
1900 inst.set_arg_k(1);
1901 }
1902 if is_vararg {
1903 inst.set_arg_c(numparams + 1);
1904 }
1905 cg_set_inst_at(fs, i, inst);
1906 }
1907 Some(OpCode::Jmp) => {
1908 let target = cg_final_target(fs, i);
1909 let _ = cg_fix_jump(fs, i, target);
1910 }
1911 _ => {}
1912 }
1913 }
1914}
1915
1916fn cg_emit_return(fs: &mut FuncState, line: i32, first: i32, nret: i32) {
1920 let op = match nret {
1921 0 => lua_code::opcodes::OpCode::Return0,
1922 1 => lua_code::opcodes::OpCode::Return1,
1923 _ => lua_code::opcodes::OpCode::Return,
1924 };
1925 let inst = lua_code::opcodes::Instruction::abck(
1926 op,
1927 first as u32,
1928 (nret + 1) as u32,
1929 0,
1930 0,
1931 );
1932 emit_inst(fs, line, inst);
1933}
1934
1935fn error_expected(ls: &mut LexState, token: TokenKind) -> LuaError {
1948 let tok_str = lua_lex::token2str(&ls.lex, token);
1950 let mut msg: Vec<u8> = Vec::with_capacity(tok_str.len() + 10);
1951 msg.extend_from_slice(&tok_str);
1952 msg.extend_from_slice(b" expected");
1953 lua_lex::syntax_error(&mut ls.lex, &msg)
1954}
1955
1956fn error_limit(fs: &FuncState, limit: i32, what: &str) -> LuaError {
1959 let line = fs.f.linedefined;
1961 if line == 0 {
1962 LuaError::syntax(format_args!(
1963 "too many {} (limit is {}) in main function", what, limit
1964 ))
1965 } else {
1966 LuaError::syntax(format_args!(
1967 "too many {} (limit is {}) in function at line {}", what, limit, line
1968 ))
1969 }
1970}
1971
1972fn check_limit(fs: &FuncState, v: i32, l: i32, what: &str) -> Result<(), LuaError> {
1974 if v > l {
1975 return Err(error_limit(fs, l, what));
1976 }
1977 Ok(())
1978}
1979
1980fn test_next(ls: &mut LexState, state: &mut LuaState, c: TokenKind) -> Result<bool, LuaError> {
1985 if ls.t.token == c {
1986 lex_next(ls, state)?;
1988 Ok(true)
1989 } else {
1990 Ok(false)
1991 }
1992}
1993
1994fn check(ls: &mut LexState, c: TokenKind) -> Result<(), LuaError> {
1996 if ls.t.token != c {
1997 return Err(error_expected(ls, c));
1998 }
1999 Ok(())
2000}
2001
2002fn check_next(ls: &mut LexState, state: &mut LuaState, c: TokenKind) -> Result<(), LuaError> {
2004 check(ls, c)?;
2005 lex_next(ls, state)?;
2007 Ok(())
2008}
2009
2010fn str_check_name(ls: &mut LexState, state: &mut LuaState) -> Result<GcRef<LuaString>, LuaError> {
2013 check(ls, TK_NAME)?;
2015 let ts = ls.t.seminfo.ts.clone()
2016 .ok_or_else(|| LuaError::syntax(format_args!("name expected")))?;
2017 lex_next(ls, state)?;
2018 Ok(ts)
2019}
2020
2021fn init_exp(e: &mut ExprDesc, k: ExprKind, i: i32) {
2023 e.f = NO_JUMP;
2024 e.t = NO_JUMP;
2025 e.k = k;
2026 e.u.info = i;
2027}
2028
2029fn codestring(e: &mut ExprDesc, s: GcRef<LuaString>) {
2031 e.f = NO_JUMP;
2032 e.t = NO_JUMP;
2033 e.k = ExprKind::KStr;
2034 e.u.strval = Some(s);
2035}
2036
2037fn codename(ls: &mut LexState, state: &mut LuaState, e: &mut ExprDesc) -> Result<(), LuaError> {
2039 let name = str_check_name(ls, state)?;
2041 codestring(e, name);
2042 Ok(())
2043}
2044
2045fn register_local_var(
2051 ls: &mut LexState,
2052 state: &mut LuaState,
2053 fs: &mut FuncState,
2054 varname: GcRef<LuaString>,
2055) -> Result<i32, LuaError> {
2056 let idx = fs.ndebugvars as usize;
2059 while fs.f.locvars.len() <= idx {
2060 fs.f.locvars.push(LocalVar {
2062 varname: varname.clone(), startpc: 0,
2064 endpc: 0,
2065 });
2066 }
2067 fs.f.locvars[idx].varname = varname;
2068 fs.f.locvars[idx].startpc = fs.pc;
2069 let result = fs.ndebugvars as i32;
2071 fs.ndebugvars += 1;
2072 Ok(result)
2073}
2074
2075fn new_local_var(
2079 ls: &mut LexState,
2080 state: &mut LuaState,
2081 name: GcRef<LuaString>,
2082) -> Result<i32, LuaError> {
2083 let fs = ls.fs.as_ref().unwrap();
2085 let n = ls.dyd.actvar.len() as i32;
2086 let first_local = fs.firstlocal;
2087 check_limit(fs, n + 1 - first_local, MAX_VARS, "local variables")?;
2088
2089 let mut var = VarDesc::default();
2092 var.kind = VarKind::Reg;
2093 var.name = Some(name);
2094 ls.dyd.actvar.push(var);
2095 let result = ls.dyd.actvar.len() as i32 - 1 - first_local;
2096 Ok(result)
2097}
2098
2099fn get_local_var_desc<'a>(ls: &'a LexState, fs: &FuncState, vidx: i32) -> &'a VarDesc {
2102 &ls.dyd.actvar[(fs.firstlocal + vidx) as usize]
2103}
2104
2105fn get_local_var_desc_mut(ls: &mut LexState, first_local: i32, vidx: i32) -> &mut VarDesc {
2107 &mut ls.dyd.actvar[(first_local + vidx) as usize]
2108}
2109
2110fn reg_level(ls: &LexState, fs: &FuncState, nvar: i32) -> i32 {
2113 let mut nvar = nvar;
2115 while nvar > 0 {
2116 nvar -= 1;
2117 let vd = get_local_var_desc(ls, fs, nvar);
2118 if vd.kind != VarKind::CompileTimeConst {
2119 return vd.ridx as i32 + 1;
2120 }
2121 }
2122 0
2123}
2124
2125pub fn nvarstack(ls: &LexState, fs: &FuncState) -> i32 {
2129 reg_level(ls, fs, fs.nactvar as i32)
2130}
2131
2132fn local_debug_info<'a>(ls: &LexState, fs: &'a mut FuncState, vidx: i32) -> Option<&'a mut LocalVar> {
2136 let vd = get_local_var_desc(ls, fs, vidx);
2137 if vd.kind == VarKind::CompileTimeConst {
2138 return None; }
2140 let idx = vd.pidx as usize;
2141 debug_assert!((idx as i16) < fs.ndebugvars);
2142 Some(&mut fs.f.locvars[idx])
2144}
2145
2146fn init_var(ls: &LexState, fs: &FuncState, e: &mut ExprDesc, vidx: i32) {
2148 e.f = NO_JUMP;
2149 e.t = NO_JUMP;
2150 e.k = ExprKind::Local;
2151 e.u.var_vidx = vidx as u16;
2152 e.u.var_ridx = get_local_var_desc(ls, fs, vidx).ridx;
2153}
2154
2155fn check_readonly(ls: &mut LexState, state: &mut LuaState, e: &ExprDesc) -> Result<(), LuaError> {
2158 let varname: Option<GcRef<LuaString>> = {
2160 let fs = ls.fs.as_ref().unwrap();
2161 match e.k {
2162 ExprKind::Const => {
2163 ls.dyd.actvar[e.u.info as usize].name.clone()
2165 }
2166 ExprKind::Local => {
2167 let vd = get_local_var_desc(ls, fs, e.u.var_vidx as i32);
2168 if vd.kind != VarKind::Reg {
2169 vd.name.clone()
2170 } else {
2171 None
2172 }
2173 }
2174 ExprKind::UpVal => {
2175 let up = &fs.f.upvalues[e.u.info as usize];
2176 if VarKind::from_u8(up.kind) != VarKind::Reg {
2177 up.name.clone()
2178 } else {
2179 None
2180 }
2181 }
2182 _ => None,
2183 }
2184 };
2185 if let Some(vname) = varname {
2186 let _ = state;
2190 let msg = format!(
2191 "attempt to assign to const variable '{}'",
2192 String::from_utf8_lossy(vname.as_bytes())
2193 );
2194 return Err(lua_lex::syntax_error(&mut ls.lex, msg.as_bytes()));
2195 }
2196 Ok(())
2197}
2198
2199fn adjust_local_vars(ls: &mut LexState, state: &mut LuaState, nvars: i32) -> Result<(), LuaError> {
2202 let first_local = ls.fs.as_ref().unwrap().firstlocal;
2204 let nactvar_start = ls.fs.as_ref().unwrap().nactvar as i32;
2205 let mut reglevel_val = {
2206 let fs = ls.fs.as_ref().unwrap();
2207 reg_level(ls, fs, fs.nactvar as i32)
2208 };
2209
2210 for i in 0..nvars {
2211 let vidx = nactvar_start + i;
2212 ls.fs.as_mut().unwrap().nactvar += 1;
2213 let var_name = ls.dyd.actvar[(first_local + vidx) as usize].name.clone();
2215 ls.dyd.actvar[(first_local + vidx) as usize].ridx = reglevel_val as u8;
2216 reglevel_val += 1;
2217 if let Some(vn) = var_name {
2218 let mut fs_box = ls.fs.take().unwrap();
2219 let pidx_result = register_local_var(ls, state, &mut fs_box, vn);
2220 ls.fs = Some(fs_box);
2221 let pidx = pidx_result?;
2222 ls.dyd.actvar[(first_local + vidx) as usize].pidx = pidx as i16;
2223 } else {
2224 }
2226 }
2227 Ok(())
2228}
2229
2230fn remove_vars(ls: &mut LexState, fs: &mut FuncState, tolevel: i32) {
2233 let delta = fs.nactvar as i32 - tolevel;
2242 while fs.nactvar as i32 > tolevel {
2243 fs.nactvar -= 1;
2244 let nactvar = fs.nactvar as i32;
2246 let vd_kind = {
2247 let first_local = fs.firstlocal;
2248 ls.dyd.actvar.get((first_local + nactvar) as usize)
2249 .map(|v| v.kind)
2250 .unwrap_or(VarKind::Reg)
2251 };
2252 if vd_kind != VarKind::CompileTimeConst {
2253 let vd_pidx = {
2254 let first_local = fs.firstlocal;
2255 ls.dyd.actvar.get((first_local + nactvar) as usize)
2256 .map(|v| v.pidx)
2257 .unwrap_or(0)
2258 };
2259 if let Some(lv) = fs.f.locvars.get_mut(vd_pidx as usize) {
2260 lv.endpc = fs.pc;
2261 }
2262 }
2263 }
2264 if delta > 0 {
2265 let new_len = ls.dyd.actvar.len().saturating_sub(delta as usize);
2266 ls.dyd.actvar.truncate(new_len);
2267 }
2268}
2269
2270fn search_upvalue(fs: &FuncState, name: &GcRef<LuaString>) -> i32 {
2276 for (i, up) in fs.f.upvalues.iter().enumerate() {
2277 if up.name.as_ref().map_or(false, |n| GcRef::ptr_eq(n, name)) {
2278 return i as i32;
2279 }
2280 }
2281 -1
2282}
2283
2284fn alloc_upvalue(fs: &mut FuncState) -> Result<usize, LuaError> {
2287 if fs.nups as i32 + 1 > MAX_UPVAL as i32 {
2289 return Err(error_limit(fs, MAX_UPVAL as i32, "upvalues"));
2290 }
2291 let idx = fs.nups as usize;
2293 while fs.f.upvalues.len() <= idx {
2294 fs.f.upvalues.push(UpvalDesc { name: None, instack: false, idx: 0, kind: 0 });
2295 }
2296 fs.nups += 1;
2297 Ok(idx)
2298}
2299
2300fn new_upvalue(
2303 ls: &LexState,
2304 fs: &mut FuncState,
2305 name: GcRef<LuaString>,
2306 v: &ExprDesc,
2307) -> Result<i32, LuaError> {
2308 let idx = alloc_upvalue(fs)?;
2309 let kind: u8 = if v.k == ExprKind::Local {
2310 let prev = fs.prev.as_deref().expect("upvalue capture requires enclosing FuncState");
2312 get_local_var_desc(ls, prev, v.u.var_vidx as i32).kind.as_u8()
2313 } else {
2314 let prev = fs.prev.as_deref().expect("upvalue chain requires enclosing FuncState");
2316 prev.f.upvalues[v.u.info as usize].kind
2317 };
2318 let up = &mut fs.f.upvalues[idx];
2319 if v.k == ExprKind::Local {
2320 up.instack = true;
2322 up.idx = v.u.var_ridx;
2323 } else {
2324 up.instack = false;
2326 up.idx = v.u.info as u8;
2327 }
2328 up.kind = kind;
2329 up.name = Some(name);
2330 Ok(fs.nups as i32 - 1)
2332}
2333
2334fn searchvar(
2337 ls: &LexState,
2338 fs: &FuncState,
2339 n: &GcRef<LuaString>,
2340 var: &mut ExprDesc,
2341) -> i32 {
2342 let mut i = fs.nactvar as i32 - 1;
2344 while i >= 0 {
2345 let vd = get_local_var_desc(ls, fs, i);
2346 if vd.name.as_ref().map_or(false, |nm| GcRef::ptr_eq(nm, n)) {
2347 if vd.kind == VarKind::CompileTimeConst {
2348 init_exp(var, ExprKind::Const, fs.firstlocal + i);
2350 } else {
2351 init_var(ls, fs, var, i);
2352 }
2353 return var.k as i32; }
2355 i -= 1;
2356 }
2357 -1
2358}
2359
2360fn markupval(fs: &mut FuncState, level: i32) {
2363 let mut current = fs.bl.as_deref_mut();
2365 while let Some(b) = current {
2366 if (b.nactvar as i32) <= level {
2367 b.upval = true;
2368 break;
2369 }
2370 current = b.previous.as_deref_mut();
2371 }
2372 fs.needclose = true;
2373}
2374
2375fn marktobeclosed(fs: &mut FuncState) {
2377 if let Some(bl) = fs.bl.as_mut() {
2378 bl.upval = true;
2379 bl.insidetbc = true;
2380 }
2381 fs.needclose = true;
2382}
2383
2384fn singlevaraux(
2390 ls: &LexState,
2391 fs: Option<&mut FuncState>,
2392 n: &GcRef<LuaString>,
2393 var: &mut ExprDesc,
2394 base: bool,
2395) -> Result<(), LuaError> {
2396 match fs {
2397 None => {
2398 init_exp(var, ExprKind::Void, 0);
2399 }
2400 Some(fs) => {
2401 let v = searchvar(ls, fs, n, var);
2402 if v >= 0 {
2403 if v == ExprKind::Local as i32 && !base {
2404 markupval(fs, var.u.var_vidx as i32);
2405 }
2406 } else {
2407 let idx = search_upvalue(fs, n);
2408 let final_idx = if idx < 0 {
2409 singlevaraux(ls, fs.prev.as_deref_mut(), n, var, false)?;
2410 if var.k == ExprKind::Local || var.k == ExprKind::UpVal {
2411 new_upvalue(ls, fs, n.clone(), var)?
2412 } else {
2413 return Ok(());
2414 }
2415 } else {
2416 idx
2417 };
2418 init_exp(var, ExprKind::UpVal, final_idx);
2419 }
2420 }
2421 }
2422 Ok(())
2423}
2424
2425fn singlevar(ls: &mut LexState, state: &mut LuaState, var: &mut ExprDesc) -> Result<(), LuaError> {
2428 let varname = str_check_name(ls, state)?;
2429 let mut fs_box = ls.fs.take();
2430 let recurse_result = singlevaraux(ls, fs_box.as_deref_mut(), &varname, var, true);
2431 ls.fs = fs_box;
2432 recurse_result?;
2433 if var.k == ExprKind::Void {
2434 let envn = ls.envn.clone().expect("envn must be set when resolving globals");
2435 let mut env_var = ExprDesc::default();
2436 let mut fs_box = ls.fs.take();
2437 let r = singlevaraux(ls, fs_box.as_deref_mut(), &envn, &mut env_var, true);
2438 ls.fs = fs_box;
2439 r?;
2440 debug_assert!(env_var.k != ExprKind::Void, "_ENV must resolve");
2441 let line = ls.lastline;
2442 let fs = ls.fs.as_mut().unwrap();
2443 cg_exp_to_any_reg_up(fs, line, &mut env_var)?;
2444 let mut key = ExprDesc::default();
2445 codestring(&mut key, varname);
2446 cg_indexed(fs, line, &mut env_var, &mut key)?;
2447 *var = env_var;
2448 }
2449 Ok(())
2450}
2451
2452fn adjust_assign(
2454 ls: &mut LexState,
2455 state: &mut LuaState,
2456 nvars: i32,
2457 nexps: i32,
2458 e: &mut ExprDesc,
2459) -> Result<(), LuaError> {
2460 let needed = nvars - nexps;
2461 let line = ls.lastline;
2462 let fs = ls.fs.as_mut().unwrap();
2463 if e.k.has_mult_ret() {
2464 let extra = if needed + 1 < 0 { 0 } else { needed + 1 };
2466 cg_set_returns(fs, e, extra);
2467 } else {
2468 if e.k != ExprKind::Void {
2469 cg_exp_to_next_reg(fs, line, e)?;
2470 }
2471 if needed > 0 {
2472 let from = fs.freereg as i32;
2473 cg_emit_nil(fs, line, from, needed);
2474 }
2475 }
2476 if needed > 0 {
2477 for _ in 0..needed {
2478 reserve_reg(fs)?;
2479 }
2480 } else {
2481 fs.freereg = (fs.freereg as i32 + needed) as u8;
2482 }
2483 Ok(())
2484}
2485
2486fn cg_emit_newtable(fs: &mut FuncState, line: i32) -> i32 {
2490 let newtable = lua_code::opcodes::Instruction::abck(
2491 lua_code::opcodes::OpCode::NewTable, 0, 0, 0, 0,
2492 );
2493 let pc = emit_inst(fs, line, newtable);
2494 let extra = lua_code::opcodes::Instruction::ax(
2495 lua_code::opcodes::OpCode::ExtraArg, 0,
2496 );
2497 emit_inst(fs, line, extra);
2498 pc
2499}
2500
2501fn cg_settablesize(fs: &mut FuncState, pc: i32, ra: i32, asize: i32, hsize: i32) {
2505 let rb = if hsize != 0 {
2506 (hsize as u32).next_power_of_two().trailing_zeros() as i32 + 1
2507 } else {
2508 0
2509 };
2510 let maxc = lua_code::opcodes::MAXARG_C as i32 + 1;
2511 let extra = asize / maxc;
2512 let rc = asize % maxc;
2513 let k = if extra > 0 { 1u32 } else { 0u32 };
2514 let newtable = lua_code::opcodes::Instruction::abck(
2515 lua_code::opcodes::OpCode::NewTable,
2516 ra as u32, rb as u32, rc as u32, k,
2517 );
2518 fs.f.code[pc as usize] = lua_types::opcode::Instruction::new(newtable.0);
2519 let extra_inst = lua_code::opcodes::Instruction::ax(
2520 lua_code::opcodes::OpCode::ExtraArg, extra as u32,
2521 );
2522 fs.f.code[pc as usize + 1] = lua_types::opcode::Instruction::new(extra_inst.0);
2523}
2524
2525fn cg_setlist(fs: &mut FuncState, line: i32, base: i32, nelems: i32, tostore: i32) {
2530 let maxc = lua_code::opcodes::MAXARG_C as i32;
2531 let tostore_arg = if tostore == LUA_MULTRET { 0 } else { tostore };
2532 if nelems <= maxc {
2533 let inst = lua_code::opcodes::Instruction::abck(
2534 lua_code::opcodes::OpCode::SetList,
2535 base as u32, tostore_arg as u32, nelems as u32, 0,
2536 );
2537 emit_inst(fs, line, inst);
2538 } else {
2539 let extra = nelems / (maxc + 1);
2540 let nelems_lo = nelems % (maxc + 1);
2541 let inst = lua_code::opcodes::Instruction::abck(
2542 lua_code::opcodes::OpCode::SetList,
2543 base as u32, tostore_arg as u32, nelems_lo as u32, 1,
2544 );
2545 emit_inst(fs, line, inst);
2546 let extra_inst = lua_code::opcodes::Instruction::ax(
2547 lua_code::opcodes::OpCode::ExtraArg, extra as u32,
2548 );
2549 emit_inst(fs, line, extra_inst);
2550 }
2551 fs.freereg = (base + 1) as u8;
2552}
2553
2554fn cg_indexed(fs: &mut FuncState, line: i32, t: &mut ExprDesc, k: &mut ExprDesc) -> Result<(), LuaError> {
2559 if k.k == ExprKind::KStr {
2560 let s = k.u.strval.clone()
2561 .ok_or_else(|| LuaError::syntax(format_args!("internal: VKStr with no strval")))?;
2562 let k_idx = add_k_string(fs, s);
2563 k.u.info = k_idx;
2564 k.k = ExprKind::K;
2565 }
2566 let k_is_kstr = k.k == ExprKind::K
2567 && k.u.info >= 0
2568 && (k.u.info as u32) <= lua_code::opcodes::MAXARG_B;
2569 if t.k == ExprKind::UpVal && !k_is_kstr {
2570 cg_exp_to_any_reg(fs, line, t)?;
2571 }
2572 if t.k == ExprKind::UpVal {
2573 let temp = t.u.info as u8;
2574 t.u.ind_t = temp;
2575 t.u.ind_idx = k.u.info as i16;
2576 t.k = ExprKind::IndexUp;
2577 return Ok(());
2578 }
2579 let t_reg = match t.k {
2580 ExprKind::Local => t.u.var_ridx,
2581 ExprKind::NonReloc => t.u.info as u8,
2582 _ => return Err(LuaError::syntax(format_args!(
2583 "internal: cg_indexed on non-register table kind {:?}", t.k
2584 ))),
2585 };
2586 t.u.ind_t = t_reg;
2587 if k.k == ExprKind::K && k_is_kstr {
2588 t.u.ind_idx = k.u.info as i16;
2589 t.k = ExprKind::IndexStr;
2590 } else if k.k == ExprKind::KInt && cg_fits_int_key(k.u.ival) {
2591 t.u.ind_idx = k.u.ival as i16;
2592 t.k = ExprKind::IndexI;
2593 } else {
2594 cg_exp_to_any_reg(fs, line, k)?;
2595 t.u.ind_idx = k.u.info as i16;
2596 t.k = ExprKind::Indexed;
2597 }
2598 Ok(())
2599}
2600
2601fn cg_fits_int_key(i: i64) -> bool {
2602 i >= 0 && (i as u32) <= lua_code::opcodes::MAXARG_C
2603}
2604
2605fn cg_self(
2610 fs: &mut FuncState,
2611 line: i32,
2612 e: &mut ExprDesc,
2613 key: &mut ExprDesc,
2614) -> Result<(), LuaError> {
2615 cg_exp_to_any_reg(fs, line, e)?;
2616 let ereg = e.u.info;
2617 cg_free_exp(fs, e);
2618 let base = fs.freereg as i32;
2619 e.u.info = base;
2620 e.k = ExprKind::NonReloc;
2621 reserve_regs(fs, 2)?;
2622 let key_str = key.u.strval.clone()
2623 .ok_or_else(|| LuaError::syntax(format_args!(
2624 "internal: cg_self expected VKStr key, got {:?}", key.k
2625 )))?;
2626 let k_idx = add_k_string(fs, key_str);
2627 let (c_arg, k_flag) = if (k_idx as u32) <= lua_code::opcodes::MAXINDEXRK {
2628 (k_idx as u32, 1u32)
2629 } else {
2630 key.k = ExprKind::K;
2631 key.u.info = k_idx;
2632 cg_exp_to_any_reg(fs, line, key)?;
2633 (key.u.info as u32, 0u32)
2634 };
2635 let inst = lua_code::opcodes::Instruction::abck(
2636 lua_code::opcodes::OpCode::Self_,
2637 base as u32,
2638 ereg as u32,
2639 c_arg,
2640 k_flag,
2641 );
2642 emit_inst(fs, line, inst);
2643 cg_free_exp(fs, key);
2644 Ok(())
2645}
2646
2647fn cg_exp_to_any_reg_up(fs: &mut FuncState, line: i32, e: &mut ExprDesc) -> Result<(), LuaError> {
2650 if matches!(e.k, ExprKind::UpVal | ExprKind::K) {
2651 return Ok(());
2652 }
2653 cg_exp_to_any_reg(fs, line, e)?;
2654 Ok(())
2655}
2656
2657fn cg_emit_nil(fs: &mut FuncState, line: i32, from: i32, n: i32) {
2661 let inst = lua_code::opcodes::Instruction::abck(
2662 lua_code::opcodes::OpCode::LoadNil,
2663 from as u32,
2664 (n - 1) as u32,
2665 0,
2666 0,
2667 );
2668 emit_inst(fs, line, inst);
2669}
2670
2671fn jumpscopeerror(ls: &LexState, gt_idx: usize) -> LuaError {
2675 let gt = &ls.dyd.gt[gt_idx];
2676 let line = gt.line;
2677 let gt_name_bytes: &[u8] = gt.name.as_ref().map(|n| n.as_bytes()).unwrap_or(b"");
2678 let gt_name = String::from_utf8_lossy(gt_name_bytes);
2679 let varname_bytes: &[u8] = ls.fs.as_ref()
2680 .and_then(|fs| {
2681 let vidx = gt.nactvar as i32;
2682 if (fs.firstlocal + vidx) >= 0 && ((fs.firstlocal + vidx) as usize) < ls.dyd.actvar.len() {
2683 let vd = get_local_var_desc(ls, fs, vidx);
2684 vd.name.as_ref().map(|n| n.as_bytes())
2685 } else {
2686 None
2687 }
2688 })
2689 .unwrap_or(b"");
2690 let varname = String::from_utf8_lossy(varname_bytes);
2691 LuaError::syntax(format_args!(
2692 "<goto {}> at line {} jumps into the scope of local '{}'", gt_name, line, varname
2693 ))
2694}
2695
2696fn solvegoto(
2699 ls: &mut LexState,
2700 state: &mut LuaState,
2701 g: usize,
2702 label_pc: i32,
2703 label_nactvar: u8,
2704) -> Result<(), LuaError> {
2705 if ls.dyd.gt[g].nactvar < label_nactvar {
2707 return Err(jumpscopeerror(ls, g));
2708 }
2709 let gt_pc = ls.dyd.gt[g].pc;
2710 cg_patch_list(ls.fs.as_mut().unwrap(), gt_pc, label_pc)?;
2711 ls.dyd.gt.remove(g);
2712 Ok(())
2713}
2714
2715fn findlabel(ls: &LexState, name: &GcRef<LuaString>) -> Option<usize> {
2718 let first = ls.fs.as_ref().unwrap().firstlabel as usize;
2719 for i in first..ls.dyd.label.len() {
2720 let lb = &ls.dyd.label[i];
2721 if lb.name.as_ref().map_or(false, |n| GcRef::ptr_eq(n, name)) {
2722 return Some(i);
2723 }
2724 }
2725 None
2726}
2727
2728fn new_label_entry(
2731 ls: &mut LexState,
2732 state: &mut LuaState,
2733 is_goto: bool,
2734 name: GcRef<LuaString>,
2735 line: i32,
2736 pc: i32,
2737) -> Result<usize, LuaError> {
2738 let nactvar = ls.fs.as_ref().unwrap().nactvar;
2739 let entry = LabelDesc { name: Some(name), pc, line, nactvar, close: false };
2740 let list = if is_goto { &mut ls.dyd.gt } else { &mut ls.dyd.label };
2741 let n = list.len();
2743 list.push(entry);
2744 Ok(n)
2745}
2746
2747fn new_goto_entry(
2749 ls: &mut LexState,
2750 state: &mut LuaState,
2751 name: GcRef<LuaString>,
2752 line: i32,
2753 pc: i32,
2754) -> Result<usize, LuaError> {
2755 new_label_entry(ls, state, true, name, line, pc)
2756}
2757
2758fn solvegotos(ls: &mut LexState, state: &mut LuaState, lb_idx: usize) -> Result<bool, LuaError> {
2762 let lb_name = ls.dyd.label[lb_idx].name.clone();
2763 let lb_pc = ls.dyd.label[lb_idx].pc;
2764 let lb_nactvar = ls.dyd.label[lb_idx].nactvar;
2765 let first_goto = ls.fs.as_ref().unwrap().bl.as_ref().map_or(0, |b| b.firstgoto) as usize;
2766
2767 let mut i = first_goto;
2768 let mut needs_close = false;
2769 while i < ls.dyd.gt.len() {
2770 let gt_name = ls.dyd.gt[i].name.clone();
2771 let names_match = lb_name.as_ref().and_then(|ln| gt_name.as_ref().map(|gn| GcRef::ptr_eq(ln, gn))).unwrap_or(false);
2772 if names_match {
2773 needs_close |= ls.dyd.gt[i].close;
2774 solvegoto(ls, state, i, lb_pc, lb_nactvar)?;
2776 } else {
2777 i += 1;
2778 }
2779 }
2780 Ok(needs_close)
2781}
2782
2783fn createlabel(
2786 ls: &mut LexState,
2787 state: &mut LuaState,
2788 name: GcRef<LuaString>,
2789 line: i32,
2790 last: bool,
2791) -> Result<bool, LuaError> {
2792 let label_pc = cg_get_label(ls.fs.as_mut().unwrap());
2793 let l = new_label_entry(ls, state, false, name, line, label_pc)?;
2794 if last {
2795 let bl_nactvar = ls.fs.as_ref().unwrap().bl.as_ref().map_or(0, |b| b.nactvar);
2797 ls.dyd.label[l].nactvar = bl_nactvar;
2798 }
2799 let needs_close = solvegotos(ls, state, l)?;
2800 if needs_close {
2801 let nstack = nvarstack(ls, ls.fs.as_ref().unwrap()) as u32;
2803 let inst = lua_code::opcodes::Instruction::abck(
2804 lua_code::opcodes::OpCode::Close,
2805 nstack,
2806 0,
2807 0,
2808 0,
2809 );
2810 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
2811 return Ok(true);
2812 }
2813 Ok(false)
2814}
2815
2816fn movegotosout(ls: &mut LexState, bl_firstgoto: usize, bl_nactvar: u8, bl_upval: bool) {
2819 let fs = ls.fs.as_ref().unwrap();
2820 let first_goto = bl_firstgoto;
2821 let n_gt = ls.dyd.gt.len();
2822 drop(fs); for i in first_goto..ls.dyd.gt.len() {
2825 let gt_nactvar = ls.dyd.gt[i].nactvar;
2826 if bl_upval {
2829 ls.dyd.gt[i].close = true;
2830 }
2831 ls.dyd.gt[i].nactvar = bl_nactvar;
2832 }
2833}
2834
2835fn enter_block(ls: &mut LexState, isloop: bool) {
2838 let firstlabel = ls.dyd.label.len() as i32;
2839 let firstgoto = ls.dyd.gt.len() as i32;
2840 let insidetbc = ls.fs.as_ref()
2841 .and_then(|f| f.bl.as_ref())
2842 .map_or(false, |b| b.insidetbc);
2843 let fs = ls.fs.as_mut().unwrap();
2844 let nactvar = fs.nactvar;
2845 let new_bl = Box::new(BlockCnt {
2846 previous: fs.bl.take(),
2847 firstlabel,
2848 firstgoto,
2849 nactvar,
2850 upval: false,
2851 isloop,
2852 insidetbc,
2853 });
2854 fs.bl = Some(new_bl);
2855 debug_assert!(fs.freereg as i32 == {
2856 fs.freereg as i32 });
2859}
2860
2861fn undef_goto(ls: &LexState, gt_idx: usize) -> LuaError {
2863 let gt = &ls.dyd.gt[gt_idx];
2864 let line = gt.line;
2865 let name_bytes: &[u8] = gt.name.as_ref().map(|n| n.as_bytes()).unwrap_or(b"");
2866 if name_bytes == b"break" {
2867 LuaError::syntax(format_args!("break outside loop at line {}", line))
2868 } else {
2869 let name_str = String::from_utf8_lossy(name_bytes);
2870 LuaError::syntax(format_args!("no visible label '{}' for <goto> at line {}", name_str, line))
2871 }
2872}
2873
2874fn leave_block(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
2877 let (bl_nactvar, bl_isloop, bl_upval, bl_firstgoto, bl_firstlabel) = {
2881 let bl = ls
2882 .fs
2883 .as_ref()
2884 .unwrap()
2885 .bl
2886 .as_ref()
2887 .expect("leave_block: no current block");
2888 (bl.nactvar, bl.isloop, bl.upval, bl.firstgoto, bl.firstlabel)
2889 };
2890
2891 let stklevel = reg_level(ls, ls.fs.as_ref().unwrap(), bl_nactvar as i32);
2892 let mut fs_box = ls.fs.take().unwrap();
2893 remove_vars(ls, &mut fs_box, bl_nactvar as i32);
2894 debug_assert!(bl_nactvar == fs_box.nactvar);
2895 ls.fs = Some(fs_box);
2896
2897 let hasclose = if bl_isloop {
2898 let break_str = state.intern_str(b"break")?;
2900 createlabel(ls, state, break_str, 0, false)?
2901 } else {
2902 false
2903 };
2904
2905 let mut bl_box = ls.fs.as_mut().unwrap().bl.take().unwrap();
2907 let previous = bl_box.previous.take();
2908 ls.fs.as_mut().unwrap().bl = previous;
2909
2910 let has_prev_block = ls.fs.as_ref().unwrap().bl.is_some();
2911 if !hasclose && has_prev_block && bl_upval {
2912 let line = ls.lastline;
2917 let inst = lua_code::opcodes::Instruction::abck(
2918 lua_code::opcodes::OpCode::Close,
2919 stklevel as u32,
2920 0,
2921 0,
2922 0,
2923 );
2924 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
2925 }
2926 ls.fs.as_mut().unwrap().freereg = stklevel as u8;
2927
2928 ls.dyd.label.truncate(bl_firstlabel as usize);
2930
2931 if has_prev_block {
2932 movegotosout(ls, bl_firstgoto as usize, bl_nactvar, bl_upval);
2933 } else {
2934 if (bl_firstgoto as usize) < ls.dyd.gt.len() {
2936 return Err(undef_goto(ls, bl_firstgoto as usize));
2937 }
2938 }
2939 Ok(())
2940}
2941
2942fn add_prototype(ls: &mut LexState, state: &mut LuaState) -> Result<Box<LuaProto>, LuaError> {
2948 let np = ls.fs.as_ref().unwrap().np as usize;
2950 let new_proto = Box::new(LuaProto::placeholder());
2953 while ls.fs.as_ref().unwrap().f.p.len() <= np {
2954 ls.fs
2955 .as_mut()
2956 .unwrap()
2957 .f
2958 .p
2959 .push(GcRef::new(LuaProto::placeholder()));
2960 }
2961 ls.fs.as_mut().unwrap().np += 1;
2962 Ok(new_proto)
2964}
2965
2966fn codeclosure(ls: &mut LexState, _state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
2969 let line = ls.lastline;
2970 let mut child = ls.fs.take().expect("codeclosure: no current FuncState");
2971 let result = (|| -> Result<(), LuaError> {
2972 let parent = child.prev.as_mut().expect(
2973 "codeclosure: child FuncState has no parent (called outside body()?)",
2974 );
2975 let bx = (parent.np - 1) as u32;
2976 let inst = lua_code::opcodes::Instruction::abx(
2977 lua_code::opcodes::OpCode::Closure,
2978 0,
2979 bx,
2980 );
2981 let pc = emit_inst(parent, line, inst);
2982 init_exp(v, ExprKind::Reloc, pc);
2983 cg_exp_to_next_reg(parent, line, v)
2984 })();
2985 ls.fs = Some(child);
2986 result
2987}
2988
2989fn open_func(ls: &mut LexState, state: &mut LuaState, mut new_fs: FuncState) -> Result<(), LuaError> {
2992 new_fs.prev = ls.fs.take();
2994
2995 let f = &mut new_fs.f;
2996 new_fs.pc = 0;
2998 new_fs.previousline = f.linedefined;
2999 new_fs.iwthabs = 0;
3000 new_fs.lasttarget = 0;
3001 new_fs.freereg = 0;
3002 new_fs.nk = 0;
3003 new_fs.nabslineinfo = 0;
3004 new_fs.np = 0;
3005 new_fs.nups = 0;
3006 new_fs.ndebugvars = 0;
3007 new_fs.nactvar = 0;
3008 new_fs.needclose = false;
3009
3010 new_fs.firstlocal = ls.dyd.actvar.len() as i32;
3012 new_fs.firstlabel = ls.dyd.label.len() as i32;
3014 new_fs.bl = None;
3015
3016 new_fs.f.source = ls.source.clone();
3018 new_fs.f.maxstacksize = 2;
3019
3020 ls.fs = Some(Box::new(new_fs));
3023
3024 enter_block(ls, false);
3026 Ok(())
3027}
3028
3029fn close_func(ls: &mut LexState, state: &mut LuaState) -> Result<Box<LuaProto>, LuaError> {
3033 {
3035 let first = {
3036 let fs = ls.fs.as_ref().unwrap();
3037 nvarstack(ls, fs)
3038 };
3039 let line = ls.lastline;
3040 let fs = ls.fs.as_mut().unwrap();
3041 let inst = lua_code::opcodes::Instruction::abck(
3042 lua_code::opcodes::OpCode::Return0,
3043 first as u32,
3044 1,
3045 0,
3046 0,
3047 );
3048 emit_inst(fs, line, inst);
3049 }
3050 leave_block(ls, state)?;
3052 debug_assert!(ls.fs.as_ref().unwrap().bl.is_none());
3053
3054 cg_finish(ls.fs.as_mut().unwrap());
3057
3058 {
3060 let fs = ls.fs.as_mut().unwrap();
3061 let pc = fs.pc as usize;
3062 let nabslineinfo = fs.nabslineinfo as usize;
3063 let nk = fs.nk as usize;
3064 let np = fs.np as usize;
3065 let ndebugvars = fs.ndebugvars as usize;
3066 let nups = fs.nups as usize;
3067 fs.f.code.truncate(pc);
3068 fs.f.lineinfo.truncate(pc);
3069 fs.f.abslineinfo.truncate(nabslineinfo);
3070 fs.f.k.truncate(nk);
3071 fs.f.p.truncate(np);
3072 fs.f.locvars.truncate(ndebugvars);
3073 fs.f.upvalues.truncate(nups);
3074 }
3075
3076 let mut fs_box = ls.fs.take().unwrap();
3078 ls.fs = fs_box.prev.take();
3079
3080 Ok(fs_box.f)
3082}
3083
3084fn block_follow(ls: &LexState, withuntil: bool) -> bool {
3089 match ls.t.token {
3090 TK_ELSE | TK_ELSEIF | TK_END | TK_EOS => true,
3091 TK_UNTIL => withuntil,
3092 _ => false,
3093 }
3094}
3095
3096fn statlist(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3098 while !block_follow(ls, true) {
3100 if ls.t.token == TK_RETURN {
3101 statement(ls, state)?;
3102 return Ok(());
3103 }
3104 statement(ls, state)?;
3105 }
3106 Ok(())
3107}
3108
3109fn fieldsel(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3112 let line = ls.lastline;
3114 cg_exp_to_any_reg_up(ls.fs.as_mut().unwrap(), line, v)?;
3115 lex_next(ls, state)?; let mut key = ExprDesc::default();
3117 codename(ls, state, &mut key)?;
3118 cg_indexed(ls.fs.as_mut().unwrap(), line, v, &mut key)?;
3119 Ok(())
3120}
3121
3122fn yindex(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3125 lex_next(ls, state)?;
3127 expr(ls, state, v)?;
3128 check_next(ls, state, b']' as TokenKind)?;
3130 Ok(())
3131}
3132
3133fn recfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
3137 let reg = ls.fs.as_ref().unwrap().freereg as i32;
3138 let mut key = ExprDesc::default();
3139 let mut val = ExprDesc::default();
3140 if ls.t.token == TK_NAME {
3141 let fs = ls.fs.as_ref().unwrap();
3143 check_limit(fs, cc.nh, i32::MAX, "items in a constructor")?;
3144 codename(ls, state, &mut key)?;
3145 } else {
3146 yindex(ls, state, &mut key)?;
3148 }
3149 cc.nh += 1;
3150 check_next(ls, state, b'=' as TokenKind)?;
3151 let mut tab = cc.t.clone();
3152 let line = ls.lastline;
3153 cg_indexed(ls.fs.as_mut().unwrap(), line, &mut tab, &mut key)?;
3154 expr(ls, state, &mut val)?;
3155 cg_storevar(ls.fs.as_mut().unwrap(), line, &tab, &mut val)?;
3156 ls.fs.as_mut().unwrap().freereg = reg as u8;
3157 Ok(())
3158}
3159
3160fn closelistfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
3162 let _ = state;
3163 if cc.v.k == ExprKind::Void {
3164 return Ok(()); }
3166 let line = ls.lastline;
3167 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut cc.v)?;
3168 cc.v.k = ExprKind::Void;
3169 if cc.tostore == LFIELDS_PER_FLUSH {
3170 let t_info = cc.t.u.info;
3171 cg_setlist(ls.fs.as_mut().unwrap(), line, t_info, cc.na, cc.tostore);
3172 cc.na += cc.tostore;
3173 cc.tostore = 0;
3174 }
3175 Ok(())
3176}
3177
3178fn lastlistfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
3180 let _ = state;
3181 if cc.tostore == 0 {
3182 return Ok(());
3183 }
3184 let t_info = cc.t.u.info;
3185 let line = ls.lastline;
3186 if cc.v.k.has_mult_ret() {
3187 cg_set_returns(ls.fs.as_mut().unwrap(), &mut cc.v, LUA_MULTRET);
3188 cg_setlist(ls.fs.as_mut().unwrap(), line, t_info, cc.na, LUA_MULTRET);
3189 cc.na -= 1;
3190 } else {
3191 if cc.v.k != ExprKind::Void {
3192 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut cc.v)?;
3193 }
3194 cg_setlist(ls.fs.as_mut().unwrap(), line, t_info, cc.na, cc.tostore);
3195 }
3196 cc.na += cc.tostore;
3197 Ok(())
3198}
3199
3200fn listfield(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
3202 expr(ls, state, &mut cc.v)?;
3203 cc.tostore += 1;
3204 Ok(())
3205}
3206
3207fn field(ls: &mut LexState, state: &mut LuaState, cc: &mut ConsControl) -> Result<(), LuaError> {
3209 match ls.t.token {
3210 TK_NAME => {
3211 let next_is_eq = lex_lookahead(ls, state)? == b'=' as TokenKind;
3213 if !next_is_eq {
3214 listfield(ls, state, cc)?;
3215 } else {
3216 recfield(ls, state, cc)?;
3217 }
3218 }
3219 c if c == b'[' as TokenKind => {
3220 recfield(ls, state, cc)?;
3221 }
3222 _ => {
3223 listfield(ls, state, cc)?;
3224 }
3225 }
3226 Ok(())
3227}
3228
3229fn constructor(ls: &mut LexState, state: &mut LuaState, t: &mut ExprDesc) -> Result<(), LuaError> {
3231 let line = ls.lastline;
3232 let pc = cg_emit_newtable(ls.fs.as_mut().unwrap(), line);
3233
3234 let freereg = ls.fs.as_ref().unwrap().freereg as i32;
3235 init_exp(t, ExprKind::NonReloc, freereg);
3236 reserve_regs(ls.fs.as_mut().unwrap(), 1)?;
3237
3238 let mut cc = ConsControl {
3239 v: ExprDesc::default(),
3240 t: t.clone(),
3241 nh: 0,
3242 na: 0,
3243 tostore: 0,
3244 };
3245
3246 check_next(ls, state, b'{' as TokenKind)?;
3247 loop {
3248 debug_assert!(cc.v.k == ExprKind::Void || cc.tostore > 0);
3249 if ls.t.token == b'}' as TokenKind {
3250 break;
3251 }
3252 closelistfield(ls, state, &mut cc)?;
3253 field(ls, state, &mut cc)?;
3254 if !test_next(ls, state, b',' as TokenKind)?
3255 && !test_next(ls, state, b';' as TokenKind)?
3256 {
3257 break;
3258 }
3259 }
3260 check_match(ls, state, b'}' as TokenKind, b'{' as TokenKind, line)?;
3261 lastlistfield(ls, state, &mut cc)?;
3262
3263 let t_info = t.u.info;
3264 cg_settablesize(ls.fs.as_mut().unwrap(), pc, t_info, cc.na, cc.nh);
3265 Ok(())
3266}
3267
3268fn setvararg(fs: &mut FuncState, _state: &mut LuaState, nparams: i32) -> Result<(), LuaError> {
3272 fs.f.is_vararg = true;
3273 let inst = lua_code::opcodes::Instruction::abck(
3275 lua_code::opcodes::OpCode::VarArgPrep,
3276 nparams as u32,
3277 0, 0, 0,
3278 );
3279 let line = fs.previousline;
3280 emit_inst(fs, line, inst);
3281 Ok(())
3282}
3283
3284fn parlist(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3286 let mut nparams: i32 = 0;
3287 let mut isvararg = false;
3288 if ls.t.token != b')' as TokenKind {
3289 loop {
3290 match ls.t.token {
3291 TK_NAME => {
3292 let name = str_check_name(ls, state)?;
3293 new_local_var(ls, state, name)?;
3294 nparams += 1;
3295 }
3296 TK_DOTS => {
3297 lex_next(ls, state)?;
3298 isvararg = true;
3299 }
3300 _ => {
3301 return Err(LuaError::syntax(format_args!("<name> or '...' expected")));
3302 }
3303 }
3304 if isvararg || !test_next(ls, state, b',' as TokenKind)? {
3305 break;
3306 }
3307 }
3308 }
3309 adjust_local_vars(ls, state, nparams)?;
3310 let numparams = ls.fs.as_ref().unwrap().nactvar;
3311 ls.fs.as_mut().unwrap().f.numparams = numparams;
3312 if isvararg {
3313 setvararg(ls.fs.as_mut().unwrap(), state, numparams as i32)?;
3314 }
3315 let nactvar = ls.fs.as_ref().unwrap().nactvar as i32;
3317 reserve_regs(ls.fs.as_mut().unwrap(), nactvar)?;
3318 Ok(())
3319}
3320
3321fn check_match(
3323 ls: &mut LexState,
3324 state: &mut LuaState,
3325 what: TokenKind,
3326 who: TokenKind,
3327 where_line: i32,
3328) -> Result<(), LuaError> {
3329 if !test_next(ls, state, what)? {
3331 if where_line == ls.linenumber {
3332 return Err(error_expected(ls, what));
3333 } else {
3334 let what_str = lua_lex::token2str(&ls.lex, what);
3336 let who_str = lua_lex::token2str(&ls.lex, who);
3337 let mut msg: Vec<u8> = Vec::new();
3338 msg.extend_from_slice(&what_str);
3339 msg.extend_from_slice(b" expected (to close ");
3340 msg.extend_from_slice(&who_str);
3341 use std::io::Write as _;
3342 let _ = write!(msg, " at line {})", where_line);
3343 return Err(lua_lex::syntax_error(&mut ls.lex, &msg));
3344 }
3345 }
3346 Ok(())
3347}
3348
3349fn body(
3351 ls: &mut LexState,
3352 state: &mut LuaState,
3353 e: &mut ExprDesc,
3354 ismethod: bool,
3355 line: i32,
3356) -> Result<(), LuaError> {
3357 let new_proto = add_prototype(ls, state)?;
3359 let mut new_fs = FuncState {
3360 f: new_proto,
3361 prev: None,
3362 bl: None,
3363 pc: 0,
3364 lasttarget: 0,
3365 previousline: line,
3366 nk: 0,
3367 np: 0,
3368 nabslineinfo: 0,
3369 firstlocal: 0,
3370 firstlabel: 0,
3371 ndebugvars: 0,
3372 nactvar: 0,
3373 nups: 0,
3374 freereg: 0,
3375 iwthabs: 0,
3376 needclose: false,
3377 last_token_line: ls.lastline,
3378 };
3379 new_fs.f.linedefined = line;
3380 open_func(ls, state, new_fs)?;
3381
3382 check_next(ls, state, b'(' as TokenKind)?;
3383 if ismethod {
3384 let self_str = state.intern_str(b"self")?;
3385 new_local_var(ls, state, self_str)?;
3386 adjust_local_vars(ls, state, 1)?;
3387 }
3388 parlist(ls, state)?;
3389 check_next(ls, state, b')' as TokenKind)?;
3390 statlist(ls, state)?;
3391 ls.fs.as_mut().unwrap().f.lastlinedefined = ls.linenumber;
3392 check_match(ls, state, TK_END, TK_FUNCTION, line)?;
3393 codeclosure(ls, state, e)?;
3394 let inner_proto = close_func(ls, state)?;
3395 let parent = ls.fs.as_mut().expect("body: close_func left no parent FuncState");
3396 let slot = (parent.np - 1) as usize;
3397 if parent.f.p.len() <= slot {
3398 parent.f.p.resize_with(slot + 1, || GcRef::new(LuaProto::placeholder()));
3399 }
3400 parent.f.p[slot] = GcRef::new(*inner_proto);
3401 Ok(())
3402}
3403
3404fn explist(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<i32, LuaError> {
3408 let mut n = 1;
3409 expr(ls, state, v)?;
3410 while test_next(ls, state, b',' as TokenKind)? {
3411 let line = ls.lastline;
3412 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, v)?;
3413 expr(ls, state, v)?;
3414 n += 1;
3415 }
3416 Ok(n)
3417}
3418
3419fn funcargs(ls: &mut LexState, state: &mut LuaState, f: &mut ExprDesc) -> Result<(), LuaError> {
3421 let mut args = ExprDesc::default();
3422 let line = ls.linenumber;
3426 match ls.t.token {
3427 c if c == b'(' as TokenKind => {
3428 lex_next(ls, state)?; if ls.t.token == b')' as TokenKind {
3430 args.k = ExprKind::Void;
3431 } else {
3432 explist(ls, state, &mut args)?;
3433 if args.k.has_mult_ret() {
3434 cg_set_returns(ls.fs.as_mut().unwrap(), &mut args, LUA_MULTRET);
3438 }
3439 }
3440 check_match(ls, state, b')' as TokenKind, b'(' as TokenKind, line)?;
3441 }
3442 c if c == b'{' as TokenKind => {
3443 constructor(ls, state, &mut args)?;
3444 }
3445 TK_STRING => {
3446 let s = ls.t.seminfo.ts.clone()
3447 .ok_or_else(|| LuaError::syntax(format_args!("string expected")))?;
3448 codestring(&mut args, s);
3449 lex_next(ls, state)?;
3450 }
3451 _ => {
3452 return Err(LuaError::syntax(format_args!("function arguments expected")));
3453 }
3454 }
3455 debug_assert!(f.k == ExprKind::NonReloc);
3456 let base = f.u.info;
3457 let nparams: i32 = if args.k.has_mult_ret() {
3458 LUA_MULTRET
3461 } else {
3462 if args.k != ExprKind::Void {
3463 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut args)?;
3464 }
3465 ls.fs.as_ref().unwrap().freereg as i32 - (base + 1)
3466 };
3467 let call_inst = lua_code::opcodes::Instruction::abck(
3469 lua_code::opcodes::OpCode::Call,
3470 base as u32,
3471 (nparams + 1) as u32,
3472 2,
3473 0,
3474 );
3475 let call_pc = emit_inst(ls.fs.as_mut().unwrap(), line, call_inst);
3476 init_exp(f, ExprKind::Call, call_pc);
3477 ls.fs.as_mut().unwrap().freereg = base as u8 + 1;
3478 Ok(())
3479}
3480
3481fn primaryexp(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3485 match ls.t.token {
3486 c if c == b'(' as TokenKind => {
3487 let line = ls.lastline;
3488 lex_next(ls, state)?;
3489 expr(ls, state, v)?;
3490 check_match(ls, state, b')' as TokenKind, b'(' as TokenKind, line)?;
3491 cg_discharge_vars(ls.fs.as_mut().unwrap(), line, v)?;
3492 }
3493 TK_NAME => {
3494 singlevar(ls, state, v)?;
3495 }
3496 _ => {
3497 return Err(lua_lex::syntax_error(&mut ls.lex, b"unexpected symbol"));
3498 }
3499 }
3500 Ok(())
3501}
3502
3503fn suffixedexp(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3505 primaryexp(ls, state, v)?;
3506 loop {
3507 match ls.t.token {
3508 c if c == b'.' as TokenKind => {
3509 fieldsel(ls, state, v)?;
3510 }
3511 c if c == b'[' as TokenKind => {
3512 let mut key = ExprDesc::default();
3513 let line = ls.lastline;
3514 cg_exp_to_any_reg_up(ls.fs.as_mut().unwrap(), line, v)?;
3515 yindex(ls, state, &mut key)?;
3516 cg_indexed(ls.fs.as_mut().unwrap(), line, v, &mut key)?;
3517 }
3518 c if c == b':' as TokenKind => {
3519 let mut key = ExprDesc::default();
3520 lex_next(ls, state)?;
3521 codename(ls, state, &mut key)?;
3522 let line = ls.lastline;
3523 cg_self(ls.fs.as_mut().unwrap(), line, v, &mut key)?;
3524 funcargs(ls, state, v)?;
3525 }
3526 c if c == b'(' as TokenKind || c == TK_STRING || c == b'{' as TokenKind => {
3527 let line = ls.lastline;
3529 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, v)?;
3530 funcargs(ls, state, v)?;
3531 }
3532 _ => return Ok(()),
3533 }
3534 }
3535}
3536
3537fn simpleexp(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3539 match ls.t.token {
3540 TK_FLT => {
3541 init_exp(v, ExprKind::KFlt, 0);
3542 v.u.nval = ls.t.seminfo.r;
3543 }
3544 TK_INT => {
3545 init_exp(v, ExprKind::KInt, 0);
3546 v.u.ival = ls.t.seminfo.i;
3547 }
3548 TK_STRING => {
3549 let s = ls.t.seminfo.ts.clone()
3550 .ok_or_else(|| LuaError::syntax(format_args!("string value missing")))?;
3551 codestring(v, s);
3552 }
3553 TK_NIL => {
3554 init_exp(v, ExprKind::Nil, 0);
3555 }
3556 TK_TRUE => {
3557 init_exp(v, ExprKind::True, 0);
3558 }
3559 TK_FALSE => {
3560 init_exp(v, ExprKind::False, 0);
3561 }
3562 TK_DOTS => {
3563 let is_vararg = ls.fs.as_ref().unwrap().f.is_vararg;
3565 if !is_vararg {
3566 return Err(LuaError::syntax(format_args!(
3567 "cannot use '...' outside a vararg function"
3568 )));
3569 }
3570 let line = ls.lastline;
3572 let inst = lua_code::opcodes::Instruction::abck(
3573 lua_code::opcodes::OpCode::VarArg,
3574 0,
3575 0,
3576 1,
3577 0,
3578 );
3579 let pc = emit_inst(ls.fs.as_mut().unwrap(), line, inst);
3580 init_exp(v, ExprKind::VarArg, pc);
3581 }
3582 c if c == b'{' as TokenKind => {
3583 constructor(ls, state, v)?;
3584 return Ok(()); }
3586 TK_FUNCTION => {
3587 lex_next(ls, state)?;
3588 let line = ls.lastline;
3589 body(ls, state, v, false, line)?;
3590 return Ok(()); }
3592 _ => {
3593 suffixedexp(ls, state, v)?;
3594 return Ok(()); }
3596 }
3597 lex_next(ls, state)?;
3599 Ok(())
3600}
3601
3602fn getunopr(op: TokenKind) -> UnOpr {
3604 match op {
3605 TK_NOT => UnOpr::Not,
3606 c if c == b'-' as TokenKind => UnOpr::Minus,
3607 c if c == b'~' as TokenKind => UnOpr::BNot,
3608 c if c == b'#' as TokenKind => UnOpr::Len,
3609 _ => UnOpr::NoUnOpr,
3610 }
3611}
3612
3613fn getbinopr(op: TokenKind) -> BinOpr {
3615 match op {
3616 c if c == b'+' as TokenKind => BinOpr::Add,
3617 c if c == b'-' as TokenKind => BinOpr::Sub,
3618 c if c == b'*' as TokenKind => BinOpr::Mul,
3619 c if c == b'%' as TokenKind => BinOpr::Mod,
3620 c if c == b'^' as TokenKind => BinOpr::Pow,
3621 c if c == b'/' as TokenKind => BinOpr::Div,
3622 TK_IDIV => BinOpr::IDiv,
3623 c if c == b'&' as TokenKind => BinOpr::BAnd,
3624 c if c == b'|' as TokenKind => BinOpr::BOr,
3625 c if c == b'~' as TokenKind => BinOpr::BXor,
3626 TK_SHL => BinOpr::Shl,
3627 TK_SHR => BinOpr::Shr,
3628 TK_CONCAT => BinOpr::Concat,
3629 TK_NE => BinOpr::Ne,
3630 TK_EQ => BinOpr::Eq,
3631 c if c == b'<' as TokenKind => BinOpr::Lt,
3632 TK_LE => BinOpr::Le,
3633 c if c == b'>' as TokenKind => BinOpr::Gt,
3634 TK_GE => BinOpr::Ge,
3635 TK_AND => BinOpr::And,
3636 TK_OR => BinOpr::Or,
3637 _ => BinOpr::NoBinOpr,
3638 }
3639}
3640
3641fn subexpr(
3645 ls: &mut LexState,
3646 state: &mut LuaState,
3647 v: &mut ExprDesc,
3648 limit: i32,
3649) -> Result<BinOpr, LuaError> {
3650 enter_level(ls)?;
3652
3653 let uop = getunopr(ls.t.token);
3654 if uop != UnOpr::NoUnOpr {
3655 let line = ls.linenumber;
3658 lex_next(ls, state)?; subexpr(ls, state, v, UNARY_PRIORITY)?;
3660 cg_prefix(ls.fs.as_mut().unwrap(), uop, v, line)?;
3662 } else {
3663 simpleexp(ls, state, v)?;
3664 }
3665
3666 let mut op = getbinopr(ls.t.token);
3667 while op != BinOpr::NoBinOpr && PRIORITY[op as usize].0 as i32 > limit {
3668 let mut v2 = ExprDesc::default();
3669 let line = ls.linenumber;
3673 lex_next(ls, state)?;
3674 cg_infix(ls.fs.as_mut().unwrap(), op, v, line)?;
3675 let nextop = subexpr(ls, state, &mut v2, PRIORITY[op as usize].1 as i32)?;
3676 cg_posfix_fold(ls.fs.as_mut().unwrap(), op, v, &mut v2, line)?;
3677 op = nextop;
3678 }
3679
3680 leave_level(ls);
3682 Ok(op)
3683}
3684
3685fn expr(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<(), LuaError> {
3687 subexpr(ls, state, v, 0)?;
3688 Ok(())
3689}
3690
3691fn block(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3695 enter_block(ls, false);
3696 statlist(ls, state)?;
3697 leave_block(ls, state)?;
3698 Ok(())
3699}
3700
3701fn check_conflict(
3710 ls: &mut LexState,
3711 _state: &mut LuaState,
3712 lh: &mut LhsAssign,
3713 v: &ExprDesc,
3714) -> Result<(), LuaError> {
3715 let extra = ls.fs.as_ref().unwrap().freereg as i32;
3716 let line = ls.lastline;
3717 let mut conflict = false;
3718
3719 conflict |= check_one_lhs_entry(&mut lh.v, v, extra);
3720 let mut prev = lh.prev.as_deref_mut();
3721 while let Some(node) = prev {
3722 conflict |= check_one_lhs_entry(&mut node.v, v, extra);
3723 prev = node.prev.as_deref_mut();
3724 }
3725
3726 if conflict {
3727 let fs = ls.fs.as_mut().unwrap();
3728 let inst = if v.k == ExprKind::Local {
3729 lua_code::opcodes::Instruction::abck(
3730 lua_code::opcodes::OpCode::Move,
3731 extra as u32, v.u.var_ridx as u32, 0, 0,
3732 )
3733 } else {
3734 lua_code::opcodes::Instruction::abck(
3735 lua_code::opcodes::OpCode::GetUpVal,
3736 extra as u32, v.u.info as u32, 0, 0,
3737 )
3738 };
3739 emit_inst(fs, line, inst);
3740 reserve_regs(fs, 1)?;
3741 }
3742 Ok(())
3743}
3744
3745fn check_one_lhs_entry(entry: &mut ExprDesc, v: &ExprDesc, extra: i32) -> bool {
3746 if !entry.k.is_indexed() {
3747 return false;
3748 }
3749 let mut found = false;
3750 if entry.k == ExprKind::IndexUp {
3751 if v.k == ExprKind::UpVal && entry.u.ind_t == v.u.info as u8 {
3752 found = true;
3753 entry.k = ExprKind::IndexStr;
3754 entry.u.ind_t = extra as u8;
3755 }
3756 } else {
3757 if v.k == ExprKind::Local && entry.u.ind_t == v.u.var_ridx {
3758 found = true;
3759 entry.u.ind_t = extra as u8;
3760 }
3761 if entry.k == ExprKind::Indexed
3762 && v.k == ExprKind::Local
3763 && entry.u.ind_idx == v.u.var_ridx as i16
3764 {
3765 found = true;
3766 entry.u.ind_idx = extra as i16;
3767 }
3768 }
3769 found
3770}
3771
3772fn restassign(
3774 ls: &mut LexState,
3775 state: &mut LuaState,
3776 lh: &mut LhsAssign,
3777 nvars: i32,
3778) -> Result<(), LuaError> {
3779 if !lh.v.k.is_var() {
3781 return Err(lua_lex::syntax_error(&mut ls.lex, b"syntax error"));
3782 }
3783 check_readonly(ls, state, &lh.v.clone())?;
3784
3785 if test_next(ls, state, b',' as TokenKind)? {
3786 let mut nv_assign = LhsAssign {
3788 prev: None, v: ExprDesc::default(),
3790 };
3791 suffixedexp(ls, state, &mut nv_assign.v)?;
3792 if !nv_assign.v.k.is_indexed() {
3793 check_conflict(ls, state, lh, &nv_assign.v.clone())?;
3794 }
3795 enter_level(ls)?;
3797 restassign(ls, state, &mut nv_assign, nvars + 1)?;
3798 leave_level(ls);
3800 } else {
3801 let mut e = ExprDesc::default();
3803 check_next(ls, state, b'=' as TokenKind)?;
3804 let nexps = explist(ls, state, &mut e)?;
3805 if nexps != nvars {
3806 adjust_assign(ls, state, nvars, nexps, &mut e)?;
3807 } else {
3808 let line = ls.lastline;
3809 let fs = ls.fs.as_mut().unwrap();
3810 cg_set_one_ret(fs, &mut e);
3811 cg_storevar(fs, line, &lh.v, &mut e)?;
3812 return Ok(());
3813 }
3814 }
3815 let line = ls.lastline;
3816 let fs = ls.fs.as_mut().unwrap();
3817 let freereg = fs.freereg as i32 - 1;
3818 let mut e = ExprDesc::default();
3819 init_exp(&mut e, ExprKind::NonReloc, freereg);
3820 cg_storevar(fs, line, &lh.v, &mut e)?;
3821 Ok(())
3822}
3823
3824fn cond(ls: &mut LexState, state: &mut LuaState) -> Result<i32, LuaError> {
3827 let mut v = ExprDesc::default();
3828 expr(ls, state, &mut v)?;
3829 if v.k == ExprKind::Nil {
3830 v.k = ExprKind::False; }
3832 let line = ls.lastline;
3833 cg_go_if_true(ls.fs.as_mut().unwrap(), line, &mut v)?;
3834 Ok(v.f)
3835}
3836
3837fn gotostat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3839 let line = ls.lastline;
3840 let name = str_check_name(ls, state)?;
3841 let lb = findlabel(ls, &name);
3842 if lb.is_none() {
3843 let pc = cg_jump(ls.fs.as_mut().unwrap(), line);
3844 new_goto_entry(ls, state, name, line, pc)?;
3845 } else {
3846 let lb_idx = lb.unwrap();
3847 let lb_pc = ls.dyd.label[lb_idx].pc;
3848 let lb_nactvar = ls.dyd.label[lb_idx].nactvar;
3849 let lblevel = reg_level(ls, ls.fs.as_ref().unwrap(), lb_nactvar as i32);
3850 let cur_nvarstack = {
3851 let fs = ls.fs.as_ref().unwrap();
3852 nvarstack(ls, fs)
3853 };
3854 if cur_nvarstack > lblevel {
3855 let inst = lua_code::opcodes::Instruction::abck(
3857 lua_code::opcodes::OpCode::Close,
3858 lblevel as u32,
3859 0,
3860 0,
3861 0,
3862 );
3863 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
3864 }
3865 let jpc = cg_jump(ls.fs.as_mut().unwrap(), line);
3866 cg_patch_list(ls.fs.as_mut().unwrap(), jpc, lb_pc)?;
3867 }
3868 Ok(())
3869}
3870
3871fn breakstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3873 let line = ls.lastline;
3874 lex_next(ls, state)?;
3876 let break_str = state.intern_str(b"break")?;
3878 let pc = cg_jump(ls.fs.as_mut().unwrap(), line);
3879 new_goto_entry(ls, state, break_str, line, pc)?;
3880 Ok(())
3881}
3882
3883fn checkrepeated(ls: &LexState, name: &GcRef<LuaString>) -> Result<(), LuaError> {
3885 if let Some(lb_idx) = findlabel(ls, name) {
3886 let name_str = String::from_utf8_lossy(name.as_bytes());
3887 let line = ls.dyd.label[lb_idx].line;
3888 return Err(LuaError::syntax(format_args!(
3889 "label '{}' already defined on line {}", name_str, line
3890 )));
3891 }
3892 Ok(())
3893}
3894
3895fn labelstat(
3897 ls: &mut LexState,
3898 state: &mut LuaState,
3899 name: GcRef<LuaString>,
3900 line: i32,
3901) -> Result<(), LuaError> {
3902 check_next(ls, state, TK_DBCOLON)?;
3904 while ls.t.token == b';' as TokenKind || ls.t.token == TK_DBCOLON {
3906 statement(ls, state)?;
3907 }
3908 checkrepeated(ls, &name)?;
3909 let is_last = block_follow(ls, false);
3910 createlabel(ls, state, name, line, is_last)?;
3911 Ok(())
3912}
3913
3914fn whilestat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
3916 lex_next(ls, state)?;
3918 let whileinit = cg_get_label(ls.fs.as_mut().unwrap());
3920 let condexit = cond(ls, state)?;
3921 enter_block(ls, true);
3922 check_next(ls, state, TK_DO)?;
3923 block(ls, state)?;
3924 let back = cg_jump(ls.fs.as_mut().unwrap(), ls.lastline);
3930 cg_patch_list(ls.fs.as_mut().unwrap(), back, whileinit)?;
3931 check_match(ls, state, TK_END, TK_WHILE, line)?;
3932 leave_block(ls, state)?;
3933 cg_patch_to_here(ls.fs.as_mut().unwrap(), condexit)?;
3935 Ok(())
3936}
3937
3938fn repeatstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
3940 let repeat_init = cg_get_label(ls.fs.as_mut().unwrap());
3941 enter_block(ls, true);
3942 enter_block(ls, false);
3943 lex_next(ls, state)?;
3944 statlist(ls, state)?;
3945 check_match(ls, state, TK_UNTIL, TK_REPEAT, line)?;
3946 let condexit = cond(ls, state)?;
3947
3948 let bl2_upval = ls.fs.as_ref().unwrap().bl.as_ref().unwrap().upval;
3949 let bl2_nactvar = ls.fs.as_ref().unwrap().bl.as_ref().unwrap().nactvar as i32;
3950 leave_block(ls, state)?;
3951
3952 let mut condexit = condexit;
3953 if bl2_upval {
3954 let exit = cg_jump(ls.fs.as_mut().unwrap(), line);
3955 cg_patch_to_here(ls.fs.as_mut().unwrap(), condexit)?;
3956 let close_level = reg_level(ls, ls.fs.as_ref().unwrap(), bl2_nactvar) as u32;
3957 let close_inst = lua_code::opcodes::Instruction::abck(
3958 lua_code::opcodes::OpCode::Close,
3959 close_level,
3960 0,
3961 0,
3962 0,
3963 );
3964 emit_inst(ls.fs.as_mut().unwrap(), line, close_inst);
3965 condexit = cg_jump(ls.fs.as_mut().unwrap(), line);
3966 cg_patch_to_here(ls.fs.as_mut().unwrap(), exit)?;
3967 }
3968 cg_patch_list(ls.fs.as_mut().unwrap(), condexit, repeat_init)?;
3969 leave_block(ls, state)?;
3970 Ok(())
3971}
3972
3973fn exp1(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
3976 let mut e = ExprDesc::default();
3977 expr(ls, state, &mut e)?;
3978 let line = ls.lastline;
3979 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut e)?;
3980 debug_assert!(e.k == ExprKind::NonReloc);
3981 Ok(())
3982}
3983
3984fn fixforjump(fs: &mut FuncState, pc: i32, dest: i32, back: bool) -> Result<(), LuaError> {
3986 let mut offset = dest - (pc + 1);
3987 if back {
3988 offset = -offset;
3989 }
3990 if offset > MAXARG_BX {
3991 return Err(LuaError::syntax(format_args!("control structure too long")));
3992 }
3993 let raw = fs.f.code[pc as usize].0;
3994 let mut inst = lua_code::opcodes::Instruction(raw);
3995 inst.set_arg_bx(offset as u32);
3996 fs.f.code[pc as usize] = lua_types::opcode::Instruction::new(inst.0);
3997 Ok(())
3998}
3999
4000fn forbody(
4002 ls: &mut LexState,
4003 state: &mut LuaState,
4004 base: i32,
4005 line: i32,
4006 nvars: i32,
4007 isgen: bool,
4008) -> Result<(), LuaError> {
4009 check_next(ls, state, TK_DO)?;
4010 let prep_op = if isgen { OpCode::TForPrep } else { OpCode::ForPrep };
4011 let prep = {
4012 let fs = ls.fs.as_mut().unwrap();
4013 let inst = lua_code::opcodes::Instruction::abx(prep_op, base as u32, 0);
4014 emit_inst(fs, line, inst)
4015 };
4016
4017 enter_block(ls, false);
4018 adjust_local_vars(ls, state, nvars)?;
4019 reserve_regs(ls.fs.as_mut().unwrap(), nvars)?;
4020 block(ls, state)?;
4021 leave_block(ls, state)?;
4022
4023 let label_pc = ls.fs.as_ref().unwrap().pc;
4024 fixforjump(ls.fs.as_mut().unwrap(), prep, label_pc, false)?;
4025
4026 if isgen {
4027 let fs = ls.fs.as_mut().unwrap();
4028 let inst = lua_code::opcodes::Instruction::abck(
4029 OpCode::TForCall, base as u32, 0, nvars as u32, 0,
4030 );
4031 emit_inst(fs, line, inst);
4032 }
4033 let loop_op = if isgen { OpCode::TForLoop } else { OpCode::ForLoop };
4034 let endfor = {
4035 let fs = ls.fs.as_mut().unwrap();
4036 let inst = lua_code::opcodes::Instruction::abx(loop_op, base as u32, 0);
4037 emit_inst(fs, line, inst)
4038 };
4039 fixforjump(ls.fs.as_mut().unwrap(), endfor, prep + 1, true)?;
4040 Ok(())
4041}
4042
4043fn fornum(
4045 ls: &mut LexState,
4046 state: &mut LuaState,
4047 varname: GcRef<LuaString>,
4048 line: i32,
4049) -> Result<(), LuaError> {
4050 let base = ls.fs.as_ref().unwrap().freereg as i32;
4051 let for_state_str = state.intern_str(b"(for state)")?;
4053 new_local_var(ls, state, for_state_str.clone())?;
4054 new_local_var(ls, state, for_state_str.clone())?;
4055 new_local_var(ls, state, for_state_str)?;
4056 new_local_var(ls, state, varname)?;
4057 check_next(ls, state, b'=' as TokenKind)?;
4058 exp1(ls, state)?; check_next(ls, state, b',' as TokenKind)?;
4060 exp1(ls, state)?; if test_next(ls, state, b',' as TokenKind)? {
4062 exp1(ls, state)?; } else {
4064 let fs = ls.fs.as_mut().unwrap();
4065 let reg = fs.freereg as u32;
4066 let bx = (1i32 + lua_code::opcodes::OFFSET_S_BX) as u32;
4067 let inst = lua_code::opcodes::Instruction::abx(
4068 lua_code::opcodes::OpCode::LoadI, reg, bx,
4069 );
4070 emit_inst(fs, line, inst);
4071 reserve_regs(fs, 1)?;
4072 }
4073 adjust_local_vars(ls, state, 3)?; forbody(ls, state, base, line, 1, false)?;
4075 Ok(())
4076}
4077
4078fn forlist(
4080 ls: &mut LexState,
4081 state: &mut LuaState,
4082 indexname: GcRef<LuaString>,
4083) -> Result<(), LuaError> {
4084 let mut nvars: i32 = 5; let base = ls.fs.as_ref().unwrap().freereg as i32;
4086 let for_state_str = state.intern_str(b"(for state)")?;
4088 new_local_var(ls, state, for_state_str.clone())?;
4089 new_local_var(ls, state, for_state_str.clone())?;
4090 new_local_var(ls, state, for_state_str.clone())?;
4091 new_local_var(ls, state, for_state_str)?;
4092 new_local_var(ls, state, indexname)?;
4093 while test_next(ls, state, b',' as TokenKind)? {
4094 let extra_name = str_check_name(ls, state)?;
4095 new_local_var(ls, state, extra_name)?;
4096 nvars += 1;
4097 }
4098 check_next(ls, state, TK_IN)?;
4099 let line = ls.linenumber;
4104 let mut e = ExprDesc::default();
4105 let nexps = explist(ls, state, &mut e)?;
4106 adjust_assign(ls, state, 4, nexps, &mut e)?;
4107 adjust_local_vars(ls, state, 4)?;
4108 marktobeclosed(ls.fs.as_mut().unwrap()); forbody(ls, state, base, line, nvars - 4, true)?;
4112 Ok(())
4113}
4114
4115fn forstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
4117 enter_block(ls, true); lex_next(ls, state)?;
4120 let varname = str_check_name(ls, state)?;
4121 match ls.t.token {
4122 c if c == b'=' as TokenKind => fornum(ls, state, varname, line)?,
4123 c if c == b',' as TokenKind || c == TK_IN => forlist(ls, state, varname)?,
4124 _ => {
4125 return Err(LuaError::syntax(format_args!("'=' or 'in' expected")));
4126 }
4127 }
4128 check_match(ls, state, TK_END, TK_FOR, line)?;
4129 leave_block(ls, state)?; Ok(())
4131}
4132
4133fn test_then_block(
4135 ls: &mut LexState,
4136 state: &mut LuaState,
4137 escapelist: &mut i32,
4138) -> Result<(), LuaError> {
4139 lex_next(ls, state)?;
4141 let mut v = ExprDesc::default();
4142 expr(ls, state, &mut v)?;
4143 check_next(ls, state, TK_THEN)?;
4144
4145 let jf: i32;
4146 if ls.t.token == TK_BREAK {
4147 let line = ls.lastline;
4148 cg_go_if_false(ls.fs.as_mut().unwrap(), line, &mut v)?;
4150 lex_next(ls, state)?; enter_block(ls, false);
4152 let break_str = state.intern_str(b"break")?;
4154 new_goto_entry(ls, state, break_str, line, v.t)?;
4155 while test_next(ls, state, b';' as TokenKind)? {}
4157 if block_follow(ls, false) {
4158 leave_block(ls, state)?;
4159 return Ok(());
4160 } else {
4161 jf = cg_jump(ls.fs.as_mut().unwrap(), ls.linenumber);
4163 }
4164 } else {
4165 let line = ls.lastline;
4166 cg_go_if_true(ls.fs.as_mut().unwrap(), line, &mut v)?;
4167 enter_block(ls, false);
4168 jf = v.f;
4169 }
4170
4171 statlist(ls, state)?;
4172 leave_block(ls, state)?;
4173
4174 if ls.t.token == TK_ELSE || ls.t.token == TK_ELSEIF {
4175 let line = ls.lastline;
4177 let j = cg_jump(ls.fs.as_mut().unwrap(), line);
4178 cg_concat(ls.fs.as_mut().unwrap(), escapelist, j)?;
4179 }
4180 cg_patch_to_here(ls.fs.as_mut().unwrap(), jf)?;
4182 Ok(())
4183}
4184
4185fn ifstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
4187 let mut escapelist = NO_JUMP;
4188 test_then_block(ls, state, &mut escapelist)?; while ls.t.token == TK_ELSEIF {
4190 test_then_block(ls, state, &mut escapelist)?;
4191 }
4192 if test_next(ls, state, TK_ELSE)? {
4193 block(ls, state)?;
4194 }
4195 check_match(ls, state, TK_END, TK_IF, line)?;
4196 cg_patch_to_here(ls.fs.as_mut().unwrap(), escapelist)?;
4198 Ok(())
4199}
4200
4201fn localfunc(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4203 let mut b = ExprDesc::default();
4204 let fvar = ls.fs.as_ref().unwrap().nactvar as i32;
4205 let name = str_check_name(ls, state)?;
4206 new_local_var(ls, state, name)?;
4207 adjust_local_vars(ls, state, 1)?; let line = ls.lastline;
4209 body(ls, state, &mut b, false, line)?;
4210 let pc = ls.fs.as_ref().unwrap().pc;
4212 Ok(())
4214}
4215
4216fn getlocalattribute(ls: &mut LexState, state: &mut LuaState) -> Result<VarKind, LuaError> {
4219 if test_next(ls, state, b'<' as TokenKind)? {
4220 let attr_name = str_check_name(ls, state)?;
4221 check_next(ls, state, b'>' as TokenKind)?;
4222 let bytes = attr_name.as_bytes();
4223 if bytes == b"const" {
4224 return Ok(VarKind::Const);
4225 } else if bytes == b"close" {
4226 return Ok(VarKind::ToBeClosed);
4227 } else {
4228 let name_str = String::from_utf8_lossy(bytes);
4229 return Err(LuaError::syntax(format_args!(
4230 "unknown attribute '{}'", name_str
4231 )));
4232 }
4233 }
4234 Ok(VarKind::Reg)
4235}
4236
4237fn checktoclose(ls: &mut LexState, state: &mut LuaState, level: i32) -> Result<(), LuaError> {
4239 if level != -1 {
4240 marktobeclosed(ls.fs.as_mut().unwrap());
4241 let rl = reg_level(ls, ls.fs.as_ref().unwrap(), level);
4243 let line = ls.lastline;
4244 let inst = lua_code::opcodes::Instruction::abck(
4245 lua_code::opcodes::OpCode::Tbc,
4246 rl as u32,
4247 0,
4248 0,
4249 0,
4250 );
4251 emit_inst(ls.fs.as_mut().unwrap(), line, inst);
4252 }
4253 Ok(())
4254}
4255
4256fn localstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4258 let mut toclose: i32 = -1;
4259 let mut nvars: i32 = 0;
4260 let mut vidx = 0i32;
4261 loop {
4262 let name = str_check_name(ls, state)?;
4263 vidx = new_local_var(ls, state, name)?;
4264 let kind = getlocalattribute(ls, state)?;
4265 get_local_var_desc_mut(ls, ls.fs.as_ref().unwrap().firstlocal, vidx).kind = kind;
4266 if kind == VarKind::ToBeClosed {
4267 if toclose != -1 {
4268 return Err(LuaError::syntax(format_args!(
4269 "multiple to-be-closed variables in local list"
4270 )));
4271 }
4272 toclose = ls.fs.as_ref().unwrap().nactvar as i32 + nvars;
4273 }
4274 nvars += 1;
4275 if !test_next(ls, state, b',' as TokenKind)? {
4276 break;
4277 }
4278 }
4279 let nexps: i32;
4280 let mut e = ExprDesc::default();
4281 if test_next(ls, state, b'=' as TokenKind)? {
4282 nexps = explist(ls, state, &mut e)?;
4283 } else {
4284 e.k = ExprKind::Void;
4285 nexps = 0;
4286 }
4287 let first_local = ls.fs.as_ref().unwrap().firstlocal;
4288 let last_vd_kind = ls.dyd.actvar[(first_local + vidx) as usize].kind;
4289 if nvars == nexps
4290 && last_vd_kind == VarKind::Const
4291 {
4292 let is_const = false; if is_const {
4296 ls.dyd.actvar[(first_local + vidx) as usize].kind = VarKind::CompileTimeConst;
4297 adjust_local_vars(ls, state, nvars - 1)?;
4298 ls.fs.as_mut().unwrap().nactvar += 1;
4299 } else {
4300 adjust_assign(ls, state, nvars, nexps, &mut e)?;
4301 adjust_local_vars(ls, state, nvars)?;
4302 }
4303 } else {
4304 adjust_assign(ls, state, nvars, nexps, &mut e)?;
4305 adjust_local_vars(ls, state, nvars)?;
4306 }
4307 checktoclose(ls, state, toclose)?;
4308 Ok(())
4309}
4310
4311fn funcname(ls: &mut LexState, state: &mut LuaState, v: &mut ExprDesc) -> Result<bool, LuaError> {
4314 let mut ismethod = false;
4315 singlevar(ls, state, v)?;
4316 while ls.t.token == b'.' as TokenKind {
4317 fieldsel(ls, state, v)?;
4318 }
4319 if ls.t.token == b':' as TokenKind {
4320 ismethod = true;
4321 fieldsel(ls, state, v)?;
4322 }
4323 Ok(ismethod)
4324}
4325
4326fn funcstat(ls: &mut LexState, state: &mut LuaState, line: i32) -> Result<(), LuaError> {
4328 lex_next(ls, state)?;
4330 let mut v = ExprDesc::default();
4331 let mut b = ExprDesc::default();
4332 let ismethod = funcname(ls, state, &mut v)?;
4333 body(ls, state, &mut b, ismethod, line)?;
4334 check_readonly(ls, state, &v.clone())?;
4335 let fs = ls.fs.as_mut().unwrap();
4336 cg_storevar(fs, line, &v, &mut b)?;
4337 Ok(())
4339}
4340
4341fn exprstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4343 let mut v_assign = LhsAssign { prev: None, v: ExprDesc::default() };
4344 suffixedexp(ls, state, &mut v_assign.v)?;
4345 if ls.t.token == b'=' as TokenKind || ls.t.token == b',' as TokenKind {
4346 restassign(ls, state, &mut v_assign, 1)?;
4348 } else {
4349 if v_assign.v.k != ExprKind::Call {
4351 return Err(lua_lex::syntax_error(&mut ls.lex, b"syntax error"));
4352 }
4353 let info = v_assign.v.u.info as usize;
4355 let fs = ls.fs.as_mut().unwrap();
4356 let mut lc = lua_code::opcodes::Instruction(fs.f.code[info].0);
4357 lc.set_arg_c(1);
4358 fs.f.code[info] = lua_types::opcode::Instruction::new(lc.0);
4359 }
4360 Ok(())
4361}
4362
4363fn retstat(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4365 let mut first = {
4366 let fs = ls.fs.as_ref().unwrap();
4367 nvarstack(ls, fs)
4368 };
4369 let mut nret: i32;
4370 if block_follow(ls, true) || ls.t.token == b';' as TokenKind {
4371 nret = 0;
4372 } else {
4373 let mut e = ExprDesc::default();
4374 nret = explist(ls, state, &mut e)?;
4375 if e.k.has_mult_ret() {
4376 cg_set_returns(ls.fs.as_mut().unwrap(), &mut e, LUA_MULTRET);
4378 if e.k == ExprKind::Call && nret == 1 {
4379 let insidetbc = ls.fs.as_ref().unwrap().bl.as_ref().map_or(false, |b| b.insidetbc);
4381 if !insidetbc {
4382 let fs = ls.fs.as_mut().unwrap();
4384 let info = e.u.info as usize;
4385 let mut lc = lua_code::opcodes::Instruction(fs.f.code[info].0);
4386 lc.set_opcode(lua_code::opcodes::OpCode::TailCall);
4387 fs.f.code[info] = lua_types::opcode::Instruction::new(lc.0);
4388 }
4389 }
4390 nret = LUA_MULTRET;
4391 } else {
4392 let line = ls.lastline;
4393 if nret == 1 {
4394 first = cg_exp_to_any_reg(ls.fs.as_mut().unwrap(), line, &mut e)? as i32;
4396 } else {
4397 cg_exp_to_next_reg(ls.fs.as_mut().unwrap(), line, &mut e)?;
4399 }
4400 }
4401 }
4402 let line = ls.lastline;
4404 cg_emit_return(ls.fs.as_mut().unwrap(), line, first, nret);
4405 test_next(ls, state, b';' as TokenKind)?;
4407 Ok(())
4408}
4409
4410fn statement(ls: &mut LexState, state: &mut LuaState) -> Result<(), LuaError> {
4413 let line = ls.linenumber;
4419 enter_level(ls)?;
4421 match ls.t.token {
4422 c if c == b';' as TokenKind => {
4423 lex_next(ls, state)?;
4424 }
4425 TK_IF => {
4426 ifstat(ls, state, line)?;
4427 }
4428 TK_WHILE => {
4429 whilestat(ls, state, line)?;
4430 }
4431 TK_DO => {
4432 lex_next(ls, state)?; block(ls, state)?;
4434 check_match(ls, state, TK_END, TK_DO, line)?;
4435 }
4436 TK_FOR => {
4437 forstat(ls, state, line)?;
4438 }
4439 TK_REPEAT => {
4440 repeatstat(ls, state, line)?;
4441 }
4442 TK_FUNCTION => {
4443 funcstat(ls, state, line)?;
4444 }
4445 TK_LOCAL => {
4446 lex_next(ls, state)?; if test_next(ls, state, TK_FUNCTION)? {
4448 localfunc(ls, state)?;
4449 } else {
4450 localstat(ls, state)?;
4451 }
4452 }
4453 TK_DBCOLON => {
4454 lex_next(ls, state)?; let name = str_check_name(ls, state)?;
4456 labelstat(ls, state, name, line)?;
4457 }
4458 TK_RETURN => {
4459 lex_next(ls, state)?; retstat(ls, state)?;
4461 }
4462 TK_BREAK => {
4463 breakstat(ls, state)?;
4464 }
4465 TK_GOTO => {
4466 lex_next(ls, state)?; gotostat(ls, state)?;
4468 }
4469 _ => {
4470 exprstat(ls, state)?;
4471 }
4472 }
4473 debug_assert!(
4474 ls.fs.as_ref().unwrap().f.maxstacksize >= ls.fs.as_ref().unwrap().freereg
4475 && ls.fs.as_ref().unwrap().freereg as i32
4476 >= nvarstack(ls, ls.fs.as_ref().unwrap())
4477 );
4478 let nv = nvarstack(ls, ls.fs.as_ref().unwrap());
4479 ls.fs.as_mut().unwrap().freereg = nv as u8;
4480 leave_level(ls);
4482 Ok(())
4483}
4484
4485fn mainfunc(ls: &mut LexState, state: &mut LuaState, main_fs: FuncState) -> Result<Box<LuaProto>, LuaError> {
4490 open_func(ls, state, main_fs)?;
4492
4493 setvararg(ls.fs.as_mut().unwrap(), state, 0)?;
4495
4496 let env_name = ls.envn.clone();
4498 {
4499 let idx = alloc_upvalue(ls.fs.as_mut().unwrap())?;
4500 let up = &mut ls.fs.as_mut().unwrap().f.upvalues[idx];
4501 up.instack = true;
4502 up.idx = 0;
4503 up.kind = VarKind::Reg.as_u8();
4504 up.name = env_name.clone();
4505 }
4506 lex_next(ls, state)?;
4510
4511 statlist(ls, state)?;
4512
4513 check(ls, TK_EOS)?;
4515
4516 close_func(ls, state)
4517}
4518
4519pub fn parse(
4528 state: &mut LuaState,
4529 dyd: DynData,
4530 source: &[u8],
4531 name: &[u8],
4532 firstchar: i32,
4533) -> Result<Box<LuaProto>, LuaError> {
4534 let source_str = state.intern_str(name)?;
4535 let envn_str = state.intern_str(lua_lex::LUA_ENV)?;
4536
4537 let rest_bytes: Vec<u8> = source.iter().skip(1).copied().collect();
4538 let z = lua_lex::ZIO::from_bytes(rest_bytes);
4539
4540 let lex_ls = lua_lex::LexState {
4541 current: firstchar,
4542 linenumber: 1,
4543 lastline: 1,
4544 t: lua_lex::Token::eos(),
4545 lookahead: lua_lex::Token::eos(),
4546 fs: None,
4547 z,
4548 buff: lua_lex::LexBuffer::new(),
4549 h: None,
4550 long_str_anchor: std::collections::HashMap::new(),
4551 dyd: None,
4552 source: source_str.clone(),
4553 envn: envn_str.clone(),
4554 };
4555
4556 let mut lexstate = LexState {
4557 current: lex_ls.current,
4558 linenumber: lex_ls.linenumber,
4559 lastline: lex_ls.lastline,
4560 t: LexToken::default(),
4561 lookahead: LexToken::default(),
4562 fs: None,
4563 dyd,
4564 source: Some(source_str.clone()),
4565 envn: Some(lex_ls.envn.clone()),
4566 lex: lex_ls,
4567 recursion_depth: 0,
4568 };
4569 let mut main_proto = Box::new(LuaProto::placeholder());
4575 main_proto.source = Some(source_str);
4576 main_proto.is_vararg = true;
4577 let main_fs = FuncState {
4578 f: main_proto,
4579 prev: None,
4580 bl: None,
4581 pc: 0,
4582 lasttarget: 0,
4583 previousline: 0,
4584 nk: 0,
4585 np: 0,
4586 nabslineinfo: 0,
4587 firstlocal: 0,
4588 firstlabel: 0,
4589 ndebugvars: 0,
4590 nactvar: 0,
4591 nups: 0,
4592 freereg: 0,
4593 iwthabs: 0,
4594 needclose: false,
4595 last_token_line: 0,
4596 };
4597
4598 mainfunc(&mut lexstate, state, main_fs)
4599}
4600
4601fn local_token_value(v: &lua_lex::TokenValue) -> TokenValue {
4606 match v {
4607 lua_lex::TokenValue::None => TokenValue::default(),
4608 lua_lex::TokenValue::Float(r) => TokenValue { r: *r, i: 0, ts: None },
4609 lua_lex::TokenValue::Int(i) => TokenValue { r: 0.0, i: *i, ts: None },
4610 lua_lex::TokenValue::Str(s) => TokenValue { r: 0.0, i: 0, ts: Some(s.clone()) },
4611 }
4612}
4613
4614