Code gardening.

This commit is contained in:
James Harton 2019-03-23 09:36:45 +13:00
parent b52e236c67
commit 811776d9e7
15 changed files with 245 additions and 90 deletions

View file

@ -33,6 +33,10 @@ impl Block {
self.ir self.ir
} }
pub fn ir_ref(&self) -> Vec<&IR> {
self.ir.iter().collect()
}
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.ir.is_empty() self.ir.is_empty()
} }

View file

@ -26,6 +26,21 @@ pub struct Context {
impl Context { impl Context {
/// Declare an anonymous trait as an aggregate of other types. /// Declare an anonymous trait as an aggregate of other types.
pub fn anonymous_trait(&mut self, requirements: Vec<TyIdx>, location: Location) -> TyIdx { pub fn anonymous_trait(&mut self, requirements: Vec<TyIdx>, 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 idx = self.types.len();
let ty = Ty::new_trait(None, location, requirements); let ty = Ty::new_trait(None, location, requirements);
self.types.push(ty); self.types.push(ty);
@ -114,7 +129,7 @@ impl Context {
} }
/// Retrieve a specific block by it's index. /// 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)) self.blocks.get(usize::from(idx))
} }

View file

@ -18,6 +18,18 @@ impl CompileError {
kind, 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 { impl fmt::Display for CompileError {

View file

@ -26,6 +26,14 @@ impl Function {
self.clauses.push(Clause::new(arguments, block)); self.clauses.push(Clause::new(arguments, block));
idx.into() idx.into()
} }
pub fn clauses(&self) -> Vec<&Clause> {
self.clauses.iter().collect()
}
pub fn return_type(&self) -> &TyIdx {
&self.return_type
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -42,6 +50,14 @@ impl Clause {
}); });
Clause { arguments, body } 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)] #[derive(Debug, Clone, PartialEq)]

View file

@ -28,7 +28,11 @@ pub fn pass(ir: &mut IR, context: &mut Context) {
BinOp::ShiftRight => "shift_right", BinOp::ShiftRight => "shift_right",
}; };
let method_name = context.constant_string(method_name); 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()],
));
} }
} }

View file

@ -12,7 +12,11 @@ pub fn pass(ir: &mut IR, context: &mut Context) {
UnOp::Plus => "unary_plus", UnOp::Plus => "unary_plus",
}; };
let method_name = context.constant_string(method_name); 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(),
));
} }
} }

View file

@ -1,7 +1,6 @@
use crate::context::Context; use crate::context::Context;
use crate::ir::{IRKind, Val, IR}; use crate::ir::{IRKind, Val, IR};
use huia_parser::ast::binary::Operator as BinOp; use huia_parser::ast::binary::Operator as BinOp;
use huia_parser::ast::unary::Operator as UnOp;
use std::f64; use std::f64;
/// Perform constant folding on the provided node, or not. /// 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 { if let Some(value) = value {
ir.set_kind(IRKind::Constant(Val::Integer(value))); ir.set_kind(IRKind::Constant(Val::Integer(value)));
let idx = context.constant_string("Huia.Native.Integer"); 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() { } else if lhs.is_float() && rhs.is_float() {
let lhs = lhs.float().unwrap(); let lhs = lhs.float().unwrap();
@ -31,47 +30,7 @@ pub fn pass(ir: &mut IR, context: &mut Context) {
if let Some(value) = value { if let Some(value) = value {
ir.set_kind(IRKind::Constant(Val::Float(value))); ir.set_kind(IRKind::Constant(Val::Float(value)));
let idx = context.constant_string("Huia.Native.Float"); let idx = context.constant_string("Huia.Native.Float");
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 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)));
}
} }
} }
} }
@ -138,21 +97,4 @@ mod test {
assert!(ir.is_constant()); assert!(ir.is_constant());
assert!(ir.get_value().unwrap().float().unwrap() - 1.0 < f64::EPSILON); 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());
}
} }

View file

@ -0,0 +1,4 @@
pub mod desugar_infix;
pub mod desugar_unary;
pub mod infix_folding;
pub mod unary_folding;

View file

@ -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());
}
}

View file

@ -570,6 +570,7 @@ impl Builder {
let ty = context.declare_trait(&ty_idx, types, location); let ty = context.declare_trait(&ty_idx, types, location);
self.push_ty(ty.clone()); self.push_ty(ty.clone());
self.push_block();
for node in body { for node in body {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
@ -827,7 +828,6 @@ mod test {
let ir = builder.pop_ir().unwrap(); let ir = builder.pop_ir().unwrap();
assert!(ir.is_jump_if_true()); assert!(ir.is_jump_if_true());
let block = builder.pop_block().unwrap(); let block = builder.pop_block().unwrap();
println!("Block: {:?}", block);
assert!(block.is_empty()); assert!(block.is_empty());
} }
@ -849,7 +849,7 @@ mod test {
let mut context = Context::test(); let mut context = Context::test();
builder.build(term, &mut context); builder.build(term, &mut context);
let ir = builder.pop_ir().unwrap(); 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("Delorean").is_some());
assert!(context.find_type("Huia.Native.Integer").is_some()); assert!(context.find_type("Huia.Native.Integer").is_some());
} }

View file

