📜 Add better documentation across the compiler. #3
@@ -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())?;
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<syntax::Program> 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<Vec<syntax::Statement>> for ir::Program {
|
||||
fn from(mut value: Vec<syntax::Statement>) -> Self {
|
||||
ir::Program {
|
||||
statements: value.drain(..).map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<syntax::Statement> for ir::Statement {
|
||||
impl From<syntax::Statement> 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<syntax::Expression> 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<ir::Statement> {
|
||||
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::Statement>, 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<syntax::Expression> for ir::ValueOrRef {
|
||||
fn from(value: syntax::Expression) -> Self {
|
||||
match value {
|
||||
syntax::Expression::Primitive(loc, _, _) => {
|
||||
panic!("{:?}: couldn't convert to valueorref", loc)
|
||||
}
|
||||
|
||||
syntax::Expression::Reference(loc, var) => {
|
||||
ir::ValueOrRef::Ref(loc, ArcIntern::new(var))
|
||||
fn rebind(self, base_name: &str) -> (Vec<ir::Statement>, 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();
|
||||
|
||||
for expr in expressions.drain(..) {
|
||||
let (mut cur_prereqs, arg) = expr.rebind(base_name);
|
||||
prereqs.append(&mut cur_prereqs);
|
||||
new_exprs.push(arg);
|
||||
}
|
||||
|
||||
syntax::Expression::Value(loc, val) => ir::ValueOrRef::Value(loc, val.into()),
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<syntax::Value> 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<String> for ir::Primitive {
|
||||
fn from(value: String) -> Self {
|
||||
value.try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn gensym(name: &str) -> ArcIntern<String> {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ pub struct REPL {
|
||||
file_database: SimpleFiles<String, String>,
|
||||
jitter: Backend<JITModule>,
|
||||
variable_binding_sites: HashMap<String, Location>,
|
||||
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()?;
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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<Statement> {
|
||||
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<Statement>, 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user