examples: Add sevenfold example demonstrating (and testing) Visit and Fold
This commit is contained in:
162
examples/7fold.rs
Normal file
162
examples/7fold.rs
Normal file
@@ -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<T> 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<dyn Error>> {
|
||||||
|
let ast: Anno<Expr> = 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<A: Annotation>(&mut self, expr: &'a Expr<A>) -> 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<A: Annotation>(&mut self, item: &'a Bind<A>) -> Result<(), Self::Error> {
|
||||||
|
self.binds += 1;
|
||||||
|
item.children(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_make<A: Annotation>(&mut self, item: &'a Make<A>) -> Result<(), Self::Error> {
|
||||||
|
self.makes += 1;
|
||||||
|
item.children(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_makearm<A: Annotation>(&mut self, item: &'a MakeArm<A>) -> Result<(), Self::Error> {
|
||||||
|
self.makearms += 1;
|
||||||
|
item.children(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Sevenfold;
|
||||||
|
|
||||||
|
impl<A: Annotation> Fold<A> for Sevenfold {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn fold_literal(&mut self, _lit: Literal) -> Result<Literal, Self::Error> {
|
||||||
|
Ok(Literal::Int(7, 10))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user