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