diff --git a/examples/fib.qf b/examples/fib.qf new file mode 100644 index 0000000..cdb2a91 --- /dev/null +++ b/examples/fib.qf @@ -0,0 +1,8 @@ +func fib(si32 i) si32 { + if(i <= 1_si32) { + ret 1 + } + + var si32 test = fib(i - 1_si32) + fib(i - 2_si32) + ret test +} \ No newline at end of file diff --git a/ir/src/conv/control.rs b/ir/src/conv/control.rs index 67e80d6..66fca53 100644 --- a/ir/src/conv/control.rs +++ b/ir/src/conv/control.rs @@ -30,7 +30,7 @@ pub fn parse_if_statement_ir(func: &mut IRFunction, ctx: &IRContext, node: Box { ctx.builder.position_at_end(ir_branches[ind]); - let cond_val = parse_ir_value(Some(&func.lctx), ctx, cond.unwrap(), None, false)?; + let cond_val = parse_ir_value(Some(&func), ctx, cond.unwrap(), None, false)?; let int_cond_val = match cond_val.obtain(ctx)?.obtain_as_bool() { Some(v) => *v, @@ -121,7 +121,7 @@ pub fn parse_for_statement_ir(func: &mut IRFunction, ctx: &IRContext, node: Box< let bool_type = ctx.type_storage.get(BOOL_TYPE_HASH).expect("Boolean type wasn't found!"); - let cond_val = parse_ir_value(Some(&func.lctx), ctx, cond, None, false)?; + let cond_val = parse_ir_value(Some(&func), ctx, cond, None, false)?; let cond_int = cond_val.obtain(ctx)?.obtain_as_bool().expect("Cannot cast condition result as int"); ctx.builder.build_conditional_branch(*cond_int, for_body_block, post_block); diff --git a/ir/src/conv/func.rs b/ir/src/conv/func.rs index 0a52fe6..220a5cd 100644 --- a/ir/src/conv/func.rs +++ b/ir/src/conv/func.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use commons::err::{PositionlessError, PositionlessResult}; use parser::{ast::{func, tree::ASTTreeNode}, parse_ast_ctx}; -use crate::{conv::{control::{parse_for_statement_ir, parse_if_statement_ir}, val::parse_ir_value}, ctx::{IRContext, IRLocalContext}, irstruct::{funcs::IRFunction, ptr::IRPointer}, refs::IRValueRef, types::typing::IRType}; +use crate::{conv::{control::{parse_for_statement_ir, parse_if_statement_ir}, val::parse_ir_value}, ctx::{IRContext, IRLocalContext}, irstruct::{funcs::IRFunction, ptr::IRPointer}, refs::IRValueRef, types::typing::IRType, values::IRValue}; pub fn parse_ir_shadow_function_decl(ctx: &mut IRContext, node: Box) -> PositionlessResult> { if let ASTTreeNode::ShadowFunctionDeclaration { func_name, args, returnType } = *node { @@ -12,7 +12,7 @@ pub fn parse_ir_shadow_function_decl(ctx: &mut IRContext, node: Box None => None }; - let mut arguments: Vec> = vec![]; + let mut arguments: Vec<(Rc, u64)> = vec![]; for k in args { let t = match ctx.type_storage.get(k.argument_type) { @@ -20,14 +20,14 @@ pub fn parse_ir_shadow_function_decl(ctx: &mut IRContext, node: Box None => return Err(PositionlessError::new(&format!("Cannot get type with hash {} for argument {}!", k.argument_type, k.name.val))) }; - arguments.push(t); + arguments.push((t, k.name.hash)); } - let func = IRFunction::create_shadow(ctx, func_name.val.clone(), &ctx.module, return_type, arguments)?; + let func = IRFunction::create_shadow(ctx, func_name.val.clone(), func_name.hash, &ctx.module, return_type, arguments)?; ctx.add_function(func_name.hash, func)?; - return Ok(ctx.get_funtion(func_name.hash)?); + return Ok(ctx.get_function(func_name.hash)?); } return Err(PositionlessError::new("Cannot parse ir shadow funtion decl as the node is incompatible!")); @@ -40,7 +40,7 @@ pub fn parse_ir_function_decl(ctx: &mut IRContext, node: Box) -> Po None => None }; - let mut arguments: Vec> = vec![]; + let mut arguments: Vec<(Rc, u64)> = vec![]; for k in args { let t = match ctx.type_storage.get(k.argument_type) { @@ -48,10 +48,18 @@ pub fn parse_ir_function_decl(ctx: &mut IRContext, node: Box) -> Po None => return Err(PositionlessError::new(&format!("Cannot get type with hash {} for argument {}!", k.argument_type, k.name.val))) }; - arguments.push(t); + arguments.push((t, k.name.hash)); } - let mut func = IRFunction::create(ctx, func_name.val, &ctx.module, return_type, arguments)?; + let mut func = IRFunction::create(ctx, func_name.val,func_name.hash, &ctx.module, return_type, arguments)?; + + let mut ind = 0; + for argument in &func.args { + let val = func.get_nth_arg(ind)?; + + func.lctx.add_argument(argument.1, IRValue::new(val, argument.0.clone()))?; + ind += 1; + } func.prepare_body_filling(ctx); parse_ir_body(ctx, &mut func, body, true)?; @@ -63,9 +71,9 @@ pub fn parse_ir_function_decl(ctx: &mut IRContext, node: Box) -> Po }; } - ctx.add_function(func_name.hash, func); + ctx.add_function(func_name.hash, func)?; - return ctx.get_funtion(func_name.hash); + return ctx.get_function(func_name.hash); } return Err(PositionlessError::new("Given node in parse_ir_function_decl wasn't a function decl!")); @@ -83,8 +91,8 @@ pub fn parse_ir_body(ctx: &IRContext, func: &mut IRFunction, nodes: Vec, owner: Option, grab_result: bool) -> PositionlessResult> { - if let ASTTreeNode::FunctionCall { func, args } = *node { +pub fn parse_ir_function_call(ctx: &IRContext, f: &IRFunction, node: Box, owner: Option, grab_result: bool) -> PositionlessResult> { + if let ASTTreeNode::FunctionCall { func: ff, args } = *node { let mut arguments = vec![]; if owner.as_ref().is_some() { @@ -92,12 +100,19 @@ pub fn parse_ir_function_call(ctx: &IRContext, lctx: &IRLocalContext, node: Box< } for v in args { - arguments.push(parse_ir_value(Some(lctx), ctx, v, None, false)?); + arguments.push(parse_ir_value(Some(&f), ctx, v, None, false)?); } - let func = ctx.get_funtion(func.hash)?; - let ret =func.call(ctx, arguments, grab_result)?; + let ret; + + if ff.hash == f.hash { + ret = f.call(ctx, arguments, grab_result)?; + } else { + let func = ctx.get_function(ff.hash)?; + + ret = func.call(ctx, arguments, grab_result)?; + } if !grab_result || ret.is_none() { return Ok(None); @@ -120,7 +135,7 @@ pub fn parse_ir_function_body_member(ctx: &IRContext, func: &mut IRFunction, nod println!("Var name: {}", var_name.val.clone()); let initial = if let Some(v) = value { - Some(parse_ir_value(Some(&func.lctx), ctx, v, None, true)?) + Some(parse_ir_value(Some(&func), ctx, v, None, true)?) } else { None }; @@ -135,19 +150,19 @@ pub fn parse_ir_function_body_member(ctx: &IRContext, func: &mut IRFunction, nod }, ASTTreeNode::StructLRFunction { .. } => { - parse_ir_value(Some(&func.lctx), ctx, node, None, false)?; + parse_ir_value(Some(&func), ctx, node, None, false)?; return Ok(true) }, ASTTreeNode::StructLRVariable { .. } => { - parse_ir_value(Some(&func.lctx), ctx, node, None, false)?; + parse_ir_value(Some(&func), ctx, node, None, false)?; return Ok(true) }, ASTTreeNode::FunctionCall { .. } => { - parse_ir_function_call(ctx, &func.lctx, node, None, false)?; + parse_ir_function_call(ctx, &func, node, None, false)?; return Ok(true) }, @@ -159,7 +174,7 @@ pub fn parse_ir_function_body_member(ctx: &IRContext, func: &mut IRFunction, nod return Ok(true); } - let val = parse_ir_value(Some(&func.lctx), ctx, val.unwrap(), None, true)?; + let val = parse_ir_value(Some(&func), ctx, val.unwrap(), None, true)?; ctx.builder.build_return(Some(&val.obtain(ctx)?.obtain().inner)); @@ -179,7 +194,7 @@ pub fn parse_ir_function_body_member(ctx: &IRContext, func: &mut IRFunction, nod return Err(PositionlessError::new("Cannot use a math expression in IR body if it is not assignments!")) } - parse_ir_value(Some(&func.lctx), ctx, node, None, false)?; + parse_ir_value(Some(&func), ctx, node, None, false)?; return Ok(true); } diff --git a/ir/src/conv/val.rs b/ir/src/conv/val.rs index d3f40c5..25e4cea 100644 --- a/ir/src/conv/val.rs +++ b/ir/src/conv/val.rs @@ -16,11 +16,16 @@ pub fn get_variable_ref(lctx: &IRLocalContext, ctx: &IRContext, hash: u64) -> Po match lctx.get_variable(hash) { Ok(v) => return Ok(IRValueRef::from_pointer(IRPointer::clone(v))), - Err(_) => return Err(PositionlessError::new(&format!("Cannot find variable with hash {} in the current context", hash))) + Err(_) => {} }; + + match lctx.get_argument(hash) { + Ok(v) => return Ok(IRValueRef::from_val(IRValue::clone(v))), + Err(_) => return Err(PositionlessError::new(&format!("Cannot find variable with hash {} in the current context", hash))) + } } -pub fn parse_ir_value<'a>(lctx: Option<&IRLocalContext>, ctx: &IRContext, node: Box, left: Option, in_var: bool) -> PositionlessResult { +pub fn parse_ir_value<'a>(f: Option<&IRFunction>, ctx: &IRContext, node: Box, left: Option, in_var: bool) -> PositionlessResult { match node.as_ref() { ASTTreeNode::IntegerLit { val: v, hash} => { let t = ctx.type_storage.get(*hash); @@ -62,18 +67,18 @@ pub fn parse_ir_value<'a>(lctx: Option<&IRLocalContext>, ctx: &IRContext, node: return Ok(IRValueRef::from_pointer(ptr)); } - let var = get_variable_ref(&lctx.unwrap(), ctx, e.hash)?; + let var = get_variable_ref(&f.unwrap().lctx, ctx, e.hash)?; return Ok(var); }, ASTTreeNode::FunctionCall { func, args } => { - if lctx.is_none() { + if f.is_none() { return Err(PositionlessError::new("Cannot use function calls outside of a function!")) } - let k = parse_ir_function_call(ctx, lctx.unwrap(), node, left, in_var)?; + let k = parse_ir_function_call(ctx, f.unwrap(), node, left, in_var)?; if k.is_none() { return Err(PositionlessError::new("Function call returns void! cannot use as a value!")); @@ -83,8 +88,8 @@ pub fn parse_ir_value<'a>(lctx: Option<&IRLocalContext>, ctx: &IRContext, node: }, ASTTreeNode::MathResult { lval, rval, operator, assigns } => { - let left = parse_ir_value(lctx, ctx, lval.clone(), None, in_var)?; - let right = parse_ir_value(lctx, ctx, rval.clone(), None, in_var)?; + let left = parse_ir_value(f, ctx, lval.clone(), None, in_var)?; + let right = parse_ir_value(f, ctx, rval.clone(), None, in_var)?; let t = left.get_type(); @@ -113,8 +118,8 @@ pub fn parse_ir_value<'a>(lctx: Option<&IRLocalContext>, ctx: &IRContext, node: }, ASTTreeNode::OperatorBasedConditionMember { lval, rval, operator } => { - let l_val = parse_ir_value(lctx, ctx, lval.clone(), None, in_var)?; - let r_val = parse_ir_value(lctx, ctx, rval.clone(), None, in_var)?; + let l_val = parse_ir_value(f, ctx, lval.clone(), None, in_var)?; + let r_val = parse_ir_value(f, ctx, rval.clone(), None, in_var)?; let cmp = make_bool_cmp_int(ctx, l_val, r_val, operator.clone())?; @@ -122,7 +127,7 @@ pub fn parse_ir_value<'a>(lctx: Option<&IRLocalContext>, ctx: &IRContext, node: }, ASTTreeNode::BooleanBasedConditionMember { val, negate } => { - let v = parse_ir_value(lctx, ctx, val.clone(), None, in_var)?; + let v = parse_ir_value(f, ctx, val.clone(), None, in_var)?; if *negate { return Ok(IRValueRef::from_val(make_bool_xor(ctx, v)?)) @@ -132,17 +137,17 @@ pub fn parse_ir_value<'a>(lctx: Option<&IRLocalContext>, ctx: &IRContext, node: } ASTTreeNode::StructLRFunction { l, r } => { - let l_val = parse_ir_value(lctx, ctx, l.clone(), None, in_var)?; + let l_val = parse_ir_value(f, ctx, l.clone(), None, in_var)?; let l_ptr = l_val.as_pointer()?; - return parse_ir_value(lctx, ctx, r.clone(), Some(l_ptr), in_var); + return parse_ir_value(f, ctx, r.clone(), Some(l_ptr), in_var); }, ASTTreeNode::StructLRVariable { l, r } => { - let l_val = parse_ir_value(lctx, ctx, l.clone(), None, in_var)?; + let l_val = parse_ir_value(f, ctx, l.clone(), None, in_var)?; let l_ptr = l_val.as_pointer()?; - return parse_ir_value(lctx, ctx, r.clone(), Some(l_ptr), in_var); + return parse_ir_value(f, ctx, r.clone(), Some(l_ptr), in_var); } _ => return Err(PositionlessError::new("The given node cannot be parsed as a value!")) diff --git a/ir/src/ctx.rs b/ir/src/ctx.rs index 20dcdae..61bf206 100644 --- a/ir/src/ctx.rs +++ b/ir/src/ctx.rs @@ -5,7 +5,7 @@ use std::{collections::HashMap, mem::transmute, ops::{Add, Deref, DerefMut}, rc: use commons::{err::{PositionlessError, PositionlessResult}, utils::map::HashedMap}; use inkwell::{AddressSpace, builder::Builder, context::Context, module::Module, types::{PointerType, VoidType}}; -use crate::{irstruct::{funcs::IRFunction, ptr::IRPointer, staticvars::IRStaticVariable}, types::storage::IRTypeStorage, utils::{LateInit, SelfHash}}; +use crate::{irstruct::{funcs::IRFunction, ptr::IRPointer, staticvars::IRStaticVariable}, types::storage::IRTypeStorage, utils::{LateInit, SelfHash}, values::IRValue}; /// The global IR context. /// Basically holds anything related to the current IR compilation (eg: functions, types, global vars) @@ -66,7 +66,7 @@ impl IRContext { return self.functions.get(&SelfHash { hash }).is_some() || self.static_vars.get(&SelfHash {hash}).is_some() || self.type_storage.get(hash).is_some(); } - pub fn get_funtion(&self, hash: u64) -> PositionlessResult> { + pub fn get_function(&self, hash: u64) -> PositionlessResult> { return match self.functions.get(&SelfHash { hash }) { Some(v) => Ok(v.clone()), None => Err(PositionlessError::new(&format!("Invalid function name! Got hash {}", hash))) @@ -93,12 +93,13 @@ pub struct LocalIRVariable { /// Holds anything held and created in the given body (eg: vars). pub struct IRLocalContext { pub vars: HashedMap, + pub arguments: HashedMap, pub current_depth: i64, // Starts at 0 where 0 is function body } impl IRLocalContext { pub fn new() -> Self { - return IRLocalContext { vars: HashedMap::new(0), current_depth: 0 } + return IRLocalContext { vars: HashedMap::new(0), arguments: HashedMap::new(0), current_depth: 0 } } /// Attempts to add a variable in the current local context. Will return an error if the operation is impossible @@ -111,6 +112,15 @@ impl IRLocalContext { return Ok(true); } + pub fn add_argument(&mut self, hash: u64, val: IRValue) -> PositionlessResult { + if self.arguments.get(hash).is_some() { + return Err(PositionlessError::new(&format!("Argument named {} is already present in the current scope!", hash))) + } + + self.arguments.put(hash, val); + return Ok(true); + } + pub fn get_variable(&self, hash: u64) -> PositionlessResult<&IRPointer> { return match self.vars.get(hash) { Some(v) => Ok(&v.ptr), @@ -118,6 +128,13 @@ impl IRLocalContext { }; } + pub fn get_argument(&self, hash: u64) -> PositionlessResult<&IRValue> { + return match self.arguments.get(hash) { + Some(v) => Ok(v), + None => return Err(PositionlessError::new(&format!("Invalid argument hash {}", hash))) + } + } + pub fn increment_body_depth(&mut self) { self.current_depth += 1; } diff --git a/ir/src/irstruct/funcs.rs b/ir/src/irstruct/funcs.rs index 18b205d..1c54b4a 100644 --- a/ir/src/irstruct/funcs.rs +++ b/ir/src/irstruct/funcs.rs @@ -11,8 +11,9 @@ pub struct IRFunction { pub inkwell_func: FunctionValue<'static>, pub ret_type: Option>, - args: Vec>, + pub args: Vec<(Rc, u64)>, name: String, + pub hash: u64, pub lctx: IRLocalContext, @@ -20,22 +21,22 @@ pub struct IRFunction { } impl IRFunction { - pub fn new(ctx: &IRContext, name: String, func: FunctionValue, ret_type: Option>, args: Vec>) -> Self { + pub fn new(ctx: &IRContext, name: String, hash: u64, func: FunctionValue, ret_type: Option>, args: Vec<(Rc, u64)>) -> Self { let block = ctx.inkwell_ctx.append_basic_block(func, "entry"); - return IRFunction { owned: ctx.inkwell_ctx.clone(), inkwell_func: unsafe { transmute(func)}, ret_type, args, name, entry: Some(unsafe { transmute(block) }), lctx: IRLocalContext::new().into() } + return IRFunction { owned: ctx.inkwell_ctx.clone(), inkwell_func: unsafe { transmute(func)}, ret_type, args, name, hash, entry: Some(unsafe { transmute(block) }), lctx: IRLocalContext::new().into() } } - pub fn new_shadow(ctx: &IRContext, name: String, func: FunctionValue, ret_type: Option>, args: Vec>) -> Self { - return IRFunction { owned: ctx.inkwell_ctx.clone(), inkwell_func: unsafe { transmute(func)}, ret_type, args, name, entry: None, lctx: IRLocalContext::new().into() } + pub fn new_shadow(ctx: &IRContext, name: String, hash: u64, func: FunctionValue, ret_type: Option>, args: Vec<(Rc, u64)>) -> Self { + return IRFunction { owned: ctx.inkwell_ctx.clone(), inkwell_func: unsafe { transmute(func)}, ret_type, args, name, hash, entry: None, lctx: IRLocalContext::new().into() } } - pub fn create_shadow(ctx: &IRContext, name: String, module: &Module, ret_type: Option>, args: Vec>) -> PositionlessResult { + pub fn create_shadow(ctx: &IRContext, name: String, hash: u64, module: &Module, ret_type: Option>, args: Vec<(Rc, u64)>) -> PositionlessResult { let mut kargs = vec![]; for k in &args { - kargs.push(*k.get_inkwell_base_metadatatype()?); + kargs.push(*k.0.get_inkwell_base_metadatatype()?); } let t = match &ret_type { @@ -45,14 +46,14 @@ impl IRFunction { let func = module.add_function(&name, t, None); - return Ok(IRFunction::new_shadow(ctx, name, func, ret_type, args)); + return Ok(IRFunction::new_shadow(ctx, name, hash, func, ret_type, args)); } - pub fn create(ctx: &IRContext, name: String, module: &Module, ret_type: Option>, args: Vec>) -> PositionlessResult { + pub fn create(ctx: &IRContext, name: String, hash: u64, module: &Module, ret_type: Option>, args: Vec<(Rc, u64)>) -> PositionlessResult { let mut kargs = vec![]; for k in &args { - kargs.push(*k.get_inkwell_base_metadatatype()?); + kargs.push(*k.0.get_inkwell_base_metadatatype()?); } let t = match &ret_type { @@ -62,7 +63,7 @@ impl IRFunction { let func = module.add_function(&name, t, None); - return Ok(IRFunction::new(ctx, name, func, ret_type, args)); + return Ok(IRFunction::new(ctx, name, hash, func, ret_type, args)); } pub fn call(&self, ctx: &IRContext, args: Vec, grab_return: bool) -> PositionlessResult> { @@ -117,7 +118,7 @@ impl IRFunction { } pub fn get_nth_arg_int(&self, ind: u32) -> PositionlessResult { - if !self.args[ind as usize].is_numeric_type() { + if !self.args[ind as usize].0.is_numeric_type() { return Err(PositionlessError::new("Tried getting nth argument but given argument's type isn't numeric!")); } diff --git a/ir/src/refs.rs b/ir/src/refs.rs index 29dfe05..bfd0e58 100644 --- a/ir/src/refs.rs +++ b/ir/src/refs.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use commons::err::{PositionlessError, PositionlessResult}; use inkwell::{builder::Builder, types::{AnyTypeEnum, BasicTypeEnum}, values::PointerValue}; -use crate::{ctx::IRContext, irstruct::{ptr::IRPointer, staticvars::IRStaticVariable}, types::typing::{IRType, OwnedPointerValue}, values::IRValue}; +use crate::{ctx::IRContext, irstruct::{funcs::IRFunction, ptr::IRPointer, staticvars::IRStaticVariable}, types::typing::{IRType, OwnedPointerValue}, values::IRValue}; pub enum IRValueRefKind { Ptr(Rc, IRPointer), @@ -52,7 +52,7 @@ impl IRValueRef { IRValueRefKind::Global(t, global) => { Ok(IRValue::new(global.as_val()?, t.clone())) - }, + } _ => return Err(PositionlessError::new("Cannot use obtain on said IR value type!")) }