roc/tests/test_gen.rs
2019-11-09 03:31:42 -05:00

171 lines
4.4 KiB
Rust

#[macro_use]
extern crate pretty_assertions;
#[macro_use]
extern crate indoc;
extern crate bumpalo;
extern crate inkwell;
extern crate roc;
mod helpers;
#[cfg(test)]
mod test_gen {
use helpers::can_expr;
use inkwell::context::Context;
use inkwell::execution_engine::ExecutionEngine;
use inkwell::passes::PassManager;
use roc::gen::{content_to_basic_type, Function, ModuleBuilder, Prototype};
use roc::infer::infer_expr;
// HELPERS
fn gen_engine(src: &str) -> ExecutionEngine {
use inkwell::OptimizationLevel;
// use self::inkwell::support::add_symbol;
let (expr, output, _problems, procedures, mut subs, variable) = can_expr(src);
let content = infer_expr(
&mut subs,
procedures.clone(), /* TODO shouldn't have to clone this... */
&output.constraint,
variable,
);
let context = Context::create();
let module = context.create_module("repl");
let builder = context.create_builder();
// Create FPM
let fpm = PassManager::create(&module);
fpm.add_instruction_combining_pass();
fpm.add_reassociate_pass();
fpm.add_gvn_pass();
fpm.add_cfg_simplification_pass();
fpm.add_basic_alias_analysis_pass();
fpm.add_promote_memory_to_register_pass();
fpm.add_instruction_combining_pass();
fpm.add_reassociate_pass();
fpm.initialize();
// make module
let module = context.create_module("tmp");
let name = "main".to_string();
let prototype = Prototype {
name,
args: Vec::new(),
ret: content_to_basic_type(content, &mut subs, &context).unwrap_or_else(|reason| {
panic!(
"content_to_basic_type failed during test because: {}",
reason
)
}),
};
let function = Function {
prototype,
body: Some(expr),
is_anon: false,
};
// make main(), a function which returns an f64
ModuleBuilder::build(
&context,
&builder,
&fpm,
&procedures,
&subs,
&module,
&function,
)
.expect("Error compiling main");
// make execution engine
module
.create_jit_execution_engine(OptimizationLevel::None)
.unwrap()
}
#[test]
fn gen_float() {
let ee = gen_engine("12345.0");
let maybe_fn = unsafe { ee.get_function::<unsafe extern "C" fn() -> f64>("main") };
let compiled_fn = match maybe_fn {
Ok(f) => f,
Err(err) => {
panic!("!> Error during execution: {:?}", err);
}
};
unsafe {
assert_eq!(12345.0, compiled_fn.call());
}
}
#[test]
fn gen_int() {
let ee = gen_engine(indoc!(r#"321"#));
let maybe_fn = unsafe { ee.get_function::<unsafe extern "C" fn() -> i64>("main") };
let compiled_fn = match maybe_fn {
Ok(f) => f,
Err(err) => {
panic!("!> Error during execution: {:?}", err);
}
};
unsafe {
assert_eq!(321, compiled_fn.call());
}
}
#[test]
fn gen_case_take_first_branch() {
let ee = gen_engine(indoc!(
r#"
case 1 when
1 -> 12
2 -> 34
"#
));
let maybe_fn = unsafe { ee.get_function::<unsafe extern "C" fn() -> i64>("main") };
let compiled_fn = match maybe_fn {
Ok(f) => f,
Err(err) => {
panic!("!> Error during execution: {:?}", err);
}
};
unsafe {
assert_eq!(12, compiled_fn.call());
}
}
#[test]
fn gen_case_take_second_branch() {
let ee = gen_engine(indoc!(
r#"
case 1 when
2 -> 33
1 -> 48
"#
));
let maybe_fn = unsafe { ee.get_function::<unsafe extern "C" fn() -> i64>("main") };
let compiled_fn = match maybe_fn {
Ok(f) => f,
Err(err) => {
panic!("!> Error during execution: {:?}", err);
}
};
unsafe {
assert_eq!(48, compiled_fn.call());
}
}
}