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

Added global variables.

parent c75b6257
......@@ -356,6 +356,44 @@ impl Function {
}
}
#[derive(Clone)]
pub struct Global {
var: Var,
var_type: Type,
value: Box<dyn Exp>,
}
impl Global {
pub fn print(&self) -> String {
format!(
"GlobalVar({:?}, {}, {})",
self.var_type,
self.var.print(),
self.value.print()
)
}
pub fn var(&self) -> &Var {
&self.var
}
pub fn var_type(&self) -> &Type {
&self.var_type
}
pub fn value(&self) -> &Box<dyn Exp> {
&self.value
}
pub fn new(var: Var, var_type: Type, value: Box<dyn Exp>) -> Global {
Global {
var,
var_type,
value,
}
}
}
pub trait Exp: ExpClone {
fn print(&self) -> String;
unsafe fn code_gen(
......@@ -1796,9 +1834,6 @@ impl Exp for BinaryExp {
};
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 {
......@@ -1846,34 +1881,50 @@ impl Exp for BinaryExp {
)),
_ => Err("Unsupported type".parse().unwrap()),
},
'<' => match lhs_type {
Type::Double => {
let cmp = LLVMBuildFCmp(
context.builder,
LLVMRealOLT,
lhs,
rhs,
"cmptmp\0".as_ptr() as *const c_char,
);
'<' => {
let lhs_type = self
.lhs
.get_type(&context.var_type_map, &context.fn_type_map);
Ok(cmp)
}
Type::Int => {
let cmp = LLVMBuildICmp(
context.builder,
LLVMIntULT,
lhs,
rhs,
"cmptmp\0".as_ptr() as *const c_char,
);
match lhs_type {
Type::Double => {
let cmp = LLVMBuildFCmp(
context.builder,
LLVMRealOLT,
lhs,
rhs,
"cmptmp\0".as_ptr() as *const c_char,
);
Ok(cmp)
}
Type::Int => {
let cmp = LLVMBuildICmp(
context.builder,
LLVMIntULT,
lhs,
rhs,
"cmptmp\0".as_ptr() as *const c_char,
);
Ok(cmp)
Ok(cmp)
}
_ => Err("Unsupported type".parse().unwrap()),
}
_ => Err("Unsupported type".parse().unwrap()),
},
}
'=' => {
let var_name = self.lhs().print(); // format!("{}", self.lhs().print());
match context.global_vars.get(var_name.as_str()) {
Some((var_type, value)) => {
context
.global_vars
.insert(var_name.clone(), (var_type.clone(), rhs));
return Ok(rhs);
}
None => (),
}
let variable = match context.named_values.get(var_name.as_str()) {
Some(vl) => *vl,
None => return Err(String::from("Unknown variable name")),
......@@ -1960,8 +2011,20 @@ impl Exp for BinaryExp {
return Ok(var);
}
'=' => {
let var_name = self.lhs().print();
match mu_vm.global_vars.get(var_name.as_str()) {
Some((var_type, value)) => {
mu_vm
.global_vars
.insert(var_name.clone(), (var_type.clone(), rhs.clone()));
return Ok(rhs);
}
None => (),
};
let current_block = mu_vm.blocks_map.get_mut(&mu_vm.curr_block).unwrap();
let var_name = &*lhs.name();
current_block.store.insert(var_name.clone(), rhs.clone());
return Ok(rhs);
}
......@@ -1990,6 +2053,10 @@ impl Exp for BinaryExp {
return Type::Bool;
}
if self.c == '=' {
return self.rhs.get_type(var_type_table, fn_type_table);
}
let type_lhs = self.lhs.get_type(var_type_table, fn_type_table);
let type_rhs = self.rhs.get_type(var_type_table, fn_type_table);
......@@ -2144,10 +2211,60 @@ impl Exp for Var {
module: &*mut LLVMModule,
context: &mut Context,
) -> Result<*mut LLVMValue, String> {
match context.named_values.get(self.name()) {
let global_var = return_var_value(&self, module, context, true);
match global_var {
t @ Ok(_) => return t,
Err(e) => (),
};
let local_var = return_var_value(&self, module, context, false);
match local_var {
t @ Ok(_) => return t,
Err(e) => panic!("Variable not found."),
}
}
unsafe fn code_gen_mu(
&self,
mu_vm: &mut Mu_VM,
function_version: &mut MuFunctionVersion,
) -> Result<P<TreeNode>, String> {
match mu_vm.global_vars.get(self.name.as_str()) {
Some((var_type, val)) => return Ok(val.clone()),
None => (),
}
let current_block = mu_vm.blocks_map.get_mut(&mu_vm.curr_block).unwrap();
let r = current_block.store.get(self.name.as_str());
match r {
Some(v) => Ok(v.clone()),
None => panic!("Variable not found."),
}
}
fn get_type(
&self,
var_type_table: &HashMap<String, Type, RandomState>,
fn_type_table: &HashMap<String, Type, RandomState>,
) -> Type {
var_type_table.get(self.name.as_str()).unwrap().clone()
}
}
pub unsafe fn return_var_value(
var: &Var,
module: &*mut LLVMModule,
context: &mut Context,
global: bool,
) -> Result<*mut LLVMValue, String> {
if global == false {
match context.named_values.get(var.name()) {
Some(val) => {
let name = format!("{}\0", self.name.clone());
match self.get_type(&context.var_type_map, &context.fn_type_map) {
let name = format!("{}\0", var.name.clone());
match var.get_type(&context.var_type_map, &context.fn_type_map) {
Type::Int | Type::Bool | Type::Double => {
let var = LLVMBuildLoad(
context.builder,
......@@ -2175,31 +2292,36 @@ impl Exp for Var {
_ => panic!("Unsupported type"),
}
}
None => unimplemented!(),
None => Err(String::from("Variable not found.")),
}
}
} else {
match context.global_vars.get(var.name()) {
Some((var_type, val)) => {
let name = format!("{}\0", var.name.clone());
match var_type {
Type::Int | Type::Bool | Type::Double => Ok(*val),
Type::IntArray(_) | Type::BoolArray(_) | Type::DoubleArray(_) => {
let pos = [
LLVMConstInt(context.get_llvm_type(&Type::Int), 0, false as i32),
LLVMConstInt(context.get_llvm_type(&Type::Int), 0, false as i32),
];
unsafe fn code_gen_mu(
&self,
mu_vm: &mut Mu_VM,
function_version: &mut MuFunctionVersion,
) -> Result<P<TreeNode>, String> {
let current_block = mu_vm.blocks_map.get_mut(&mu_vm.curr_block).unwrap();
let pointer = LLVMBuildInBoundsGEP(
context.builder,
*val,
pos.as_ptr() as *mut LLVMValueRef,
2,
"tmp\0".as_ptr() as *const c_char,
);
let r = current_block.store.get(self.name.as_str());
match r {
Some(v) => Ok(v.clone()),
None => unimplemented!(),
Ok(pointer)
}
_ => panic!("Unsupported type"),
}
}
None => Err(String::from("Variable not found.")),
}
}
fn get_type(
&self,
var_type_table: &HashMap<String, Type, RandomState>,
fn_type_table: &HashMap<String, Type, RandomState>,
) -> Type {
var_type_table.get(self.name.as_str()).unwrap().clone()
}
}
impl Exp for CallExp {
......
......@@ -55,6 +55,7 @@ pub struct Context {
pub context: LLVMContextRef,
pub builder: LLVMBuilderRef,
pub named_values: HashMap<String, LLVMValueRef>,
pub global_vars: HashMap<String, (Type, LLVMValueRef)>,
pub var_type_map: HashMap<String, Type>,
pub fn_type_map: HashMap<String, Type>,
pub curr_function: i32,
......@@ -103,6 +104,7 @@ impl Context {
context,
builder,
named_values,
global_vars : HashMap::new(),
var_type_map: HashMap::new(),
fn_type_map: HashMap::new(),
curr_function: 0,
......@@ -238,6 +240,13 @@ pub unsafe fn code_gen(filename: String, mut nodes: ASTNodes) -> Vec<Result<RunR
let mut module_number = 0;
let mut returning_values = vec![];
for global_var in nodes.global_vars.iter_mut() {
let out_file = CString::new(format!("out_{}.ll", module_number)).unwrap();
global_var.code_gen(&module, &mut context);
llvm::core::LLVMPrintModuleToFile(module, out_file.as_ptr(), ptr::null_mut());
}
for prototype in nodes.prototypes.iter_mut() {
let out_file = CString::new(format!("out_{}.ll", module_number)).unwrap();
prototype.code_gen(&module, &mut context);
......@@ -277,6 +286,24 @@ trait Code_gen {
) -> Result<LLVMValueRef, String>;
}
impl Code_gen for Global {
unsafe fn code_gen(&mut self, module: &*mut LLVMModule, context: &mut Context) -> Result<*mut LLVMValue, String> {
let llvm_var_type = context.get_llvm_type(self.var_type());
let var_name = self.var().name().clone();
let global = LLVMAddGlobal(*module, llvm_var_type, var_name.as_str().as_ptr() as *const c_char);
let init_value = match self.value().code_gen(module, context) {
Ok(init_value) => init_value,
e @ Err(_) => return e,
};
context.global_vars.insert(var_name.clone(), (self.var_type().clone(), init_value));
Ok(global)
}
}
impl Code_gen for Prototype {
unsafe fn code_gen(
&mut self,
......
......@@ -24,6 +24,7 @@ pub enum Token {
BOOL_ARRAY,
INT_ARRAY,
DOUBLE_ARRAY,
GLOBAL
}
pub fn read_file() -> (String, Vec<Token>) {
......@@ -149,11 +150,16 @@ fn parse_identifier_or_keyword(c: char, input_str: &[u8], index: &mut i32) -> To
let double_array_token = String::from("double[]");
let false_token = String::from("false");
let true_token = String::from("true");
let global_token = String::from("global");
if result.eq(&def_token) {
return Token::DEF;
}
if result.eq(&global_token) {
return Token::GLOBAL;
}
if result.eq(&for_token) {
return Token::FOR;
}
......
......@@ -39,6 +39,7 @@ pub struct Mu_VM {
pub curr_function: i32,
pub curr_block: MuID,
pub blocks_map: LinkedHashMap<MuID, Mu_Block>,
pub global_vars : HashMap<String, (Type, P<TreeNode>)>,
pub types_mu_types_map: HashMap<Type, P<MuType>>,
pub ref_types_mu_types_map: HashMap<RefType, P<MuType>>,
pub functions: HashMap<String, P<TreeNode>>,
......@@ -81,6 +82,7 @@ impl Mu_VM {
curr_function,
curr_block: 0,
blocks_map,
global_vars : HashMap::new(),
types_mu_types_map,
ref_types_mu_types_map,
functions,
......@@ -246,6 +248,23 @@ pub unsafe fn code_gen(
let mut vm = Mu_VM::new(use_llvm_aot, debug);
let mut results = vec![];
for global in nodes.global_vars {
let var_name = global.var().name();
let var_type = global.var_type().clone();
let func_ver: &mut MuFunctionVersion = std::mem::uninitialized();;
let var_val = match global.value().code_gen_mu(&mut vm, func_ver) {
Ok(v) => v,
Err(e) => panic!("Could not initialize variable.")
};
vm.global_vars
.insert(var_name.clone(), (var_type, var_val));
}
for prototype in nodes.prototypes {
vm.extern_prototypes
.insert(prototype.name().clone(), prototype.clone());
......
......@@ -9,6 +9,7 @@ use std::ops::Deref;
pub struct ASTNodes {
pub functions: Vec<Function>,
pub prototypes: Vec<Prototype>,
pub global_vars: Vec<Global>,
}
pub fn parse_program(tokens: Vec<Token>) -> ASTNodes {
......@@ -17,6 +18,7 @@ pub fn parse_program(tokens: Vec<Token>) -> ASTNodes {
let mut nodes = ASTNodes {
functions: vec![],
prototypes: vec![],
global_vars: vec![],
};
while curr_token < tokens.len() {
......@@ -32,6 +34,13 @@ pub fn parse_program(tokens: Vec<Token>) -> ASTNodes {
nodes.functions.push(*function);
}
}
Token::GLOBAL => {
let global = parse_global(&tokens, &mut curr_token);
if let Some(var) = global {
println!("{}", var.print());
nodes.global_vars.push(*var);
}
}
Token::EXTERN => {
let prototype = parse_extern(&tokens, &mut curr_token);
if let Some(prototype) = prototype {
......@@ -52,6 +61,58 @@ pub fn parse_program(tokens: Vec<Token>) -> ASTNodes {
nodes
}
fn parse_global(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<Global>> {
// skip GLOBAL token
*curr_token += 1;
let var_type = match &tokens[*curr_token] {
Token::BOOL => Type::Bool,
Token::INT => Type::Int,
Token::DOUBLE => Type::Double,
Token::BOOL_ARRAY => Type::BoolArray(-1),
Token::INT_ARRAY => Type::IntArray(-1),
Token::DOUBLE_ARRAY => Type::DoubleArray(-1),
_ => return None,
};
*curr_token += 1;
let var_name = match &tokens[*curr_token] {
Token::ID(id) => id.clone(),
_ => return None,
};
*curr_token += 1;
let mut assigned_var = false;
match &tokens[*curr_token] {
Token::CHAR('=') => {
*curr_token += 1;
assigned_var = true;
}
_ => (),
}
if assigned_var {
let assigned_exp = match parse_expression(&tokens, curr_token) {
Some(exp) => exp,
None => return None,
};
Some(Box::new(Global::new(Var::new(var_name), var_type, assigned_exp)))
} else {
let default_exp: Box<dyn Exp> = match var_type {
Type::Double => Box::new(RealLiteral::new(0.0)),
Type::Bool => Box::new(BoolLiteral::new(false)),
Type::Int => Box::new(IntLiteral::new(0)),
_ => panic!("Variable must be explicitly initialized."),
};
Some(Box::new(Global::new(
Var::new(var_name),
var_type,
default_exp,
)))
}
}
fn parse_definition(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<Function>> {
// skip DEF token
*curr_token += 1;
......@@ -225,7 +286,12 @@ fn parse_var_exp(tokens: &Vec<Token>, curr_token: &mut usize) -> Option<Box<dyn
vars.push((var_type, var, assigned_exp));
} else {
let default_exp = Box::new(RealLiteral::new(0.0));
let default_exp: Box<dyn Exp> = match var_type {
Type::Double => Box::new(RealLiteral::new(0.0)),
Type::Bool => Box::new(BoolLiteral::new(false)),
Type::Int => Box::new(IntLiteral::new(0)),
_ => panic!("Variable must be explicitly initialized."),
};
vars.push((var_type, var, default_exp));
}
......
......@@ -679,7 +679,7 @@ fn test_array_access_variable() {
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
// let mu_llvm_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(
String::from("test_array_access_variable\0"),
......@@ -691,18 +691,18 @@ fn test_array_access_variable() {
false,
false,
);
// mu_llvm_values = mu_generator::code_gen(
// String::from("test_int_mutable_fibonacci_iter"),
// nodes.clone(),
// true,
// false,
// );
mu_llvm_values = mu_generator::code_gen(
String::from("test_int_mutable_fibonacci_iter"),
nodes.clone(),
true,
false,
);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Int(33))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
// assert_eq!(mu_llvm_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
......@@ -716,7 +716,7 @@ var int[] x = {13, 25, 32} in
let nodes = parser::parse_program(tokens);
let llvm_values;
let mu_values;
// let mu_llvm_values;
let mu_llvm_values;
unsafe {
llvm_values = generator::code_gen(
String::from("test_array_access_variable_function\0"),
......@@ -728,16 +728,96 @@ var int[] x = {13, 25, 32} in
false,
false,
);
// mu_llvm_values = mu_generator::code_gen(
// String::from("test_array_access_variable_function"),
// nodes.clone(),
// true,
// false,
// );
mu_llvm_values = mu_generator::code_gen(
String::from("test_array_access_variable_function"),
nodes.clone(),
true,
false,
);
}
let expected: Vec<Result<RunResult, String>> = vec![Ok(RunResult::Int(25))];
assert_eq!(llvm_values, expected);
assert_eq!(mu_values, expected);
// assert_eq!(mu_llvm_values, expected);
assert_eq!(mu_llvm_values, expected);
}
#[test]
fn test_global_variable() {
let input = "global int x = 42;
def int foo()
x
foo()";
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_global_variable\0"),
nodes.clone(),
);
mu_values = mu_generator::code_gen(
String::from("test_global_variable"),
nodes.clone(),
false,
false,
);
mu_llvm_values = mu_generator::code_gen(
String::from("test_global_variable"),
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_global_variable_mutable() {
let input = "global int x = 42;
def int seq (int x int y) y
def int foo()
seq(x=1 x)
foo()";
let tokens = lexer::tokenize(String::from(input));
let nodes = parser::parse_program(tokens);
let llvm_values;