From 82ec6770c89bccb4847aba9dbbd637ab569a0b71 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 2 Nov 2025 01:17:39 -0400 Subject: [PATCH] examples: Add sevenfold example demonstrating (and testing) Visit and Fold --- examples/7fold.rs | 162 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 examples/7fold.rs diff --git a/examples/7fold.rs b/examples/7fold.rs new file mode 100644 index 0000000..8e9c66f --- /dev/null +++ b/examples/7fold.rs @@ -0,0 +1,162 @@ +//! 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)) + } +}