diff options
author | Greg Brown <gmb60@cam.ac.uk> | 2021-01-08 18:00:11 +0000 |
---|---|---|
committer | Greg Brown <gmb60@cam.ac.uk> | 2021-01-08 18:00:11 +0000 |
commit | e1452227b8bd9ad3805480f8a5a66a75fb8370dd (patch) | |
tree | b02c9dfdc157d753e3f1c8a09bbd2ffb0bbfcc36 /src/chomp/check/inline.rs | |
parent | fe2eac31d9dbec772796c3ea75be32e9cd01b810 (diff) |
Do more restructuring.
Diffstat (limited to 'src/chomp/check/inline.rs')
-rw-r--r-- | src/chomp/check/inline.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/chomp/check/inline.rs b/src/chomp/check/inline.rs new file mode 100644 index 0000000..a6a831c --- /dev/null +++ b/src/chomp/check/inline.rs @@ -0,0 +1,105 @@ +use super::{ + super::{ + ast::{Alt, Call, Cat, Epsilon, Expression, Fix, Function, Literal, Parameter, Variable}, + error::SubstituteError, + visit::{Folder, Visitable}, + }, + SubstituteParams, +}; + +#[derive(Clone, Debug)] +pub struct InlineCalls { + function: Function, +} + +impl InlineCalls { + pub fn new(function: Function) -> Self { + Self { function } + } +} + +impl Folder for InlineCalls { + type Out = Result<Expression, SubstituteError>; + + fn fold_epsilon(&mut self, eps: Epsilon) -> Self::Out { + Ok(eps.into()) + } + + fn fold_literal(&mut self, lit: Literal) -> Self::Out { + Ok(lit.into()) + } + + fn fold_cat(&mut self, mut cat: Cat) -> Self::Out { + cat.fst = Box::new(cat.fst.fold(self)?); + cat.snd = Box::new(cat.snd.fold(self)?); + Ok(cat.into()) + } + + fn fold_alt(&mut self, mut alt: Alt) -> Self::Out { + alt.left = Box::new(alt.left.fold(self)?); + alt.right = Box::new(alt.right.fold(self)?); + Ok(alt.into()) + } + + fn fold_fix(&mut self, mut fix: Fix) -> Self::Out { + fix.inner = Box::new(fix.inner.fold(self)?); + Ok(fix.into()) + } + + fn fold_variable(&mut self, var: Variable) -> Self::Out { + Ok(var.into()) + } + + fn fold_parameter(&mut self, param: Parameter) -> Self::Out { + Ok(param.into()) + } + + fn fold_call(&mut self, mut call: Call) -> Self::Out { + call.args = call + .args + .into_iter() + .map(|arg| arg.fold(self)) + .collect::<Result<_, _>>()?; + + if call.name != self.function.name { + Ok(call.into()) + } else if call.args.len() != self.function.params { + Err(SubstituteError::WrongArgCount { + call, + expected: self.function.params, + }) + } else { + self.function + .expr + .clone() + .fold(&mut SubstituteParams::new(call.args)) + } + } +} + +#[cfg(test)] +mod tests { + use proc_macro2::Span; + use syn::Ident; + + use super::*; + + const OPT_NAME: &str = "opt"; + const OPT: Function = Function::new( + Ident::new(OPT_NAME, Span::call_site()), + 1, + Expression::Alt(Alt::new( + Epsilon::default().into(), + None, + Parameter::new(None, 0).into(), + )), + None, + ); + + #[test] + fn test_inline_absent() { + let expr = Epsilon::default(); + let inlined = expr.fold(&mut InlineCalls::new(OPT)); + assert_eq!(inlined, Ok(Expression::from(Epsilon::default()))) + } +} |