1use crate::frontend::ast::*;
6use crate::frontend::error::SyntaxError;
7use crate::frontend::lexer::Lexer;
8use crate::frontend::span::Span;
9use crate::frontend::token::{Token, TokenInfo};
10use crate::version::LuaVersion;
11
12const MAX_DEPTH: u32 = 200;
18
19type DeclList = (Option<Attrib>, Vec<AttribName>, Vec<ExprId>);
21
22fn bin_priority(op: BinOp) -> (u8, u8) {
25 match op {
26 BinOp::Or => (1, 1),
27 BinOp::And => (2, 2),
28 BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge | BinOp::Ne | BinOp::Eq => (3, 3),
29 BinOp::BOr => (4, 4),
30 BinOp::BXor => (5, 5),
31 BinOp::BAnd => (6, 6),
32 BinOp::Shl | BinOp::Shr => (7, 7),
33 BinOp::Concat => (9, 8),
34 BinOp::Add | BinOp::Sub => (10, 10),
35 BinOp::Mul | BinOp::Div | BinOp::IDiv | BinOp::Mod => (11, 11),
36 BinOp::Pow => (14, 13),
37 }
38}
39
40const UNARY_PRIORITY: u8 = 12;
41
42fn bin_op_of(tok: &Token) -> Option<BinOp> {
43 Some(match tok {
44 Token::Plus => BinOp::Add,
45 Token::Minus => BinOp::Sub,
46 Token::Star => BinOp::Mul,
47 Token::Slash => BinOp::Div,
48 Token::DSlash => BinOp::IDiv,
49 Token::Percent => BinOp::Mod,
50 Token::Caret => BinOp::Pow,
51 Token::Concat => BinOp::Concat,
52 Token::Eq => BinOp::Eq,
53 Token::Ne => BinOp::Ne,
54 Token::Lt => BinOp::Lt,
55 Token::Le => BinOp::Le,
56 Token::Gt => BinOp::Gt,
57 Token::Ge => BinOp::Ge,
58 Token::And => BinOp::And,
59 Token::Or => BinOp::Or,
60 Token::Amp => BinOp::BAnd,
61 Token::Pipe => BinOp::BOr,
62 Token::Tilde => BinOp::BXor,
63 Token::Shl => BinOp::Shl,
64 Token::Shr => BinOp::Shr,
65 _ => return None,
66 })
67}
68
69fn un_op_of(tok: &Token) -> Option<UnOp> {
70 Some(match tok {
71 Token::Minus => UnOp::Neg,
72 Token::Not => UnOp::Not,
73 Token::Hash => UnOp::Len,
74 Token::Tilde => UnOp::BNot,
75 _ => return None,
76 })
77}
78
79pub(crate) enum TokenSource<'s> {
85 Lexer(Lexer<'s>),
87 PreExpanded {
91 tokens: Vec<TokenInfo>,
92 cursor: usize,
93 src: &'s [u8],
94 },
95}
96
97impl<'s> TokenSource<'s> {
98 fn next_token(&mut self) -> Result<TokenInfo, SyntaxError> {
99 match self {
100 TokenSource::Lexer(l) => l.next_token(),
101 TokenSource::PreExpanded {
102 tokens,
103 cursor,
104 src,
105 } => {
106 if *cursor >= tokens.len() {
107 let line = tokens.last().map(|t| t.line).unwrap_or(1);
108 let _ = src;
109 Ok(TokenInfo {
110 tok: Token::Eof,
111 span: Span::new(0, 0),
112 line,
113 })
114 } else {
115 let t = tokens[*cursor].clone();
116 *cursor += 1;
117 Ok(t)
118 }
119 }
120 }
121 }
122
123 fn src(&self) -> &'s [u8] {
124 match self {
125 TokenSource::Lexer(l) => l.src(),
126 TokenSource::PreExpanded { src, .. } => src,
127 }
128 }
129}
130
131pub fn parse(src: &[u8], version: LuaVersion) -> Result<Chunk, SyntaxError> {
140 let lex = Lexer::new(src, version);
141 parse_from_source(TokenSource::Lexer(lex), version)
142}
143
144pub fn parse_tokens(
149 tokens: Vec<TokenInfo>,
150 src: &[u8],
151 version: LuaVersion,
152) -> Result<Chunk, SyntaxError> {
153 parse_from_source(
154 TokenSource::PreExpanded {
155 tokens,
156 cursor: 0,
157 src,
158 },
159 version,
160 )
161}
162
163fn parse_from_source<'s>(
164 mut lex: TokenSource<'s>,
165 version: LuaVersion,
166) -> Result<Chunk, SyntaxError> {
167 let tok = lex.next_token()?;
168 let mut p = Parser {
169 lex,
170 tok,
171 peeked: None,
172 prev_line: 1,
173 exprs: Vec::new(),
174 stats: Vec::new(),
175 stat_lines: Vec::new(),
176 depth: 0,
177 version,
178 func_local_count: vec![(0, 0)],
180 upval_chain_51: if version <= LuaVersion::Lua51 {
181 vec![FnUvSlot {
182 line_defined: 0,
183 ..Default::default()
184 }]
185 } else {
186 Vec::new()
187 },
188 };
189 let block = p.block()?;
190 if p.tok.tok != Token::Eof {
191 return Err(p.error("'<eof>' expected"));
192 }
193 let end_line = p.prev_line;
194 Ok(Chunk {
195 exprs: p.exprs,
196 stats: p.stats,
197 stat_lines: p.stat_lines,
198 block,
199 end_line,
200 })
201}
202
203struct Parser<'s> {
204 lex: TokenSource<'s>,
205 tok: TokenInfo,
206 peeked: Option<TokenInfo>,
207 prev_line: u32,
209 exprs: Vec<Expr>,
210 stats: Vec<Stat>,
211 stat_lines: Vec<u32>,
214 depth: u32,
215 version: LuaVersion,
216 func_local_count: Vec<(u32, u32)>,
222 upval_chain_51: Vec<FnUvSlot>,
233}
234
235#[derive(Default)]
236struct FnUvSlot {
237 locals: Vec<Box<str>>,
238 upvalues: std::collections::HashSet<Box<str>>,
239 line_defined: u32,
240}
241
242impl<'s> Parser<'s> {
243 fn advance(&mut self) -> Result<TokenInfo, SyntaxError> {
246 let next = match self.peeked.take() {
247 Some(t) => t,
248 None => self.lex.next_token()?,
249 };
250 self.prev_line = self.tok.line;
251 Ok(std::mem::replace(&mut self.tok, next))
252 }
253
254 fn peek(&mut self) -> Result<&Token, SyntaxError> {
255 if self.peeked.is_none() {
256 self.peeked = Some(self.lex.next_token()?);
257 }
258 Ok(&self.peeked.as_ref().unwrap().tok)
259 }
260
261 fn near(&self) -> String {
262 self.tok
263 .tok
264 .describe(self.lex.src(), self.tok.span, self.version)
265 }
266
267 fn error(&self, msg: impl AsRef<str>) -> SyntaxError {
268 let mut bytes = msg.as_ref().as_bytes().to_vec();
269 bytes.extend_from_slice(b" near ");
270 bytes.extend_from_slice(self.near().as_bytes());
271 SyntaxError {
272 line: self.tok.line,
273 msg: bytes,
274 }
275 }
276
277 fn accept(&mut self, tok: Token) -> Result<bool, SyntaxError> {
278 if self.tok.tok == tok {
279 self.advance()?;
280 Ok(true)
281 } else {
282 Ok(false)
283 }
284 }
285
286 fn expect(&mut self, tok: Token, what: &str) -> Result<(), SyntaxError> {
287 if !self.accept(tok)? {
288 return Err(self.error(format!("'{what}' expected")));
289 }
290 Ok(())
291 }
292
293 fn expect_match(
295 &mut self,
296 tok: Token,
297 what: &str,
298 who: &str,
299 who_line: u32,
300 ) -> Result<(), SyntaxError> {
301 if !self.accept(tok)? {
302 if who_line == self.tok.line {
303 return Err(self.error(format!("'{what}' expected")));
304 }
305 return Err(self.error(format!(
306 "'{what}' expected (to close '{who}' at line {who_line})"
307 )));
308 }
309 Ok(())
310 }
311
312 fn expect_name(&mut self) -> Result<Name, SyntaxError> {
313 if !matches!(self.tok.tok, Token::Name(_)) {
314 return Err(self.error("<name> expected"));
315 }
316 let info = self.advance()?;
317 let Token::Name(text) = info.tok else {
318 unreachable!()
319 };
320 Ok(Name {
321 text,
322 line: info.line,
323 })
324 }
325
326 fn enter(&mut self) -> Result<(), SyntaxError> {
327 self.depth += 1;
328 if self.depth > MAX_DEPTH {
329 let msg: &[u8] = if self.version <= LuaVersion::Lua51 {
334 b"chunk has too many syntax levels"
335 } else {
336 b"too many C levels (limit is 200) in main function"
337 };
338 return Err(SyntaxError {
339 line: self.tok.line,
340 msg: msg.to_vec(),
341 });
342 }
343 Ok(())
344 }
345
346 fn leave(&mut self) {
347 self.depth -= 1;
348 }
349
350 fn push_expr(&mut self, e: Expr) -> ExprId {
351 self.exprs.push(e);
352 ExprId((self.exprs.len() - 1) as u32)
353 }
354
355 fn push_stat(&mut self, s: Stat) -> StatId {
356 self.stats.push(s);
357 StatId((self.stats.len() - 1) as u32)
358 }
359
360 fn block_follow(&self) -> bool {
363 matches!(
364 self.tok.tok,
365 Token::Eof | Token::End | Token::Else | Token::Elseif | Token::Until
366 )
367 }
368
369 fn block(&mut self) -> Result<Block, SyntaxError> {
370 self.enter()?;
371 let local_snapshot = self.func_local_count.last().expect("func ctx").0;
376 let locals_51_snap = self.snap_locals_51();
377 let mut stats = Vec::new();
378 loop {
379 if self.block_follow() {
380 break;
381 }
382 if self.tok.tok == Token::Return {
383 stats.push(self.return_stat()?);
384 break;
385 }
386 if self.tok.tok == Token::Break && self.version.break_is_last_statement() {
387 let line = self.tok.line;
388 self.advance()?;
389 stats.push(self.push_stat(Stat::Break { line }));
390 self.accept(Token::Semi)?;
391 break;
392 }
393 if let Some(s) = self.statement()? {
394 stats.push(s);
395 }
396 if !self.version.has_empty_statement() {
397 self.accept(Token::Semi)?;
399 }
400 }
401 self.leave();
402 self.func_local_count.last_mut().expect("func ctx").0 = local_snapshot;
403 self.restore_locals_51(locals_51_snap);
404 Ok(Block { stats })
405 }
406
407 fn return_stat(&mut self) -> Result<StatId, SyntaxError> {
408 let line = self.tok.line;
409 self.advance()?;
410 let exprs = if self.block_follow() || self.tok.tok == Token::Semi {
411 Vec::new()
412 } else {
413 self.exprlist()?
414 };
415 self.accept(Token::Semi)?;
416 Ok(self.push_stat(Stat::Return { exprs, line }))
417 }
418
419 fn statement(&mut self) -> Result<Option<StatId>, SyntaxError> {
420 let start_line = self.tok.line;
427 if self.version.has_global_decl()
432 && matches!(&self.tok.tok, Token::Name(n) if &**n == "global")
433 && matches!(
434 self.peek()?,
435 Token::Name(_) | Token::Star | Token::Function | Token::Lt
436 )
437 {
438 let stat = self.global_stat()?;
439 return Ok(Some(stat));
440 }
441 let stat = match self.tok.tok {
442 Token::Semi => {
443 if !self.version.has_empty_statement() {
444 return Err(self.error("unexpected symbol"));
445 }
446 self.advance()?;
447 None
448 }
449 Token::If => Some(self.if_stat()?),
450 Token::While => Some(self.while_stat()?),
451 Token::Do => {
452 let line = self.tok.line;
453 self.advance()?;
454 let body = self.block()?;
455 self.expect_match(Token::End, "end", "do", line)?;
456 Some(self.push_stat(Stat::Do(body)))
457 }
458 Token::For => Some(self.for_stat()?),
459 Token::Repeat => Some(self.repeat_stat()?),
460 Token::Function => Some(self.function_stat()?),
461 Token::Local => Some(self.local_stat()?),
462 Token::DColon => {
463 self.advance()?;
464 let name = self.expect_name()?;
465 self.expect(Token::DColon, "::")?;
466 Some(self.push_stat(Stat::Label(name)))
467 }
468 Token::Break => {
469 let line = self.tok.line;
470 self.advance()?;
471 Some(self.push_stat(Stat::Break { line }))
472 }
473 Token::Goto => {
474 self.advance()?;
475 let name = self.expect_name()?;
476 Some(self.push_stat(Stat::Goto(name)))
477 }
478 _ => Some(self.expr_stat()?),
479 };
480 if let Some(sid) = stat {
481 let idx = sid.0 as usize;
482 if self.stat_lines.len() <= idx {
483 self.stat_lines.resize(idx + 1, 0);
484 }
485 self.stat_lines[idx] = start_line;
486 }
487 Ok(stat)
488 }
489
490 fn if_stat(&mut self) -> Result<StatId, SyntaxError> {
491 let line = self.tok.line;
492 self.advance()?;
493 let mut arms = Vec::new();
494 let cond = self.expr()?;
495 let then_line = self.tok.line;
496 self.expect(Token::Then, "then")?;
497 arms.push((cond, then_line, self.block()?));
498 while self.tok.tok == Token::Elseif {
499 self.advance()?;
500 let cond = self.expr()?;
501 let then_line = self.tok.line;
502 self.expect(Token::Then, "then")?;
503 arms.push((cond, then_line, self.block()?));
504 }
505 let else_body = if self.accept(Token::Else)? {
506 Some(self.block()?)
507 } else {
508 None
509 };
510 self.expect_match(Token::End, "end", "if", line)?;
511 Ok(self.push_stat(Stat::If { arms, else_body }))
512 }
513
514 fn while_stat(&mut self) -> Result<StatId, SyntaxError> {
515 let line = self.tok.line;
516 self.advance()?;
517 let cond = self.expr()?;
518 self.expect(Token::Do, "do")?;
519 let body = self.block()?;
520 self.expect_match(Token::End, "end", "while", line)?;
521 Ok(self.push_stat(Stat::While { cond, body }))
522 }
523
524 fn repeat_stat(&mut self) -> Result<StatId, SyntaxError> {
525 let line = self.tok.line;
526 self.advance()?;
527 let body = self.block()?;
528 self.expect_match(Token::Until, "until", "repeat", line)?;
529 let cond = self.expr()?;
530 Ok(self.push_stat(Stat::Repeat { body, cond }))
531 }
532
533 fn for_stat(&mut self) -> Result<StatId, SyntaxError> {
534 let line = self.tok.line;
535 self.advance()?;
536 let first = self.expect_name()?;
537 match self.tok.tok {
538 Token::Assign => {
539 self.advance()?;
540 let start = self.expr()?;
541 self.expect(Token::Comma, ",")?;
542 let limit = self.expr()?;
543 let step = if self.accept(Token::Comma)? {
544 Some(self.expr()?)
545 } else {
546 None
547 };
548 self.expect(Token::Do, "do")?;
549 self.add_local_51(&first.text);
550 let body = self.block()?;
551 self.expect_match(Token::End, "end", "for", line)?;
552 Ok(self.push_stat(Stat::NumericFor {
553 var: first,
554 start,
555 limit,
556 step,
557 body,
558 }))
559 }
560 Token::Comma | Token::In => {
561 let mut vars = vec![first];
562 while self.accept(Token::Comma)? {
563 vars.push(self.expect_name()?);
564 }
565 self.expect(Token::In, "in")?;
566 let expr_line = self.tok.line;
567 let exprs = self.exprlist()?;
568 self.expect(Token::Do, "do")?;
569 for v in &vars {
570 self.add_local_51(&v.text);
571 }
572 let body = self.block()?;
573 self.expect_match(Token::End, "end", "for", line)?;
574 Ok(self.push_stat(Stat::GenericFor {
575 vars,
576 exprs,
577 body,
578 expr_line,
579 }))
580 }
581 _ => Err(self.error("'=' or 'in' expected")),
582 }
583 }
584
585 fn function_stat(&mut self) -> Result<StatId, SyntaxError> {
586 let line = self.tok.line;
587 self.advance()?;
588 let base = self.expect_name()?;
589 let mut path = Vec::new();
590 while self.accept(Token::Dot)? {
591 path.push(self.expect_name()?);
592 }
593 let method = if self.accept(Token::Colon)? {
594 Some(self.expect_name()?)
595 } else {
596 None
597 };
598 let body = self.func_body(line)?;
599 Ok(self.push_stat(Stat::Function {
600 name: FuncName { base, path, method },
601 body,
602 }))
603 }
604
605 fn attrib(&mut self) -> Result<Option<Attrib>, SyntaxError> {
606 if !(self.version.has_attribs() && self.tok.tok == Token::Lt) {
607 return Ok(None);
608 }
609 self.advance()?;
610 let name = self.expect_name()?;
611 let attrib = match &*name.text {
612 "const" => Attrib::Const,
613 "close" => Attrib::Close,
614 other => {
615 return Err(SyntaxError {
616 line: name.line,
617 msg: format!("unknown attribute '{other}'").into_bytes(),
618 });
619 }
620 };
621 self.expect(Token::Gt, ">")?;
622 Ok(Some(attrib))
623 }
624
625 fn attnamelist(&mut self) -> Result<DeclList, SyntaxError> {
628 let collective = if self.version.has_collective_attrib() {
629 self.attrib()?
630 } else {
631 None
632 };
633 let mut names = Vec::new();
634 loop {
635 let name = self.expect_name()?;
636 let attrib = self.attrib()?;
637 names.push(AttribName { name, attrib });
638 if !self.accept(Token::Comma)? {
639 break;
640 }
641 }
642 let exprs = if self.accept(Token::Assign)? {
643 self.exprlist()?
644 } else {
645 Vec::new()
646 };
647 Ok((collective, names, exprs))
648 }
649
650 fn local_stat(&mut self) -> Result<StatId, SyntaxError> {
651 self.advance()?;
652 if self.accept(Token::Function)? {
653 let line = self.prev_line;
654 let name = self.expect_name()?;
655 self.bump_locals(1)?;
658 self.add_local_51(&name.text);
659 let body = self.func_body(line)?;
660 return Ok(self.push_stat(Stat::LocalFunction { name, body }));
661 }
662 let (collective, names, exprs) = self.attnamelist()?;
663 self.bump_locals(names.len() as u32)?;
664 for an in &names {
665 self.add_local_51(&an.name.text);
666 }
667 Ok(self.push_stat(Stat::Local {
668 collective,
669 names,
670 exprs,
671 }))
672 }
673
674 fn global_stat(&mut self) -> Result<StatId, SyntaxError> {
675 self.advance()?;
676 if self.accept(Token::Function)? {
677 let line = self.prev_line;
678 let name = self.expect_name()?;
679 let body = self.func_body(line)?;
680 return Ok(self.push_stat(Stat::GlobalFunction { name, body }));
681 }
682 let leading = self.attrib()?;
684 if self.accept(Token::Star)? {
685 return Ok(self.push_stat(Stat::GlobalAll { attrib: leading }));
686 }
687 let mut names = Vec::new();
688 loop {
689 let name = self.expect_name()?;
690 let attrib = self.attrib()?;
691 names.push(AttribName { name, attrib });
692 if !self.accept(Token::Comma)? {
693 break;
694 }
695 }
696 let exprs = if self.accept(Token::Assign)? {
697 self.exprlist()?
698 } else {
699 Vec::new()
700 };
701 Ok(self.push_stat(Stat::Global {
702 collective: leading,
703 names,
704 exprs,
705 }))
706 }
707
708 fn expr_stat(&mut self) -> Result<StatId, SyntaxError> {
709 let first = self.suffixed_expr()?;
710 if matches!(self.tok.tok, Token::Assign | Token::Comma) {
711 let mut targets = vec![first];
712 while self.accept(Token::Comma)? {
713 if targets.len() >= 200 {
718 let msg: &[u8] = if self.version <= LuaVersion::Lua51 {
719 b"chunk has too many syntax levels"
720 } else {
721 b"too many C levels (limit is 200) in main function"
722 };
723 return Err(SyntaxError {
724 line: self.tok.line,
725 msg: msg.to_vec(),
726 });
727 }
728 targets.push(self.suffixed_expr()?);
729 }
730 self.expect(Token::Assign, "=")?;
731 for &t in &targets {
732 if !matches!(self.exprs[t.0 as usize], Expr::Name(_) | Expr::Index { .. }) {
733 return Err(self.error("syntax error"));
734 }
735 }
736 let exprs = self.exprlist()?;
737 return Ok(self.push_stat(Stat::Assign { targets, exprs }));
738 }
739 if !matches!(
740 self.exprs[first.0 as usize],
741 Expr::Call { .. } | Expr::MethodCall { .. }
742 ) {
743 return Err(self.error("syntax error"));
744 }
745 Ok(self.push_stat(Stat::Call(first)))
746 }
747
748 fn exprlist(&mut self) -> Result<Vec<ExprId>, SyntaxError> {
751 let mut list = vec![self.expr()?];
752 while self.accept(Token::Comma)? {
753 list.push(self.expr()?);
754 }
755 Ok(list)
756 }
757
758 fn expr(&mut self) -> Result<ExprId, SyntaxError> {
759 self.sub_expr(0)
760 }
761
762 fn sub_expr(&mut self, limit: u8) -> Result<ExprId, SyntaxError> {
763 self.enter()?;
764 let mut left = if let Some(op) = un_op_of(&self.tok.tok) {
765 let line = self.tok.line;
766 self.advance()?;
767 let operand = self.sub_expr(UNARY_PRIORITY)?;
768 self.push_expr(Expr::UnOp { op, operand, line })
769 } else {
770 self.simple_expr()?
771 };
772 while let Some(op) = bin_op_of(&self.tok.tok) {
773 let (lp, rp) = bin_priority(op);
774 if lp <= limit {
775 break;
776 }
777 let line = self.tok.line;
778 self.advance()?;
779 let rhs = self.sub_expr(rp)?;
780 left = self.push_expr(Expr::BinOp {
781 op,
782 lhs: left,
783 rhs,
784 line,
785 });
786 }
787 self.leave();
788 Ok(left)
789 }
790
791 fn simple_expr(&mut self) -> Result<ExprId, SyntaxError> {
792 let e = match &self.tok.tok {
793 Token::Nil => {
794 self.advance()?;
795 Expr::Nil
796 }
797 Token::True => {
798 self.advance()?;
799 Expr::True
800 }
801 Token::False => {
802 self.advance()?;
803 Expr::False
804 }
805 Token::Ellipsis => {
806 self.advance()?;
807 Expr::Vararg
808 }
809 Token::Int(_) => {
810 let Token::Int(v) = self.advance()?.tok else {
811 unreachable!()
812 };
813 Expr::Int(v)
814 }
815 Token::Float(_) => {
816 let Token::Float(v) = self.advance()?.tok else {
817 unreachable!()
818 };
819 Expr::Float(v)
820 }
821 Token::Str(_) => {
822 let Token::Str(s) = self.advance()?.tok else {
823 unreachable!()
824 };
825 Expr::Str(s)
826 }
827 Token::LBrace => return self.table_constructor(),
828 Token::Function => {
829 let line = self.tok.line;
830 self.advance()?;
831 Expr::Function(self.func_body(line)?)
832 }
833 _ => return self.suffixed_expr(),
834 };
835 Ok(self.push_expr(e))
836 }
837
838 fn primary_expr(&mut self) -> Result<ExprId, SyntaxError> {
839 match &self.tok.tok {
840 Token::Name(_) => {
841 let name = self.expect_name()?;
842 self.ident_lookup_51(&name.text)?;
843 Ok(self.push_expr(Expr::Name(name)))
844 }
845 Token::LParen => {
846 let line = self.tok.line;
847 self.advance()?;
848 let inner = self.expr()?;
849 self.expect_match(Token::RParen, ")", "(", line)?;
850 Ok(self.push_expr(Expr::Paren(inner)))
851 }
852 _ => Err(self.error("unexpected symbol")),
853 }
854 }
855
856 fn suffixed_expr(&mut self) -> Result<ExprId, SyntaxError> {
857 let primary_line = self.tok.line;
872 let mut e = self.primary_expr()?;
873 loop {
874 match &self.tok.tok {
875 Token::Dot => {
876 self.advance()?;
877 let name = self.expect_name()?;
878 let key = self.push_expr(Expr::Str(name.text.into_boxed_bytes().into_vec()));
879 e = self.push_expr(Expr::Index { obj: e, key });
880 }
881 Token::LBracket => {
882 self.advance()?;
883 let key = self.expr()?;
884 self.expect(Token::RBracket, "]")?;
885 e = self.push_expr(Expr::Index { obj: e, key });
886 }
887 Token::Colon => {
888 self.advance()?;
889 let method = self.expect_name()?;
890 let line = if self.version <= LuaVersion::Lua53 {
891 primary_line
892 } else {
893 self.tok.line
894 };
895 let args = self.call_args()?;
896 e = self.push_expr(Expr::MethodCall {
897 obj: e,
898 method,
899 args,
900 line,
901 });
902 }
903 Token::LParen | Token::Str(_) | Token::LBrace => {
904 let line = if self.version <= LuaVersion::Lua53 {
905 primary_line
906 } else {
907 self.tok.line
908 };
909 let args = self.call_args()?;
910 e = self.push_expr(Expr::Call {
911 func: e,
912 args,
913 line,
914 });
915 }
916 _ => break,
917 }
918 }
919 Ok(e)
920 }
921
922 fn call_args(&mut self) -> Result<Vec<ExprId>, SyntaxError> {
923 match &self.tok.tok {
924 Token::LParen => {
925 if self.version == LuaVersion::Lua51 && self.tok.line != self.prev_line {
927 return Err(self.error("ambiguous syntax (function call x new statement)"));
928 }
929 let line = self.tok.line;
930 self.advance()?;
931 let args = if self.tok.tok == Token::RParen {
932 Vec::new()
933 } else {
934 self.exprlist()?
935 };
936 self.expect_match(Token::RParen, ")", "(", line)?;
937 Ok(args)
938 }
939 Token::Str(_) => {
940 let Token::Str(s) = self.advance()?.tok else {
941 unreachable!()
942 };
943 Ok(vec![self.push_expr(Expr::Str(s))])
944 }
945 Token::LBrace => Ok(vec![self.table_constructor()?]),
946 _ => Err(self.error("function arguments expected")),
947 }
948 }
949
950 fn table_constructor(&mut self) -> Result<ExprId, SyntaxError> {
951 let line = self.tok.line;
952 self.expect(Token::LBrace, "{")?;
953 let mut fields = Vec::new();
954 loop {
955 if self.tok.tok == Token::RBrace {
956 break;
957 }
958 if self.tok.tok == Token::LBracket {
959 self.advance()?;
960 let key = self.expr()?;
961 self.expect(Token::RBracket, "]")?;
962 self.expect(Token::Assign, "=")?;
963 let value = self.expr()?;
964 fields.push(TableField::Keyed(key, value));
965 } else if matches!(self.tok.tok, Token::Name(_)) && *self.peek()? == Token::Assign {
966 let name = self.expect_name()?;
967 self.advance()?; let value = self.expr()?;
969 fields.push(TableField::Named(name, value));
970 } else {
971 fields.push(TableField::Item(self.expr()?));
972 }
973 if !(self.accept(Token::Comma)? || self.accept(Token::Semi)?) {
974 break;
975 }
976 }
977 self.expect_match(Token::RBrace, "}", "{", line)?;
978 Ok(self.push_expr(Expr::Table { fields, line }))
979 }
980
981 fn func_body(&mut self, line: u32) -> Result<FuncBody, SyntaxError> {
984 self.expect(Token::LParen, "(")?;
985 self.func_local_count.push((0, line));
986 self.enter_fn_51(line);
987 let mut params = Vec::new();
988 let mut vararg = Vararg::None;
989 if self.tok.tok != Token::RParen {
990 loop {
991 match &self.tok.tok {
992 Token::Ellipsis => {
993 self.advance()?;
994 vararg = if self.version.has_named_vararg()
995 && matches!(self.tok.tok, Token::Name(_))
996 {
997 Vararg::Named(self.expect_name()?)
998 } else {
999 Vararg::Anonymous
1000 };
1001 if let Vararg::Named(ref n) = vararg {
1002 self.add_local_51(&n.text);
1003 }
1004 break;
1005 }
1006 Token::Name(_) => {
1007 let p = self.expect_name()?;
1008 self.add_local_51(&p.text);
1009 params.push(p);
1010 }
1011 _ => return Err(self.error("<name> expected")),
1012 }
1013 if !self.accept(Token::Comma)? {
1014 break;
1015 }
1016 }
1017 }
1018 self.expect(Token::RParen, ")")?;
1019 let nparams = params.len() as u32 + matches!(vararg, Vararg::Named(_)) as u32;
1023 self.bump_locals(nparams)?;
1024 let block = self.block()?;
1025 let end_line = self.tok.line; self.expect_match(Token::End, "end", "function", line)?;
1027 self.func_local_count.pop();
1028 self.leave_fn_51();
1029 Ok(FuncBody {
1030 params,
1031 vararg,
1032 block,
1033 line,
1034 end_line,
1035 })
1036 }
1037
1038 fn track_uv_51(&self) -> bool {
1039 !self.upval_chain_51.is_empty()
1040 }
1041
1042 fn add_local_51(&mut self, name: &str) {
1043 if self.track_uv_51() {
1044 self.upval_chain_51
1045 .last_mut()
1046 .expect("fn ctx")
1047 .locals
1048 .push(name.into());
1049 }
1050 }
1051
1052 fn snap_locals_51(&self) -> usize {
1053 if self.track_uv_51() {
1054 self.upval_chain_51.last().expect("fn ctx").locals.len()
1055 } else {
1056 0
1057 }
1058 }
1059
1060 fn restore_locals_51(&mut self, snap: usize) {
1061 if self.track_uv_51() {
1062 self.upval_chain_51
1063 .last_mut()
1064 .expect("fn ctx")
1065 .locals
1066 .truncate(snap);
1067 }
1068 }
1069
1070 fn enter_fn_51(&mut self, line_defined: u32) {
1071 if self.track_uv_51() {
1072 self.upval_chain_51.push(FnUvSlot {
1073 line_defined,
1074 ..Default::default()
1075 });
1076 }
1077 }
1078
1079 fn leave_fn_51(&mut self) {
1080 if self.track_uv_51() {
1081 self.upval_chain_51.pop();
1082 }
1083 }
1084
1085 fn ident_lookup_51(&mut self, name: &str) -> Result<(), SyntaxError> {
1091 if !self.track_uv_51() {
1092 return Ok(());
1093 }
1094 const MAXUPVAL: usize = 60;
1095 let n = self.upval_chain_51.len();
1096 let mut owner: Option<usize> = None;
1097 for k in (0..n).rev() {
1098 if self.upval_chain_51[k]
1099 .locals
1100 .iter()
1101 .any(|s| s.as_ref() == name)
1102 {
1103 owner = Some(k);
1104 break;
1105 }
1106 }
1107 let Some(owner_idx) = owner else {
1108 return Ok(());
1109 };
1110 if owner_idx + 1 == n {
1111 return Ok(());
1112 }
1113 for k in (owner_idx + 1)..n {
1114 let inserted = self.upval_chain_51[k].upvalues.insert(name.into());
1115 if inserted && self.upval_chain_51[k].upvalues.len() > MAXUPVAL {
1116 let line_defined = self.upval_chain_51[k].line_defined;
1117 let where_ = if k == 0 {
1118 "main function".to_string()
1119 } else {
1120 format!("function at line {line_defined}")
1121 };
1122 return Err(SyntaxError {
1123 line: self.tok.line,
1124 msg: format!("too many upvalues (limit is {MAXUPVAL}) in {where_}")
1125 .into_bytes(),
1126 });
1127 }
1128 }
1129 Ok(())
1130 }
1131
1132 fn bump_locals(&mut self, n: u32) -> Result<(), SyntaxError> {
1137 const MAXVARS: u32 = 200;
1138 let depth = self.func_local_count.len();
1139 let &(cur, line_defined) = self.func_local_count.last().expect("func ctx pushed");
1140 let new = cur.saturating_add(n);
1141 if new > MAXVARS {
1142 let where_ = if depth == 1 {
1143 "main function".to_string()
1144 } else {
1145 format!("function at line {line_defined}")
1146 };
1147 return Err(SyntaxError {
1148 line: self.tok.line,
1149 msg: format!("too many local variables (limit is {MAXVARS}) in {where_}")
1150 .into_bytes(),
1151 });
1152 }
1153 self.func_local_count.last_mut().unwrap().0 = new;
1154 Ok(())
1155 }
1156}