Skip to main content

oak_lua/parser/
mod.rs

1pub mod element_type;
2pub use element_type::LuaElementType;
3
4use crate::{language::LuaLanguage, lexer::LuaLexer};
5use oak_core::{
6    GreenNode, OakError, TextEdit,
7    parser::{
8        ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer,
9        pratt::{Associativity, Pratt, PrattParser, binary, unary},
10    },
11    source::Source,
12};
13
14pub(crate) type State<'a, S> = ParserState<'a, LuaLanguage, S>;
15
16pub struct LuaParser<'config> {
17    pub(crate) config: &'config LuaLanguage,
18}
19
20impl<'config> LuaParser<'config> {
21    pub fn new(config: &'config LuaLanguage) -> Self {
22        Self { config }
23    }
24
25    pub(crate) fn parse_root_internal<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<&'a GreenNode<'a, LuaLanguage>, OakError> {
26        use crate::lexer::LuaTokenType::*;
27        let checkpoint = state.checkpoint();
28
29        while state.not_at_end() {
30            self.parse_statement(state).ok();
31        }
32
33        Ok(state.finish_at(checkpoint, crate::parser::element_type::LuaElementType::SourceFile))
34    }
35
36    fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
37        use crate::lexer::LuaTokenType::*;
38        match state.peek_kind() {
39            Some(Local) => self.parse_local_statement(state)?,
40            Some(If) => self.parse_if_statement(state)?,
41            Some(While) => self.parse_while_statement(state)?,
42            Some(For) => self.parse_for_statement(state)?,
43            Some(Repeat) => self.parse_repeat_statement(state)?,
44            Some(Function) => self.parse_function_declaration(state)?,
45            Some(Return) => self.parse_return_statement(state)?,
46            Some(Break) => self.parse_break_statement(state)?,
47            Some(Do) => self.parse_do_statement(state)?,
48            Some(Goto) => self.parse_goto_statement(state)?,
49            Some(ColonColon) => self.parse_label_statement(state)?,
50            _ => {
51                let cp = state.checkpoint();
52                PrattParser::parse(state, 0, self);
53                if state.at(Comma) || state.at(Eq) {
54                    while state.eat(Comma) {
55                        PrattParser::parse(state, 0, self);
56                    }
57                    state.expect(Eq).ok();
58                    PrattParser::parse(state, 0, self);
59                    while state.eat(Comma) {
60                        PrattParser::parse(state, 0, self);
61                    }
62                    state.finish_at(cp, crate::parser::element_type::LuaElementType::AssignmentStatement);
63                }
64                else {
65                    state.finish_at(cp, crate::parser::element_type::LuaElementType::ExpressionStatement);
66                }
67                state.eat(Semicolon);
68            }
69        }
70        Ok(())
71    }
72
73    fn parse_local_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
74        use crate::lexer::LuaTokenType::*;
75        let cp = state.checkpoint();
76        state.expect(Local).ok();
77        if state.eat(Function) {
78            state.expect(Identifier).ok();
79            self.parse_function_body(state)?;
80        }
81        else {
82            state.expect(Identifier).ok();
83            while state.eat(Comma) {
84                state.expect(Identifier).ok();
85            }
86            if state.eat(Eq) {
87                PrattParser::parse(state, 0, self);
88                while state.eat(Comma) {
89                    PrattParser::parse(state, 0, self);
90                }
91            }
92        }
93        state.eat(Semicolon);
94        state.finish_at(cp, crate::parser::element_type::LuaElementType::LocalStatement);
95        Ok(())
96    }
97
98    fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
99        use crate::lexer::LuaTokenType::*;
100        let cp = state.checkpoint();
101        state.expect(If).ok();
102        PrattParser::parse(state, 0, self);
103        state.expect(Then).ok();
104        self.parse_block(state)?;
105        while state.eat(Elseif) {
106            PrattParser::parse(state, 0, self);
107            state.expect(Then).ok();
108            self.parse_block(state)?;
109        }
110        if state.eat(Else) {
111            self.parse_block(state)?;
112        }
113        state.expect(End).ok();
114        state.finish_at(cp, crate::parser::element_type::LuaElementType::IfStatement);
115        Ok(())
116    }
117
118    fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
119        use crate::lexer::LuaTokenType::*;
120        let cp = state.checkpoint();
121        state.expect(While).ok();
122        PrattParser::parse(state, 0, self);
123        state.expect(Do).ok();
124        self.parse_block(state)?;
125        state.expect(End).ok();
126        state.finish_at(cp, crate::parser::element_type::LuaElementType::WhileStatement);
127        Ok(())
128    }
129
130    fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
131        use crate::lexer::LuaTokenType::*;
132        let cp = state.checkpoint();
133        state.expect(For).ok();
134        state.expect(Identifier).ok();
135        if state.eat(Eq) {
136            PrattParser::parse(state, 0, self);
137            state.expect(Comma).ok();
138            PrattParser::parse(state, 0, self);
139            if state.eat(Comma) {
140                PrattParser::parse(state, 0, self);
141            }
142        }
143        else {
144            while state.eat(Comma) {
145                state.expect(Identifier).ok();
146            }
147            state.expect(In).ok();
148            PrattParser::parse(state, 0, self);
149            while state.eat(Comma) {
150                PrattParser::parse(state, 0, self);
151            }
152        }
153        state.expect(Do).ok();
154        self.parse_block(state)?;
155        state.expect(End).ok();
156        state.finish_at(cp, crate::parser::element_type::LuaElementType::ForStatement);
157        Ok(())
158    }
159
160    fn parse_repeat_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
161        use crate::lexer::LuaTokenType::*;
162        let cp = state.checkpoint();
163        state.expect(Repeat).ok();
164        self.parse_block(state)?;
165        state.expect(Until).ok();
166        PrattParser::parse(state, 0, self);
167        state.finish_at(cp, crate::parser::element_type::LuaElementType::RepeatStatement);
168        Ok(())
169    }
170
171    fn parse_function_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
172        use crate::lexer::LuaTokenType::*;
173        let cp = state.checkpoint();
174        state.expect(Function).ok();
175        state.expect(Identifier).ok();
176        while state.eat(Dot) {
177            state.expect(Identifier).ok();
178        }
179        if state.eat(Colon) {
180            state.expect(Identifier).ok();
181        }
182        self.parse_function_body(state)?;
183        state.finish_at(cp, crate::parser::element_type::LuaElementType::FunctionDeclaration);
184        Ok(())
185    }
186
187    fn parse_function_body<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
188        use crate::lexer::LuaTokenType::*;
189        state.expect(LeftParen).ok();
190        if !state.at(RightParen) {
191            if state.eat(DotDotDot) {
192                // vararg
193            }
194            else {
195                state.expect(Identifier).ok();
196                while state.eat(Comma) {
197                    if state.eat(DotDotDot) {
198                        break;
199                    }
200                    state.expect(Identifier).ok();
201                }
202            }
203        }
204        state.expect(RightParen).ok();
205        self.parse_block(state)?;
206        state.expect(End).ok();
207        Ok(())
208    }
209
210    fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
211        use crate::lexer::LuaTokenType::*;
212        let cp = state.checkpoint();
213        state.expect(Return).ok();
214        if !state.at(End) && !state.at(Else) && !state.at(Elseif) && !state.at(Until) && !state.at(Semicolon) {
215            PrattParser::parse(state, 0, self);
216            while state.eat(Comma) {
217                PrattParser::parse(state, 0, self);
218            }
219        }
220        state.eat(Semicolon);
221        state.finish_at(cp, crate::parser::element_type::LuaElementType::ReturnStatement);
222        Ok(())
223    }
224
225    fn parse_break_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
226        use crate::lexer::LuaTokenType::*;
227        let cp = state.checkpoint();
228        state.expect(Break).ok();
229        state.finish_at(cp, crate::parser::element_type::LuaElementType::BreakStatement);
230        Ok(())
231    }
232
233    fn parse_do_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
234        use crate::lexer::LuaTokenType::*;
235        let cp = state.checkpoint();
236        state.expect(Do).ok();
237        self.parse_block(state)?;
238        state.expect(End).ok();
239        state.finish_at(cp, crate::parser::element_type::LuaElementType::DoStatement);
240        Ok(())
241    }
242
243    fn parse_goto_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
244        use crate::lexer::LuaTokenType::*;
245        let cp = state.checkpoint();
246        state.expect(Goto).ok();
247        state.expect(Identifier).ok();
248        state.finish_at(cp, crate::parser::element_type::LuaElementType::GotoStatement);
249        Ok(())
250    }
251
252    fn parse_label_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
253        use crate::lexer::LuaTokenType::*;
254        let cp = state.checkpoint();
255        state.expect(ColonColon).ok();
256        state.expect(Identifier).ok();
257        state.expect(ColonColon).ok();
258        state.finish_at(cp, crate::parser::element_type::LuaElementType::LabelStatement);
259        Ok(())
260    }
261
262    fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
263        use crate::lexer::LuaTokenType::*;
264        while state.not_at_end() && !state.at(End) && !state.at(Else) && !state.at(Elseif) && !state.at(Until) {
265            self.parse_statement(state)?;
266        }
267        Ok(())
268    }
269
270    fn parse_table_constructor<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, LuaLanguage> {
271        use crate::lexer::LuaTokenType::*;
272        let cp = state.checkpoint();
273        state.expect(LeftBrace).ok();
274        while state.not_at_end() && !state.at(RightBrace) {
275            let field_cp = state.checkpoint();
276            if state.eat(LeftBracket) {
277                PrattParser::parse(state, 0, self);
278                state.expect(RightBracket).ok();
279                state.expect(Eq).ok();
280                PrattParser::parse(state, 0, self);
281            }
282            else if state.at(Identifier) && state.peek_non_trivia_kind_at(1) == Some(Eq) {
283                state.bump();
284                state.expect(Eq).ok();
285                PrattParser::parse(state, 0, self);
286            }
287            else {
288                PrattParser::parse(state, 0, self);
289            }
290            state.finish_at(field_cp, crate::parser::element_type::LuaElementType::TableField);
291            if !state.eat(Comma) && !state.eat(Semicolon) {
292                break;
293            }
294        }
295        state.expect(RightBrace).ok();
296        state.finish_at(cp, crate::parser::element_type::LuaElementType::TableConstructorExpression)
297    }
298}
299
300impl<'config> Pratt<LuaLanguage> for LuaParser<'config> {
301    fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, LuaLanguage> {
302        use crate::lexer::LuaTokenType::*;
303        let cp = state.checkpoint();
304        match state.peek_kind() {
305            Some(Nil) | Some(False) | Some(True) | Some(Number) | Some(String) | Some(DotDotDot) => {
306                state.bump();
307                state.finish_at(cp, crate::parser::element_type::LuaElementType::LiteralExpression)
308            }
309            Some(Identifier) => {
310                state.bump();
311                state.finish_at(cp, crate::parser::element_type::LuaElementType::IdentifierExpression)
312            }
313            Some(Function) => {
314                state.bump();
315                self.parse_function_body(state).ok();
316                state.finish_at(cp, crate::parser::element_type::LuaElementType::FunctionExpression)
317            }
318            Some(LeftParen) => {
319                state.bump();
320                PrattParser::parse(state, 0, self);
321                state.expect(RightParen).ok();
322                state.finish_at(cp, crate::parser::element_type::LuaElementType::ParenthesizedExpression)
323            }
324            Some(LeftBrace) => self.parse_table_constructor(state),
325            _ => {
326                use crate::lexer::LuaTokenType;
327                let current_kind = state.peek_kind();
328                state.record_expected("expression");
329                if state.not_at_end() {
330                    // Don't bump if we are at a token that could be part of the following structure
331                    match current_kind {
332                        Some(LuaTokenType::RightParen)
333                        | Some(LuaTokenType::RightBrace)
334                        | Some(LuaTokenType::RightBracket)
335                        | Some(LuaTokenType::Comma)
336                        | Some(LuaTokenType::Semicolon)
337                        | Some(LuaTokenType::End)
338                        | Some(LuaTokenType::Else)
339                        | Some(LuaTokenType::Elseif)
340                        | Some(LuaTokenType::Until) => {
341                            // Don't bump, let the caller handle it
342                        }
343                        _ => {
344                            state.bump();
345                        }
346                    }
347                }
348                state.finish_at(cp, crate::parser::element_type::LuaElementType::Error)
349            }
350        }
351    }
352
353    fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, LuaLanguage> {
354        use crate::{lexer::LuaTokenType as TT, parser::element_type::LuaElementType as ET};
355        let kind = state.peek_kind();
356        match kind {
357            Some(TT::Minus) | Some(TT::Not) | Some(TT::Hash) | Some(TT::Tilde) => {
358                let op_kind = kind.unwrap();
359                unary(state, op_kind, 11, ET::UnaryExpression, |s, p| PrattParser::parse(s, p, self))
360            }
361            _ => self.primary(state),
362        }
363    }
364
365    fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, LuaLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, LuaLanguage>> {
366        use crate::{lexer::LuaTokenType as TT, parser::element_type::LuaElementType as ET};
367        let kind = state.peek_kind()?;
368
369        let (prec, assoc) = match kind {
370            TT::Or => (1, Associativity::Left),
371            TT::And => (2, Associativity::Left),
372            TT::Lt | TT::Gt | TT::LtEq | TT::GtEq | TT::TildeEq | TT::EqEq => (3, Associativity::Left),
373            TT::Pipe => (4, Associativity::Left),
374            TT::Tilde => (5, Associativity::Left),
375            TT::Ampersand => (6, Associativity::Left),
376            TT::LtLt | TT::GtGt => (7, Associativity::Left),
377            TT::DotDot => (8, Associativity::Right),
378            TT::Plus | TT::Minus => (9, Associativity::Left),
379            TT::Star | TT::Slash | TT::SlashSlash | TT::Percent => (10, Associativity::Left),
380            TT::Caret => (12, Associativity::Right),
381            TT::Dot | TT::Colon | TT::LeftParen | TT::LeftBrace | TT::String | TT::LeftBracket => (13, Associativity::Left),
382            _ => return None,
383        };
384
385        if prec < min_precedence {
386            return None;
387        }
388
389        match kind {
390            TT::Dot => {
391                let cp = state.checkpoint_before(left);
392                state.bump();
393                state.expect(TT::Identifier).ok();
394                Some(state.finish_at(cp, ET::MemberExpression))
395            }
396            TT::Colon => {
397                let cp = state.checkpoint_before(left);
398                state.bump();
399                state.expect(TT::Identifier).ok();
400                Some(state.finish_at(cp, ET::MemberExpression))
401            }
402            TT::LeftBracket => {
403                let cp = state.checkpoint_before(left);
404                state.bump();
405                PrattParser::parse(state, 0, self);
406                state.expect(TT::RightBracket).ok();
407                Some(state.finish_at(cp, ET::IndexExpression))
408            }
409            TT::LeftParen | TT::LeftBrace | TT::String => {
410                let cp = state.checkpoint_before(left);
411                if state.eat(TT::LeftParen) {
412                    if !state.at(TT::RightParen) {
413                        PrattParser::parse(state, 0, self);
414                        while state.eat(TT::Comma) {
415                            PrattParser::parse(state, 0, self);
416                        }
417                    }
418                    state.expect(TT::RightParen).ok();
419                }
420                else if state.at(TT::LeftBrace) {
421                    self.parse_table_constructor(state);
422                }
423                else if state.at(TT::String) {
424                    state.bump();
425                }
426                else {
427                    state.record_expected("arguments");
428                }
429                Some(state.finish_at(cp, ET::CallExpression))
430            }
431            _ => Some(binary(state, left, kind, prec, assoc, ET::BinaryExpression, |s, p| PrattParser::parse(s, p, self))),
432        }
433    }
434}
435
436impl<'config> Parser<LuaLanguage> for LuaParser<'config> {
437    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<LuaLanguage>) -> ParseOutput<'a, LuaLanguage> {
438        let lexer = LuaLexer::new(self.config);
439        parse_with_lexer(&lexer, text, edits, cache, |state| self.parse_root_internal(state))
440    }
441}