Skip to content
This repository has been archived by the owner on Sep 16, 2021. It is now read-only.

Conditional statement #148

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions compiler/src/codegen/functions/if_function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use super::{Function, FunctionContext, VarArgs};
use codegen::values::{AnyValue, NumValue};
use inkwell::values::PointerValue;
use inkwell::{FloatPredicate};
use mir::block;

pub struct IfFunction {}
impl Function for IfFunction {
fn function_type() -> block::Function { block::Function::If }

fn gen_call(
func: &mut FunctionContext,
args: &[PointerValue],
_varargs: Option<VarArgs>,
result: PointerValue,
) {

let condition_num = NumValue::new(args[0]);
let condition_vec = condition_num.get_vec(func.ctx.b);
let left_index = func.ctx.context.i32_type().const_int(0, false);
let condition_left = func.ctx
.b
.build_extract_element(&condition_vec, &left_index, "condition.left")
.into_float_value();
let condition_bool = func.ctx.b.build_float_compare(
FloatPredicate::ONE,
condition_left,
func.ctx.context.f32_type().const_float(0.0),
"conditionbool",
);

let then_any = AnyValue::new(args[1]);
let alternative_any = AnyValue::new(args[2]);
let left_index = func.ctx.context.i32_type().const_int(0, false);
let evaluated = func.ctx.b.build_select(condition_bool,
then_any.get_value_ptr(),
alternative_any.get_value_ptr(),
"evaluated");
let evaluated_ptr = evaluated.as_pointer_value();
let evaluated_any = AnyValue::new(*evaluated_ptr);
let result_any = AnyValue::new(result);

evaluated_any.copy_to(func.ctx.b, func.ctx.module, &result_any);
}
}
5 changes: 4 additions & 1 deletion compiler/src/codegen/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod channel_function;
mod defer_function;
mod delay_function;
mod function_context;
mod if_function;
mod indexed_function;
mod note_function;
mod num_function;
Expand Down Expand Up @@ -33,6 +34,7 @@ pub use self::biquad_filter_function::*;
pub use self::channel_function::*;
pub use self::defer_function::*;
pub use self::delay_function::*;
pub use self::if_function::*;
pub use self::indexed_function::*;
pub use self::note_function::*;
pub use self::num_function::*;
Expand Down Expand Up @@ -163,7 +165,8 @@ map_functions! {
Note => NoteFunction,
Voices => VoicesFunction,
Channel => ChannelFunction,
Indexed => IndexedFunction
Indexed => IndexedFunction,
If => IfFunction
}

fn get_lifecycle_func(
Expand Down
43 changes: 43 additions & 0 deletions compiler/src/codegen/values/any_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use codegen::util;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::module::Module;
use inkwell::types::StructType;
use inkwell::values::{IntValue, PointerValue};

#[derive(Debug, Clone)]
pub struct AnyValue {
pub val: PointerValue,
}

impl AnyValue {
pub fn get_type(context: &Context) -> StructType {
// TODO Just returning Number structure for now. Can this infer what its correct type should be from context?
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what should be returned here, think some restructuring might be necessary in order to infer the actual type the AnyValue is representing and return space for that?

// Maybe return space to hold largest possible type?
context.struct_type(
&[&context.f32_type().vec_type(2), &context.i8_type()],
false,
)
}

pub fn new(val: PointerValue) -> Self {
AnyValue { val }
}

pub fn copy_to(&self, builder: &mut Builder, module: &Module, other: &AnyValue) {
util::copy_ptr(builder, module, self.val, other.val)
}

pub fn get_value_ptr(&self) -> PointerValue {
self.val
}

pub fn get_form_ptr(&self, builder: &mut Builder) -> PointerValue {
unsafe { builder.build_struct_gep(&self.val, 1, "any.form.ptr") }
}

pub fn get_form(&self, builder: &mut Builder) -> IntValue {
let vec = self.get_form_ptr(builder);
builder.build_load(&vec, "any.form").into_int_value()
}
}
5 changes: 4 additions & 1 deletion compiler/src/codegen/values/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ mod midi_event_value;
mod midi_value;
mod num_value;
mod tuple_value;
mod any_value;

pub use self::array_value::{ArrayValue, ARRAY_CAPACITY};
pub use self::midi_event_value::MidiEventValue;
pub use self::midi_value::MidiValue;
pub use self::num_value::NumValue;
pub use self::tuple_value::TupleValue;
pub use self::any_value::AnyValue;

use inkwell::context::Context;
use inkwell::types::{BasicType, StructType};
Expand All @@ -27,7 +29,8 @@ pub fn remap_type(context: &Context, mir_type: &VarType) -> StructType {
}
VarType::Array(inner_type) => {
ArrayValue::get_type(context, remap_type(context, &inner_type))
}
},
VarType::Any => AnyValue::get_type(context)
}
}

Expand Down
5 changes: 3 additions & 2 deletions compiler/src/mir/block/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ macro_rules! define_functions {
}
}

pub const FUNCTION_TABLE: [&str; 53] = [$($str_name, )*];
pub const FUNCTION_TABLE: [&str; 54] = [$($str_name, )*];
);
}

Expand Down Expand Up @@ -108,7 +108,8 @@ define_functions! {
Note = "note" func![(Midi) -> Tuple(vec![Num, Num, Num, Num])],
Voices = "voices" func![(Midi, VarType::new_array(Num)) -> VarType::new_array(Midi)],
Channel = "channel" func![(Midi, Num) -> Midi],
Indexed = "indexed" func![(Num) -> VarType::new_array(Num)]
Indexed = "indexed" func![(Num) -> VarType::new_array(Num)],
If = "if" func![(Num, Any, Any) -> Any]
}

#[derive(Debug, Clone)]
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/mir/var_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub enum VarType {
Midi,
Tuple(Vec<VarType>),
Array(Box<VarType>),
Any
}

impl VarType {
Expand Down Expand Up @@ -118,6 +119,7 @@ impl fmt::Display for VarType {
write!(f, ")")
}
VarType::Array(ref subtype) => write!(f, "array [{:?}]", subtype),
VarType::Any => write!(f, "any")
}
}
}
6 changes: 5 additions & 1 deletion compiler/src/pass/lower_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use {CompileError, CompileResult};
// lowers an AST into a Block MIR object
pub fn lower_ast(id: mir::BlockId, block: &ast::Block) -> CompileResult<mir::Block> {
let mut lower = AstLower::new(id);
println!("--- Expressions in block before lowering AST:");
for expr in &block.expressions {
println!("{:?}", expr);
lower.lower_expression(expr)?;
}
Ok(lower.block)
Expand Down Expand Up @@ -769,7 +771,9 @@ impl<'a> AstLower<'a> {
expected_type: mir::VarType,
actual_type: mir::VarType,
) -> Option<CompileError> {
if expected_type != actual_type {
if (expected_type != actual_type)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type safety checking is disabled for Any type here. It would be good if there was some way of linking the output type of a function etc to its input types? ie. an if function has midi messages as its arguments, so the output takes the type of a midi message, haven't worked out the best way to do this yet.

&& (expected_type != mir::VarType::Any)
&& (actual_type != mir::VarType::Any) {
Some(CompileError::mismatched_type(
expected_type,
actual_type,
Expand Down