From 811776d9e757274999f060f8f3af97e1d0f9efdf Mon Sep 17 00:00:00 2001 From: James Harton Date: Sat, 23 Mar 2019 09:36:45 +1300 Subject: [PATCH] Code gardening. --- huia-compiler/src/block.rs | 4 ++ huia-compiler/src/context.rs | 17 ++++- huia-compiler/src/error.rs | 12 ++++ huia-compiler/src/function.rs | 16 +++++ .../src/{ir => improvements}/desugar_infix.rs | 6 +- .../src/{ir => improvements}/desugar_unary.rs | 6 +- .../infix_folding.rs} | 62 +--------------- huia-compiler/src/improvements/mod.rs | 4 ++ .../src/improvements/unary_folding.rs | 72 +++++++++++++++++++ huia-compiler/src/ir/builder.rs | 4 +- huia-compiler/src/ir/mod.rs | 57 ++++++++++----- huia-compiler/src/lib.rs | 8 ++- huia-compiler/src/ty.rs | 63 ++++++++++++++++ huia-parser/src/ast/function.rs | 2 - huia-parser/src/ast/term.rs | 2 - 15 files changed, 245 insertions(+), 90 deletions(-) rename huia-compiler/src/{ir => improvements}/desugar_infix.rs (92%) rename huia-compiler/src/{ir => improvements}/desugar_unary.rs (88%) rename huia-compiler/src/{ir/constant_folding.rs => improvements/infix_folding.rs} (59%) create mode 100644 huia-compiler/src/improvements/mod.rs create mode 100644 huia-compiler/src/improvements/unary_folding.rs diff --git a/huia-compiler/src/block.rs b/huia-compiler/src/block.rs index 5bf49da..7f10512 100644 --- a/huia-compiler/src/block.rs +++ b/huia-compiler/src/block.rs @@ -33,6 +33,10 @@ impl Block { self.ir } + pub fn ir_ref(&self) -> Vec<&IR> { + self.ir.iter().collect() + } + pub fn is_empty(&self) -> bool { self.ir.is_empty() } diff --git a/huia-compiler/src/context.rs b/huia-compiler/src/context.rs index 7d68a2b..76d604c 100644 --- a/huia-compiler/src/context.rs +++ b/huia-compiler/src/context.rs @@ -26,6 +26,21 @@ pub struct Context { impl Context { /// Declare an anonymous trait as an aggregate of other types. pub fn anonymous_trait(&mut self, requirements: Vec, location: Location) -> TyIdx { + // If there's only one type in the requirement we can just return a reference to that instead. + if requirements.len() == 1 { + return requirements[0].clone(); + } + + // If there's already an anonymous trait with the same dependencies then return a reference to that instead. + for (i, ty) in self.types.iter().enumerate() { + if ty.is_trait() + && ty.is_anonymous() + && ty.get_dependencies() == Some(requirements.iter().collect()) + { + return i.into(); + } + } + let idx = self.types.len(); let ty = Ty::new_trait(None, location, requirements); self.types.push(ty); @@ -114,7 +129,7 @@ impl Context { } /// Retrieve a specific block by it's index. - pub fn get_block(&self, idx: BlockIdx) -> Option<&Block> { + pub fn get_block(&self, idx: &BlockIdx) -> Option<&Block> { self.blocks.get(usize::from(idx)) } diff --git a/huia-compiler/src/error.rs b/huia-compiler/src/error.rs index 7c5ddd7..d07109d 100644 --- a/huia-compiler/src/error.rs +++ b/huia-compiler/src/error.rs @@ -18,6 +18,18 @@ impl CompileError { kind, } } + + pub fn message(&self) -> &str { + &self.message + } + + pub fn location(&self) -> &Location { + &self.location + } + + pub fn kind(&self) -> &ErrorKind { + &self.kind + } } impl fmt::Display for CompileError { diff --git a/huia-compiler/src/function.rs b/huia-compiler/src/function.rs index 4585bcc..4391f40 100644 --- a/huia-compiler/src/function.rs +++ b/huia-compiler/src/function.rs @@ -26,6 +26,14 @@ impl Function { self.clauses.push(Clause::new(arguments, block)); idx.into() } + + pub fn clauses(&self) -> Vec<&Clause> { + self.clauses.iter().collect() + } + + pub fn return_type(&self) -> &TyIdx { + &self.return_type + } } #[derive(Debug)] @@ -42,6 +50,14 @@ impl Clause { }); Clause { arguments, body } } + + pub fn arguments(&self) -> Vec<(&StringIdx, &TyIdx)> { + self.arguments.iter().collect() + } + + pub fn body(&self) -> &BlockIdx { + &self.body + } } #[derive(Debug, Clone, PartialEq)] diff --git a/huia-compiler/src/ir/desugar_infix.rs b/huia-compiler/src/improvements/desugar_infix.rs similarity index 92% rename from huia-compiler/src/ir/desugar_infix.rs rename to huia-compiler/src/improvements/desugar_infix.rs index 53a2f97..9b3457d 100644 --- a/huia-compiler/src/ir/desugar_infix.rs +++ b/huia-compiler/src/improvements/desugar_infix.rs @@ -28,7 +28,11 @@ pub fn pass(ir: &mut IR, context: &mut Context) { BinOp::ShiftRight => "shift_right", }; let method_name = context.constant_string(method_name); - ir.kind = IRKind::MethodCall(Box::new(lhs.clone()), method_name, vec![rhs.clone()]); + ir.set_kind(IRKind::MethodCall( + Box::new(lhs.clone()), + method_name, + vec![rhs.clone()], + )); } } diff --git a/huia-compiler/src/ir/desugar_unary.rs b/huia-compiler/src/improvements/desugar_unary.rs similarity index 88% rename from huia-compiler/src/ir/desugar_unary.rs rename to huia-compiler/src/improvements/desugar_unary.rs index 98547c0..7c152a6 100644 --- a/huia-compiler/src/ir/desugar_unary.rs +++ b/huia-compiler/src/improvements/desugar_unary.rs @@ -12,7 +12,11 @@ pub fn pass(ir: &mut IR, context: &mut Context) { UnOp::Plus => "unary_plus", }; let method_name = context.constant_string(method_name); - ir.kind = IRKind::MethodCall(Box::new(rhs.clone()), method_name, Vec::default()); + ir.set_kind(IRKind::MethodCall( + Box::new(rhs.clone()), + method_name, + Vec::default(), + )); } } diff --git a/huia-compiler/src/ir/constant_folding.rs b/huia-compiler/src/improvements/infix_folding.rs similarity index 59% rename from huia-compiler/src/ir/constant_folding.rs rename to huia-compiler/src/improvements/infix_folding.rs index 83c3d01..51f236f 100644 --- a/huia-compiler/src/ir/constant_folding.rs +++ b/huia-compiler/src/improvements/infix_folding.rs @@ -1,7 +1,6 @@ use crate::context::Context; use crate::ir::{IRKind, Val, IR}; use huia_parser::ast::binary::Operator as BinOp; -use huia_parser::ast::unary::Operator as UnOp; use std::f64; /// Perform constant folding on the provided node, or not. @@ -22,7 +21,7 @@ pub fn pass(ir: &mut IR, context: &mut Context) { if let Some(value) = value { ir.set_kind(IRKind::Constant(Val::Integer(value))); let idx = context.constant_string("Huia.Native.Integer"); - ir.set_result_type(context.reference_type(&idx, ir.location.clone())); + ir.set_result_type(context.reference_type(&idx, ir.get_location().clone())); } } else if lhs.is_float() && rhs.is_float() { let lhs = lhs.float().unwrap(); @@ -31,47 +30,7 @@ pub fn pass(ir: &mut IR, context: &mut Context) { if let Some(value) = value { ir.set_kind(IRKind::Constant(Val::Float(value))); let idx = context.constant_string("Huia.Native.Float"); - ir.set_result_type(context.reference_type(&idx, ir.location.clone())); - } - } - } else if ir.is_unary() { - let (op, rhs) = ir.get_unary().unwrap(); - if !rhs.is_constant() { - return; - } - let rhs = rhs.get_value().unwrap(); - - match op { - UnOp::LogicalNot => { - if rhs.is_boolean() { - // if the RHS is a boolean constant then fold it. - let value = rhs.boolean().unwrap(); - ir.set_kind(IRKind::Constant(Val::Boolean(!value))); - } else { - // otherwise just return false for all other constant values. - ir.set_kind(IRKind::Constant(Val::Boolean(false))); - } - let tyname = context.constant_string("Huia.Native.Boolean"); - let ty = context.reference_type(&tyname, ir.location.clone()); - ir.set_result_type(ty) - } - UnOp::Minus => { - if rhs.is_integer() { - let value = rhs.integer().unwrap(); - ir.set_kind(IRKind::Constant(Val::Integer(-value))); - } else if rhs.is_float() { - let value = rhs.float().unwrap(); - ir.set_kind(IRKind::Constant(Val::Float(-value))); - } - } - UnOp::Plus => { - if rhs.is_integer() { - let value = rhs.integer().unwrap(); - ir.set_kind(IRKind::Constant(Val::Integer(value))); - } else if rhs.is_float() { - let value = rhs.float().unwrap(); - ir.set_kind(IRKind::Constant(Val::Float(value))); - } + ir.set_result_type(context.reference_type(&idx, ir.get_location().clone())); } } } @@ -138,21 +97,4 @@ mod test { assert!(ir.is_constant()); assert!(ir.get_value().unwrap().float().unwrap() - 1.0 < f64::EPSILON); } - - #[test] - fn integer_unary_folding() { - let term = Term::input("!3").unwrap()[0].clone(); - let mut context = Context::test(); - let mut builder = Builder::default(); - - builder.build(term, &mut context); - let mut ir = builder.pop_ir().unwrap(); - ir.improve(&mut context, pass); - - assert!(ir.is_constant()); - assert!(!ir.get_value().unwrap().boolean().unwrap()); - - let ty = context.get_type(&ir.result_type()).unwrap(); - assert!(ty.is_native_boolean()); - } } diff --git a/huia-compiler/src/improvements/mod.rs b/huia-compiler/src/improvements/mod.rs new file mode 100644 index 0000000..7eb7cb2 --- /dev/null +++ b/huia-compiler/src/improvements/mod.rs @@ -0,0 +1,4 @@ +pub mod desugar_infix; +pub mod desugar_unary; +pub mod infix_folding; +pub mod unary_folding; diff --git a/huia-compiler/src/improvements/unary_folding.rs b/huia-compiler/src/improvements/unary_folding.rs new file mode 100644 index 0000000..60249cd --- /dev/null +++ b/huia-compiler/src/improvements/unary_folding.rs @@ -0,0 +1,72 @@ +use crate::context::Context; +use crate::ir::{IRKind, Val, IR}; +use huia_parser::ast::unary::Operator as UnOp; + +/// Perform constant folding on the provided node, or not. +pub fn pass(ir: &mut IR, context: &mut Context) { + if ir.is_unary() { + let (op, rhs) = ir.get_unary().unwrap(); + if !rhs.is_constant() { + return; + } + let rhs = rhs.get_value().unwrap(); + + match op { + UnOp::LogicalNot => { + if rhs.is_boolean() { + // if the RHS is a boolean constant then fold it. + let value = rhs.boolean().unwrap(); + ir.set_kind(IRKind::Constant(Val::Boolean(!value))); + } else { + // otherwise just return false for all other constant values. + ir.set_kind(IRKind::Constant(Val::Boolean(false))); + } + let tyname = context.constant_string("Huia.Native.Boolean"); + let ty = context.reference_type(&tyname, ir.get_location().clone()); + ir.set_result_type(ty) + } + UnOp::Minus => { + if rhs.is_integer() { + let value = rhs.integer().unwrap(); + ir.set_kind(IRKind::Constant(Val::Integer(-value))); + } else if rhs.is_float() { + let value = rhs.float().unwrap(); + ir.set_kind(IRKind::Constant(Val::Float(-value))); + } + } + UnOp::Plus => { + if rhs.is_integer() { + let value = rhs.integer().unwrap(); + ir.set_kind(IRKind::Constant(Val::Integer(value))); + } else if rhs.is_float() { + let value = rhs.float().unwrap(); + ir.set_kind(IRKind::Constant(Val::Float(value))); + } + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::ir::builder::Builder; + use huia_parser::ast::Term; + + #[test] + fn integer_unary_folding() { + let term = Term::input("!3").unwrap()[0].clone(); + let mut context = Context::test(); + let mut builder = Builder::default(); + + builder.build(term, &mut context); + let mut ir = builder.pop_ir().unwrap(); + ir.improve(&mut context, pass); + + assert!(ir.is_constant()); + assert!(!ir.get_value().unwrap().boolean().unwrap()); + + let ty = context.get_type(&ir.result_type()).unwrap(); + assert!(ty.is_native_boolean()); + } +} diff --git a/huia-compiler/src/ir/builder.rs b/huia-compiler/src/ir/builder.rs index 22166c2..4cb5b12 100644 --- a/huia-compiler/src/ir/builder.rs +++ b/huia-compiler/src/ir/builder.rs @@ -570,6 +570,7 @@ impl Builder { let ty = context.declare_trait(&ty_idx, types, location); self.push_ty(ty.clone()); + self.push_block(); for node in body { self.build(node.clone(), &mut context); @@ -827,7 +828,6 @@ mod test { let ir = builder.pop_ir().unwrap(); assert!(ir.is_jump_if_true()); let block = builder.pop_block().unwrap(); - println!("Block: {:?}", block); assert!(block.is_empty()); } @@ -849,7 +849,7 @@ mod test { let mut context = Context::test(); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); - assert!(ir.is_constuctor()); + assert!(ir.is_constructor()); assert!(context.find_type("Delorean").is_some()); assert!(context.find_type("Huia.Native.Integer").is_some()); } diff --git a/huia-compiler/src/ir/mod.rs b/huia-compiler/src/ir/mod.rs index aada17f..4a88527 100644 --- a/huia-compiler/src/ir/mod.rs +++ b/huia-compiler/src/ir/mod.rs @@ -1,7 +1,4 @@ pub mod builder; -pub mod constant_folding; -pub mod desugar_infix; -pub mod desugar_unary; use crate::block::BlockIdx; use crate::context::Context; @@ -28,6 +25,13 @@ impl IR { } } + pub fn get_call(&self) -> Option<(&IR, &Vec)> { + match self.kind { + IRKind::Call(ref ir, ref args) => Some((ir, args)), + _ => None, + } + } + pub fn get_infix(&self) -> Option<(&BinOp, &IR, &IR)> { match self.kind { IRKind::Infix(ref op, ref lhs, ref rhs) => Some((op, lhs, rhs)), @@ -35,6 +39,14 @@ impl IR { } } + pub fn get_kind(&self) -> &IRKind { + &self.kind + } + + pub fn get_location(&self) -> &Location { + &self.location + } + pub fn get_unary(&self) -> Option<(&UnOp, &IR)> { match self.kind { IRKind::Unary(ref op, ref rhs) => Some((op, rhs)), @@ -142,7 +154,7 @@ impl IR { } } - pub fn is_constuctor(&self) -> bool { + pub fn is_constructor(&self) -> bool { match self.kind { IRKind::Constructor(..) => true, _ => false, @@ -427,13 +439,13 @@ pub enum IRKind { /// A constant value. #[derive(Debug, PartialEq, Clone)] pub enum Val { + Array(Vec), Atom(StringIdx), Boolean(bool), Float(f64), Integer(i64), - String(StringIdx), - Array(Vec), Map(Vec<(IR, IR)>), + String(StringIdx), } impl Val { @@ -444,6 +456,13 @@ impl Val { } } + pub fn atom(&self) -> Option<&StringIdx> { + match self { + Val::Atom(ref atom) => Some(atom), + _ => None, + } + } + pub fn boolean(&self) -> Option { match self { Val::Boolean(ref value) => Some(*value), @@ -465,6 +484,13 @@ impl Val { } } + pub fn is_array(&self) -> bool { + match self { + Val::Array(..) => true, + _ => false, + } + } + pub fn is_atom(&self) -> bool { match self { Val::Atom(..) => true, @@ -493,18 +519,6 @@ impl Val { } } - pub fn is_string(&self) -> bool { - match self { - Val::String(..) => true, - _ => false, - } - } - pub fn is_array(&self) -> bool { - match self { - Val::Array(..) => true, - _ => false, - } - } pub fn is_map(&self) -> bool { match self { Val::Map(..) => true, @@ -512,6 +526,13 @@ impl Val { } } + pub fn is_string(&self) -> bool { + match self { + Val::String(..) => true, + _ => false, + } + } + pub fn map(&self) -> Option> { match self { Val::Map(ref elements) => Some(elements.iter().collect()), diff --git a/huia-compiler/src/lib.rs b/huia-compiler/src/lib.rs index 35d76cb..a247902 100644 --- a/huia-compiler/src/lib.rs +++ b/huia-compiler/src/lib.rs @@ -3,6 +3,7 @@ mod context; mod env; mod error; mod function; +mod improvements; mod ir; mod location; mod method; @@ -24,9 +25,10 @@ pub fn compile_file(path: &str) -> Context { } context.improve_ir(|mut ir, mut context| { - ir::constant_folding::pass(&mut ir, &mut context); - ir::desugar_infix::pass(&mut ir, &mut context); - ir::desugar_unary::pass(&mut ir, &mut context); + improvements::infix_folding::pass(&mut ir, &mut context); + improvements::unary_folding::pass(&mut ir, &mut context); + improvements::desugar_infix::pass(&mut ir, &mut context); + improvements::desugar_unary::pass(&mut ir, &mut context); }); context diff --git a/huia-compiler/src/ty.rs b/huia-compiler/src/ty.rs index f1f0f2f..e313886 100644 --- a/huia-compiler/src/ty.rs +++ b/huia-compiler/src/ty.rs @@ -17,6 +17,13 @@ pub struct Ty { } impl Ty { + pub fn get_dependencies(&self) -> Option> { + match self.inner { + TyInner::Trait { ref dependencies } => Some(dependencies.iter().collect()), + _ => None, + } + } + pub fn get_prop_type(&self, name: &StringIdx) -> Option<&TyIdx> { match self.inner { TyInner::Type { ref properties } => properties.get(name), @@ -24,6 +31,20 @@ impl Ty { } } + pub fn get_properties(&self) -> Option> { + match self.inner { + TyInner::Type { ref properties } => Some(properties.iter().collect()), + _ => None, + } + } + + pub fn is_anonymous(&self) -> bool { + match self.name { + None => true, + _ => false, + } + } + pub fn is_impl(&self) -> bool { match self.kind { TyKind::Impl => true, @@ -31,6 +52,20 @@ impl Ty { } } + pub fn is_native_array(&self) -> bool { + match self.inner { + TyInner::NativeArray => true, + _ => false, + } + } + + pub fn is_native_atom(&self) -> bool { + match self.inner { + TyInner::NativeAtom => true, + _ => false, + } + } + pub fn is_native_boolean(&self) -> bool { match self.inner { TyInner::NativeBoolean => true, @@ -38,6 +73,34 @@ impl Ty { } } + pub fn is_native_float(&self) -> bool { + match self.inner { + TyInner::NativeFloat => true, + _ => false, + } + } + + pub fn is_native_integer(&self) -> bool { + match self.inner { + TyInner::NativeInteger => true, + _ => false, + } + } + + pub fn is_native_map(&self) -> bool { + match self.inner { + TyInner::NativeMap => true, + _ => false, + } + } + + pub fn is_native_string(&self) -> bool { + match self.inner { + TyInner::NativeString => true, + _ => false, + } + } + pub fn is_unresolved(&self) -> bool { match self.kind { TyKind::Unresolved => true, diff --git a/huia-parser/src/ast/function.rs b/huia-parser/src/ast/function.rs index 9ea0338..cc47fa7 100644 --- a/huia-parser/src/ast/function.rs +++ b/huia-parser/src/ast/function.rs @@ -67,14 +67,12 @@ impl<'a> From> for Clause { fn from(pair: Pair<'a, Rule>) -> Self { match pair.as_rule() { Rule::function_clause => { - println!("clause = {:#?}", pair); let mut inner = pair.clone().into_inner(); let arguments = inner .next() .unwrap() .into_inner() .map(|p| { - println!("p = {:?}", p); let mut inner = p.into_inner(); let keyword = Identifier::from(inner.next().unwrap()); let typespec = TypeSpec::from(inner.next().unwrap()); diff --git a/huia-parser/src/ast/term.rs b/huia-parser/src/ast/term.rs index a1b2491..82a97bc 100644 --- a/huia-parser/src/ast/term.rs +++ b/huia-parser/src/ast/term.rs @@ -1119,8 +1119,6 @@ mod test { fn test_if_else() { let terms = Term::input(" if true do 123 else 456 end ").unwrap(); let (_test, positive, negative) = terms[0].if_expr().unwrap(); - println!("positive: {:?}", positive); - println!("negative: {:?}", negative); assert_eq!(positive.len(), 1); assert_eq!(negative.len(), 1); }