From 17ee16e38f5c6f9f406263f5cf7f051a7122f364 Mon Sep 17 00:00:00 2001 From: jonathan Date: Sat, 25 Nov 2023 18:11:02 +0100 Subject: [PATCH] Refactor atomize --- compiler/src/passes/atomize/atomize.rs | 152 ++++++++++--------------- compiler/src/passes/atomize/mod.rs | 25 ++-- compiler/src/passes/atomize/tests.rs | 7 +- duplicate_arg | 0 4 files changed, 75 insertions(+), 109 deletions(-) delete mode 100644 duplicate_arg diff --git a/compiler/src/passes/atomize/atomize.rs b/compiler/src/passes/atomize/atomize.rs index 6548173..430bfcf 100644 --- a/compiler/src/passes/atomize/atomize.rs +++ b/compiler/src/passes/atomize/atomize.rs @@ -36,47 +36,33 @@ fn atomize_def(def: DefRevealed) -> DefAtomized { } } -fn atomize_expr<'p>(expr: Meta>, RExpr<'p>>) -> Meta>, AExpr<'p>> { +fn atomize_expr<'p>( + expr: Meta>, RExpr<'p>>, +) -> Meta>, AExpr<'p>> { + // Keep track of all the priors. These are bindings that should come before evaluating the expression. + let mut priors = Vec::new(); + + // Returns the atomized expression. This can hold `Var`s that must be bound by the priors. let inner = match expr.inner { RExpr::Lit { val } => AExpr::Atom { atm: Atom::Val { val }, }, - RExpr::Var { sym} => AExpr::Atom { + RExpr::Var { sym } => AExpr::Atom { atm: Atom::Var { sym }, }, - RExpr::BinaryOp { op, exprs: [lhs, rhs] } => { - let (lhs_arg, lhs_extra) = atomize_atom(*lhs); - let (rhs_arg, rhs_extra) = atomize_atom(*rhs); - - [lhs_extra, rhs_extra] - .into_iter() - .flatten() - .rfold(AExpr::BinaryOp { op, exprs: [lhs_arg, rhs_arg] }, |bdy, (sym, bnd)| { - AExpr::Let { - sym, - bnd: Box::new(bnd), - bdy: Box::new(Meta { - inner: bdy, - meta: expr.meta.clone() - }), - } - }) + RExpr::BinaryOp { + op, + exprs: [lhs, rhs], + } => AExpr::BinaryOp { + op, + exprs: [ + atomize_atom(*lhs, &mut priors), + atomize_atom(*rhs, &mut priors), + ], }, - RExpr::UnaryOp { op, expr: arg } => { - let (arg, extra) = atomize_atom(*arg); - - extra - .into_iter() - .rfold(AExpr::UnaryOp { op, expr: arg }, |bdy, (sym, bnd)| { - AExpr::Let { - sym, - bnd: Box::new(bnd), - bdy: Box::new(Meta { - inner: bdy, - meta: expr.meta.clone() - }), - } - }) + RExpr::UnaryOp { op, expr: arg } => AExpr::UnaryOp { + op, + expr: atomize_atom(*arg, &mut priors), }, RExpr::Let { sym, bnd, bdy } => AExpr::Let { sym, @@ -93,28 +79,14 @@ fn atomize_expr<'p>(expr: Meta>, RExpr<'p>>) -> Meta, Vec<_>) = args - .into_iter() - .map(atomize_atom) - .zip(params) - .map(|((arg, extra), arg_typ)| ((arg, arg_typ), extra)) - .unzip(); - - let (fun, fun_expr) = atomize_atom(*fun); - - fun_expr - .into_iter() - .chain(extras.into_iter().flatten()) - .rfold(AExpr::Apply { fun, args}, |bdy, (sym, bnd)| { - AExpr::Let { - sym, - bnd: Box::new(bnd), - bdy: Box::new(Meta { - inner: bdy, - meta: expr.meta.clone() - }), - } - }) + AExpr::Apply { + fun: atomize_atom(*fun, &mut priors), + args: args + .into_iter() + .map(|arg| atomize_atom(arg, &mut priors)) + .zip(params) + .collect(), + } } RExpr::FunRef { sym } => AExpr::FunRef { sym }, RExpr::Loop { bdy } => AExpr::Loop { @@ -135,55 +107,49 @@ fn atomize_expr<'p>(expr: Meta>, RExpr<'p>>) -> Meta AExpr::Return { bdy: Box::new(atomize_expr(*bdy)), }, - RExpr::Struct { sym, fields } => { - let (fields, extras): (Vec<_>, Vec<_>) = fields + RExpr::Struct { sym, fields } => AExpr::Struct { + sym, + fields: fields .into_iter() .map(|(sym, expr)| { - let (field, extra) = atomize_atom(expr); - ((sym, field), extra) + let field = atomize_atom(expr, &mut priors); + (sym, field) }) - .unzip(); - - extras.into_iter().flatten().rfold( - AExpr::Struct { sym, fields }, - |bdy , (sym, bnd)| AExpr::Let { - sym, - bnd: Box::new(bnd), - bdy: Box::new(Meta { - inner: bdy, - meta: expr.meta.clone() - }), - }, - ) - } - RExpr::AccessField { strct, field } => { - let (strct, extra) = atomize_atom(*strct); - - extra.into_iter().rfold( - AExpr::AccessField { strct, field }, - |bdy, (sym, bnd)| AExpr::Let { - sym, - bnd: Box::new(bnd), - bdy: Box::new(Meta { - inner: bdy, - meta: expr.meta.clone() - }), - }, - ) - } + .collect(), + }, + RExpr::AccessField { strct, field } => AExpr::AccessField { + strct: atomize_atom(*strct, &mut priors), + field, + }, }; + // Chains all the priors with the atomized expression as the body. + let inner = priors + .into_iter() + .rfold(inner, |bdy, (sym, bnd)| AExpr::Let { + sym, + bnd: Box::new(bnd), + bdy: Box::new(Meta { + inner: bdy, + meta: expr.meta.clone(), + }), + }); + Meta { inner, - meta: expr.meta + meta: expr.meta, } } -fn atomize_atom<'p>(expr: Meta>, RExpr<'p>>) -> (Atom<'p>, Option<(UniqueSym<'p>, Meta>, AExpr<'p>>)>) { +fn atomize_atom<'p>( + expr: Meta>, RExpr<'p>>, + priors: &mut Vec<(UniqueSym<'p>, Meta>, AExpr<'p>>)>, +) -> Atom<'p> { if let RExpr::Lit { val } = expr.inner { - (Atom::Val { val }, None) + Atom::Val { val } } else { let tmp = gen_sym("tmp"); - (Atom::Var { sym: tmp }, Some((tmp, atomize_expr(expr)))) + priors.push((tmp, atomize_expr(expr))); + Atom::Var { sym: tmp } } } diff --git a/compiler/src/passes/atomize/mod.rs b/compiler/src/passes/atomize/mod.rs index 731da05..d445589 100644 --- a/compiler/src/passes/atomize/mod.rs +++ b/compiler/src/passes/atomize/mod.rs @@ -4,10 +4,10 @@ mod tests; use crate::passes::parse::types::Type; use crate::passes::parse::{BinaryOp, Def, Meta, UnaryOp}; +use crate::passes::select::io::Std; use crate::passes::validate::{DefValidated, ExprValidated, PrgValidated, TLit}; use crate::utils::gen_sym::UniqueSym; use std::collections::HashMap; -use crate::passes::select::io::Std; pub struct PrgAtomized<'p> { pub defs: HashMap, DefAtomized<'p>>, @@ -123,7 +123,9 @@ impl<'p> From> for DefValidated<'p> { } } -impl<'p> From>, AExpr<'p>>> for Meta>, ExprValidated<'p>> { +impl<'p> From>, AExpr<'p>>> + for Meta>, ExprValidated<'p>> +{ fn from(value: Meta>, AExpr<'p>>) -> Self { let inner = match value.inner { AExpr::Atom { atm, .. } => return atm.into(), @@ -176,18 +178,16 @@ impl<'p> From>, AExpr<'p>>> for Meta> .into_iter() .map(|(sym, atm)| (sym, atm.into())) .collect(), - }, AExpr::AccessField { strct, field } => ExprValidated::AccessField { strct: Box::new(strct.into()), field, - }, }; - + Meta { inner, - meta: value.meta + meta: value.meta, } } } @@ -195,13 +195,12 @@ impl<'p> From>, AExpr<'p>>> for Meta> // Note that casting to Never here is safe because this `From` is only used by the interpreter which doesn't care about the type information. impl<'p> From> for Meta>, ExprValidated<'p>> { fn from(value: Atom<'p>) -> Self { - Meta { meta: Type::Never, inner: match value { - Atom::Val { val } => ExprValidated::Lit { - val, - }, - Atom::Var { sym } => ExprValidated::Var { - sym, + Meta { + meta: Type::Never, + inner: match value { + Atom::Val { val } => ExprValidated::Lit { val }, + Atom::Var { sym } => ExprValidated::Var { sym }, }, - }} + } } } diff --git a/compiler/src/passes/atomize/tests.rs b/compiler/src/passes/atomize/tests.rs index 0070e63..53b50d8 100644 --- a/compiler/src/passes/atomize/tests.rs +++ b/compiler/src/passes/atomize/tests.rs @@ -1,13 +1,14 @@ -use test_each_file::test_each_file; use crate::interpreter::TestIO; -use crate::utils::split_test::split_test; use crate::passes::parse::parse::parse_program; use crate::passes::validate::PrgValidated; +use crate::utils::split_test::split_test; +use test_each_file::test_each_file; fn atomize([test]: [&str; 1]) { let (input, expected_output, expected_return, _) = split_test(test); - let program: PrgValidated = parse_program(test).unwrap() + let program: PrgValidated = parse_program(test) + .unwrap() .validate() .unwrap() .reveal() diff --git a/duplicate_arg b/duplicate_arg deleted file mode 100644 index e69de29..0000000