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