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