//! Demonstrates the visitor pattern use std::{convert::Infallible, error::Error}; use doughlang::{ ast::{ fold::{Fold, Foldable}, 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)?; let mut counters = CountNodes::new(); counters.visit(&ast); println!("{counters:#?}"); let Ok(ast) = ast.fold_in(&mut Sevenfold) else { return Ok(()); }; println!("\nSevenfold:\n{ast}"); Ok(()) } #[derive(Clone, Debug, Default, PartialEq, Eq)] struct CountNodes { exprs: usize, idents: usize, paths: usize, literals: usize, uses: usize, patterns: usize, binds: usize, makes: usize, makearms: usize, } impl CountNodes { fn new() -> Self { Self::default() } } impl<'a> Visit<'a> for CountNodes { type Error = Infallible; fn visit_expr(&mut self, expr: &'a Expr) -> Result<(), Self::Error> { self.exprs += 1; expr.children(self) } fn visit_ident(&mut self, name: &'a str) -> Result<(), Self::Error> { self.idents += 1; name.children(self) } fn visit_path(&mut self, path: &'a Path) -> Result<(), Self::Error> { self.paths += 1; path.children(self) } fn visit_literal(&mut self, lit: &'a Literal) -> Result<(), Self::Error> { self.literals += 1; lit.children(self) } fn visit_use(&mut self, item: &'a Use) -> Result<(), Self::Error> { self.uses += 1; item.children(self) } fn visit_pat(&mut self, item: &'a Pat) -> Result<(), Self::Error> { self.patterns += 1; item.children(self) } fn visit_bind(&mut self, item: &'a Bind) -> Result<(), Self::Error> { self.binds += 1; item.children(self) } fn visit_make(&mut self, item: &'a Make) -> Result<(), Self::Error> { self.makes += 1; item.children(self) } fn visit_makearm(&mut self, item: &'a MakeArm) -> Result<(), Self::Error> { self.makearms += 1; item.children(self) } } struct Sevenfold; impl Fold for Sevenfold { type Error = (); fn fold_literal(&mut self, _lit: Literal) -> Result { Ok(Literal::Int(7, 10)) } }