Skip to main content

luaur_ast/methods/
parser_parse_expr_parser_alt_b.rs

1//! Node: `cxx:Method:Luau.Ast:Ast/src/Parser.cpp:3530:parseExpr`
2//!
3//! The precedence-climbing expression parser (`Parser::parseExpr(unsigned limit)`).
4//! Operands come from `parse_assertion_expr` (and recursively from here for unary
5//! operators); binary operators expand while their left priority exceeds `limit`,
6//! right-associative ops (`^`, `..`) recurse at one-lower priority. All operand
7//! and operator helpers (`parse_unary_op`/`parse_binary_op`/`check_*_confusables`)
8//! are already ported; only this driver was a stub.
9
10use crate::records::ast_expr::AstExpr;
11use crate::records::ast_expr_binary::AstExprBinary;
12use crate::records::ast_expr_unary::AstExprUnary;
13use crate::records::binary_op_priority::BinaryOpPriority;
14use crate::records::cst_expr_op::CstExprOp;
15use crate::records::location::Location;
16use crate::records::parser::Parser;
17
18impl Parser {
19    pub fn parse_expr_i32(&mut self, limit: u32) -> *mut AstExpr {
20        // Per-operator {left, right} binding priorities, indexed by
21        // `AstExprBinaryOp as usize` (same order as the C++ table).
22        const fn p(left: u8, right: u8) -> BinaryOpPriority {
23            BinaryOpPriority { left, right }
24        }
25        let binary_priority: [BinaryOpPriority; 16] = [
26            p(6, 6),  // +
27            p(6, 6),  // -
28            p(7, 7),  // *
29            p(7, 7),  // /
30            p(7, 7),  // //
31            p(7, 7),  // %
32            p(10, 9), // ^ (right associative)
33            p(5, 4),  // .. (right associative)
34            p(3, 3),  // ~=
35            p(3, 3),  // ==
36            p(3, 3),  // <
37            p(3, 3),  // <=
38            p(3, 3),  // >
39            p(3, 3),  // >=
40            p(2, 2),  // and
41            p(1, 1),  // or
42        ];
43        const UNARY_PRIORITY: u32 = 8;
44
45        let start = self.lexer.current().location;
46
47        // C++ parseExpr enforces the recursion limit here (the port dropped it
48        // entirely, so deeply-nested expressions never hit LuauRecursionLimit).
49        let old_recursion_count = self.recursion_counter;
50        // this handles recursive calls to parse_sub_expr/parse_expr
51        self.increment_recursion_counter("expression");
52
53        let curr = *self.lexer.current();
54        let mut uop = self.parse_unary_op(&curr);
55        if uop.is_none() {
56            uop = self.check_unary_confusables();
57        }
58
59        let mut expr: *mut AstExpr;
60        if let Some(uop) = uop {
61            let op_position = self.lexer.current().location.begin;
62            self.next_lexeme();
63            let subexpr = self.parse_expr_i32(UNARY_PRIORITY);
64            let end = unsafe { (*subexpr).base.location.end };
65            let node = unsafe {
66                (*self.allocator).alloc(AstExprUnary::new(
67                    Location::new(start.begin, end),
68                    uop,
69                    subexpr,
70                ))
71            };
72            if self.options.store_cst_data {
73                let cst_node = unsafe { (*self.allocator).alloc(CstExprOp::new(op_position)) };
74                self.cst_node_map.try_insert(
75                    node as *mut crate::records::ast_node::AstNode,
76                    cst_node as *mut crate::records::cst_node::CstNode,
77                );
78            }
79            expr = node as *mut AstExpr;
80        } else {
81            expr = self.parse_assertion_expr();
82        }
83
84        // Expand while operators have priority higher than `limit`.
85        let curr = *self.lexer.current();
86        let mut op = self.parse_binary_op(&curr);
87        if op.is_none() {
88            op = self.check_binary_confusables(&binary_priority, limit);
89        }
90
91        while let Some(o) = op {
92            if binary_priority[o as usize].left as u32 <= limit {
93                break;
94            }
95            let op_position = self.lexer.current().location.begin;
96            self.next_lexeme();
97            let next = self.parse_expr_i32(binary_priority[o as usize].right as u32);
98            let end = unsafe { (*next).base.location.end };
99            let node = unsafe {
100                (*self.allocator).alloc(AstExprBinary::new(
101                    Location::new(start.begin, end),
102                    o,
103                    expr,
104                    next,
105                ))
106            };
107            if self.options.store_cst_data {
108                let cst_node = unsafe { (*self.allocator).alloc(CstExprOp::new(op_position)) };
109                self.cst_node_map.try_insert(
110                    node as *mut crate::records::ast_node::AstNode,
111                    cst_node as *mut crate::records::cst_node::CstNode,
112                );
113            }
114            expr = node as *mut AstExpr;
115            let curr = *self.lexer.current();
116            op = self.parse_binary_op(&curr);
117            if op.is_none() {
118                op = self.check_binary_confusables(&binary_priority, limit);
119            }
120
121            // note: while the parser isn't recursive here, we're generating
122            // recursive structures of unbounded depth
123            self.increment_recursion_counter("expression");
124        }
125
126        self.recursion_counter = old_recursion_count;
127
128        expr
129    }
130}