1use crate::{
2 ast::*,
3 language::LuaLanguage,
4 lexer::{LuaLexer, token_type::LuaTokenType},
5 parser::{LuaElementType, LuaParser},
6};
7use oak_core::{
8 Builder, BuilderCache, Lexer, Parser, Source, TextEdit,
9 builder::BuildOutput,
10 parser::session::ParseSession,
11 tree::{GreenNode, GreenTree},
12};
13
14#[derive(Clone)]
16pub struct LuaBuilder<'config> {
17 config: &'config LuaLanguage,
18}
19
20impl<'config> LuaBuilder<'config> {
21 pub fn new(config: &'config LuaLanguage) -> Self {
22 Self { config }
23 }
24}
25
26impl<'config> Builder<LuaLanguage> for LuaBuilder<'config> {
27 fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<LuaLanguage>) -> BuildOutput<LuaLanguage> {
28 let parser = LuaParser::new(self.config);
29 let lexer = LuaLexer::new(self.config);
30
31 let mut session = ParseSession::<LuaLanguage>::default();
32 lexer.lex(source, edits, &mut session);
33 let parse_result = parser.parse(source, edits, &mut session);
34
35 match parse_result.result {
36 Ok(green_tree) => match self.build_root(green_tree.clone(), source) {
37 Ok(ast_root) => oak_core::errors::OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
38 Err(build_error) => {
39 let mut diagnostics = parse_result.diagnostics;
40 diagnostics.push(build_error.clone());
41 oak_core::errors::OakDiagnostics { result: Err(build_error), diagnostics }
42 }
43 },
44 Err(parse_error) => oak_core::errors::OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
45 }
46 }
47}
48
49impl<'config> LuaBuilder<'config> {
50 fn build_root<S: Source + ?Sized>(&self, green_tree: GreenNode<LuaLanguage>, source: &S) -> Result<LuaRoot, oak_core::OakError> {
51 let mut statements = Vec::new();
52 let mut offset = 0;
53 for child in green_tree.children() {
54 match child {
55 GreenTree::Node(node) => {
56 if let Some(stmt) = self.build_statement(node, source, offset)? {
57 statements.push(stmt)
58 }
59 }
60 GreenTree::Leaf(_) => {}
61 }
62 offset += child.len() as usize
63 }
64 Ok(LuaRoot { statements, span: (0..offset).into() })
65 }
66
67 fn build_statement<S: Source + ?Sized>(&self, node: &GreenNode<LuaLanguage>, source: &S, offset: usize) -> Result<Option<LuaStatement>, oak_core::OakError> {
68 match node.kind {
69 LuaElementType::LocalStatement => {
70 let mut names = Vec::new();
71 let mut values = Vec::new();
72 let mut child_offset = offset;
73 for child in node.children() {
74 match child {
75 GreenTree::Leaf(leaf) if leaf.kind == LuaTokenType::Identifier => names.push(source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize }).to_string()),
76 GreenTree::Node(child_node) => {
77 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
78 values.push(expr)
79 }
80 }
81 _ => {}
82 }
83 child_offset += child.len() as usize
84 }
85 Ok(Some(LuaStatement::Local(LuaLocalStatement { names, values })))
86 }
87 LuaElementType::AssignmentStatement => {
88 let mut targets = Vec::new();
89 let mut values = Vec::new();
90 let mut child_offset = offset;
91 let mut after_eq = false;
92 for child in node.children() {
93 match child {
94 GreenTree::Node(child_node) => {
95 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
96 if after_eq { values.push(expr) } else { targets.push(expr) }
97 }
98 }
99 GreenTree::Leaf(leaf) if leaf.kind == LuaTokenType::Eq => after_eq = true,
100 _ => {}
101 }
102 child_offset += child.len() as usize
103 }
104 Ok(Some(LuaStatement::Assignment(LuaAssignmentStatement { targets, values })))
105 }
106 LuaElementType::ExpressionStatement => {
107 let mut child_offset = offset;
108 for child in node.children() {
109 if let GreenTree::Node(child_node) = child {
110 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
111 return Ok(Some(LuaStatement::Expression(expr)));
112 }
113 }
114 child_offset += child.len() as usize
115 }
116 Ok(None)
117 }
118 LuaElementType::ReturnStatement => {
119 let mut values = Vec::new();
120 let mut child_offset = offset;
121 for child in node.children() {
122 if let GreenTree::Node(child_node) = child {
123 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
124 values.push(expr)
125 }
126 }
127 child_offset += child.len() as usize
128 }
129 Ok(Some(LuaStatement::Return(LuaReturnStatement { values })))
130 }
131 LuaElementType::BreakStatement => Ok(Some(LuaStatement::Break)),
132 LuaElementType::GotoStatement => {
133 let mut child_offset = offset;
134 for child in node.children() {
135 if let GreenTree::Leaf(leaf) = child {
136 if leaf.kind == LuaTokenType::Identifier {
137 let text = source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize });
138 return Ok(Some(LuaStatement::Goto(text.to_string())));
139 }
140 }
141 child_offset += child.len() as usize
142 }
143 Ok(None)
144 }
145 LuaElementType::LabelStatement => {
146 let mut child_offset = offset;
147 for child in node.children() {
148 if let GreenTree::Leaf(leaf) = child {
149 if leaf.kind == LuaTokenType::Identifier {
150 let text = source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize });
151 return Ok(Some(LuaStatement::Label(text.to_string())));
152 }
153 }
154 child_offset += child.len() as usize
155 }
156 Ok(None)
157 }
158 LuaElementType::IfStatement => {
159 let mut condition = None;
160 let mut then_block = Vec::new();
161 let mut else_ifs = Vec::new();
162 let mut else_block = None;
163
164 let mut child_offset = offset;
165 let mut state = 0; for child in node.children() {
168 match child {
169 GreenTree::Leaf(leaf) => match leaf.kind {
170 LuaTokenType::If => state = 0,
171 LuaTokenType::Then => {
172 if state == 0 {
173 state = 1
174 }
175 else if state == 2 {
176 state = 3
177 }
178 }
179 LuaTokenType::Elseif => state = 2,
180 LuaTokenType::Else => {
181 state = 4;
182 else_block = Some(Vec::new())
183 }
184 _ => {}
185 },
186 GreenTree::Node(child_node) => match state {
187 0 => {
188 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
189 condition = Some(expr)
190 }
191 }
192 1 => {
193 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
194 then_block.push(stmt)
195 }
196 }
197 2 => {
198 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
199 else_ifs.push((expr, Vec::new()))
200 }
201 }
202 3 => {
203 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
204 if let Some(last) = else_ifs.last_mut() {
205 last.1.push(stmt)
206 }
207 }
208 }
209 4 => {
210 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
211 if let Some(block) = &mut else_block {
212 block.push(stmt)
213 }
214 }
215 }
216 _ => {}
217 },
218 }
219 child_offset += child.len() as usize
220 }
221
222 if let Some(cond) = condition { Ok(Some(LuaStatement::If(LuaIfStatement { condition: cond, then_block, else_ifs, else_block }))) } else { Ok(None) }
223 }
224 LuaElementType::WhileStatement => {
225 let mut condition = None;
226 let mut block = Vec::new();
227 let mut child_offset = offset;
228 let mut in_block = false;
229
230 for child in node.children() {
231 match child {
232 GreenTree::Leaf(leaf) if leaf.kind == LuaTokenType::Do => in_block = true,
233 GreenTree::Node(child_node) => {
234 if in_block {
235 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
236 block.push(stmt)
237 }
238 }
239 else {
240 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
241 condition = Some(expr)
242 }
243 }
244 }
245 _ => {}
246 }
247 child_offset += child.len() as usize
248 }
249 if let Some(cond) = condition { Ok(Some(LuaStatement::While(LuaWhileStatement { condition: cond, block }))) } else { Ok(None) }
250 }
251 LuaElementType::ForStatement => {
252 let mut variables = Vec::new();
253 let mut expressions = Vec::new();
254 let mut block = Vec::new();
255 let mut child_offset = offset;
256 let mut in_block = false;
257 let mut after_in = false;
258 let mut after_eq = false;
259
260 for child in node.children() {
261 match child {
262 GreenTree::Leaf(leaf) => match leaf.kind {
263 LuaTokenType::Identifier => variables.push(source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize }).to_string()),
264 LuaTokenType::Eq => after_eq = true,
265 LuaTokenType::In => after_in = true,
266 LuaTokenType::Do => in_block = true,
267 _ => {}
268 },
269 GreenTree::Node(child_node) => {
270 if in_block {
271 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
272 block.push(stmt)
273 }
274 }
275 else {
276 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
277 expressions.push(expr)
278 }
279 }
280 }
281 }
282 child_offset += child.len() as usize
283 }
284
285 if after_in {
286 Ok(Some(LuaStatement::For(LuaForStatement::Generic { variables, iterators: expressions, block })))
287 }
288 else if after_eq && !variables.is_empty() && expressions.len() >= 2 {
289 Ok(Some(LuaStatement::For(LuaForStatement::Numeric { variable: variables[0].clone(), start: expressions[0].clone(), end: expressions[1].clone(), step: expressions.get(2).cloned(), block })))
290 }
291 else {
292 Ok(None)
293 }
294 }
295 LuaElementType::RepeatStatement => {
296 let mut block = Vec::new();
297 let mut condition = None;
298 let mut child_offset = offset;
299 let mut after_until = false;
300
301 for child in node.children() {
302 match child {
303 GreenTree::Leaf(leaf) if leaf.kind == LuaTokenType::Until => after_until = true,
304 GreenTree::Node(child_node) => {
305 if after_until {
306 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
307 condition = Some(expr)
308 }
309 }
310 else {
311 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
312 block.push(stmt)
313 }
314 }
315 }
316 _ => {}
317 }
318 child_offset += child.len() as usize
319 }
320 if let Some(cond) = condition { Ok(Some(LuaStatement::Repeat(LuaRepeatStatement { block, condition: cond }))) } else { Ok(None) }
321 }
322 LuaElementType::DoStatement => {
323 let mut block = Vec::new();
324 let mut child_offset = offset;
325 for child in node.children() {
326 if let GreenTree::Node(child_node) = child {
327 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
328 block.push(stmt)
329 }
330 }
331 child_offset += child.len() as usize
332 }
333 Ok(Some(LuaStatement::Do(block)))
334 }
335 LuaElementType::FunctionDeclaration => {
336 let mut name = Vec::new();
337 let mut receiver = None;
338 let mut parameters = Vec::new();
339 let mut is_vararg = false;
340 let mut block = Vec::new();
341
342 let mut child_offset = offset;
343 let mut state = 0; for child in node.children() {
346 match child {
347 GreenTree::Leaf(leaf) => {
348 match leaf.kind {
349 LuaTokenType::Identifier => {
350 let text = source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize }).to_string();
351 if state == 0 {
352 name.push(text)
353 }
354 else if state == 1 {
355 parameters.push(text)
356 }
357 }
358 LuaTokenType::Colon => {
359 if state == 0 {
363 if !name.is_empty() {
368 receiver = name.pop()
369 }
370 }
371 }
372 LuaTokenType::LeftParen => state = 1,
373 LuaTokenType::RightParen => state = 2,
374 LuaTokenType::DotDotDot => is_vararg = true,
375 _ => {}
376 }
377 }
378 GreenTree::Node(child_node) => {
379 if state == 2 {
380 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
381 block.push(stmt)
382 }
383 }
384 else if child_node.kind == LuaElementType::FunctionName {
385 let mut name_offset = child_offset;
387 for name_child in child_node.children() {
388 match name_child {
389 GreenTree::Leaf(leaf) => {
390 if leaf.kind == LuaTokenType::Identifier {
391 name.push(source.get_text_in(oak_core::Range { start: name_offset, end: name_offset + leaf.length as usize }).to_string())
392 }
393 else if leaf.kind == LuaTokenType::Colon {
394 if !name.is_empty() {
395 receiver = name.pop()
396 }
397 }
398 }
399 _ => {}
400 }
401 name_offset += name_child.len() as usize
402 }
403 }
404 }
405 }
406 child_offset += child.len() as usize
407 }
408
409 Ok(Some(LuaStatement::Function(LuaFunctionStatement { name, receiver, parameters, is_vararg, block })))
410 }
411 _ => Ok(None),
412 }
413 }
414
415 fn build_expression<S: Source + ?Sized>(&self, node: &GreenNode<LuaLanguage>, source: &S, offset: usize) -> Result<Option<LuaExpression>, oak_core::OakError> {
416 match node.kind {
417 LuaElementType::LiteralExpression => {
418 for child in node.children() {
419 if let GreenTree::Leaf(leaf) = child {
420 match leaf.kind {
421 LuaTokenType::Number => {
422 let text = source.get_text_in(oak_core::Range { start: offset, end: offset + leaf.length as usize });
423 if let Ok(val) = text.parse::<f64>() {
424 return Ok(Some(LuaExpression::Number(val)));
425 }
426 }
427 LuaTokenType::String => {
428 let text = source.get_text_in(oak_core::Range { start: offset, end: offset + leaf.length as usize });
429 let s = if text.len() >= 2 { &text[1..text.len() - 1] } else { &text };
431 return Ok(Some(LuaExpression::String(s.to_string())));
432 }
433 LuaTokenType::True => return Ok(Some(LuaExpression::Boolean(true))),
434 LuaTokenType::False => return Ok(Some(LuaExpression::Boolean(false))),
435 LuaTokenType::Nil => return Ok(Some(LuaExpression::Nil)),
436 _ => {}
437 }
438 }
439 }
440 Ok(None)
441 }
442 LuaElementType::IdentifierExpression => {
443 for child in node.children() {
444 if let GreenTree::Leaf(leaf) = child {
445 if leaf.kind == LuaTokenType::Identifier {
446 let name = source.get_text_in(oak_core::Range { start: offset, end: offset + leaf.length as usize }).to_string();
447 return Ok(Some(LuaExpression::Identifier(name)));
448 }
449 }
450 }
451 Ok(None)
452 }
453 LuaElementType::BinaryExpression => {
454 let mut left = None;
455 let mut op = String::new();
456 let mut right = None;
457 let mut child_offset = offset;
458
459 for child in node.children() {
460 match child {
461 GreenTree::Node(child_node) => {
462 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
463 if left.is_none() { left = Some(expr) } else { right = Some(expr) }
464 }
465 }
466 GreenTree::Leaf(leaf) => {
467 match leaf.kind {
469 LuaTokenType::Plus
470 | LuaTokenType::Minus
471 | LuaTokenType::Star
472 | LuaTokenType::Slash
473 | LuaTokenType::Percent
474 | LuaTokenType::Caret
475 | LuaTokenType::Lt
476 | LuaTokenType::LtEq
477 | LuaTokenType::Gt
478 | LuaTokenType::GtEq
479 | LuaTokenType::EqEq
480 | LuaTokenType::TildeEq
481 | LuaTokenType::Ampersand
482 | LuaTokenType::Pipe
483 | LuaTokenType::Tilde
484 | LuaTokenType::LtLt
485 | LuaTokenType::GtGt
486 | LuaTokenType::SlashSlash
487 | LuaTokenType::And
488 | LuaTokenType::Or
489 | LuaTokenType::DotDot => op = source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize }).to_string(),
490 _ => {}
491 }
492 }
493 }
494 child_offset += child.len() as usize
495 }
496
497 if let (Some(l), Some(r)) = (left, right) { Ok(Some(LuaExpression::Binary(Box::new(LuaBinaryExpression { left: l, op, right: r })))) } else { Ok(None) }
498 }
499 LuaElementType::UnaryExpression => {
500 let mut op = String::new();
501 let mut operand = None;
502 let mut child_offset = offset;
503
504 for child in node.children() {
505 match child {
506 GreenTree::Node(child_node) => operand = self.build_expression(child_node, source, child_offset)?,
507 GreenTree::Leaf(leaf) => match leaf.kind {
508 LuaTokenType::Minus | LuaTokenType::Not | LuaTokenType::Hash | LuaTokenType::Tilde => op = source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize }).to_string(),
509 _ => {}
510 },
511 }
512 child_offset += child.len() as usize
513 }
514
515 if let Some(o) = operand { Ok(Some(LuaExpression::Unary(Box::new(LuaUnaryExpression { op, operand: o })))) } else { Ok(None) }
516 }
517 LuaElementType::CallExpression => {
518 let mut function = None;
519 let mut arguments = Vec::new();
520 let mut child_offset = offset;
521
522 for child in node.children() {
523 if let GreenTree::Node(child_node) = child {
524 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
525 if function.is_none() { function = Some(expr) } else { arguments.push(expr) }
526 }
527 }
528 else if let GreenTree::Leaf(leaf) = child {
529 if leaf.kind == LuaTokenType::String {
530 let text = source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize });
531 let s = if text.len() >= 2 { &text[1..text.len() - 1] } else { &text };
532 arguments.push(LuaExpression::String(s.to_string()))
533 }
534 }
535 child_offset += child.len() as usize
536 }
537
538 if let Some(f) = function { Ok(Some(LuaExpression::Call(Box::new(LuaCallExpression { function: f, arguments })))) } else { Ok(None) }
539 }
540 LuaElementType::TableConstructorExpression => {
541 let mut fields = Vec::new();
542 let mut child_offset = offset;
543 for child in node.children() {
544 if let GreenTree::Node(child_node) = child {
545 if child_node.kind == LuaElementType::TableField {
546 let mut key = None;
547 let mut value = None;
548 let mut name = None;
549 let mut field_offset = child_offset;
550 let mut after_eq = false;
551
552 for field_child in child_node.children() {
553 match field_child {
554 GreenTree::Leaf(leaf) => {
555 if leaf.kind == LuaTokenType::Identifier && !after_eq {
556 name = Some(source.get_text_in(oak_core::Range { start: field_offset, end: field_offset + leaf.length as usize }).to_string())
557 }
558 else if leaf.kind == LuaTokenType::Eq {
559 after_eq = true
560 }
561 }
562 GreenTree::Node(field_node) => {
563 if let Some(expr) = self.build_expression(field_node, source, field_offset)? {
564 if key.is_none() && !after_eq && name.is_none() { key = Some(expr) } else { value = Some(expr) }
565 }
566 }
567 }
568 field_offset += field_child.len() as usize
569 }
570
571 if let Some(v) = value {
572 if let Some(k) = key {
573 fields.push(LuaTableField::Keyed { key: k, value: v })
574 }
575 else if let Some(n) = name {
576 fields.push(LuaTableField::Named { name: n, value: v })
577 }
578 else {
579 fields.push(LuaTableField::List { value: v })
580 }
581 }
582 else if let Some(k) = key {
583 fields.push(LuaTableField::List { value: k })
584 }
585 }
586 }
587 child_offset += child.len() as usize
588 }
589 Ok(Some(LuaExpression::Table(LuaTableConstructor { fields })))
590 }
591 LuaElementType::FunctionExpression => {
592 let mut parameters = Vec::new();
593 let mut is_vararg = false;
594 let mut block = Vec::new();
595 let mut child_offset = offset;
596 let mut state = 0; for child in node.children() {
599 match child {
600 GreenTree::Leaf(leaf) => match leaf.kind {
601 LuaTokenType::Identifier if state == 0 => parameters.push(source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize }).to_string()),
602 LuaTokenType::DotDotDot => is_vararg = true,
603 LuaTokenType::RightParen => state = 1,
604 _ => {}
605 },
606 GreenTree::Node(child_node) => {
607 if state == 1 {
608 if let Some(stmt) = self.build_statement(child_node, source, child_offset)? {
609 block.push(stmt)
610 }
611 }
612 }
613 }
614 child_offset += child.len() as usize
615 }
616 Ok(Some(LuaExpression::Function(LuaFunctionExpression { parameters, is_vararg, block })))
617 }
618 LuaElementType::MemberExpression => {
619 let mut table = None;
620 let mut member = String::new();
621 let mut is_method = false;
622 let mut child_offset = offset;
623
624 for child in node.children() {
625 match child {
626 GreenTree::Node(child_node) => {
627 if table.is_none() {
628 table = self.build_expression(child_node, source, child_offset)?
629 }
630 }
631 GreenTree::Leaf(leaf) => {
632 if leaf.kind == LuaTokenType::Identifier {
633 member = source.get_text_in(oak_core::Range { start: child_offset, end: child_offset + leaf.length as usize }).to_string()
634 }
635 else if leaf.kind == LuaTokenType::Colon {
636 is_method = true
637 }
638 }
639 }
640 child_offset += child.len() as usize
641 }
642
643 if let Some(t) = table { Ok(Some(LuaExpression::Member(Box::new(LuaMemberExpression { table: t, member, is_method })))) } else { Ok(None) }
644 }
645 LuaElementType::IndexExpression => {
646 let mut table = None;
647 let mut index = None;
648 let mut child_offset = offset;
649
650 for child in node.children() {
651 if let GreenTree::Node(child_node) = child {
652 if table.is_none() { table = self.build_expression(child_node, source, child_offset)? } else { index = self.build_expression(child_node, source, child_offset)? }
653 }
654 child_offset += child.len() as usize
655 }
656
657 if let (Some(t), Some(i)) = (table, index) { Ok(Some(LuaExpression::Index(Box::new(LuaIndexExpression { table: t, index: i })))) } else { Ok(None) }
658 }
659 LuaElementType::VarargExpression => Ok(Some(LuaExpression::Vararg)),
660 LuaElementType::ParenthesizedExpression => {
661 let mut child_offset = offset;
662 for child in node.children() {
663 if let GreenTree::Node(child_node) = child {
664 if let Some(expr) = self.build_expression(child_node, source, child_offset)? {
665 return Ok(Some(expr));
666 }
667 }
668 child_offset += child.len() as usize
669 }
670 Ok(None)
671 }
672 _ => Ok(None),
673 }
674 }
675}