Skip to main content

brooks_lib/mel/compiler/
compile.rs

1// brooks, Copyright 2026, Will Hawkins
2//
3// This file is part of brooks.
4
5// This file is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18use regex::RegexBuilder;
19use std::collections::HashMap;
20use std::fmt::Debug;
21use std::net::IpAddr;
22use std::sync::Arc;
23use tree_sitter::{self, Node};
24
25use crate::common::TextLocation;
26use crate::mel::ast::Expr::BinaryExpr;
27use crate::mel::ast::Expr::MemberAccess;
28use crate::mel::ast::Expr::TernaryExpr;
29use crate::mel::ast::Literal::{Boolean, Number};
30use crate::mel::ast::LogicOperator::{And, Or};
31use crate::mel::ast::MathOperator::{Divide, Minus, Modulo, Multiply, Plus};
32use crate::mel::ast::{Argument, BinaryInfixOperator, StringConcatOperator};
33use crate::mel::compiler::error::CompilerError;
34use crate::mel::compiler::error::CompilerLocatableError;
35use crate::mel::{
36    ast::{self, ArgumentList, Expr, Identifier},
37    grammar::GrammarNode,
38};
39use crate::utils;
40
41pub type SyntaxVisitorResult<T> = Result<T, CompilerLocatableError>;
42
43pub trait SyntaxVisitor<T>: Sized {
44    fn visit_function_call(
45        &self,
46        syntax: Node,
47        context: T,
48        driver: &SyntaxVisitorDriver,
49    ) -> SyntaxVisitorResult<T>;
50    fn visit_error(
51        &self,
52        syntax: Node,
53        context: T,
54        driver: &SyntaxVisitorDriver,
55    ) -> CompilerLocatableError;
56    fn visit_expr(
57        &self,
58        syntax: Node,
59        context: T,
60        driver: &SyntaxVisitorDriver,
61    ) -> SyntaxVisitorResult<T> {
62        let node = syntax.named_child(0).ok_or(CompilerLocatableError {
63            error: CompilerError::BadGrammarElement,
64            location: syntax.into(),
65        })?;
66        driver.visit(node, self, context)
67    }
68    fn visit_identifier(
69        &self,
70        syntax: Node,
71        context: T,
72        driver: &SyntaxVisitorDriver,
73    ) -> SyntaxVisitorResult<T>;
74    fn visit_argument_list(
75        &self,
76        syntax: Node,
77        context: T,
78        driver: &SyntaxVisitorDriver,
79    ) -> SyntaxVisitorResult<T>;
80    fn visit_argument(
81        &self,
82        syntax: Node,
83        context: T,
84        driver: &SyntaxVisitorDriver,
85    ) -> SyntaxVisitorResult<T>;
86    fn visit_string_concat_operator(
87        &self,
88        syntax: Node,
89        context: T,
90        driver: &SyntaxVisitorDriver,
91    ) -> SyntaxVisitorResult<T>;
92    fn visit_comparison_operator(
93        &self,
94        syntax: Node,
95        context: T,
96        driver: &SyntaxVisitorDriver,
97    ) -> SyntaxVisitorResult<T>;
98    fn visit_logic_operator(
99        &self,
100        syntax: Node,
101        context: T,
102        driver: &SyntaxVisitorDriver,
103    ) -> SyntaxVisitorResult<T>;
104    fn visit_math_operator(
105        &self,
106        syntax: Node,
107        context: T,
108        driver: &SyntaxVisitorDriver,
109    ) -> SyntaxVisitorResult<T>;
110    fn visit_member_access_expr(
111        &self,
112        syntax: Node,
113        context: T,
114        driver: &SyntaxVisitorDriver,
115    ) -> SyntaxVisitorResult<T>;
116    fn visit_member_access_oper(
117        &self,
118        syntax: Node,
119        context: T,
120        driver: &SyntaxVisitorDriver,
121    ) -> SyntaxVisitorResult<T>;
122    fn visit_binary_expr(
123        &self,
124        syntax: Node,
125        context: T,
126        driver: &SyntaxVisitorDriver,
127    ) -> SyntaxVisitorResult<T>;
128    fn visit_ternary_operator(
129        &self,
130        syntax: Node,
131        context: T,
132        driver: &SyntaxVisitorDriver,
133    ) -> SyntaxVisitorResult<T>;
134    fn visit_ternary_expr(
135        &self,
136        syntax: Node,
137        context: T,
138        driver: &SyntaxVisitorDriver,
139    ) -> SyntaxVisitorResult<T>;
140    fn visit_literal(
141        &self,
142        syntax: Node,
143        context: T,
144        driver: &SyntaxVisitorDriver,
145    ) -> SyntaxVisitorResult<T>;
146    fn visit_boolean_literal(
147        &self,
148        syntax: Node,
149        context: T,
150        driver: &SyntaxVisitorDriver,
151    ) -> SyntaxVisitorResult<T>;
152    fn visit_number_literal(
153        &self,
154        syntax: Node,
155        context: T,
156        driver: &SyntaxVisitorDriver,
157    ) -> SyntaxVisitorResult<T>;
158    fn visit_string_literal(
159        &self,
160        syntax: Node,
161        context: T,
162        driver: &SyntaxVisitorDriver,
163    ) -> SyntaxVisitorResult<T>;
164    fn visit_regex_literal(
165        &self,
166        syntax: Node,
167        context: T,
168        driver: &SyntaxVisitorDriver,
169    ) -> SyntaxVisitorResult<T>;
170    fn visit_ipaddress_literal(
171        &self,
172        syntax: Node,
173        context: T,
174        driver: &SyntaxVisitorDriver,
175    ) -> SyntaxVisitorResult<T>;
176    fn visit_mel(
177        &self,
178        syntax: Node,
179        context: T,
180        driver: &SyntaxVisitorDriver,
181    ) -> SyntaxVisitorResult<T>;
182}
183
184/// A context for compilation used when visiting the parse tree.
185#[derive(Default, Debug, Clone)]
186pub enum MELCompilerContext {
187    Expr(ast::Expr<()>),
188    BinaryOperator(ast::BinaryInfixOperator),
189    TernaryOperator(ast::TernaryOperator),
190    #[default]
191    Empty,
192}
193
194/// Expect that the [`MELCompilerContext`] has an Expr.
195#[macro_export]
196macro_rules! expect_expr {
197    ( $t:ident, $x:expr ) => {{
198        match $x {
199            $t::Expr(e) => Some(e),
200            _ => None,
201        }
202    }};
203}
204
205pub struct MELCompiler {
206    source: String,
207}
208
209impl MELCompiler {
210    pub fn new(source: &str) -> Self {
211        MELCompiler {
212            source: source.to_string(),
213        }
214    }
215
216    pub fn extract_error(&self, en: &Node) -> CompilerLocatableError {
217        let error_tok = en
218            .utf8_text(self.source.as_bytes())
219            .or::<String>(Ok(""))
220            .expect("Could not get error token");
221
222        let repr = en
223            .to_string()
224            .trim_start_matches("(")
225            .trim_end_matches(")")
226            .to_string();
227
228        let msg = if repr.starts_with("UNEXPECTED") {
229            format!("Unexpected token {error_tok}")
230        } else if repr.starts_with("MISSING") {
231            let msg = repr.trim_start_matches("MISSING ");
232            format!("Missing: {msg}")
233        } else {
234            format!("Bad token: {error_tok}")
235        };
236
237        CompilerLocatableError {
238            error: CompilerError::SyntaxError(msg),
239            location: (*en).into(),
240        }
241    }
242}
243
244impl SyntaxVisitor<MELCompilerContext> for MELCompiler {
245    fn visit_function_call(
246        &self,
247        syntax: Node,
248        _context: MELCompilerContext,
249        _driver: &SyntaxVisitorDriver,
250    ) -> SyntaxVisitorResult<MELCompilerContext> {
251        let mut walker = syntax.walk();
252        walker.goto_first_child();
253
254        let callee = match _driver.visit(walker.node(), self, _context.clone())? {
255            MELCompilerContext::Expr(callee) => {
256                Result::<Expr<()>, CompilerLocatableError>::Ok(callee)
257            }
258            _ => Result::<Expr<()>, CompilerLocatableError>::Err(CompilerLocatableError {
259                error: CompilerError::EmptyContext,
260                location: syntax.into(),
261            }),
262        }?;
263
264        walker.goto_next_sibling();
265
266        let argument_list = match _driver.visit(walker.node(), self, _context.clone())? {
267            MELCompilerContext::Expr(ast::Expr::ArgumentList(args)) => {
268                Result::<Arc<ArgumentList<()>>, CompilerLocatableError>::Ok(args)
269            }
270            _ => Result::<Arc<ArgumentList<()>>, CompilerLocatableError>::Err(
271                CompilerLocatableError {
272                    error: CompilerError::EmptyContext,
273                    location: syntax.into(),
274                },
275            ),
276        }?;
277
278        Ok(MELCompilerContext::Expr(Expr::FunctionCall(Arc::new(
279            ast::FunctionCall::<()> {
280                callee: callee.clone(),
281                arguments: (*argument_list).clone(),
282                location: syntax.into(),
283                aug: (),
284            },
285        ))))
286    }
287
288    fn visit_mel(
289        &self,
290        syntax: Node,
291        context: MELCompilerContext,
292        driver: &SyntaxVisitorDriver,
293    ) -> SyntaxVisitorResult<MELCompilerContext> {
294        // A mel is just a wrapper. Navigate deeper.
295        let mut context = context;
296        for child in syntax.children(&mut syntax.walk()) {
297            context = driver.visit(child, self, context)?;
298        }
299
300        Ok(context)
301    }
302
303    fn visit_identifier(
304        &self,
305        syntax: Node,
306        _context: MELCompilerContext,
307        _driver: &SyntaxVisitorDriver,
308    ) -> SyntaxVisitorResult<MELCompilerContext> {
309        let identifier =
310            syntax
311                .utf8_text(self.source.as_bytes())
312                .map_err(|_| CompilerLocatableError {
313                    error: CompilerError::InvalidRange,
314                    location: syntax.into(),
315                })?;
316        let id = Identifier {
317            identifier: identifier.to_string(),
318            location: syntax.into(),
319            aug: (),
320        };
321        Ok(MELCompilerContext::Expr(Expr::Identifier(Arc::new(id))))
322    }
323
324    fn visit_argument(
325        &self,
326        syntax: Node,
327        _context: MELCompilerContext,
328        _driver: &SyntaxVisitorDriver,
329    ) -> SyntaxVisitorResult<MELCompilerContext> {
330        // An argument is just a wrapper around an expr!
331        let mut walker = syntax.walk();
332        walker.goto_first_child();
333
334        match _driver.visit(walker.node(), self, _context.clone())? {
335            MELCompilerContext::Expr(expr) => Ok(MELCompilerContext::Expr(Expr::Argument(
336                Arc::new(ast::Argument {
337                    expr,
338                    location: syntax.into(),
339                    aug: (),
340                }),
341            ))),
342            _ => Err(CompilerLocatableError {
343                error: CompilerError::EmptyContext,
344                location: syntax.into(),
345            }),
346        }
347    }
348
349    fn visit_argument_list(
350        &self,
351        syntax: Node,
352        context: MELCompilerContext,
353        driver: &SyntaxVisitorDriver,
354    ) -> SyntaxVisitorResult<MELCompilerContext> {
355        let mut walker = syntax.walk();
356        let mut args: Vec<Argument<()>> = vec![];
357        for arg in syntax.named_children(&mut walker) {
358            let argument = match driver.visit(arg, self, context.clone())? {
359                MELCompilerContext::Expr(Expr::Argument(arg)) => {
360                    Result::<Arc<Argument<()>>, CompilerLocatableError>::Ok(arg)
361                }
362                _ => Result::<Arc<Argument<()>>, CompilerLocatableError>::Err(
363                    CompilerLocatableError {
364                        error: CompilerError::EmptyContext,
365                        location: syntax.into(),
366                    },
367                ),
368            }?;
369            args.push((*argument).clone());
370        }
371
372        Ok(MELCompilerContext::Expr(Expr::ArgumentList(Arc::new(
373            ArgumentList {
374                arguments: args,
375                location: syntax.into(),
376                aug: (),
377            },
378        ))))
379    }
380
381    fn visit_string_concat_operator(
382        &self,
383        syntax: Node,
384        _context: MELCompilerContext,
385        _driver: &SyntaxVisitorDriver,
386    ) -> SyntaxVisitorResult<MELCompilerContext> {
387        let mut walker = syntax.walk();
388        walker.goto_first_child();
389
390        if walker.node().grammar_name() == "string_concat" {
391            return Ok(MELCompilerContext::BinaryOperator(
392                BinaryInfixOperator::Concat(StringConcatOperator {}),
393            ));
394        }
395        Err(CompilerLocatableError {
396            error: CompilerError::BadGrammarElement,
397            location: syntax.into(),
398        })
399    }
400
401    fn visit_logic_operator(
402        &self,
403        syntax: Node,
404        _context: MELCompilerContext,
405        _driver: &SyntaxVisitorDriver,
406    ) -> SyntaxVisitorResult<MELCompilerContext> {
407        let mut walker = syntax.walk();
408        walker.goto_first_child();
409
410        if walker.node().grammar_name() == "and" {
411            return Ok(MELCompilerContext::BinaryOperator(
412                BinaryInfixOperator::Logic(And),
413            ));
414        } else if walker.node().grammar_name() == "or" {
415            return Ok(MELCompilerContext::BinaryOperator(
416                BinaryInfixOperator::Logic(Or),
417            ));
418        }
419        Err(CompilerLocatableError {
420            error: CompilerError::BadGrammarElement,
421            location: syntax.into(),
422        })
423    }
424
425    fn visit_math_operator(
426        &self,
427        syntax: Node,
428        _context: MELCompilerContext,
429        _driver: &SyntaxVisitorDriver,
430    ) -> SyntaxVisitorResult<MELCompilerContext> {
431        let mut walker = syntax.walk();
432        walker.goto_first_child();
433
434        if walker.node().grammar_name() == "plus" {
435            return Ok(MELCompilerContext::BinaryOperator(
436                BinaryInfixOperator::Math(Plus),
437            ));
438        } else if walker.node().grammar_name() == "minus" {
439            return Ok(MELCompilerContext::BinaryOperator(
440                BinaryInfixOperator::Math(Minus),
441            ));
442        } else if walker.node().grammar_name() == "mul" {
443            return Ok(MELCompilerContext::BinaryOperator(
444                BinaryInfixOperator::Math(Multiply),
445            ));
446        } else if walker.node().grammar_name() == "div" {
447            return Ok(MELCompilerContext::BinaryOperator(
448                BinaryInfixOperator::Math(Divide),
449            ));
450        } else if walker.node().grammar_name() == "modulo" {
451            return Ok(MELCompilerContext::BinaryOperator(
452                BinaryInfixOperator::Math(Modulo),
453            ));
454        }
455        Err(CompilerLocatableError {
456            error: CompilerError::BadGrammarElement,
457            location: syntax.into(),
458        })
459    }
460
461    fn visit_binary_expr(
462        &self,
463        syntax: Node,
464        context: MELCompilerContext,
465        driver: &SyntaxVisitorDriver,
466    ) -> SyntaxVisitorResult<MELCompilerContext> {
467        let mut walker = syntax.walk();
468
469        walker.goto_first_child();
470
471        let left = match driver.visit(walker.node(), self, context.clone())? {
472            MELCompilerContext::Expr(left) => Result::<Expr<()>, CompilerLocatableError>::Ok(left),
473            _ => Result::<Expr<()>, CompilerLocatableError>::Err(CompilerLocatableError {
474                error: CompilerError::EmptyContext,
475                location: syntax.into(),
476            }),
477        }?;
478
479        walker.goto_next_sibling();
480
481        let operator = match driver.visit(walker.node(), self, context.clone())? {
482            MELCompilerContext::BinaryOperator(oper) => {
483                Result::<BinaryInfixOperator, CompilerLocatableError>::Ok(oper)
484            }
485            _ => {
486                Result::<BinaryInfixOperator, CompilerLocatableError>::Err(CompilerLocatableError {
487                    error: CompilerError::EmptyContext,
488                    location: syntax.into(),
489                })
490            }
491        }?;
492
493        walker.goto_next_sibling();
494
495        let right = match driver.visit(walker.node(), self, context.clone())? {
496            MELCompilerContext::Expr(right) => {
497                Result::<Expr<()>, CompilerLocatableError>::Ok(right)
498            }
499            _ => Result::<Expr<()>, CompilerLocatableError>::Err(CompilerLocatableError {
500                error: CompilerError::EmptyContext,
501                location: syntax.into(),
502            }),
503        }?;
504
505        Ok(MELCompilerContext::Expr(BinaryExpr(Arc::new(
506            ast::BinaryExpr {
507                left,
508                op: operator,
509                right,
510                location: syntax.into(),
511                aug: (),
512            },
513        ))))
514    }
515
516    fn visit_ternary_operator(
517        &self,
518        syntax: Node,
519        _context: MELCompilerContext,
520        _driver: &SyntaxVisitorDriver,
521    ) -> SyntaxVisitorResult<MELCompilerContext> {
522        let mut walker = syntax.walk();
523        walker.goto_first_child();
524        if walker.node().grammar_name() == "ternary_question" {
525            return Ok(MELCompilerContext::TernaryOperator(
526                ast::TernaryOperator::Question,
527            ));
528        } else if walker.node().grammar_name() == "ternary_colon" {
529            return Ok(MELCompilerContext::TernaryOperator(
530                ast::TernaryOperator::Colon,
531            ));
532        }
533        Err(CompilerLocatableError {
534            error: CompilerError::BadGrammarElement,
535            location: syntax.into(),
536        })
537    }
538
539    fn visit_ternary_expr(
540        &self,
541        syntax: Node,
542        context: MELCompilerContext,
543        driver: &SyntaxVisitorDriver,
544    ) -> SyntaxVisitorResult<MELCompilerContext> {
545        let mut walker = syntax.walk();
546
547        walker.goto_first_child();
548
549        let condition = match driver.visit(walker.node(), self, context.clone())? {
550            MELCompilerContext::Expr(condition) => {
551                Result::<Expr<()>, CompilerLocatableError>::Ok(condition)
552            }
553            _ => Result::<Expr<()>, CompilerLocatableError>::Err(CompilerLocatableError {
554                error: CompilerError::EmptyContext,
555                location: syntax.into(),
556            }),
557        }?;
558
559        walker.goto_next_sibling();
560
561        match driver.visit(walker.node(), self, context.clone())? {
562            MELCompilerContext::TernaryOperator(ast::TernaryOperator::Question) => {
563                Result::<(), CompilerLocatableError>::Ok(())
564            }
565            _ => Result::<(), CompilerLocatableError>::Err(CompilerLocatableError {
566                error: CompilerError::BadGrammarElement,
567                location: syntax.into(),
568            }),
569        }?;
570
571        walker.goto_next_sibling();
572
573        let yes = match driver.visit(walker.node(), self, context.clone())? {
574            MELCompilerContext::Expr(yes) => Result::<Expr<()>, CompilerLocatableError>::Ok(yes),
575            _ => Result::<Expr<()>, CompilerLocatableError>::Err(CompilerLocatableError {
576                error: CompilerError::BadGrammarElement,
577                location: syntax.into(),
578            }),
579        }?;
580
581        walker.goto_next_sibling();
582
583        match driver.visit(walker.node(), self, context.clone())? {
584            MELCompilerContext::TernaryOperator(ast::TernaryOperator::Colon) => {
585                Result::<(), CompilerLocatableError>::Ok(())
586            }
587            _ => Result::<(), CompilerLocatableError>::Err(CompilerLocatableError {
588                error: CompilerError::BadGrammarElement,
589                location: syntax.into(),
590            }),
591        }?;
592
593        walker.goto_next_sibling();
594
595        let no = match driver.visit(walker.node(), self, context.clone())? {
596            MELCompilerContext::Expr(no) => Result::<Expr<()>, CompilerLocatableError>::Ok(no),
597            _ => Result::<Expr<()>, CompilerLocatableError>::Err(CompilerLocatableError {
598                error: CompilerError::BadGrammarElement,
599                location: syntax.into(),
600            }),
601        }?;
602
603        Ok(MELCompilerContext::Expr(TernaryExpr(Arc::new(
604            ast::TernaryExpr {
605                condition,
606                yes,
607                no,
608                location: syntax.into(),
609                aug: (),
610            },
611        ))))
612    }
613
614    fn visit_literal(
615        &self,
616        syntax: Node,
617        context: MELCompilerContext,
618        driver: &SyntaxVisitorDriver,
619    ) -> SyntaxVisitorResult<MELCompilerContext> {
620        let mut walker = syntax.walk();
621        walker.goto_first_child();
622        driver.visit(walker.node(), self, context)
623    }
624
625    fn visit_boolean_literal(
626        &self,
627        syntax: Node,
628        _context: MELCompilerContext,
629        _driver: &SyntaxVisitorDriver,
630    ) -> SyntaxVisitorResult<MELCompilerContext> {
631        let literal =
632            syntax
633                .utf8_text(self.source.as_bytes())
634                .map_err(|_| CompilerLocatableError {
635                    error: CompilerError::InvalidRange,
636                    location: syntax.into(),
637                })?;
638        if literal == "true" {
639            return Ok(MELCompilerContext::Expr(Expr::Literal(
640                Boolean(ast::BooleanLiteral::True),
641                syntax.into(),
642                (),
643            )));
644        } else if literal == "false" {
645            return Ok(MELCompilerContext::Expr(Expr::Literal(
646                Boolean(ast::BooleanLiteral::False),
647                syntax.into(),
648                (),
649            )));
650        }
651        Err(CompilerLocatableError {
652            error: CompilerError::BadGrammarElement,
653            location: syntax.into(),
654        })
655    }
656    fn visit_number_literal(
657        &self,
658        syntax: Node,
659        _context: MELCompilerContext,
660        _driver: &SyntaxVisitorDriver,
661    ) -> SyntaxVisitorResult<MELCompilerContext> {
662        let literal =
663            syntax
664                .utf8_text(self.source.as_bytes())
665                .map_err(|_| CompilerLocatableError {
666                    error: CompilerError::InvalidRange,
667                    location: syntax.into(),
668                })?;
669        let number: usize = literal
670            .parse::<usize>()
671            .map_err(|e| CompilerLocatableError {
672                error: CompilerError::BadLiteral(e.to_string()),
673                location: syntax.into(),
674            })?;
675
676        Ok(MELCompilerContext::Expr(Expr::Literal(
677            Number(ast::NumberLiteral { literal: number }),
678            syntax.into(),
679            (),
680        )))
681    }
682
683    fn visit_string_literal(
684        &self,
685        syntax: Node,
686        _context: MELCompilerContext,
687        _driver: &SyntaxVisitorDriver,
688    ) -> SyntaxVisitorResult<MELCompilerContext> {
689        let literal =
690            syntax
691                .utf8_text(self.source.as_bytes())
692                .map_err(|_| CompilerLocatableError {
693                    error: CompilerError::InvalidRange,
694                    location: syntax.into(),
695                })?;
696        Ok(MELCompilerContext::Expr(Expr::Literal(
697            ast::Literal::String(ast::StringLiteral {
698                literal: utils::strip_quotes(literal),
699            }),
700            syntax.into(),
701            (),
702        )))
703    }
704
705    fn visit_comparison_operator(
706        &self,
707        syntax: Node,
708        _context: MELCompilerContext,
709        _driver: &SyntaxVisitorDriver,
710    ) -> SyntaxVisitorResult<MELCompilerContext> {
711        let mut walker = syntax.walk();
712        walker.goto_first_child();
713
714        if walker.node().grammar_name() == "eq" {
715            return Ok(MELCompilerContext::BinaryOperator(
716                BinaryInfixOperator::Comparison(ast::ComparisonOperator::Eq),
717            ));
718        } else if walker.node().grammar_name() == "lt" {
719            return Ok(MELCompilerContext::BinaryOperator(
720                BinaryInfixOperator::Comparison(ast::ComparisonOperator::Lt),
721            ));
722        } else if walker.node().grammar_name() == "lte" {
723            return Ok(MELCompilerContext::BinaryOperator(
724                BinaryInfixOperator::Comparison(ast::ComparisonOperator::Lte),
725            ));
726        } else if walker.node().grammar_name() == "gt" {
727            return Ok(MELCompilerContext::BinaryOperator(
728                BinaryInfixOperator::Comparison(ast::ComparisonOperator::Gt),
729            ));
730        } else if walker.node().grammar_name() == "gte" {
731            return Ok(MELCompilerContext::BinaryOperator(
732                BinaryInfixOperator::Comparison(ast::ComparisonOperator::Gte),
733            ));
734        } else if walker.node().grammar_name() == "ne" {
735            return Ok(MELCompilerContext::BinaryOperator(
736                BinaryInfixOperator::Comparison(ast::ComparisonOperator::Ne),
737            ));
738        } else if walker.node().grammar_name() == "regex_eq" {
739            return Ok(MELCompilerContext::BinaryOperator(
740                BinaryInfixOperator::Comparison(ast::ComparisonOperator::Re),
741            ));
742        } else if walker.node().grammar_name() == "ipmatch" {
743            return Ok(MELCompilerContext::BinaryOperator(
744                BinaryInfixOperator::Comparison(ast::ComparisonOperator::IP),
745            ));
746        }
747
748        Err(CompilerLocatableError {
749            error: CompilerError::BadGrammarElement,
750            location: syntax.into(),
751        })
752    }
753
754    fn visit_member_access_expr(
755        &self,
756        syntax: Node,
757        context: MELCompilerContext,
758        driver: &SyntaxVisitorDriver,
759    ) -> SyntaxVisitorResult<MELCompilerContext> {
760        let mut walker = syntax.walk();
761
762        walker.goto_first_child();
763
764        let base = match driver.visit(walker.node(), self, context.clone())? {
765            MELCompilerContext::Expr(base) => Result::<Expr<()>, CompilerLocatableError>::Ok(base),
766            _ => Result::<Expr<()>, CompilerLocatableError>::Err(CompilerLocatableError {
767                error: CompilerError::EmptyContext,
768                location: syntax.into(),
769            }),
770        }?;
771
772        walker.goto_next_sibling();
773
774        match driver.visit(walker.node(), self, context.clone())? {
775            MELCompilerContext::BinaryOperator(BinaryInfixOperator::MemberAccess(_)) => {
776                Result::<(), CompilerLocatableError>::Ok(())
777            }
778            _ => Result::<(), CompilerLocatableError>::Err(CompilerLocatableError {
779                error: CompilerError::BadGrammarElement,
780                location: syntax.into(),
781            }),
782        }?;
783
784        walker.goto_next_sibling();
785
786        let member = match driver.visit(walker.node(), self, context.clone())? {
787            MELCompilerContext::Expr(ast::Expr::Identifier(id)) => {
788                Result::<Arc<Identifier<()>>, CompilerLocatableError>::Ok(id)
789            }
790            _ => {
791                Result::<Arc<Identifier<()>>, CompilerLocatableError>::Err(CompilerLocatableError {
792                    error: CompilerError::EmptyContext,
793                    location: syntax.into(),
794                })
795            }
796        }?;
797
798        Ok(MELCompilerContext::Expr(MemberAccess(Arc::new(
799            ast::MemberAccessExpression {
800                base,
801                member: (*member).clone(),
802                oper: ast::MemberAccessOperator::MemberAccess,
803                location: syntax.into(),
804                aug: (),
805            },
806        ))))
807    }
808
809    fn visit_member_access_oper(
810        &self,
811        syntax: Node,
812        _context: MELCompilerContext,
813        _driver: &SyntaxVisitorDriver,
814    ) -> SyntaxVisitorResult<MELCompilerContext> {
815        let mut walker = syntax.walk();
816        walker.goto_first_child();
817
818        if walker.node().grammar_name() == "member_access" {
819            return Ok(MELCompilerContext::BinaryOperator(
820                BinaryInfixOperator::MemberAccess(ast::MemberAccessOperator::MemberAccess),
821            ));
822        }
823        Err(CompilerLocatableError {
824            error: CompilerError::BadGrammarElement,
825            location: syntax.into(),
826        })
827    }
828
829    fn visit_regex_literal(
830        &self,
831        syntax: Node,
832        _context: MELCompilerContext,
833        _driver: &SyntaxVisitorDriver,
834    ) -> SyntaxVisitorResult<MELCompilerContext> {
835        let literal =
836            syntax
837                .utf8_text(self.source.as_bytes())
838                .map_err(|_| CompilerLocatableError {
839                    error: CompilerError::InvalidRange,
840                    location: syntax.into(),
841                })?;
842
843        let regex = match RegexBuilder::new(&utils::strip_slashes(literal)).build() {
844            Ok(regex) => regex,
845            Err(e) => {
846                return Err(CompilerLocatableError {
847                    error: CompilerError::BadLiteral(e.to_string()),
848                    location: syntax.into(),
849                });
850            }
851        };
852
853        Ok(MELCompilerContext::Expr(Expr::Literal(
854            ast::Literal::Regex(ast::RegexLiteral { literal: regex }),
855            syntax.into(),
856            (),
857        )))
858    }
859
860    fn visit_ipaddress_literal(
861        &self,
862        syntax: Node,
863        _context: MELCompilerContext,
864        _driver: &SyntaxVisitorDriver,
865    ) -> SyntaxVisitorResult<MELCompilerContext> {
866        let literal =
867            syntax
868                .utf8_text(self.source.as_bytes())
869                .map_err(|_| CompilerLocatableError {
870                    error: CompilerError::InvalidRange,
871                    location: syntax.into(),
872                })?;
873
874        let ip_addr: IpAddr = literal
875            .parse::<IpAddr>()
876            .map_err(|e| CompilerLocatableError {
877                error: CompilerError::BadLiteral(e.to_string()),
878                location: syntax.into(),
879            })?;
880
881        Ok(MELCompilerContext::Expr(Expr::Literal(
882            ast::Literal::IPAddress(ast::IPAddressLiteral { literal: ip_addr }),
883            syntax.into(),
884            (),
885        )))
886    }
887
888    fn visit_error(
889        &self,
890        syntax: Node,
891        _context: MELCompilerContext,
892        _driver: &SyntaxVisitorDriver,
893    ) -> CompilerLocatableError {
894        // if the node is an error, then the error is really in the child.
895
896        if syntax.is_error()
897            && let Some(child) = syntax.child(0)
898        {
899            self.extract_error(&child)
900        // if the node is missing, then the error is right here.
901        } else if syntax.is_missing() {
902            self.extract_error(&syntax)
903        } else {
904            CompilerLocatableError {
905                error: CompilerError::SyntaxError(
906                    "Unknown syntax error (couldn't get token)".to_string(),
907                ),
908                location: syntax.into(),
909            }
910        }
911    }
912}
913
914pub struct SyntaxVisitorDriver {}
915
916impl SyntaxVisitorDriver {
917    pub fn visit<T, U: SyntaxVisitor<T>>(
918        &self,
919        node: Node,
920        visitor: &U,
921        context: T,
922    ) -> SyntaxVisitorResult<T> {
923        type Visitor<T, U> = fn(&U, Node, T, &SyntaxVisitorDriver) -> SyntaxVisitorResult<T>;
924
925        let mut hm: HashMap<String, Visitor<T, U>> = HashMap::new();
926
927        // Register each of the appropriate visitor functions with the grammar nodes (as
928        // defined by the grammar_node macro).
929        ast::FunctionCall::<()>::name().iter().for_each(|name| {
930            hm.insert(
931                name.clone(),
932                U::visit_function_call as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
933            );
934        });
935        ast::Expr::<()>::name().iter().for_each(|name| {
936            hm.insert(
937                name.clone(),
938                U::visit_expr as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
939            );
940        });
941        ast::Mel::<()>::name().iter().for_each(|name| {
942            hm.insert(
943                name.clone(),
944                U::visit_mel as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
945            );
946        });
947        ast::Identifier::<()>::name().iter().for_each(|name| {
948            hm.insert(
949                name.clone(),
950                U::visit_identifier as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
951            );
952        });
953        ast::ArgumentList::<()>::name().iter().for_each(|name| {
954            hm.insert(
955                name.clone(),
956                U::visit_argument_list as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
957            );
958        });
959        ast::Argument::<()>::name().iter().for_each(|name| {
960            hm.insert(
961                name.clone(),
962                U::visit_argument as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
963            );
964        });
965        ast::LogicOperator::name().iter().for_each(|name| {
966            hm.insert(
967                name.clone(),
968                U::visit_logic_operator as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
969            );
970        });
971        ast::StringConcatOperator::name().iter().for_each(|name| {
972            hm.insert(
973                name.clone(),
974                U::visit_string_concat_operator as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
975            );
976        });
977        ast::ComparisonOperator::name().iter().for_each(|name| {
978            hm.insert(
979                name.clone(),
980                U::visit_comparison_operator as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
981            );
982        });
983        ast::BinaryExpr::<()>::name().iter().for_each(|name| {
984            hm.insert(
985                name.clone(),
986                U::visit_binary_expr as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
987            );
988        });
989        ast::MemberAccessExpression::<()>::name()
990            .iter()
991            .for_each(|name| {
992                hm.insert(
993                    name.clone(),
994                    U::visit_member_access_expr as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
995                );
996            });
997        ast::MemberAccessOperator::name().iter().for_each(|name| {
998            hm.insert(
999                name.clone(),
1000                U::visit_member_access_oper as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1001            );
1002        });
1003        ast::TernaryExpr::<()>::name().iter().for_each(|name| {
1004            hm.insert(
1005                name.clone(),
1006                U::visit_ternary_expr as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1007            );
1008        });
1009        ast::MathOperator::name().iter().for_each(|name| {
1010            hm.insert(
1011                name.clone(),
1012                U::visit_math_operator as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1013            );
1014        });
1015        ast::TernaryOperator::name().iter().for_each(|name| {
1016            hm.insert(
1017                name.clone(),
1018                U::visit_ternary_operator as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1019            );
1020        });
1021        ast::Literal::name().iter().for_each(|name| {
1022            hm.insert(
1023                name.clone(),
1024                U::visit_literal as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1025            );
1026        });
1027        ast::BooleanLiteral::name().iter().for_each(|name| {
1028            hm.insert(
1029                name.clone(),
1030                U::visit_boolean_literal as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1031            );
1032        });
1033        ast::NumberLiteral::name().iter().for_each(|name| {
1034            hm.insert(
1035                name.clone(),
1036                U::visit_number_literal as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1037            );
1038        });
1039        ast::StringLiteral::name().iter().for_each(|name| {
1040            hm.insert(
1041                name.clone(),
1042                U::visit_string_literal as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1043            );
1044        });
1045        ast::RegexLiteral::name().iter().for_each(|name| {
1046            hm.insert(
1047                name.clone(),
1048                U::visit_regex_literal as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1049            );
1050        });
1051        ast::IPAddressLiteral::name().iter().for_each(|name| {
1052            hm.insert(
1053                name.clone(),
1054                U::visit_ipaddress_literal as fn(&U, Node, _, &Self) -> SyntaxVisitorResult<T>,
1055            );
1056        });
1057
1058        // Special case for errors.
1059        if node.is_error() || node.is_missing() || node.is_extra() {
1060            Err(visitor.visit_error(node, context, self))
1061        } else {
1062            match hm.get(node.grammar_name()) {
1063                Some(callable) => (callable)(visitor, node, context, self),
1064                None => Err(CompilerLocatableError {
1065                    error: CompilerError::NoSuchVisitor(node.grammar_name().into()),
1066                    location: node.into(),
1067                }),
1068            }
1069        }
1070    }
1071}
1072
1073impl From<Node<'_>> for TextLocation {
1074    fn from(value: Node) -> Self {
1075        TextLocation {
1076            start: value.start_byte(),
1077            extent: value.end_byte() - value.start_byte(),
1078        }
1079    }
1080}