@ -1,7 +1,4 @@
pub mod builder; pub mod builder;
pub mod constant_folding;
pub mod desugar_infix;
pub mod desugar_unary;
use crate::block::BlockIdx; use crate::block::BlockIdx;
use crate::context::Context; use crate::context::Context;
@ -28,6 +25,13 @@ impl IR {
} }
} }
pub fn get_call(&self) -> Option<(&IR, &Vec<IR>)> {
match self.kind {
IRKind::Call(ref ir, ref args) => Some((ir, args)),
_ => None,
}
}
pub fn get_infix(&self) -> Option<(&BinOp, &IR, &IR)> { pub fn get_infix(&self) -> Option<(&BinOp, &IR, &IR)> {
match self.kind { match self.kind {
IRKind::Infix(ref op, ref lhs, ref rhs) => Some((op, lhs, rhs)), 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)> { pub fn get_unary(&self) -> Option<(&UnOp, &IR)> {
match self.kind { match self.kind {
IRKind::Unary(ref op, ref rhs) => Some((op, rhs)), 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 { match self.kind {
IRKind::Constructor(..) => true, IRKind::Constructor(..) => true,
_ => false, _ => false,
@ -427,13 +439,13 @@ pub enum IRKind {
/// A constant value. /// A constant value.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Val { pub enum Val {
Array(Vec<IR>),
Atom(StringIdx), Atom(StringIdx),
Boolean(bool), Boolean(bool),
Float(f64), Float(f64),
Integer(i64), Integer(i64),
String(StringIdx),
Array(Vec<IR>),
Map(Vec<(IR, IR)>), Map(Vec<(IR, IR)>),
String(StringIdx),
} }
impl Val { 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<bool> { pub fn boolean(&self) -> Option<bool> {
match self { match self {
Val::Boolean(ref value) => Some(*value), 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 { pub fn is_atom(&self) -> bool {
match self { match self {
Val::Atom(..) => true, 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 { pub fn is_map(&self) -> bool {
match self { match self {
Val::Map(..) => true, 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<Vec<&(IR, IR)>> { pub fn map(&self) -> Option<Vec<&(IR, IR)>> {
match self { match self {
Val::Map(ref elements) => Some(elements.iter().collect()), Val::Map(ref elements) => Some(elements.iter().collect()),

View file

@ -3,6 +3,7 @@ mod context;
mod env; mod env;
mod error; mod error;
mod function; mod function;
mod improvements;
mod ir; mod ir;
mod location; mod location;
mod method; mod method;
@ -24,9 +25,10 @@ pub fn compile_file(path: &str) -> Context {
} }
context.improve_ir(|mut ir, mut context| { context.improve_ir(|mut ir, mut context| {
ir::constant_folding::pass(&mut ir, &mut context); improvements::infix_folding::pass(&mut ir, &mut context);
ir::desugar_infix::pass(&mut ir, &mut context); improvements::unary_folding::pass(&mut ir, &mut context);
ir::desugar_unary::pass(&mut ir, &mut context); improvements::desugar_infix::pass(&mut ir, &mut context);
improvements::desugar_unary::pass(&mut ir, &mut context);
}); });
context context

View file

@ -17,6 +17,13 @@ pub struct Ty {
} }
impl Ty { impl Ty {
pub fn get_dependencies(&self) -> Option<Vec<&TyIdx>> {
match self.inner {
TyInner::Trait { ref dependencies } => Some(dependencies.iter().collect()),
_ => None,
}
}
pub fn get_prop_type(&self, name: &StringIdx) -> Option<&TyIdx> { pub fn get_prop_type(&self, name: &StringIdx) -> Option<&TyIdx> {
match self.inner { match self.inner {
TyInner::Type { ref properties } => properties.get(name), TyInner::Type { ref properties } => properties.get(name),
@ -24,6 +31,20 @@ impl Ty {
} }
} }
pub fn get_properties(&self) -> Option<Vec<(&StringIdx, &TyIdx)>> {
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 { pub fn is_impl(&self) -> bool {
match self.kind { match self.kind {
TyKind::Impl => true, 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 { pub fn is_native_boolean(&self) -> bool {
match self.inner { match self.inner {
TyInner::NativeBoolean => true, 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 { pub fn is_unresolved(&self) -> bool {
match self.kind { match self.kind {
TyKind::Unresolved => true, TyKind::Unresolved => true,

View file

@ -67,14 +67,12 @@ impl<'a> From<Pair<'a, Rule>> for Clause {
fn from(pair: Pair<'a, Rule>) -> Self { fn from(pair: Pair<'a, Rule>) -> Self {
match pair.as_rule() { match pair.as_rule() {
Rule::function_clause => { Rule::function_clause => {
println!("clause = {:#?}", pair);
let mut inner = pair.clone().into_inner(); let mut inner = pair.clone().into_inner();
let arguments = inner let arguments = inner
.next() .next()
.unwrap() .unwrap()
.into_inner() .into_inner()
.map(|p| { .map(|p| {
println!("p = {:?}", p);
let mut inner = p.into_inner(); let mut inner = p.into_inner();
let keyword = Identifier::from(inner.next().unwrap()); let keyword = Identifier::from(inner.next().unwrap());
let typespec = TypeSpec::from(inner.next().unwrap()); let typespec = TypeSpec::from(inner.next().unwrap());

View file

@ -1119,8 +1119,6 @@ mod test {
fn test_if_else() { fn test_if_else() {
let terms = Term::input(" if true do 123 else 456 end ").unwrap(); let terms = Term::input(" if true do 123 else 456 end ").unwrap();
let (_test, positive, negative) = terms[0].if_expr().unwrap(); let (_test, positive, negative) = terms[0].if_expr().unwrap();
println!("positive: {:?}", positive);
println!("negative: {:?}", negative);
assert_eq!(positive.len(), 1); assert_eq!(positive.len(), 1);
assert_eq!(negative.len(), 1); assert_eq!(negative.len(), 1);
} }