WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 10eead0a authored by Eduardo Souza's avatar Eduardo Souza
Browse files

Adding tests for Typed Kaleidoscope.

parent d72eddb8
......@@ -12,11 +12,12 @@ use std::os::raw::{c_char, c_double, c_uint};
use crate::ir_macros;
use crate::ast::Type::Double;
use llvm_sys::LLVMIntPredicate::LLVMIntULT;
use llvm_sys::LLVMIntPredicate::{LLVMIntULT, LLVMIntNE};
use mu::ast::inst::Instruction_;
use mu::ast::inst::*;
use mu::ast::ir::*;
use mu::ast::op::BinOp::{FAdd, FMul, FSub, Udiv};
use mu::ast::op::CmpOp::FOLT;
use mu::ast::op::BinOp;
use mu::ast::op::CmpOp;
use mu::ast::types::*;
use mu::runtime::*;
use mu::utils::LinkedHashMap;
......@@ -379,14 +380,15 @@ impl Exp for VarExp {
e @ Err(_) => return e,
};
let variable = create_block_alloca(context, llvm_block, name.name.as_str());
LLVMBuildStore(context.builder, init_value, variable);
old_bindings.push(context.named_values.remove(name.name.as_str()));
old_type_bindings.push(context.var_type_map.remove(name.name.as_str()));
context.named_values.insert(name.name.clone(), variable);
context
.var_type_map
.insert(name.name.clone(), var_type.clone());
let variable = create_block_alloca(context, llvm_block, name.name.as_str());
LLVMBuildStore(context.builder, init_value, variable);
old_bindings.push(context.named_values.remove(name.name.as_str()));
context.named_values.insert(name.name.clone(), variable);
}
let body_value: *mut LLVMValue = match self.body_exp.code_gen(module, context) {
......@@ -446,7 +448,9 @@ impl Exp for VarExp {
old_bindings.push(current_block.store.remove(name.name.as_str()));
old_var_type.push(current_block.var_type_map.remove(name.name.as_str()));
current_block.store.insert(name.name.clone(), start_exp);
current_block.var_type_map.insert(name.name.clone(), var_type.clone());
current_block
.var_type_map
.insert(name.name.clone(), var_type.clone());
}
let body_value = match self.body_exp.code_gen_mu(vm, fun_ver) {
......@@ -467,7 +471,9 @@ impl Exp for VarExp {
Some(Some(value)) => {
current_block.store.insert(name.name.clone(), value);
let var_type = old_var_type_iter.next().unwrap().unwrap();
current_block.var_type_map.insert(name.name.clone(), var_type.clone());
current_block
.var_type_map
.insert(name.name.clone(), var_type.clone());
}
_ => (),
}
......@@ -537,12 +543,13 @@ impl Exp for ForExp {
e @ Err(_) => return e,
};
let zero = LLVMConstReal(context.get_llvm_type(&Type::Double), 0.0);
let end_cond = LLVMBuildFCmp(
let zero_bool = LLVMConstInt(context.get_llvm_type(&Type::Bool), 0, true as i32);
let zero_double = LLVMConstReal(context.get_llvm_type(&Type::Double), 0.0);
let end_cond = LLVMBuildICmp(
context.builder,
LLVMRealONE,
LLVMIntNE,
end_exp,
zero,
zero_bool,
"loopcond\0".as_ptr() as *const c_char,
);
......@@ -597,7 +604,7 @@ impl Exp for ForExp {
None => (),
}
Ok(zero)
Ok(zero_double)
}
unsafe fn code_gen_mu(
......@@ -666,7 +673,7 @@ impl Exp for ForExp {
current_block.instr.push(branch_preloop);
preloop_store.insert(phi_node_name.clone(), phi_node.clone());
preloop_var_type_map.insert(phi_node_name.clone(), self.var_type.clone());
preloop_var_type_map.insert(self.var.name.clone(), self.var_type.clone());
args_preloop.push(phi_node.clone_value());
vm.blocks_map.insert(
......@@ -813,7 +820,7 @@ impl Exp for ForExp {
hdr: MuEntityHeader::unnamed(vm.vm.next_id()),
value: Some(vec![var.clone_value()]),
ops: vec![phi_node.clone(), step_exp.clone()],
v: Instruction_::BinOp(FAdd, 0, 1),
v: Instruction_::BinOp(BinOp::FAdd, 0, 1),
});
let current_block = vm.blocks_map.get_mut(&loop_block_id).unwrap();
......@@ -882,10 +889,10 @@ impl Exp for ConditionalExp {
e @ Err(_) => return e,
};
let zero = LLVMConstReal(context.get_llvm_type(&Type::Double), 0.0);
let ifcond = LLVMBuildFCmp(
let zero = LLVMConstInt(context.get_llvm_type(&Type::Bool), 0, true as i32);
let ifcond = LLVMBuildICmp(
context.builder,
LLVMRealONE,
LLVMIntNE,
cond,
zero,
"if_cond\0".as_ptr() as *const c_char,
......@@ -909,6 +916,8 @@ impl Exp for ConditionalExp {
"ifcont\0".as_ptr() as *const c_char,
);
let if_type = self.get_type(&context.var_type_map, &context.fn_type_map);
LLVMBuildCondBr(context.builder, ifcond, then_block, else_block);
LLVMPositionBuilderAtEnd(context.builder, then_block);
......@@ -930,7 +939,7 @@ impl Exp for ConditionalExp {
LLVMPositionBuilderAtEnd(context.builder, merge_block);
let mut phi = LLVMBuildPhi(
context.builder,
context.get_llvm_type(&Type::Double),
context.get_llvm_type(&if_type),
"ifphi\0".as_ptr() as *const c_char,
);
......@@ -956,7 +965,7 @@ impl Exp for ConditionalExp {
fun_ver: &mut MuFunctionVersion,
) -> Result<Arc<TreeNode>, String> {
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
let if_type = self.get_type( &current_block.var_type_map, &vm.fn_type_map);
let if_type = self.get_type(&current_block.var_type_map, &vm.fn_type_map);
// process and create cond
let cond = match self.cond.code_gen_mu(vm, fun_ver) {
......@@ -1261,9 +1270,8 @@ impl Exp for BinaryExp {
e @ Err(_) => return e,
};
let exp_type = self
.rhs
.get_type(&context.var_type_map, &context.fn_type_map);
let exp_type = self.get_type(&context.var_type_map, &context.fn_type_map);
let lhs_type = self.lhs.get_type(&context.var_type_map, &context.fn_type_map);
match self.c() {
'+' => match exp_type {
......@@ -1311,7 +1319,7 @@ impl Exp for BinaryExp {
)),
_ => Err("Unsupported type".parse().unwrap()),
},
'<' => match exp_type {
'<' => match lhs_type {
Type::Double => {
let cmp = LLVMBuildFCmp(
context.builder,
......@@ -1321,12 +1329,7 @@ impl Exp for BinaryExp {
"cmptmp\0".as_ptr() as *const c_char,
);
Ok(LLVMBuildUIToFP(
context.builder,
cmp,
context.get_llvm_type(&Type::Double),
"booltmp\0".as_ptr() as *const c_char,
))
Ok(cmp)
}
Type::Int => {
let cmp = LLVMBuildICmp(
......@@ -1383,15 +1386,37 @@ impl Exp for BinaryExp {
mu_vm.vm.set_name(var.as_entity());
let op = match self.c() {
'+' => FAdd,
'-' => FSub,
'*' => FMul,
'+' => match exp_type {
Type::Double => BinOp::FAdd,
Type::Int => BinOp::Add,
_ => return Err("Unsupported type".parse().unwrap()),
},
'-' => match exp_type {
Type::Double => BinOp::FSub,
Type::Int => BinOp::Sub,
_ => return Err("Unsupported type".parse().unwrap()),
},
'*' => match exp_type {
Type::Double => BinOp::FMul,
Type::Int => BinOp::Mul,
_ => return Err("Unsupported type".parse().unwrap()),
},
'<' => {
let var = function_version.new_ssa(
MuEntityHeader::named(mu_vm.vm.next_id(), Arc::new(String::from("r"))),
mu_vm.get_mu_type(&Type::Bool),
);
let current_block = mu_vm.blocks_map.get_mut(&mu_vm.curr_block).unwrap();
let lhs_type = self
.lhs
.get_type(&current_block.var_type_map, &mu_vm.fn_type_map);
let op = match lhs_type {
Type::Double => CmpOp::FOLT,
Type::Int => CmpOp::SLT,
_ => return Err("Unsupported type".parse().unwrap()),
};
mu_vm.vm.set_name(var.as_entity());
let cmpop = create_cmp_op_instruction(
......@@ -1399,6 +1424,7 @@ impl Exp for BinaryExp {
mu_vm,
&var,
vec![lhs.clone(), rhs.clone()],
op,
);
let current_block = mu_vm.blocks_map.get_mut(&mu_vm.curr_block).unwrap();
......@@ -1510,7 +1536,17 @@ impl Exp for Int_Lit {
vm: &mut Mu_VM,
function_version: &mut MuFunctionVersion,
) -> Result<P<TreeNode>, String> {
unimplemented!()
let name = format!("const_{}", self.val);
let value = vm.vm.declare_const(
MuEntityHeader::named(vm.vm.next_id(), Arc::new(name)),
vm.get_mu_type(&Type::Int),
Constant::Int(self.val as u64),
);
let value_local = function_version.new_constant(value.clone());
Ok(value_local)
}
fn get_type(
......@@ -1545,7 +1581,18 @@ impl Exp for Bool_Lit {
vm: &mut Mu_VM,
function_version: &mut MuFunctionVersion,
) -> Result<P<TreeNode>, String> {
unimplemented!()
let val = if self.val { 1 } else { 0 };
let name = format!("const_{}", self.val);
let value = vm.vm.declare_const(
MuEntityHeader::named(vm.vm.next_id(), Arc::new(name)),
vm.get_mu_type(&Type::Bool),
Constant::Int(val),
);
let value_local = function_version.new_constant(value.clone());
Ok(value_local)
}
fn get_type(
......@@ -1678,7 +1725,7 @@ impl Exp for CallExp {
);
}
None => return Err(String::from("Function has not been defined.")),
}
},
};
let callee_type = mu_vm.fn_type_map.get(self.callee.as_str()).unwrap();
......@@ -1737,7 +1784,9 @@ fn code_gen_extern_call(
mu_vm: &mut Mu_VM,
function_version: &mut MuFunctionVersion,
) -> Result<P<TreeNode>, String> {
let args_type: Vec<P<MuType>> = proto.args.iter()
let args_type: Vec<P<MuType>> = proto
.args
.iter()
.map(|(arg_type, arg_name)| -> P<MuType> { mu_vm.get_mu_type(arg_type) })
.collect();
......
......@@ -353,7 +353,7 @@ pub unsafe fn create_block_alloca(
let var = format!("{}\0", var_name);
LLVMBuildAlloca(
builder,
context.get_llvm_type(&Type::Double),
context.get_llvm_type(context.var_type_map.get(var_name).unwrap()),
var.as_str().as_ptr() as *const c_char,
)
}
......
......@@ -280,7 +280,9 @@ impl Mu_code_gen for Function {
.body()
.get_type(&curr_var_type_table, &curr_fn_type_table);
mu_vm.fn_type_map.insert(name.clone(), function_type.clone());
mu_vm
.fn_type_map
.insert(name.clone(), function_type.clone());
mu_vm.curr_function += 1;
function_sig = create_mu_sig(
......@@ -523,12 +525,13 @@ pub fn create_cmp_op_instruction(
mu_vm: &mut Mu_VM,
var: &P<TreeNode>,
ops: Vec<P<TreeNode>>,
op: CmpOp,
) -> P<TreeNode> {
function_version.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(mu_vm.vm.next_id()),
value: Some(vec![var.clone_value()]),
ops,
v: Instruction_::CmpOp(mu::ast::op::CmpOp::FOLT, 0, 1),
v: Instruction_::CmpOp(op, 0, 1),
})
}
......
......@@ -5,7 +5,7 @@ use crate::mu_generator;
use crate::parser;
#[test]
fn test_single_exp() {
fn test_double_literal() {
let input = "42.0";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
......@@ -13,15 +13,15 @@ fn test_single_exp() {
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(String::from("test_single_exp\0"), nodes.clone());
llvm_values = generator::code_gen(String::from("test_double_literal\0"), nodes.clone());
mu_values = mu_generator::code_gen(
String::from("test_single_exp\0"),
String::from("test_double_literal\0"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_single_exp\0"),
String::from("test_double_literal\0"),
nodes.clone(),
true,
false,
......@@ -34,6 +34,66 @@ fn test_single_exp() {
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_int_literal() {
let input = "42";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(String::from("test_int_literal\0"), nodes.clone());
mu_values = mu_generator::code_gen(
String::from("test_int_literal\0"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_int_literal\0"),
nodes.clone(),
true,
false,
);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Int(42))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_bool_literal() {
let input = "true";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(String::from("test_bool_literal\0"), nodes.clone());
mu_values = mu_generator::code_gen(
String::from("test_bool_literal\0"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_bool_literal\0"),
nodes.clone(),
true,
false,
);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Bool(true))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_multiple_exps() {
let input = "14.0-2.0 + 3.0*2.0*5.0; 12.0 + 6.0*5.0";
......@@ -66,7 +126,7 @@ fn test_multiple_exps() {
}
#[test]
fn test_function_call() {
fn test_double_function_call() {
let input = "def double foo(double x double y) x*y; foo(3.0 2.0);";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
......@@ -74,15 +134,15 @@ fn test_function_call() {
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(String::from("test_function_call\0"), nodes.clone());
llvm_values = generator::code_gen(String::from("test_double_function_call\0"), nodes.clone());
mu_values = mu_generator::code_gen(
String::from("test_function_call\0"),
String::from("test_double_function_call\0"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_function_call\0"),
String::from("test_double_function_call\0"),
nodes.clone(),
true,
false,
......@@ -95,6 +155,35 @@ fn test_function_call() {
assert_eq!(mu_llvm_values, expected);
}
fn test_int_function_call() {
let input = "def int foo(int x int y) x*y; foo(3 2);";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(String::from("test_double_function_call\0"), nodes.clone());
mu_values = mu_generator::code_gen(
String::from("test_double_function_call\0"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_double_function_call\0"),
nodes.clone(),
true,
false,
);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Int(6))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_extern_function_call() {
let input = "extern double sin(double a); sin(1.23)";
......@@ -152,6 +241,32 @@ fn test_simple_if() {
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_simple_if_true() {
let input = "if true then 1.0 else 2.0";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(String::from("test_simple_if_bool\0"), nodes.clone());
mu_values = mu_generator::code_gen(
String::from("test_simple_if_bool\0"),
nodes.clone(),
false,
false,
);
mu_llvm_values =
mu_generator::code_gen(String::from("test_simple_if_bool\0"), nodes.clone(), true, false);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Double(1.0))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_simple_if_else_case() {
let input = "if 4.0 < 3.0 then 1.0 else 2.0";
......@@ -210,6 +325,33 @@ fn test_fibonacci() {
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_fibonacci_int() {
let input =
"def int fib(int x) if x < 3 then 1 else fib(x-1)+fib(x-2); fib(10)";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(String::from("test_fibonacci\0"), nodes.clone());
mu_values = mu_generator::code_gen(
String::from("test_fibonacci\0"),
nodes.clone(),
false,
false,
);
mu_llvm_values =
mu_generator::code_gen(String::from("test_fibonacci\0"), nodes.clone(), true, false);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Int(55))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_for_loop_no_mutable() {
let input = "def double foo(double x) for double i = 1.0, i < x, 1.0 in x+1.0; foo(5.0)";
......@@ -275,6 +417,73 @@ fn test_mutable_assignment_binary_op() {
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_int_mutable_assignment_binary_op() {
let input =
"def int seq (int x int y) y; def int foo(int x) seq(x = 10 x) foo(4)";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(
String::from("test_int_mutable_assignment_binary_op\0"),
nodes.clone(),
);
mu_values = mu_generator::code_gen(
String::from("test_int_mutable_assignment_binary_op"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_int_mutable_assignment_binary_op"),
nodes.clone(),
true,
false,
);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Int(10))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_int_mutable_var_plus_one_function_with_assignment_expr() {
let input = "def int plusone(int x) var int y = x in y + 1 plusone(3)";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(
String::from("test_int_mutable_var_plus_one_function_with_assignment_expr\0"),
nodes.clone(),
);
mu_values = mu_generator::code_gen(
String::from("test_int_mutable_var_plus_one_function_with_assignment_expr"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_int_mutable_var_plus_one_function_with_assignment_expr"),
nodes.clone(),
true,
false,
);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Int(4))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_mutable_var_plus_one_function_with_assignment_expr() {
let input = "def double plusone(double x) var double y = x in y + 1.0 plusone(3.0)";
......@@ -340,6 +549,47 @@ fn test_mutable_pow_function() {
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_int_mutable_pow_function() {
let input = "def int seq(double x int y)
y
def int pow(int x double y)
var int total = x in
seq(for double i = 1.0, i < y in
total = total * x