From 22be68f9aaefae1f2cb778eef03f406953af689a Mon Sep 17 00:00:00 2001 From: Stephen D <webmaster@scd31.com> Date: Sun, 9 Mar 2025 12:02:01 -0400 Subject: [PATCH] flattener --- src/expr.rs | 8 ++++++- src/flatten.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 13 ++++++------ src/parser.rs | 2 +- 4 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 src/flatten.rs diff --git a/src/expr.rs b/src/expr.rs index a8a8a8d..c1652e2 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1,8 +1,14 @@ #[derive(Debug)] pub enum Expr { - Lambda(Box<Expr>), Abs(Box<Expr>), App(Box<Expr>, Box<Expr>), Var(usize), DefinitionName(String), } + +#[derive(Debug)] +pub enum FlattenedExpr { + Abs(Box<FlattenedExpr>), + App(Box<FlattenedExpr>, Box<FlattenedExpr>), + Var(usize), +} diff --git a/src/flatten.rs b/src/flatten.rs new file mode 100644 index 0000000..53e5432 --- /dev/null +++ b/src/flatten.rs @@ -0,0 +1,57 @@ +use std::collections::{HashMap, HashSet}; + +use crate::expr::{Expr, FlattenedExpr}; + +pub struct Flattener { + funcs: HashMap<String, Expr>, +} + +impl Flattener { + pub fn new(funcs: HashMap<String, Expr>) -> Self { + Self { funcs } + } + + pub fn flatten(&mut self, main: &Expr) -> Option<FlattenedExpr> { + self.flatten_expr(&main, HashSet::new()) + } + + fn flatten_expr<'a>( + &self, + expr: &'a Expr, + mut names: HashSet<&'a str>, + ) -> Option<FlattenedExpr> { + let ret = match expr { + Expr::Abs(expr) => FlattenedExpr::Abs(Box::new(self.flatten_expr(expr, names)?)), + Expr::App(left, right) => FlattenedExpr::App( + Box::new(self.flatten_expr(left, names.clone())?), + Box::new(self.flatten_expr(right, names)?), + ), + Expr::Var(x) => FlattenedExpr::Var(*x), + Expr::DefinitionName(name) => { + if names.contains(name.as_str()) { + self.print_error(&format!("Recursive definition for ${}", name)); + return None; + } + + let expr = match self.funcs.get(name) { + Some(x) => x, + None => { + self.print_error(&format!("Unknown definition ${}", name)); + + return None; + } + }; + + names.insert(name); + + self.flatten_expr(expr, names)? + } + }; + + Some(ret) + } + + fn print_error(&self, err: &str) { + eprintln!("Error: {err}"); + } +} diff --git a/src/main.rs b/src/main.rs index 4de6c3e..5c20282 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ +use flatten::Flattener; use parser::Parser; use scanner::Scanner; mod expr; +mod flatten; mod parser; mod scanner; mod token; @@ -10,7 +12,6 @@ fn main() { let scanner = Scanner::new( " $false = λtf.f -# mrow! $true = λtf.t λa.(a $true) @@ -19,13 +20,11 @@ $true = λtf.t let tokens = scanner.scan_tokens().unwrap(); - for t in &tokens { - println!("{} {:?}", t.line, t.token_type); - } - let mut parser = Parser::new(tokens); let (funcs, main) = parser.parse().unwrap(); - dbg!(funcs); - dbg!(main); + let mut flattener = Flattener::new(funcs); + let flat = flattener.flatten(&main); + + dbg!(flat); } diff --git a/src/parser.rs b/src/parser.rs index 8dd05f8..076388a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -122,7 +122,7 @@ impl Parser { for _ in 0..abs_count { self.env.pop().unwrap(); - expr = Expr::Lambda(Box::new(expr)); + expr = Expr::Abs(Box::new(expr)); } Some(expr) -- GitLab