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