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 }
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 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 }
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}