Code gardening.
This commit is contained in:
parent
b52e236c67
commit
811776d9e7
15 changed files with 245 additions and 90 deletions
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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<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 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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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()],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
4
huia-compiler/src/improvements/mod.rs
Normal file
4
huia-compiler/src/improvements/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod desugar_infix;
|
||||
pub mod desugar_unary;
|
||||
pub mod infix_folding;
|
||||
pub mod unary_folding;
|
72
huia-compiler/src/improvements/unary_folding.rs
Normal file
72
huia-compiler/src/improvements/unary_folding.rs
Normal 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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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<IR>)> {
|
||||
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<IR>),
|
||||
Atom(StringIdx),
|
||||
Boolean(bool),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
String(StringIdx),
|
||||
Array(Vec<IR>),
|
||||
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<bool> {
|
||||
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<Vec<&(IR, IR)>> {
|
||||
match self {
|
||||
Val::Map(ref elements) => Some(elements.iter().collect()),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -17,6 +17,13 @@ pub struct 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> {
|
||||
match self.inner {
|
||||
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 {
|
||||
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,
|
||||
|
|
|
@ -67,14 +67,12 @@ impl<'a> From<Pair<'a, Rule>> 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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Reference in a new issue