//! Demonstrates the visitor pattern use std::{convert::Infallible, error::Error}; use doughlang::{ ast::{ visit::{Visit, Walk}, *, }, lexer::Lexer, parser::{Parser, expr::Prec}, }; const CODE: &str = r#" let x: [i32; 4] = [1, 2, 3, 4]; use foo::bar::baz::qux::{a, b, c, d, e}; struct Point {x: T, y: T} let v = Point { x, y: 20 + x } fn main() -> (&str, bool, i128) { // An if expression is like the ternary conditional operator in C let y = if 10 < 50 { "\u{1f988}" } else { "x" } // A `while` expression is like the while-else construct in Python, // but it returns a value via the `break` keyword let z = while false { // do a thing repeatedly break true } else { // If `while` does not `break`, fall through to the `else` expression false } // The same is true of `for` expressions! let w = for idx in 0..100 { if idx > 2 * 2 { break idx } } else 12345; // semicolon operator required here // desugars to let w = match ((0..100).into_iter()) { __iter => loop match (__iter.next()) { None => break 12345, Some (idx) => { if (idx > (2 * 2)) { break idx } }, }, }; // A block evaluates to its last expression, // or Empty if there is none // (🦈, false, 5) (y, z, w) } "#; fn main() -> Result<(), Box> { let ast: Anno = Parser::new(Lexer::new(CODE)).parse(Prec::MIN)?; println!("{ast}"); let mut counters = Weight::new(); counters.visit(&ast); println!("{counters:#?}"); println!("{}", CODE.len()); Ok(()) } #[derive(Clone, Debug, Default, PartialEq, Eq)] struct Weight { size: usize, } impl Weight { fn new() -> Self { Self::default() } } impl<'a, A: AstTypes> Visit<'a, A> for Weight { type Error = Infallible; fn visit_expr(&mut self, item: &'a Expr) -> Result<(), Self::Error> { self.size += size_of_val(item); item.children(self) } fn visit_symbol(&mut self, item: &'a A::Symbol) -> Result<(), Self::Error> { self.size += size_of_val(item); Ok(()) } fn visit_path(&mut self, item: &'a A::Path) -> Result<(), Self::Error> { self.size += size_of_val(item); Ok(()) } fn visit_literal(&mut self, item: &'a A::Literal) -> Result<(), Self::Error> { self.size += size_of_val(item); Ok(()) } fn visit_use(&mut self, item: &'a Use) -> Result<(), Self::Error> { self.size += size_of_val(item); item.children(self) } fn visit_pat(&mut self, item: &'a Pat) -> Result<(), Self::Error> { self.size += size_of_val(item); item.children(self) } fn visit_bind(&mut self, item: &'a Bind) -> Result<(), Self::Error> { self.size += size_of_val(item); item.children(self) } fn visit_make(&mut self, item: &'a Make) -> Result<(), Self::Error> { self.size += size_of_val(item); item.children(self) } fn visit_makearm(&mut self, item: &'a MakeArm) -> Result<(), Self::Error> { self.size += size_of_val(item); item.children(self) } }