Skip to main content

oak_lua/builder/
mod.rs

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/// Lua AST builder.
15#[derive(Clone)]
16pub struct LuaBuilder<'config> {
17    config: &'config LuaLanguage,
18}
19
20impl<'config> LuaBuilder<'config> {
21    /// Creates a new `LuaBuilder` with the given language configuration.
22    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; // 0: if-cond, 1: then-block, 2: elseif-cond, 3: elseif-block, 4: else-block
167
168                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; // 0: name, 1: parameters, 2: block
345
346                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                                    // Receiver follows - in Lua function name: method,
361                                    // the part before colon is name parts, part after colon is method name
362                                    // But usually it's obj:method, where obj is name parts.
363                                    if state == 0 {
364                                        // The current name parts we have are the receiver parts.
365                                        // We'll move them to receiver and start fresh for method name?
366                                        // Actually LuaFunctionStatement has name: Vec<String> and receiver: Option<String>.
367                                        // Usually it's function a.b:c() -> name=["a", "b"], receiver=Some("c")
368                                        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                                // Recursive name building if nested
387                                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                                // Simple quote removal
431                                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                            // Binary operators
469                            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; // 0: params, 1: block
598
599                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}