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 01907662 authored by Eduardo Souza's avatar Eduardo Souza
Browse files

Adding tests.

parent 7653b21f
def foo(x y) x+foo(y, 4.0);
\ No newline at end of file
def foo(x y) x*y;
foo(3 2);
\ No newline at end of file
def foo(x y) x*y;
extern sin(a);
foo(3 2);
\ No newline at end of file
sin(1.23)
\ No newline at end of file
extern sin(a);
sin(1.23)
\ No newline at end of file
if 2 < 3 then
1
else
2
\ No newline at end of file
......@@ -5,5 +5,5 @@ def fib(x)
else
fib(x-1)+fib(x-2)
# This expression will compute the 40th number.
fib(40.0)
\ No newline at end of file
# This expression will compute the 10th number.
fib(10.0)
\ No newline at end of file
......@@ -22,20 +22,7 @@ use mu_aot_llvm::instr::gen_instr_branch2;
use std::borrow::Borrow;
use std::ops::Add;
pub trait Exp {
fn print(&self) -> String;
unsafe fn code_gen(
&self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<LLVMValueRef, String>;
unsafe fn code_gen_mu(
&self,
vm: &mut Mu_VM,
fun_ver: &mut MuFunctionVersion,
) -> Result<P<TreeNode>, String>;
}
#[derive(Clone)]
pub struct Number {
val: f64,
}
......@@ -50,6 +37,7 @@ impl Number {
}
}
#[derive(Clone)]
pub struct Var {
name: String,
}
......@@ -64,6 +52,7 @@ impl Var {
}
}
#[derive(Clone)]
pub struct CallExp {
callee: String,
args: Vec<Box<dyn Exp>>,
......@@ -83,6 +72,7 @@ impl CallExp {
}
}
#[derive(Clone)]
pub struct ForExp {
var: Var,
start_exp: Box<dyn Exp>,
......@@ -129,6 +119,145 @@ impl ForExp {
}
}
#[derive(Clone)]
pub struct ConditionalExp {
cond: Box<dyn Exp>,
then_branch: Box<dyn Exp>,
else_branch: Box<dyn Exp>,
}
impl ConditionalExp {
pub fn cond(&self) -> &Box<dyn Exp> {
&self.cond
}
pub fn then_branch(&self) -> &Box<dyn Exp> {
&self.then_branch
}
pub fn else_branch(&self) -> &Box<dyn Exp> {
&self.else_branch
}
pub fn new(
cond: Box<dyn Exp>,
then_branch: Box<dyn Exp>,
else_branch: Box<dyn Exp>,
) -> ConditionalExp {
ConditionalExp {
cond,
then_branch,
else_branch,
}
}
}
#[derive(Clone)]
pub struct BinaryExp {
c: char,
lhs: Box<dyn Exp>,
rhs: Box<dyn Exp>,
}
impl BinaryExp {
pub fn c(&self) -> char {
self.c
}
pub fn lhs(&self) -> &Box<dyn Exp> {
&self.lhs
}
pub fn rhs(&self) -> &Box<dyn Exp> {
&self.rhs
}
pub fn new(c: char, lhs: Box<dyn Exp>, rhs: Box<dyn Exp>) -> BinaryExp {
BinaryExp { c, lhs, rhs }
}
}
#[derive(Clone)]
pub struct Prototype {
name: String,
args: Vec<String>,
}
impl Prototype {
pub fn print(&self) -> String {
format!("Prototype({}, {:?})", self.name, self.args)
}
pub fn name(&self) -> &String {
&self.name
}
pub fn args(&self) -> &Vec<String> {
&self.args
}
pub fn new(name: String, args: Vec<String>) -> Prototype {
Prototype { name, args }
}
}
#[derive(Clone)]
pub struct Function {
proto: Box<Prototype>,
body: Box<dyn Exp>,
}
impl Function {
pub fn print(&self) -> String {
format!("Function({}, {})", self.proto.print(), self.body.print())
}
pub fn proto(&self) -> &Box<Prototype> {
&self.proto
}
pub fn body(&self) -> &Box<dyn Exp> {
&self.body
}
pub fn new(proto: Box<Prototype>, body: Box<dyn Exp>) -> Function {
Function { proto, body }
}
}
pub trait Exp: ExpClone {
fn print(&self) -> String;
unsafe fn code_gen(
&self,
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<LLVMValueRef, String>;
unsafe fn code_gen_mu(
&self,
vm: &mut Mu_VM,
fun_ver: &mut MuFunctionVersion,
) -> Result<P<TreeNode>, String>;
}
pub trait ExpClone {
fn clone_box(&self) -> Box<dyn Exp>;
}
impl Clone for Box<dyn Exp> {
fn clone(&self) -> Box<dyn Exp> {
self.clone_box()
}
}
impl<T> ExpClone for T
where
T: 'static + Exp + Clone,
{
fn clone_box(&self) -> Box<dyn Exp> {
Box::new(self.clone())
}
}
impl Exp for ForExp {
fn print(&self) -> String {
format!(
......@@ -396,7 +525,7 @@ impl Exp for ForExp {
form_args_true.form_args.clone(),
form_args_false.form_args.clone(),
&loop_block,
&after_loop_block
&after_loop_block,
);
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
......@@ -434,7 +563,6 @@ impl Exp for ForExp {
}
ops.push(var.clone());
let branch_preloop = create_branch1_instr(vm.vm.next_id(), fun_ver, ops, &preloop_block);
let current_block = vm.blocks_map.get_mut(&vm.curr_block).unwrap();
......@@ -446,8 +574,8 @@ impl Exp for ForExp {
match old_value {
Some(v) => {
preloop_block.form_args.insert(self.var.name.clone(), v);
},
None => ()
}
None => (),
}
// for loop returns 0
......@@ -465,38 +593,6 @@ impl Exp for ForExp {
}
}
pub struct ConditionalExp {
cond: Box<dyn Exp>,
then_branch: Box<dyn Exp>,
else_branch: Box<dyn Exp>,
}
impl ConditionalExp {
pub fn cond(&self) -> &Box<dyn Exp> {
&self.cond
}
pub fn then_branch(&self) -> &Box<dyn Exp> {
&self.then_branch
}
pub fn else_branch(&self) -> &Box<dyn Exp> {
&self.else_branch
}
pub fn new(
cond: Box<dyn Exp>,
then_branch: Box<dyn Exp>,
else_branch: Box<dyn Exp>,
) -> ConditionalExp {
ConditionalExp {
cond,
then_branch,
else_branch,
}
}
}
impl Exp for ConditionalExp {
fn print(&self) -> String {
format!(
......@@ -840,30 +936,6 @@ fn create_branch1_instr(
})
}
pub struct BinaryExp {
c: char,
lhs: Box<dyn Exp>,
rhs: Box<dyn Exp>,
}
impl BinaryExp {
pub fn c(&self) -> char {
self.c
}
pub fn lhs(&self) -> &Box<dyn Exp> {
&self.lhs
}
pub fn rhs(&self) -> &Box<dyn Exp> {
&self.rhs
}
pub fn new(c: char, lhs: Box<dyn Exp>, rhs: Box<dyn Exp>) -> BinaryExp {
BinaryExp { c, lhs, rhs }
}
}
impl Exp for BinaryExp {
fn print(&self) -> String {
format!(
......@@ -1240,49 +1312,3 @@ fn code_gen_extern_call(
Ok(call_result)
}
pub struct Prototype {
name: String,
args: Vec<String>,
}
impl Prototype {
pub fn print(&self) -> String {
format!("Prototype({}, {:?})", self.name, self.args)
}
pub fn name(&self) -> &String {
&self.name
}
pub fn args(&self) -> &Vec<String> {
&self.args
}
pub fn new(name: String, args: Vec<String>) -> Prototype {
Prototype { name, args }
}
}
pub struct Function {
proto: Box<Prototype>,
body: Box<dyn Exp>,
}
impl Function {
pub fn print(&self) -> String {
format!("Function({}, {})", self.proto.print(), self.body.print())
}
pub fn proto(&self) -> &Box<Prototype> {
&self.proto
}
pub fn body(&self) -> &Box<dyn Exp> {
&self.body
}
pub fn new(proto: Box<Prototype>, body: Box<dyn Exp>) -> Function {
Function { proto, body }
}
}
......@@ -64,7 +64,7 @@ unsafe fn run_function(
function: Result<*mut LLVMValue, String>,
module: *mut LLVMModule,
context: &mut Context,
) {
) -> Result<f64, String> {
let mut ee = 0 as LLVMExecutionEngineRef;
let mut error = 0 as *mut c_char;
let mut options = std::mem::uninitialized();
......@@ -74,8 +74,8 @@ unsafe fn run_function(
let result = String::from_utf8_lossy(cstr_buf.to_bytes()).into_owned();
let message = LLVMCreateMessage(error);
let message = CString::from_raw(message);
println!("{:?}", message);
return;
let message = format!("{:?}", message);
return Err(message);
}
LLVMInitializeMCJITCompilerOptions(
......@@ -93,8 +93,8 @@ unsafe fn run_function(
let result = String::from_utf8_lossy(cstr_buf.to_bytes()).into_owned();
let message = LLVMCreateMessage(error);
let message = CString::from_raw(message);
println!("{:?}", message);
return;
let message = format!("{:?}", message);
return Err(message);
}
let mut args = vec![];
......@@ -104,10 +104,7 @@ unsafe fn run_function(
f,
LLVMRunFunction(ee, f, args.len() as c_uint, args.as_mut_ptr()),
),
Err(e) => {
println!("{}", e);
return;
}
Err(e) => return Err(e)
};
let triple = LLVMGetDefaultTargetTriple();
......@@ -142,14 +139,12 @@ unsafe fn run_function(
let result = String::from_utf8_lossy(x.to_bytes()).into_owned();
let message = LLVMCreateMessage(error_str);
let message = CString::from_raw(message);
println!("{:?}", message);
return;
let message = format!("{:?}", message);
return Err(message);
}
let result = LLVMGenericValueToFloat(LLVMDoubleType(), result);
// LLVMDisposeExecutionEngine(ee);
println!("\n{}", result);
Ok(result)
}
pub extern "C" fn putchard(x: f64) -> f64 {
......@@ -164,11 +159,12 @@ pub unsafe fn init() {
);
}
pub unsafe fn code_gen(filename: String, nodes: ASTNodes) {
pub unsafe fn code_gen(filename: String, nodes: ASTNodes) -> Vec<Result<f64, String>> {
init();
let mut context = Context::new();
let mut module_number = 0;
let mut returning_values = vec![];
let module = llvm::core::LLVMModuleCreateWithName(filename.as_str().as_ptr() as *const _);
......@@ -188,13 +184,13 @@ pub unsafe fn code_gen(filename: String, nodes: ASTNodes) {
// execute module
if function.proto().name() == "" {
run_function(result, module, &mut context);
returning_values.push(run_function(result, module, &mut context));
}
let module = llvm::core::LLVMModuleCreateWithName(filename.as_str().as_ptr() as *const _);
let context = Context::new();
}
};
//LLVMDumpModule(module);
returning_values
}
trait Code_gen {
......
//use std::io::{Read, empty};
extern crate mu;
use self::mu::ast::types::*;
......@@ -12,3 +10,5 @@ pub mod lexer;
pub mod parser;
pub mod mu_generator;
pub mod tests;
......@@ -24,13 +24,21 @@ fn main() {
// parse tokens into tree
let nodes = parser::parse_program(tokens);
let values;
if USE_LLVM {
unsafe {
generator::code_gen(filename, nodes);
values = generator::code_gen(filename, nodes);
}
} else {
unsafe {
mu_generator::code_gen(filename, nodes, USE_AOT_MU_LLVM);
values = mu_generator::code_gen(filename, nodes, USE_AOT_MU_LLVM, true);
}
}
for value in values {
match value {
Ok(v) => println!("{}", v),
Err(e) => println!("{}", e)
}
}
}
......@@ -45,13 +45,21 @@ pub struct Mu_VM {
}
impl Mu_VM {
pub fn new(use_llvm_aot: bool) -> Mu_VM {
let vm = if use_llvm_aot {
VM::new_with_opts("init_mu --log-level=debug --generate-llvm --emit-debug-info ")
} else {
VM::new_with_opts("init_mu --log-level=debug --emit-debug-info ")
pub fn new(use_llvm_aot: bool, debug: bool) -> Mu_VM {
let debug_opt = "--log-level=debug --emit-debug-info ";
let generate_llvm_opt = "--generate-llvm";
let mut opts = String::from("init_mu");
if use_llvm_aot {
opts = format!("{} {}", opts, generate_llvm_opt)
};
if debug {
opts = format!("{} {}", opts, debug_opt)
};
let vm = VM::new_with_opts(opts.as_str());
let curr_function = 0;
let ty = vm.declare_type(
......@@ -109,8 +117,14 @@ pub struct Mu_Block {
pub form_args: LinkedHashMap<String, P<TreeNode>>,
}
pub unsafe fn code_gen(filename: String, nodes: ASTNodes, use_llvm_aot: bool) {
let mut vm = Mu_VM::new(use_llvm_aot);
pub unsafe fn code_gen(
filename: String,
nodes: ASTNodes,
use_llvm_aot: bool,
debug: bool,
) -> Vec<Result<f64, String>> {
let mut vm = Mu_VM::new(use_llvm_aot, debug);
let mut results = vec![];
for prototype in nodes.prototypes {
let n_args = prototype.args().len() as i32;
......@@ -134,7 +148,10 @@ pub unsafe fn code_gen(filename: String, nodes: ASTNodes, use_llvm_aot: bool) {
let lasf_function = match &vm.last_runnable_function {
Some(f) => f,
_ => return,
_ => {
results.push(Err(String::from("No runnable function has been defined.")));
return results;
}
};
make_boot_image(&vm, lasf_function, use_llvm_aot);
......@@ -147,8 +164,10 @@ pub unsafe fn code_gen(filename: String, nodes: ASTNodes, use_llvm_aot: bool) {
for f in 0..vm.curr_function {
let f = format!("f_anonn_{}", f);
run_code(&vm, &f, &deps);
results.push(run_code(&vm, &f, &deps));
}
results
}
fn make_boot_image(mu_vm: &Mu_VM, f: &MuEntityHeader, use_llvm_aot: bool) {
......@@ -185,7 +204,7 @@ fn make_boot_image(mu_vm: &Mu_VM, f: &MuEntityHeader, use_llvm_aot: bool) {
}
}
fn run_code(mu_vm: &Mu_VM, name: &String, deps: &Vec<String>) {
fn run_code(mu_vm: &Mu_VM, name: &String, deps: &Vec<String>) -> Result<f64, String> {
let libname = format!("lib{}.dylib", name);
let mut dylib_args = vec![Arc::new(name.clone())];
......@@ -199,7 +218,7 @@ fn run_code(mu_vm: &Mu_VM, name: &String, deps: &Vec<String>) {
unsafe {
let function: ll::Symbol<unsafe extern "C" fn() -> f64> = lib.get(name.as_bytes()).unwrap();
println!("{}", function());
Ok(function())
}
}
......
......@@ -4,6 +4,7 @@ use crate::lexer;
use crate::lexer::Token;
use std::ops::Deref;
#[derive(Clone)]
pub struct ASTNodes {
pub functions: Vec<Function>,
pub prototypes: Vec<Prototype>,
......@@ -378,71 +379,4 @@ fn get_precedence(c: &char) -> i32 {
'*' => 40,
_ => -1,
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse_extern() {
let contents = String::from("extern sin(a);");
let tokens = lexer::process_input(contents);
let mut curr_token = 0;
let prototype = parse_extern(&tokens, &mut curr_token);
if let Some(prototype) = prototype {
assert_eq!("Prototype(sin, [\"a\"])", prototype.print());
}
}
#[test]
fn test_parse_top_level_exp_int() {
let contents = String::from("1;");
let tokens = lexer::process_input(contents);
let mut curr_token = 0;
let top_level_exp = parse_top_level_expression(&tokens, &mut curr_token);
if let Some(function) = top_level_exp {
assert_eq!(
"Function(Prototype(__annon_expr, []), Number(1))",
function.print()
);
}
}
#[test]
fn test_parse_top_level_exp_var() {
let contents = String::from("x;");
let tokens = lexer::process_input(contents);
let mut curr_token = 0;