diff --git a/src/compiler.rs b/src/compiler.rs index 14c54e0..41cc037 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -100,9 +100,8 @@ impl Compiler { return Ok(None); } - // Now that we've validated it, turn it into IR; first we simplify it, then - // we do the conversion. - let ir = IR::from(syntax.simplify()); + // Now that we've validated it, turn it into IR. + let ir = IR::from(syntax); // Finally, send all this to Cranelift for conversion into an object file. let mut backend = Backend::object_file(Triple::host())?; diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 87705e8..3d8446d 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -57,7 +57,7 @@ impl Arbitrary for Program { fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { crate::syntax::Program::arbitrary_with(args) - .prop_map(|x| Program::from(x.simplify())) + .prop_map(Program::from) .boxed() } } diff --git a/src/ir/eval.rs b/src/ir/eval.rs index b1fd2ee..78b8b0b 100644 --- a/src/ir/eval.rs +++ b/src/ir/eval.rs @@ -71,7 +71,7 @@ impl Expression { #[test] fn two_plus_three() { let input = crate::syntax::Program::parse(0, "x = 2 + 3; print x;").expect("parse works"); - let ir = Program::from(input.simplify()); + let ir = Program::from(input); let output = ir.eval().expect("runs successfully"); assert_eq!("x = 5i64\n", &output); } @@ -80,7 +80,7 @@ fn two_plus_three() { fn lotsa_math() { let input = crate::syntax::Program::parse(0, "x = 2 + 3 * 10 / 5 - 1; print x;").expect("parse works"); - let ir = Program::from(input.simplify()); + let ir = Program::from(input); let output = ir.eval().expect("runs successfully"); assert_eq!("x = 7i64\n", &output); } diff --git a/src/ir/from_syntax.rs b/src/ir/from_syntax.rs index 9caa1ff..fbd35a6 100644 --- a/src/ir/from_syntax.rs +++ b/src/ir/from_syntax.rs @@ -1,82 +1,124 @@ use internment::ArcIntern; +use std::sync::atomic::AtomicUsize; use crate::ir::ast as ir; -use crate::syntax as syntax; +use crate::syntax; + +use super::ValueOrRef; impl From for ir::Program { fn from(mut value: syntax::Program) -> Self { - ir::Program { - statements: value.statements.drain(..).map(Into::into).collect(), + let mut statements = Vec::new(); + + for stmt in value.statements.drain(..) { + statements.append(&mut stmt.simplify()); } + + ir::Program { statements } } } -impl From> for ir::Program { - fn from(mut value: Vec) -> Self { - ir::Program { - statements: value.drain(..).map(Into::into).collect(), - } - } -} - -impl From for ir::Statement { +impl From for ir::Program { fn from(value: syntax::Statement) -> Self { - match value { - syntax::Statement::Binding(loc, name, expr) => { - ir::Statement::Binding(loc, ArcIntern::from(name), ir::Expression::from(expr)) - } - syntax::Statement::Print(loc, name) => ir::Statement::Print(loc, ArcIntern::from(name)), + ir::Program { + statements: value.simplify(), } } } -impl From for ir::Expression { - fn from(value: syntax::Expression) -> Self { - match value { - syntax::Expression::Primitive(loc, name, mut exprs) => ir::Expression::Primitive( - loc, - ir::Primitive::try_from(name.as_str()).unwrap(), - exprs.drain(..).map(Into::into).collect(), - ), +impl syntax::Statement { + fn simplify(self) -> Vec { + let mut new_statements = vec![]; + + match self { + syntax::Statement::Print(loc, name) => { + new_statements.push(ir::Statement::Print(loc, ArcIntern::new(name))) + } + syntax::Statement::Binding(loc, name, value) => { + let (mut prereqs, new_value) = value.simplify(&name); + new_statements.append(&mut prereqs); + new_statements.push(ir::Statement::Binding(loc, ArcIntern::new(name), new_value)) + } + } + + new_statements + } +} + +impl syntax::Expression { + fn simplify(self, base_name: &str) -> (Vec, ir::Expression) { + match self { + syntax::Expression::Value(loc, val) => (vec![], ir::Expression::Value(loc, val.into())), syntax::Expression::Reference(loc, name) => { - ir::Expression::Reference(loc, ArcIntern::from(name)) + (vec![], ir::Expression::Reference(loc, ArcIntern::new(name))) } - syntax::Expression::Value(loc, value) => { - ir::Expression::Value(loc, ir::Value::from(value)) + syntax::Expression::Primitive(_, _, _) => { + let (prereqs, val_or_ref) = self.rebind(base_name); + (prereqs, val_or_ref.into()) } } } -} -impl From for ir::ValueOrRef { - fn from(value: syntax::Expression) -> Self { - match value { - syntax::Expression::Primitive(loc, _, _) => { - panic!("{:?}: couldn't convert to valueorref", loc) + fn rebind(self, base_name: &str) -> (Vec, ir::ValueOrRef) { + match self { + syntax::Expression::Value(loc, val) => (vec![], ValueOrRef::Value(loc, val.into())), + syntax::Expression::Reference(loc, name) => { + (vec![], ValueOrRef::Ref(loc, ArcIntern::new(name))) } + syntax::Expression::Primitive(loc, prim, mut expressions) => { + let new_name = gensym(base_name); + let mut prereqs = Vec::new(); + let mut new_exprs = Vec::new(); - syntax::Expression::Reference(loc, var) => { - ir::ValueOrRef::Ref(loc, ArcIntern::new(var)) + for expr in expressions.drain(..) { + let (mut cur_prereqs, arg) = expr.rebind(base_name); + prereqs.append(&mut cur_prereqs); + new_exprs.push(arg); + } + + let prim = ir::Primitive::try_from(prim.as_str()).unwrap(); + prereqs.push(ir::Statement::Binding( + loc.clone(), + new_name.clone(), + ir::Expression::Primitive(loc.clone(), prim, new_exprs), + )); + + (prereqs, ValueOrRef::Ref(loc, new_name)) } - - syntax::Expression::Value(loc, val) => ir::ValueOrRef::Value(loc, val.into()), } } } impl From for ir::Value { - fn from(x: syntax::Value) -> Self { - match x { - syntax::Value::Number(base, value) => ir::Value::Number(base, value), + fn from(value: syntax::Value) -> Self { + match value { + syntax::Value::Number(base, val) => ir::Value::Number(base, val), } } } +impl From for ir::Primitive { + fn from(value: String) -> Self { + value.try_into().unwrap() + } +} + +fn gensym(name: &str) -> ArcIntern { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let new_name = format!( + "<{}:{}>", + name, + COUNTER.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + ); + ArcIntern::new(new_name) +} + proptest::proptest! { #[test] fn translation_maintains_semantics(input: syntax::Program) { let syntax_result = input.eval(); - let ir = ir::Program::from(input.simplify()); + let ir = ir::Program::from(input); let ir_result = ir.eval(); assert_eq!(syntax_result, ir_result); } diff --git a/src/repl.rs b/src/repl.rs index 7ae9f92..5d511b5 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -24,7 +24,6 @@ pub struct REPL { file_database: SimpleFiles, jitter: Backend, variable_binding_sites: HashMap, - gensym_index: usize, console: StandardStream, console_config: Config, } @@ -72,7 +71,6 @@ impl REPL { file_database: SimpleFiles::new(), jitter: Backend::jit(None)?, variable_binding_sites: HashMap::new(), - gensym_index: 1, console, console_config, }) @@ -156,7 +154,7 @@ impl REPL { return Ok(()); } - let ir = IR::from(syntax.simplify(&mut self.gensym_index)); + let ir = IR::from(syntax); let name = format!("line{}", line_no); let function_id = self.jitter.compile_function(&name, ir)?; self.jitter.module.finalize_definitions()?; diff --git a/src/syntax.rs b/src/syntax.rs index ddb10db..23eef81 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -34,7 +34,6 @@ mod arbitrary; mod ast; mod eval; mod location; -pub mod simplify; mod tokens; lalrpop_mod!( #[allow(clippy::just_underscores_and_digits, clippy::clone_on_copy)] diff --git a/src/syntax/simplify.rs b/src/syntax/simplify.rs deleted file mode 100644 index 28ad377..0000000 --- a/src/syntax/simplify.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::syntax::ast::{Expression, Program, Statement}; - -impl Program { - pub fn simplify(mut self) -> Self { - let mut new_statements = Vec::new(); - let mut gensym_index = 1; - - for stmt in self.statements.drain(..) { - new_statements.append(&mut stmt.simplify(&mut gensym_index)); - } - - self.statements = new_statements; - self - } -} - -impl Statement { - pub fn simplify(self, gensym_index: &mut usize) -> Vec { - let mut new_statements = vec![]; - - match self { - Statement::Print(_, _) => new_statements.push(self), - Statement::Binding(_, _, Expression::Reference(_, _)) => new_statements.push(self), - Statement::Binding(_, _, Expression::Value(_, _)) => new_statements.push(self), - Statement::Binding(loc, name, value) => { - let (mut prereqs, new_value) = value.rebind(&name, gensym_index); - new_statements.append(&mut prereqs); - new_statements.push(Statement::Binding(loc, name, new_value)) - } - } - - new_statements - } -} - -impl Expression { - fn rebind(self, base_name: &str, gensym_index: &mut usize) -> (Vec, Expression) { - match self { - Expression::Value(_, _) => (vec![], self), - Expression::Reference(_, _) => (vec![], self), - Expression::Primitive(loc, prim, mut expressions) => { - let mut prereqs = Vec::new(); - let mut new_exprs = Vec::new(); - - for expr in expressions.drain(..) { - let (mut cur_prereqs, arg) = expr.rebind(base_name, gensym_index); - prereqs.append(&mut cur_prereqs); - new_exprs.push(arg); - } - - let new_name = format!("<{}:{}>", base_name, *gensym_index); - *gensym_index += 1; - prereqs.push(Statement::Binding( - loc.clone(), - new_name.clone(), - Expression::Primitive(loc.clone(), prim, new_exprs), - )); - - (prereqs, Expression::Reference(loc, new_name)) - } - } - } -}