Skip to main content

oak_lua/parser/
mod.rs

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