diff --git a/.gitignore b/.gitignore index 9f97022..9340bbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -target/ \ No newline at end of file +target/ +*.ll + +out +out.* \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index f3bf43f..9aab5f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,8 @@ version = "0.1.0" dependencies = [ "commons", "inkwell", + "lexer", + "parser", ] [[package]] @@ -171,6 +173,8 @@ dependencies = [ name = "test-main" version = "0.1.0" dependencies = [ + "inkwell", + "ir", "lexer", "parser", ] diff --git a/ast.txt b/ast.txt new file mode 100644 index 0000000..4da05e4 --- /dev/null +++ b/ast.txt @@ -0,0 +1,198 @@ +Calling function call parsing on kwd abc +Tok: Dot +Tok: Var +Calling function call parsing on kwd abs +Tok: ComparingOperator( + HigherEqual, +) +Calling function call parsing on kwd def +Tok: If +Ok( + ParserCtx { + map: { + "main": FunctionDeclaration { + func_name: WithHash { + val: "main", + hash: 14467718814232352107, + }, + args: [ + FunctionDeclarationArgument { + name: WithHash { + val: "myTestArg", + hash: 14273091031817137443, + }, + argument_type: 11583643502875509928, + }, + FunctionDeclarationArgument { + name: WithHash { + val: "age", + hash: 11942856677619760021, + }, + argument_type: 11583643502875509928, + }, + ], + body: [ + VarDeclaration { + var_name: WithHash { + val: "test", + hash: 14402189752926126668, + }, + var_type: 11583643502875509928, + value: Some( + StructLRVariable { + l: StructLRFunction { + l: VariableReference( + WithHash { + val: "test", + hash: 14402189752926126668, + }, + ), + r: FunctionCall { + func: WithHash { + val: "abc", + hash: 17224545590736200989, + }, + args: [], + }, + }, + r: VariableReference( + WithHash { + val: "test", + hash: 14402189752926126668, + }, + ), + }, + ), + }, + VarDeclaration { + var_name: WithHash { + val: "test2", + hash: 12720938724704517959, + }, + var_type: 11583643502875509928, + value: Some( + OperatorBasedConditionMember { + lval: StructLRFunction { + l: VariableReference( + WithHash { + val: "test", + hash: 14402189752926126668, + }, + ), + r: FunctionCall { + func: WithHash { + val: "abs", + hash: 10550511239753159873, + }, + args: [], + }, + }, + rval: StructLRFunction { + l: VariableReference( + WithHash { + val: "test", + hash: 14402189752926126668, + }, + ), + r: FunctionCall { + func: WithHash { + val: "def", + hash: 9341360902760800985, + }, + args: [], + }, + }, + operator: HigherEqual, + }, + ), + }, + IfStatement { + cond: OperatorBasedConditionMember { + lval: VariableReference( + WithHash { + val: "test2", + hash: 12720938724704517959, + }, + ), + rval: VariableReference( + WithHash { + val: "test", + hash: 14402189752926126668, + }, + ), + operator: HigherEqual, + }, + body: [ + VarDeclaration { + var_name: WithHash { + val: "age", + hash: 11942856677619760021, + }, + var_type: 11583643502875509928, + value: Some( + IntegerLit( + 0, + ), + ), + }, + ], + else_statement: Some( + IfElseStatement { + cond: Some( + OperatorBasedConditionMember { + lval: VariableReference( + WithHash { + val: "test2", + hash: 12720938724704517959, + }, + ), + rval: VariableReference( + WithHash { + val: "test", + hash: 14402189752926126668, + }, + ), + operator: Equal, + }, + ), + body: [ + VarDeclaration { + var_name: WithHash { + val: "age", + hash: 11942856677619760021, + }, + var_type: 11583643502875509928, + value: Some( + IntegerLit( + 63, + ), + ), + }, + ], + else_statement: Some( + ElseStatement { + body: [ + VarDeclaration { + var_name: WithHash { + val: "age", + hash: 11942856677619760021, + }, + var_type: 11583643502875509928, + value: Some( + IntegerLit( + 68, + ), + ), + }, + ], + }, + ), + }, + ), + }, + ], + returnType: None, + }, + }, + }, +) \ No newline at end of file diff --git a/commons/src/err/mod.rs b/commons/src/err/mod.rs index 4777486..1bb477d 100644 --- a/commons/src/err/mod.rs +++ b/commons/src/err/mod.rs @@ -9,6 +9,7 @@ use colored::Colorize; use crate::Position; pub type PositionedResult = Result; +pub type PositionlessResult = Result; /// An error that has a position #[derive(Debug)] @@ -18,6 +19,21 @@ pub struct PositionedError { pub reason: String } +#[derive(Debug)] +pub struct PositionlessError { + pub reason: String +} + +impl PositionlessError { + pub fn new(reason: &str) -> Self { + let err = PositionlessError { reason: String::from(reason) }; + + println!("{}", err); + + return err; + } +} + impl PositionedError { pub fn new(start: Position, end: Position, reason: String) -> Self { @@ -48,6 +64,16 @@ impl fmt::Display for PositionedError { writeln!(f, "")?; writeln!(f, "{}", self.reason.bright_red())?; + Ok(()) + } +} + +impl fmt::Display for PositionlessError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{} at ??:??", "ERR".bright_red().bold())?; + + writeln!(f, "{}", self.reason.bright_red())?; + Ok(()) } } \ No newline at end of file diff --git a/commons/src/utils/map.rs b/commons/src/utils/map.rs index 24501b1..ece2e95 100644 --- a/commons/src/utils/map.rs +++ b/commons/src/utils/map.rs @@ -7,6 +7,7 @@ const BUCKET_TOMBSTONE: u8 = 0x01; const MAP_LOAD_FACTOR: f64 = 0.85; +#[derive(Debug)] pub struct HashedMap { meta: Vec, buckets: Vec>, @@ -34,6 +35,9 @@ impl HashedMap { } pub fn put(&mut self, key: u64, val: V) { + + println!("Hash {}", key); + let index = self.index_from_hash(key); let fingerprint = self.fingerprint_from_hash(key); @@ -114,6 +118,21 @@ impl HashedMap { return None; } + pub fn entries(&self) -> Vec<&(u64, V)> { + let mut vec = Vec::new(); + + for i in 0..self.capacity { + if self.meta[i] == BUCKET_EMPTY || self.meta[i] == BUCKET_TOMBSTONE { + continue; + } + + unsafe { vec.push(self.buckets[i].assume_init_ref()); } + } + + return vec; + } + + pub fn erase(&mut self, key: u64) { let index = self.index_from_hash(key); let fingerprint = self.fingerprint_from_hash(key); diff --git a/commons/src/utils/mod.rs b/commons/src/utils/mod.rs index 36c02b6..7b7c82b 100644 --- a/commons/src/utils/mod.rs +++ b/commons/src/utils/mod.rs @@ -1 +1,2 @@ -pub mod map; \ No newline at end of file +pub mod map; +pub mod num; \ No newline at end of file diff --git a/commons/src/utils/num.rs b/commons/src/utils/num.rs new file mode 100644 index 0000000..f819531 --- /dev/null +++ b/commons/src/utils/num.rs @@ -0,0 +1,19 @@ +pub fn get_signed_highbound(bits: usize) -> i128 { + return 2_i128.pow(bits as u32 - 1) - 1; +} + +pub fn get_signed_lowbound(bits: usize) -> i128 { + return 0 - 2_i128.pow(bits as u32 - 1) - 1; +} + +pub fn get_unsigned_highbound(bits: usize) -> i128 { + return 2_i128.pow(bits as u32) - 1; +} + +pub fn can_num_fit_inbits_signed(bits: usize, num: i128) -> bool { + return num >= get_signed_lowbound(bits) && num <= get_signed_highbound(bits); +} + +pub fn can_num_fit_inbits_unsigned(bits: usize, num: i128) -> bool { + return num >= 0 && num <= get_unsigned_highbound(bits); +} diff --git a/examples/sample.qf b/examples/sample.qf new file mode 100644 index 0000000..4b04418 --- /dev/null +++ b/examples/sample.qf @@ -0,0 +1,7 @@ +static staticstr bobby = "Hellossssss" + +shadowfunc printf(ptr str_pointer) + +func main() { + printf(bobby) +} \ No newline at end of file diff --git a/ir/Cargo.toml b/ir/Cargo.toml index db53bab..7b48c9a 100644 --- a/ir/Cargo.toml +++ b/ir/Cargo.toml @@ -5,4 +5,6 @@ edition = "2024" [dependencies] inkwell = { version = "0.8.0", features = ["llvm21-1"]} -commons = { path = "../commons" } \ No newline at end of file +commons = { path = "../commons" } +lexer = { path = "../lexer" } +parser = { path = "../parser" } \ No newline at end of file diff --git a/ir/src/bools.rs b/ir/src/bools.rs new file mode 100644 index 0000000..0c64507 --- /dev/null +++ b/ir/src/bools.rs @@ -0,0 +1,80 @@ +//! Everything related to boolean handling and generation + +use commons::err::{PositionlessError, PositionlessResult}; +use inkwell::IntPredicate; +use lexer::toks::comp::ComparingOperator; + +use crate::{ctx::IRContext, refs::IRValueRef, types::{BOOL_TYPE_HASH, typing::{OwnedIntType, OwnedIntValue, OwnedValueEnum}}, values::IRValue}; + +pub fn make_bool_xor(ctx: &IRContext, b: IRValueRef) -> PositionlessResult { + let val = b.obtain(ctx)?; + let inkwell = match val.obtain_as_bool() { + Some(v) => v, + None => return Err(PositionlessError::new("Cannot obtain boolean from the provided boolean value reference!")) + }; + + let bool_t = match ctx.type_storage.get(BOOL_TYPE_HASH) { + Some(v) => v, + None => return Err(PositionlessError::new("Cannot find boolean type in type storage!")) + }; + + let one = bool_t.get_inkwell_inttype()?.const_int(1, false); + + let xor_v = match ctx.builder.build_xor(inkwell.inner, one, "xor_") { + Ok(v) => v, + Err(_) => return Err(PositionlessError::new("build_xor failed!")) + }; + + return Ok(IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx, xor_v.into()), bool_t)); +} + +pub fn make_bool_cmp_int(ctx: &IRContext, a: IRValueRef, b: IRValueRef, comp: ComparingOperator) -> PositionlessResult { + let a_val = a.obtain(ctx)?; + let b_val = b.obtain(ctx)?; + + let t = a_val.t.clone(); + + let a_int = match a_val.obtain_as_int(ctx, t.clone()) { + Some(v) => v, + None => return Err(PositionlessError::new("Value a wasn't an int when trying to use comp!")) + }; + + let b_int = match b_val.obtain_as_int(ctx, t.clone()) { + Some(v) => v, + None => return Err(PositionlessError::new("Value b wasn't an int when trying to use comp!")) + }; + + let predicate: IntPredicate; + + if t.is_signed() { + predicate = match comp { + ComparingOperator::Equal => IntPredicate::EQ, + ComparingOperator::NotEqual => IntPredicate::NE, + ComparingOperator::Higher => IntPredicate::SGT, + ComparingOperator::HigherEqual => IntPredicate::SGE, + ComparingOperator::Lower => IntPredicate::SLT, + ComparingOperator::LowerEqual => IntPredicate::SLE + }; + } else { + predicate = match comp { + ComparingOperator::Equal => IntPredicate::EQ, + ComparingOperator::NotEqual => IntPredicate::NE, + ComparingOperator::Higher => IntPredicate::ULT, + ComparingOperator::HigherEqual => IntPredicate::UGT, + ComparingOperator::Lower => IntPredicate::ULE, + ComparingOperator::LowerEqual => IntPredicate::UGE + } + } + + let cmp = match ctx.builder.build_int_compare(predicate, *a_int, *b_int, "_cmp") { + Ok(v) => v, + Err(_) => return Err(PositionlessError::new("build_int_compare failed!")) + }; + + let bool_t = match ctx.type_storage.get(BOOL_TYPE_HASH) { + Some(v) => v, + None => return Err(PositionlessError::new("boolean type wasn't found!")) + }; + + return Ok(IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx,cmp.into()), bool_t)); +} \ No newline at end of file diff --git a/ir/src/conv/control.rs b/ir/src/conv/control.rs new file mode 100644 index 0000000..67e80d6 --- /dev/null +++ b/ir/src/conv/control.rs @@ -0,0 +1,143 @@ +use std::sync::Condvar; + +use commons::err::{PositionlessError, PositionlessResult}; +use parser::ast::tree::ASTTreeNode; + +use crate::{conv::{self, func::{parse_ir_body, parse_ir_function_body_member}, val::parse_ir_value}, ctx::{IRContext, IRLocalContext}, irstruct::funcs::IRFunction, types::BOOL_TYPE_HASH}; + +pub fn parse_if_statement_ir(func: &mut IRFunction, ctx: &IRContext, node: Box) -> PositionlessResult { + if let ASTTreeNode::IfStatement { cond, body, branches, depth } = *node.clone() { + let mut ir_branches = vec![]; + + let initial_branch = ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "ifbranch_then"); + + let b = branches.clone(); + + for branch in b { + match *branch { + ASTTreeNode::IfElseStatement { cond, body } => { + ir_branches.push(ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "ifelse_condition")); + ir_branches.push(ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "ifelse_then")); + }, + + ASTTreeNode::ElseStatement { body } => { + ir_branches.push(ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "else_body")); + } + + _ => {} + } + } + + ir_branches.push(ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "out")); + + let first_cond = parse_ir_value(Some(&func.lctx), ctx, cond, None, false)?; + + let bool_type = ctx.type_storage.get(BOOL_TYPE_HASH).unwrap(); + + let int = match first_cond.obtain(ctx)?.obtain_as_bool() { + Some(v) => *v, + None => return Err(PositionlessError::new("Cannot cast first cond as int")) + }; + + match ctx.builder.build_conditional_branch(int, initial_branch, ir_branches[0]) { + Ok(_) => {}, + Err(_) => return Err(PositionlessError::new("build_conditional_branch initial failed!")) + }; + + ctx.builder.position_at_end(initial_branch); + + func.lctx.increment_body_depth(); + parse_ir_body(ctx, func, body, true)?; + + let mut ind = 0; + for branch in branches { + match *branch { + ASTTreeNode::IfElseStatement { cond, body } => { + ctx.builder.position_at_end(ir_branches[ind]); + + let cond_val = parse_ir_value(Some(&func.lctx), ctx, cond.unwrap(), None, false)?; + + let int_cond_val = match cond_val.obtain(ctx)?.obtain_as_bool() { + Some(v) => *v, + None => return Err(PositionlessError::new("Cannot cast condition as int!")) + }; + + match ctx.builder.build_conditional_branch(int_cond_val, ir_branches[ind + 1], ir_branches[ind + 2]) { + Ok(_) => {}, + Err(_) => return Err(PositionlessError::new("build_conditional_branch nested failed!")) + } + + ctx.builder.position_at_end(ir_branches[ind + 1]); + + func.lctx.increment_body_depth(); + + parse_ir_body(ctx, func, body, true)?; + + match ctx.builder.build_unconditional_branch(ir_branches[ir_branches.len() - 1]) { + Ok(_) => {}, + Err(_) => return Err(PositionlessError::new("build_conditional_branch nested failed!")) + } + + ind += 2; + }, + + ASTTreeNode::ElseStatement { body } => { + ctx.builder.position_at_end(ir_branches[ind]); + + func.lctx.increment_body_depth(); + parse_ir_body(ctx, func, body, true)?; + + match ctx.builder.build_unconditional_branch(ir_branches[ir_branches.len() - 1]) { + Ok(_) => {}, + Err(_) => return Err(PositionlessError::new("build_conditional_branch nested failed!")) + } + }, + + _ => {} + } + } + + ctx.builder.position_at_end(ir_branches[ir_branches.len() - 1]); + + return Ok(true); + } + + return Err(PositionlessError::new(&format!("Cannot parse if statement as this is not an if! Instead got {:#?}", node.clone()))); +} + +pub fn parse_for_statement_ir(func: &mut IRFunction, ctx: &IRContext, node: Box) -> PositionlessResult { + if let ASTTreeNode::ForBlock { initial_state, cond, increment, body } = *node { + let for_cond_block = ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "for_cond"); + let for_body_block = ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "for_inner"); + let post_block = ctx.inkwell_ctx.append_basic_block(func.inkwell_func, "for_out"); + + parse_ir_function_body_member(ctx, func, initial_state)?; + + println!("Post initial state"); + + ctx.builder.build_unconditional_branch(for_cond_block); + + ctx.builder.position_at_end(for_cond_block); + + 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_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); + + ctx.builder.position_at_end(for_body_block); + + parse_ir_body(ctx, func, body, false)?; + + parse_ir_function_body_member(ctx, func, increment)?; + + ctx.builder.build_unconditional_branch(for_cond_block); + + ctx.builder.position_at_end(post_block); + return Ok(true); + } + + + return Err(PositionlessError::new("Cannot parse for statement as this is not an for!")); +} \ No newline at end of file diff --git a/ir/src/conv/func.rs b/ir/src/conv/func.rs new file mode 100644 index 0000000..5450ba1 --- /dev/null +++ b/ir/src/conv/func.rs @@ -0,0 +1,175 @@ +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}; + +pub fn parse_ir_shadow_function_decl(ctx: &mut IRContext, node: Box) -> PositionlessResult> { + if let ASTTreeNode::ShadowFunctionDeclaration { func_name, args, returnType } = *node { + let return_type = match returnType { + Some(h) => ctx.type_storage.get(h), + None => None + }; + + let mut arguments: Vec> = vec![]; + + for k in args { + let t = match ctx.type_storage.get(k.argument_type) { + Some(v) => v, + None => return Err(PositionlessError::new(&format!("Cannot get type with hash {} for argument {}!", k.argument_type, k.name.val))) + }; + + arguments.push(t); + } + + let func = IRFunction::create_shadow(ctx, func_name.val.clone(), &ctx.module, return_type, arguments)?; + + ctx.add_function(func_name.hash, func)?; + + return Ok(ctx.get_funtion(func_name.hash)?); + } + + return Err(PositionlessError::new("Cannot parse ir shadow funtion decl as the node is incompatible!")); +} + +pub fn parse_ir_function_decl(ctx: &mut IRContext, node: Box) -> PositionlessResult> { + if let ASTTreeNode::FunctionDeclaration { func_name, args, body, returnType } = *node { + let return_type = match returnType { + Some(h) => ctx.type_storage.get(h), + None => None + }; + + let mut arguments: Vec> = vec![]; + + for k in args { + let t = match ctx.type_storage.get(k.argument_type) { + Some(v) => v, + None => return Err(PositionlessError::new(&format!("Cannot get type with hash {} for argument {}!", k.argument_type, k.name.val))) + }; + + arguments.push(t); + } + + let mut func = IRFunction::create(ctx, func_name.val, &ctx.module, return_type, arguments)?; + + func.prepare_body_filling(ctx); + parse_ir_body(ctx, &mut func, body, true)?; + + if func.ret_type.is_none() { + match ctx.builder.build_return(None) { + Ok(_) => {}, + Err(_) => return Err(PositionlessError::new("build_return on void failed!")) + }; + } + + ctx.add_function(func_name.hash, func); + + return ctx.get_funtion(func_name.hash); + } + + return Err(PositionlessError::new("Given node in parse_ir_function_decl wasn't a function decl!")); +} + +pub fn parse_ir_body(ctx: &IRContext, func: &mut IRFunction, nodes: Vec>, drop_body: bool) -> PositionlessResult { + for node in nodes { + parse_ir_function_body_member(ctx, func, node)?; + } + + if drop_body { + func.lctx.end_nested_body_depth(); + } + + return Ok(true); +} + +pub fn parse_ir_function_call(ctx: &IRContext, lctx: &IRLocalContext, node: Box, owner: Option, grab_result: bool) -> PositionlessResult> { + if let ASTTreeNode::FunctionCall { func, args } = *node { + let mut arguments = vec![]; + + if owner.as_ref().is_some() { + arguments.push(IRValueRef::from_pointer(owner.as_ref().unwrap().clone())); + } + + for v in args { + arguments.push(parse_ir_value(Some(lctx), ctx, v, None, false)?); + } + + let func = ctx.get_funtion(func.hash)?; + + let ret =func.call(ctx, arguments, grab_result)?; + + if !grab_result || ret.is_none() { + return Ok(None); + } + + return Ok(Some(IRValueRef::from_pointer(ret.unwrap()))); + } + + return Err(PositionlessError::new("Cannot parse ir function call as the node is not a function call")) +} + +pub fn parse_ir_function_body_member(ctx: &IRContext, func: &mut IRFunction, node: Box) -> PositionlessResult { + match *node { + ASTTreeNode::VarDeclaration { var_name, var_type, value } => { + let var_t = match ctx.type_storage.get(var_type) { + Some(v) => v, + None => return Err(PositionlessError::new(&format!("Cannot find variable type {} in type storage!", var_name.val))) + }; + + 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)?) + } else { + None + }; + + let ptr = IRPointer::create(ctx, var_name.val.clone(), var_t, initial)?; + + func.lctx.add_variable(var_name.hash, ptr)?; + + println!("Added lctx value: {} -> {}", var_name.val.clone(), var_name.hash); + + return Ok(true); + }, + + ASTTreeNode::StructLRFunction { .. } => { + parse_ir_value(Some(&func.lctx), ctx, node, None, false)?; + + return Ok(true) + }, + + ASTTreeNode::StructLRVariable { .. } => { + parse_ir_value(Some(&func.lctx), ctx, node, None, false)?; + + return Ok(true) + }, + + ASTTreeNode::FunctionCall { .. } => { + parse_ir_function_call(ctx, &func.lctx, node, None, false)?; + + return Ok(true) + + } + + ASTTreeNode::IfStatement { .. } => { + return parse_if_statement_ir(func, ctx, node); + }, + + ASTTreeNode::ForBlock { .. } => { + return parse_for_statement_ir(func, ctx, node); + } + + ASTTreeNode::MathResult { lval: _, rval: _ , operator: _, assigns } => { + if !assigns { + 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)?; + return Ok(true); + } + + _ => return Err(PositionlessError::new("Cannot parse said ASTNode as a function body member!")) + }; +} \ No newline at end of file diff --git a/ir/src/conv/mod.rs b/ir/src/conv/mod.rs new file mode 100644 index 0000000..cdf0956 --- /dev/null +++ b/ir/src/conv/mod.rs @@ -0,0 +1,65 @@ +//! Critical AST -> IR conversion code module + +use commons::err::{PositionlessError, PositionlessResult}; +use parser::ast::tree::ASTTreeNode; + +use crate::{conv::{func::{parse_ir_function_decl, parse_ir_shadow_function_decl}, structs::parse_ir_struct_decl, val::parse_ir_value}, ctx::IRContext, irstruct::staticvars::IRStaticVariable, types::STATICSTR_TYPE_HASH}; + +pub mod val; +pub mod func; +pub mod control; +pub mod structs; + +pub fn parse_ir_node_toplevel(ctx: &mut IRContext, node: Box) -> PositionlessResult { + match *node { + ASTTreeNode::StaticVariableDeclaration { name, var_type, val } => { + let val = parse_ir_value(None, ctx, val, None, true)?; + + let t = match ctx.type_storage.get(var_type) { + Some(v) => v, + None => return Err(PositionlessError::new(&format!("Cannot find type {}", var_type))) + }; + + if val.obtain_tempstr().is_ok() { + let str_type = ctx.type_storage.get(STATICSTR_TYPE_HASH).expect("staticstr type was not found!"); + + if !t.is_same(&str_type) { + return Err(PositionlessError::new("Expected type staticstr for static string variable!")) + } + + let st = IRStaticVariable::from_str(ctx, &val.obtain_tempstr().unwrap(), name.val, str_type)?; + + ctx.add_variable(name.hash, st)?; + } else { + let st = IRStaticVariable::from_val(name.val, t, val.obtain(ctx)?)?; + + ctx.add_variable(name.hash, st)?; + } + + return Ok(true) + + }, + + ASTTreeNode::FunctionDeclaration { .. } => { + parse_ir_function_decl(ctx, node)?; + + return Ok(true); + }, + + ASTTreeNode::ShadowFunctionDeclaration { .. } => { + parse_ir_shadow_function_decl(ctx, node)?; + + return Ok(true); + } + + ASTTreeNode::StructLayoutDeclaration { .. } => { + parse_ir_struct_decl(ctx, node)?; + + return Ok(true); + } + + _ => { + return Err(PositionlessError::new(&format!("Invalid AST node {:#?} for top-level IR conversion!", node))); + } + } +} \ No newline at end of file diff --git a/ir/src/conv/structs.rs b/ir/src/conv/structs.rs new file mode 100644 index 0000000..4a33167 --- /dev/null +++ b/ir/src/conv/structs.rs @@ -0,0 +1,44 @@ +use std::rc::Rc; + +use commons::err::{PositionlessError, PositionlessResult}; +use parser::ast::tree::ASTTreeNode; + +use crate::{ctx::IRContext, irstruct::structs::IRStructuredType, types::typing::IRType}; + +pub fn parse_ir_struct_decl(ctx: &mut IRContext, node: Box) -> PositionlessResult> { + if let ASTTreeNode::StructLayoutDeclaration { name, layout, members } = *node.clone() { + let mut fields: Vec<(u64, Rc)> = vec![]; + + for member in members { + if let ASTTreeNode::StructFieldMember { name, member_type } = *member { + let ir_type = match ctx.type_storage.get(member_type) { + Some(v) => v, + None => return Err(PositionlessError::new(&format!("Cannot find type with hash {}", member_type))) + }; + + fields.push((name.hash, ir_type)); + } + } + + let struct_type = Rc::new(IRStructuredType::new(ctx, name.val.clone(), layout, fields)?); + + + if layout { + ctx.type_storage.insert(name.hash, IRType::Layout(struct_type)); + } else { + ctx.type_storage.insert(name.hash, IRType::Struct(struct_type)); + } + + println!("name: {} -> {}", name.val.clone(), name.hash); + println!("opt: {}", ctx.type_storage.get(name.hash).is_none()); + + let res = match ctx.type_storage.get(name.hash) { + Some(v) => v, + None => return Err(PositionlessError::new("Cannot find newly registered struct type!")) + }; + + return Ok(res); + } + + return Err(PositionlessError::new("Cannot parse as struct declaration as this node isn't a type decl!")) +} \ No newline at end of file diff --git a/ir/src/conv/val.rs b/ir/src/conv/val.rs new file mode 100644 index 0000000..2afe113 --- /dev/null +++ b/ir/src/conv/val.rs @@ -0,0 +1,146 @@ +//! AST value -> IR value conversion + +use std::rc::Rc; + +use commons::err::{PositionlessError, PositionlessResult}; +use inkwell::values::BasicValue; +use parser::ast::tree::ASTTreeNode; + +use crate::{bools::{make_bool_cmp_int, make_bool_xor}, conv::func::parse_ir_function_call, ctx::{IRContext, IRLocalContext}, irstruct::{funcs::IRFunction, ptr::IRPointer, staticvars::IRStaticVariable}, math::make_math_operation, refs::IRValueRef, types::{POINTER_TYPE_HASH, SIGNED64_TYPE_HASH, typing::OwnedValueEnum}, values::IRValue}; + +pub fn get_variable_ref(lctx: &IRLocalContext, ctx: &IRContext, hash: u64) -> PositionlessResult { + match ctx.get_variable(hash) { + Ok(v) => return Ok(IRValueRef::from_static(v.clone())), + Err(_) => {} + }; + + 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))) + }; +} + +pub fn parse_ir_value<'a>(lctx: Option<&IRLocalContext>, ctx: &IRContext, node: Box, left: Option, in_var: bool) -> PositionlessResult { + match node.as_ref() { + ASTTreeNode::IntegerLit(v) => { + let t = ctx.type_storage.get(SIGNED64_TYPE_HASH); + + if !t.is_some() { + return Err(PositionlessError::new("Invalid type storage! si64 not found!")); + } + + return Ok(IRValueRef::from_val(IRValue::from_signed(ctx, t.unwrap(), *v as i128)?)); + }, + + ASTTreeNode::StringLit(v) => { + let t = ctx.type_storage.get(POINTER_TYPE_HASH); + + if !t.is_some() { + return Err(PositionlessError::new("Invalid type storage! pointer not found!")); + } + + + if in_var { + return Ok(IRValueRef::from_tempstr(v.clone())) + } + + let global = IRStaticVariable::from_str(&ctx, v, String::from("__string_literal"), t.unwrap())?; + + return Ok(IRValueRef::from_static(Rc::new(global))); + }, + + ASTTreeNode::VariableReference(e) => { + if left.as_ref().is_some() { + let struct_t = left.as_ref().unwrap().t.get_structured_type_descriptor()?; + + let ptr = struct_t.get_pointer_for_field_noref(ctx, left.unwrap(), e.hash)?; + + return Ok(IRValueRef::from_pointer(ptr)); + } + + let var = get_variable_ref(&lctx.unwrap(), ctx, e.hash)?; + + return Ok(var); + }, + + ASTTreeNode::FunctionCall { func, args } => { + + if lctx.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)?; + + if k.is_none() { + return Err(PositionlessError::new("Function call returns void! cannot use as a value!")); + } + + return Ok(k.unwrap()); + }, + + 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 t = left.get_type(); + + let l_val = match left.obtain(ctx)?.obtain_as_int(ctx, t.clone()) { + Some(v) => *v, + None => return Err(PositionlessError::new("lval on math operation wasn't a number!")), + }; + + let r_val = match right.obtain(ctx)?.obtain_as_int(ctx, t.clone()) { + Some(v) => *v, + None => return Err(PositionlessError::new("lval on math operation wasn't a number!")), + }; + + let out = make_math_operation(&ctx.builder, l_val, r_val, String::from("_math"), operator.clone())?; + + if *assigns { + if left.as_pointer().is_err() { + return Err(PositionlessError::new("Assignments were enabled on math operation while left value wasn't a variable!")); + } + + let ptr = left.as_pointer()?; + ptr.store(ctx, out.as_basic_value_enum()); + } + + return Ok(IRValueRef::from_val(IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx, out.into()), t))); + }, + + 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 cmp = make_bool_cmp_int(ctx, l_val, r_val, operator.clone())?; + + return Ok(IRValueRef::from_val(cmp)); + }, + + ASTTreeNode::BooleanBasedConditionMember { val, negate } => { + let v = parse_ir_value(lctx, ctx, val.clone(), None, in_var)?; + + if *negate { + return Ok(IRValueRef::from_val(make_bool_xor(ctx, v)?)) + } + + return Ok(v); + } + + ASTTreeNode::StructLRFunction { l, r } => { + let l_val = parse_ir_value(lctx, 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); + }, + + ASTTreeNode::StructLRVariable { l, r } => { + let l_val = parse_ir_value(lctx, 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 Err(PositionlessError::new("The given node cannot be parsed as a value!")) + } +} \ No newline at end of file diff --git a/ir/src/ctx.rs b/ir/src/ctx.rs new file mode 100644 index 0000000..20dcdae --- /dev/null +++ b/ir/src/ctx.rs @@ -0,0 +1,155 @@ +//! IR context related code + +use std::{collections::HashMap, mem::transmute, ops::{Add, Deref, DerefMut}, rc::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}}; + +/// The global IR context. +/// Basically holds anything related to the current IR compilation (eg: functions, types, global vars) +pub struct IRContext { + pub inkwell_ctx: Rc, + pub builder: Builder<'static>, + pub ptr_type: PointerType<'static>, + pub void_type: VoidType<'static>, + + pub module: Module<'static>, + + pub type_storage: LateInit, + + pub functions: HashMap>, + pub static_vars: HashMap> +} + +impl IRContext { + pub fn new(ctx: Rc) -> Self { + + let ptr_type = unsafe { transmute::>(ctx.ptr_type(AddressSpace::from(0))) }; + let void_type = unsafe { transmute::>(ctx.void_type()) }; + let module = unsafe { transmute::>(ctx.create_module("quickfall_module")) }; + + let mut ir = IRContext { + inkwell_ctx: ctx.clone(), + builder: unsafe { transmute::>(ctx.create_builder()) }, + ptr_type, + functions: HashMap::new(), + static_vars: HashMap::new(), + type_storage: LateInit::new(), + void_type, + module + }; + + ir.type_storage.fill(IRTypeStorage::new(&ir)); + + return ir; + } + + pub fn add_variable(&mut self, hash: u64, var: IRStaticVariable) -> PositionlessResult { + if self.is_key_taken(hash) { + return Err(PositionlessError::new("There already is an element named like this!")); + } + + self.static_vars.insert(SelfHash { hash }, Rc::new(var)); + return Ok(true); + } + + pub fn get_variable(&self, hash: u64) -> PositionlessResult> { + return match self.static_vars.get(&SelfHash { hash }) { + Some(v) => Ok(v.clone()), + None => return Err(PositionlessError::new("Invalid variable name")) + }; + } + + pub fn is_key_taken(&self, hash: u64) -> bool { + 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> { + return match self.functions.get(&SelfHash { hash }) { + Some(v) => Ok(v.clone()), + None => Err(PositionlessError::new(&format!("Invalid function name! Got hash {}", hash))) + } + } + + pub fn add_function(&mut self, hash: u64, func: IRFunction) -> PositionlessResult { + if self.is_key_taken(hash) { + return Err(PositionlessError::new("There already is an element named like this!")); + } + + self.functions.insert(SelfHash { hash }, Rc::new(func)); + return Ok(true); + } + +} + +pub struct LocalIRVariable { + pub ptr: IRPointer, + pub depth: i64 // Depth is depth in body. +} + +/// The local IR context. +/// Holds anything held and created in the given body (eg: vars). +pub struct IRLocalContext { + pub vars: 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 } + } + + /// Attempts to add a variable in the current local context. Will return an error if the operation is impossible + pub fn add_variable(&mut self, hash: u64, var: IRPointer) -> PositionlessResult { + if self.vars.get(hash).is_some() { + return Err(PositionlessError::new(&format!("Variable named {} is already registered in the current context.", hash))); + } + + self.vars.put(hash, LocalIRVariable { ptr: var, depth: self.current_depth }); + return Ok(true); + } + + pub fn get_variable(&self, hash: u64) -> PositionlessResult<&IRPointer> { + return match self.vars.get(hash) { + Some(v) => Ok(&v.ptr), + None => return Err(PositionlessError::new(&format!("Invalid variable hash {}", hash))) + }; + } + + pub fn increment_body_depth(&mut self) { + self.current_depth += 1; + } + + /// Ends the current nested body. Is responsible for removing non-valid variable indices + /// Example: + /// ``` + /// func test() { + /// // body of depth 0 starts + /// if(true) { + /// // body of depth 1 starts + /// // body of depth 1 ends + /// } + /// + /// // body of depth 0 ends + /// } + /// ``` + pub fn end_nested_body_depth(&mut self) { + self.current_depth -= 1; + + let mut hashToRemove: Vec = vec![]; + + for entry in self.vars.entries() { + if entry.1.depth > self.current_depth { + println!("Dropping variable in lctx with hash {}", entry.0); + hashToRemove.push(entry.0); + } + } + + for hash in hashToRemove { + self.vars.erase(hash); + } + } + +} \ No newline at end of file diff --git a/ir/src/irstruct/funcs.rs b/ir/src/irstruct/funcs.rs new file mode 100644 index 0000000..18b205d --- /dev/null +++ b/ir/src/irstruct/funcs.rs @@ -0,0 +1,128 @@ +use std::{cell::RefCell, mem::transmute, ops::{Deref, DerefMut}, rc::Rc}; + +use commons::err::{PositionedError, PositionlessError, PositionlessResult}; +use inkwell::{basic_block::BasicBlock, builder::Builder, context::Context, module::Module, types::BasicType, values::{BasicValueEnum, FunctionValue, IntValue}}; + +use crate::{ctx::{IRContext, IRLocalContext}, irstruct::ptr::IRPointer, refs::IRValueRef, types::typing::{IRType, OwnedIntValue, OwnedValueEnum}, values::IRValue}; + + +pub struct IRFunction { + pub owned: Rc, + + pub inkwell_func: FunctionValue<'static>, + pub ret_type: Option>, + args: Vec>, + name: String, + + pub lctx: IRLocalContext, + + entry: Option> +} + +impl IRFunction { + pub fn new(ctx: &IRContext, name: String, func: FunctionValue, ret_type: Option>, args: Vec>) -> 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() } + } + + 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 create_shadow(ctx: &IRContext, name: String, module: &Module, ret_type: Option>, args: Vec>) -> PositionlessResult { + let mut kargs = vec![]; + + for k in &args { + kargs.push(*k.get_inkwell_base_metadatatype()?); + } + + let t = match &ret_type { + Some(ret) => ret.get_inkwell_basetype()?.fn_type(&kargs, false), + None => ctx.void_type.fn_type(&kargs, false) + }; + + let func = module.add_function(&name, t, None); + + return Ok(IRFunction::new_shadow(ctx, name, func, ret_type, args)); + } + + pub fn create(ctx: &IRContext, name: String, module: &Module, ret_type: Option>, args: Vec>) -> PositionlessResult { + let mut kargs = vec![]; + + for k in &args { + kargs.push(*k.get_inkwell_base_metadatatype()?); + } + + let t = match &ret_type { + Some(ret) => ret.get_inkwell_basetype()?.fn_type(&kargs, false), + None => ctx.void_type.fn_type(&kargs, false) + }; + + let func = module.add_function(&name, t, None); + + return Ok(IRFunction::new(ctx, name, func, ret_type, args)); + } + + pub fn call(&self, ctx: &IRContext, args: Vec, grab_return: bool) -> PositionlessResult> { + let mut inkwell_args = vec![]; + + for arg in args { + inkwell_args.push(arg.obtain(ctx)?.obtain().inner.into()); + } + + let call = match ctx.builder.build_call(self.inkwell_func, &inkwell_args, &self.name) { + Ok(v) => v, + Err(_) => return Err(PositionlessError::new("build_call failed!")) + }; + + if !grab_return { + return Ok(None); + } + + let return_type = match self.ret_type.as_ref() { + Some(ret) => ret.clone(), + None => return Ok(None) + }; + + let val = match call.try_as_basic_value().basic() { + Some(v) => v, + None => return Ok(None) + }; + + let val = IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx, val), return_type.clone()); + + let pointer = IRPointer::create(ctx, format!("function_ret_{}", self.name), return_type, Some(IRValueRef::from_val(val)))?; + + return Ok(Some(pointer)); + } + + /// Prepares the addition of the function body. + pub fn prepare_body_filling(&self, ctx: &IRContext) { + if self.entry.is_none() { + return; + } + + ctx.builder.position_at_end(self.entry.unwrap()); + } + + pub fn get_nth_arg(&self, ind: u32) -> PositionlessResult { + let res = match self.inkwell_func.get_nth_param(ind) { + Some(v) => v, + None => return Err(PositionlessError::new("Couldn't get nth param using get_nth_param")) + }; + + return Ok(OwnedValueEnum::new(&self.owned, res)); + } + + pub fn get_nth_arg_int(&self, ind: u32) -> PositionlessResult { + if !self.args[ind as usize].is_numeric_type() { + return Err(PositionlessError::new("Tried getting nth argument but given argument's type isn't numeric!")); + } + + return Ok(OwnedIntValue::new(&self.owned, self.get_nth_arg(ind)?.into_int_value())); + + } + +} \ No newline at end of file diff --git a/ir/src/irstruct/mod.rs b/ir/src/irstruct/mod.rs new file mode 100644 index 0000000..5ad68ad --- /dev/null +++ b/ir/src/irstruct/mod.rs @@ -0,0 +1,6 @@ +//! Common definitions used internally to structure the IR. + +pub mod ptr; +pub mod funcs; +pub mod staticvars; +pub mod structs; \ No newline at end of file diff --git a/ir/src/irstruct/ptr.rs b/ir/src/irstruct/ptr.rs new file mode 100644 index 0000000..19d4bf2 --- /dev/null +++ b/ir/src/irstruct/ptr.rs @@ -0,0 +1,55 @@ +use std::rc::Rc; + +use commons::err::{PositionlessError, PositionlessResult}; +use inkwell::{builder::Builder, context::Context, types::BasicTypeEnum, values::{BasicValue, BasicValueEnum, IntValue, PointerValue}}; + +use crate::{ctx::IRContext, refs::IRValueRef, types::typing::{IRType, OwnedTypeEnum, OwnedValueEnum}, values::IRValue}; + +#[derive(Clone)] +pub struct IRPointer { + owned: Rc, + pub inkwell_ptr: PointerValue<'static>, // Only use this directly within structs + pub t: Rc, + pub name: String +} + +impl IRPointer { + pub fn new(ptr: PointerValue<'static>, ctx: &IRContext, t: Rc, name: String) -> Self { + return IRPointer { inkwell_ptr: ptr, owned: ctx.inkwell_ctx.clone(), name, t } + } + + pub fn create(ctx: &IRContext, name: String, t: Rc, initial: Option) -> PositionlessResult { + let ptr = match ctx.builder.build_alloca(t.get_inkwell_basetype()?.inner, &name) { + Ok(v) => v, + Err(e) => return Err(PositionlessError::new(&format!("build_alloca failed! {}", e))) + }; + + if initial.is_some() { + match ctx.builder.build_store(ptr, *initial.unwrap().obtain(ctx)?.obtain()) { + Err(_) => return Err(PositionlessError::new("build_store failed!")), + Ok(_) => {} + }; + } + + return Ok(IRPointer { owned: ctx.inkwell_ctx.clone(), inkwell_ptr: ptr, t, name: name.clone() }); + } + + pub fn load(&self, ctx: &IRContext, t: Rc) -> PositionlessResult { + if !self.t.is_same(&t) { + return Err(PositionlessError::new("Provided IRType isn't the same!")); + } + + match ctx.builder.build_load(*self.t.get_inkwell_instance_basetype(ctx)?, self.inkwell_ptr, &self.name) { + Ok(v) => return Ok(IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx, v), t)), + Err(_) => return Err(PositionlessError::new("build_load failed!")) + } + } + + pub fn store(&self, ctx: &IRContext, val: BasicValueEnum) -> bool { + return match ctx.builder.build_store(self.inkwell_ptr, val) { + Ok(_) => true, + Err(_) => false + } + } + +} \ No newline at end of file diff --git a/ir/src/irstruct/staticvars.rs b/ir/src/irstruct/staticvars.rs new file mode 100644 index 0000000..3f02cc0 --- /dev/null +++ b/ir/src/irstruct/staticvars.rs @@ -0,0 +1,66 @@ +//! Static variable related code + +use std::rc::Rc; + +use commons::err::{PositionlessError, PositionlessResult}; +use inkwell::{builder::Builder, values::{BasicValueEnum, GlobalValue, IntValue}}; + +use crate::{ctx::IRContext, types::{SIGNED8_TYPE_HASH, typing::{IRType, OwnedGlobalValue, OwnedValueEnum}}, values::IRValue}; + +#[derive(Clone)] +pub struct IRStaticVariable { + inkwell: Option, + val: Option, + pub t: Rc, + pub name: String +} + +impl IRStaticVariable { + pub fn from_str(ctx: &IRContext, str: &str, name: String, t: Rc) -> PositionlessResult { + let bytes = str.as_bytes(); + + let byte_type = ctx.type_storage.get(SIGNED8_TYPE_HASH).expect("Cannot find i8 in type storage!"); + let i8_type = byte_type.get_inkwell_inttype()?; + + let array_type = i8_type.array_type((bytes.len() + 1) as u32); + + let global = ctx.module.add_global(array_type, None, &name); + + global.set_linkage(inkwell::module::Linkage::Private); + global.set_constant(true); + global.set_unnamed_addr(true); + + let mut vals: Vec = bytes.iter().map(|b| i8_type.const_int(*b as u64, false)).collect(); + + vals.push(i8_type.const_zero()); + + global.set_initializer(&i8_type.const_array(&vals)); + + return Ok(IRStaticVariable { inkwell: Some(OwnedGlobalValue::new(&ctx.inkwell_ctx, global)), t, name, val: None }); + } + + pub fn from_val(name: String, t: Rc, val: IRValue) -> PositionlessResult { + return Ok(IRStaticVariable { val: Some(val.obtain()), inkwell: None, t, name }) + } + + pub fn is_compiletime_replaceable(&self) -> bool { + return self.val.is_some(); + } + + pub fn as_val(&self) -> PositionlessResult { + if self.val.is_some() { + return Ok(self.val.as_ref().unwrap().clone()); + } + + return Ok(OwnedValueEnum::new(&self.inkwell.as_ref().unwrap().owned, self.as_string_ref()?.as_pointer_value().into())); + } + + pub fn as_string_ref(&self) -> PositionlessResult { + if self.is_compiletime_replaceable() { + return Err(PositionlessError::new("Tried using as_string_ref on a compiletime determined global var")); + } + + return Ok(self.inkwell.clone().unwrap()) + } + +} \ No newline at end of file diff --git a/ir/src/irstruct/structs.rs b/ir/src/irstruct/structs.rs new file mode 100644 index 0000000..22a4c78 --- /dev/null +++ b/ir/src/irstruct/structs.rs @@ -0,0 +1,108 @@ +//! IR representation of structure types (structs, layouts...) + +use std::{mem::transmute, rc::Rc}; + +use commons::{err::{PositionlessError, PositionlessResult}, utils::map::HashedMap}; +use inkwell::{context::Context, types::{BasicTypeEnum, StructType}}; + +use crate::{ctx::IRContext, irstruct::{funcs::IRFunction, ptr::IRPointer}, types::typing::{IRType, OwnedTypeEnum}}; + +pub struct IRStructuredType { + pub owned: Rc, + pub inkwell_type: StructType<'static>, + pub field_to_index: HashedMap, + pub field_types: Vec>, + pub functions: HashedMap>, + pub name: String, + pub is_layout: bool +} + +impl IRStructuredType { + pub fn new(ctx: &IRContext, name: String, layout: bool, fields: Vec<(u64, Rc)>) -> PositionlessResult { + let mut map = HashedMap::new(fields.len()); + let mut typeVec: Vec = Vec::new(); + let mut field_types: Vec> = Vec::new(); + + let mut ind = 0; + for entry in fields { + map.put(entry.0, ind); + + field_types.push(entry.1.clone()); + typeVec.push(entry.1.as_ref().get_inkwell_basetype()?.inner.into()); + + ind += ind; + } + + let inkwell_type = ctx.inkwell_ctx.struct_type(&typeVec, !layout); + + return Ok(Self { owned: ctx.inkwell_ctx.clone(), inkwell_type: unsafe { transmute(inkwell_type) }, field_to_index: map, name, is_layout: layout, field_types, functions: HashedMap::new(0) }) + } + + pub fn append_function(&mut self, hash: u64, func: IRFunction) -> PositionlessResult { + if self.is_layout { + return Err(PositionlessError::new("Cannot declare functions inside of a layout!")); + } + + self.functions.put(hash, Rc::new(func)); + return Ok(true); + } + + pub fn get_function(&self, hash: u64) -> PositionlessResult> { + if self.is_layout { + return Err(PositionlessError::new("Cannot use typed-functions inside of a layout!")); + } + + return match self.functions.get(hash) { + Some(v) => Ok(v.clone()), + None => Err(PositionlessError::new("Function was not founc within the struct!")) + } + } + + pub fn get_pointer_for_field_index(&self, ctx: &IRContext, instance: &IRPointer, ind: u32) -> PositionlessResult { + if ind >= self.field_types.len() as u32 { + return Err(PositionlessError::new("Invalid index given to get_pointer_for_field_index")); + } + + let field_ptr = match ctx.builder.build_struct_gep(self.inkwell_type, instance.inkwell_ptr, ind, "field_ptr") { + Ok(v) => v, + Err(_) => return Err(PositionlessError::new("build_struct_gep failed!")) + }; + + let field_type = self.field_types[ind as usize].clone(); + + return Ok(IRPointer::new(field_ptr, ctx, field_type, String::from("__inner_field_ptr"))); + } + + pub fn get_pointer_for_field_index_noref(&self, ctx: &IRContext, instance: IRPointer, ind: u32) -> PositionlessResult { + if ind >= self.field_types.len() as u32 { + return Err(PositionlessError::new("Invalid index given to get_pointer_for_field_index")); + } + + let field_ptr = match ctx.builder.build_struct_gep(self.inkwell_type, instance.inkwell_ptr, ind, "field_ptr") { + Ok(v) => v, + Err(_) => return Err(PositionlessError::new("build_struct_gep failed!")) + }; + + let field_type = self.field_types[ind as usize].clone(); + + return Ok(IRPointer::new(field_ptr, ctx, field_type, String::from("__inner_field_ptr"))); + } + + pub fn get_pointer_for_field_noref(&self, ctx: &IRContext, instance: IRPointer, hash: u64) -> PositionlessResult { + let k = match self.field_to_index.get(hash) { + Some(v) => *v, + None => return Err(PositionlessError::new(&format!("The given string hash {} doesn't represent any field in the struct {}", hash, self.name))) + }; + + return self.get_pointer_for_field_index_noref(ctx, instance, k); + } + + pub fn get_pointer_for_field(&self, ctx: &IRContext, instance: &IRPointer, hash: u64) -> PositionlessResult { + let k = match self.field_to_index.get(hash) { + Some(v) => *v, + None => return Err(PositionlessError::new(&format!("The given string hash {} doesn't represent any field in the struct {}", hash, self.name))) + }; + + return self.get_pointer_for_field_index(ctx, instance, k); + } +} diff --git a/ir/src/lib.rs b/ir/src/lib.rs index a82af7b..33168c9 100644 --- a/ir/src/lib.rs +++ b/ir/src/lib.rs @@ -1,4 +1,12 @@ //! Quickfall's Intermediate Representation code. Converts the AST into instruction like nodes to pass down to compilation. -pub mod types; \ No newline at end of file +pub mod types; +pub mod values; +pub mod math; +pub mod irstruct; +pub mod conv; +pub mod ctx; +pub mod refs; +pub mod bools; +pub mod utils; \ No newline at end of file diff --git a/ir/src/math.rs b/ir/src/math.rs new file mode 100644 index 0000000..a182b7e --- /dev/null +++ b/ir/src/math.rs @@ -0,0 +1,19 @@ +//! Math and arithmetic code + +use commons::err::{PositionlessError, PositionlessResult}; +use inkwell::{builder::Builder, values::IntValue}; +use lexer::toks::math::MathOperator; + +pub fn make_math_operation<'a>(builder: &Builder<'a>, a: IntValue<'a>, b: IntValue<'a>, name: String, operation: MathOperator) -> PositionlessResult> { + let res = match operation { + MathOperator::ADD => builder.build_int_add(a, b, &name), + MathOperator::SUBSTRACT => builder.build_int_sub(a, b, &name), + MathOperator::DIVIDE => builder.build_int_signed_div(a, b, &name), + MathOperator::MULTIPLY => builder.build_int_mul(a, b, &name) + }; + + match res { + Ok(v) => return Ok(v), + Err(_) => return Err(PositionlessError::new("Couldn't fabricate IR math operation!")) + }; +} \ No newline at end of file diff --git a/ir/src/refs.rs b/ir/src/refs.rs new file mode 100644 index 0000000..29dfe05 --- /dev/null +++ b/ir/src/refs.rs @@ -0,0 +1,106 @@ +//! IR value reference definitions + +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}; + +pub enum IRValueRefKind { + Ptr(Rc, IRPointer), + Val(IRValue), + Global(Rc, Rc), + TempString(String) +} + +/// The IR value reference. Basically represents any value whatsoever, can handle every shape of values and is used for uniform handling. +pub struct IRValueRef { + // TODO: maybe change IRValueRef to host the fields itself rather than having to use Options + kind: IRValueRefKind, +} + +impl IRValueRef { + pub fn from_tempstr(str: String) -> Self { + return IRValueRef { kind: IRValueRefKind::TempString(str) } + } + + pub fn from_val(val: IRValue) -> Self { + return IRValueRef { kind: IRValueRefKind::Val(val) } + } + + pub fn from_static(val: Rc) -> Self { + return IRValueRef { kind: IRValueRefKind::Global(val.t.clone(), val) } + } + + pub fn from_pointer(ptr: IRPointer) -> Self { + return IRValueRef { kind: IRValueRefKind::Ptr(ptr.t.clone(), ptr) } + } + + /// Determines if aqcuiring the values require a load instruction or any instruction at all to obtain the value from. + pub fn requires_load(&self) -> bool { + return matches!(self.kind, IRValueRefKind::Ptr(_, _)) + } + + pub fn obtain(&self, ctx: &IRContext) -> PositionlessResult { + match &self.kind { + IRValueRefKind::Ptr(t, ptr) => { + ptr.load(ctx, t.clone()) + }, + + IRValueRefKind::Val(v) => Ok(IRValue::clone(v)), + + IRValueRefKind::Global(t, global) => { + Ok(IRValue::new(global.as_val()?, t.clone())) + }, + + _ => return Err(PositionlessError::new("Cannot use obtain on said IR value type!")) + } + } + + pub fn get_type(&self) -> Rc { + return match &self.kind { + IRValueRefKind::Val(v) => v.t.clone(), + IRValueRefKind::Ptr(t, _) => return t.clone(), + IRValueRefKind::Global(t, _) => return t.clone(), + _ => panic!("Used get_type on temp string type!!") + } + } + + pub fn as_pointer(&self) -> PositionlessResult { + match &self.kind { + IRValueRefKind::Ptr(t, ptr) => return Ok(ptr.clone()), + _ => return Err(PositionlessError::new("Cannot cast said value reference as a pointer!")) + }; + } + + pub fn obtain_pointer(&self, ctx: &IRContext) -> PositionlessResult { + match &self.kind { + IRValueRefKind::Ptr(_, ptr) => return Ok(OwnedPointerValue::new(&ctx.inkwell_ctx, ptr.inkwell_ptr)), + + IRValueRefKind::Val(v) => { + let ptr = IRPointer::create(&ctx, String::from("_val_toptr"), v.t.clone(), Some(IRValueRef::from_val(IRValue::clone(v))))?; + + return Ok(OwnedPointerValue::new(&ctx.inkwell_ctx, ptr.inkwell_ptr)); + } + + IRValueRefKind::Global(_, g) => { + if g.is_compiletime_replaceable() { + return Ok(OwnedPointerValue::new(&ctx.inkwell_ctx, g.as_val()?.into_pointer_value())) + } + + return Ok(OwnedPointerValue::new(&ctx.inkwell_ctx, g.as_string_ref()?.as_pointer_value())); + }, + + _ => return Err(PositionlessError::new("Cannot use obtain_pointer on given IR value type!")) + } + } + + pub fn obtain_tempstr(&self) -> PositionlessResult { + match &self.kind { + IRValueRefKind::TempString(e) => Ok(e.clone()), + _ => return Err(PositionlessError::new("Cannot get temp string from IR value type!")) + } + } + +} \ No newline at end of file diff --git a/ir/src/types/mod.rs b/ir/src/types/mod.rs index c9646bc..1ea1617 100644 --- a/ir/src/types/mod.rs +++ b/ir/src/types/mod.rs @@ -12,7 +12,11 @@ pub const UNSIGNED32_TYPE_HASH: u64 = 2263434253207377038; pub const UNSIGNED64_TYPE_HASH: u64 = 9321926220436863523; pub const UNSIGNED128_TYPE_HASH: u64 = 9667664784078163512; +pub const POINTER_TYPE_HASH: u64 = 9259207781742941243; + pub const BOOL_TYPE_HASH: u64 = 10699440025065254663; +pub const STATICSTR_TYPE_HASH: u64 = 10484269008925909607; + pub mod typing; pub mod storage; \ No newline at end of file diff --git a/ir/src/types/storage.rs b/ir/src/types/storage.rs index 402b061..b0a8a0e 100644 --- a/ir/src/types/storage.rs +++ b/ir/src/types/storage.rs @@ -1,40 +1,55 @@ //! Type storage +use std::{cell::Ref, collections::HashMap, mem::transmute, ops::Add, rc::Rc}; + use commons::utils::map::HashedMap; -use inkwell::context::Context; +use inkwell::{AddressSpace, context::Context, types::{IntType, PointerType}}; -use crate::types::{BOOL_TYPE_HASH, SIGNED8_TYPE_HASH, SIGNED16_TYPE_HASH, SIGNED32_TYPE_HASH, SIGNED64_TYPE_HASH, SIGNED128_TYPE_HASH, UNSIGNED8_TYPE_HASH, UNSIGNED16_TYPE_HASH, UNSIGNED32_TYPE_HASH, UNSIGNED64_TYPE_HASH, UNSIGNED128_TYPE_HASH, typing::IRType}; +use crate::{ctx::IRContext, types::{BOOL_TYPE_HASH, POINTER_TYPE_HASH, SIGNED8_TYPE_HASH, SIGNED16_TYPE_HASH, SIGNED32_TYPE_HASH, SIGNED64_TYPE_HASH, SIGNED128_TYPE_HASH, STATICSTR_TYPE_HASH, UNSIGNED8_TYPE_HASH, UNSIGNED16_TYPE_HASH, UNSIGNED32_TYPE_HASH, UNSIGNED64_TYPE_HASH, UNSIGNED128_TYPE_HASH, typing::{IRType, OwnedIntType, OwnedPointerType}}, utils::SelfHash}; -pub struct IRTypeStorage<'a> { - map: HashedMap> +pub struct IRTypeStorage { + pub map: HashMap> } -impl<'a> IRTypeStorage<'a> { - pub fn new(ctx: &'a Context) -> Self { - let mut sto = IRTypeStorage {map: HashedMap::new(12)}; // 12 primitive types +impl IRTypeStorage { + pub fn new(ctx: &IRContext) -> Self { + let mut sto = IRTypeStorage {map: HashMap::new()}; // 12 primitive types + + let int8 = unsafe { transmute::>(ctx.inkwell_ctx.i8_type())}; + let int16 = unsafe { transmute::>(ctx.inkwell_ctx.i16_type())}; + let int32 = unsafe { transmute::>(ctx.inkwell_ctx.i32_type())}; + let int64 = unsafe { transmute::>(ctx.inkwell_ctx.i64_type())}; + let int128 = unsafe { transmute::>(ctx.inkwell_ctx.i128_type())}; + + let ptr = unsafe { transmute::>(ctx.inkwell_ctx.ptr_type(AddressSpace::from(0))) }; + let bool = unsafe { transmute::>(ctx.inkwell_ctx.bool_type()) }; + + sto.insert(UNSIGNED8_TYPE_HASH, IRType::Unsigned8(OwnedIntType::new_ref(&ctx.inkwell_ctx, &int8))); + sto.insert(UNSIGNED16_TYPE_HASH, IRType::Unsigned16(OwnedIntType::new(&ctx.inkwell_ctx, int16))); + sto.insert(UNSIGNED32_TYPE_HASH, IRType::Unsigned32(OwnedIntType::new(&ctx.inkwell_ctx, int32))); + sto.insert(UNSIGNED64_TYPE_HASH, IRType::Unsigned64(OwnedIntType::new(&ctx.inkwell_ctx, int64))); + sto.insert(UNSIGNED128_TYPE_HASH, IRType::Unsigned128(OwnedIntType::new(&ctx.inkwell_ctx, int128))); + + sto.insert(SIGNED8_TYPE_HASH, IRType::Signed8(OwnedIntType::new_ref(&ctx.inkwell_ctx, &int8))); + sto.insert(SIGNED16_TYPE_HASH, IRType::Signed16(OwnedIntType::new(&ctx.inkwell_ctx, int16))); + sto.insert(SIGNED32_TYPE_HASH, IRType::Signed32(OwnedIntType::new(&ctx.inkwell_ctx, int32))); + sto.insert(SIGNED64_TYPE_HASH, IRType::Signed64(OwnedIntType::new(&ctx.inkwell_ctx, int64))); + sto.insert(SIGNED128_TYPE_HASH, IRType::Signed128(OwnedIntType::new(&ctx.inkwell_ctx, int128))); - sto.insert(UNSIGNED8_TYPE_HASH, IRType::Unsigned8(ctx.i8_type())); - sto.insert(UNSIGNED16_TYPE_HASH, IRType::Unsigned16(ctx.i16_type())); - sto.insert(UNSIGNED32_TYPE_HASH, IRType::Unsigned32(ctx.i32_type())); - sto.insert(UNSIGNED64_TYPE_HASH, IRType::Unsigned64(ctx.i64_type())); - sto.insert(UNSIGNED128_TYPE_HASH, IRType::Unsigned128(ctx.i128_type())); + sto.insert(POINTER_TYPE_HASH, IRType::Pointer(OwnedPointerType::new(&ctx.inkwell_ctx, ptr))); - sto.insert(SIGNED8_TYPE_HASH, IRType::Signed8(ctx.i8_type())); - sto.insert(SIGNED16_TYPE_HASH, IRType::Signed16(ctx.i16_type())); - sto.insert(SIGNED32_TYPE_HASH, IRType::Signed32(ctx.i32_type())); - sto.insert(SIGNED64_TYPE_HASH, IRType::Signed64(ctx.i64_type())); - sto.insert(SIGNED128_TYPE_HASH, IRType::Signed128(ctx.i128_type())); + sto.insert(STATICSTR_TYPE_HASH, IRType::StaticString(OwnedPointerType::new(&ctx.inkwell_ctx, ptr))); - sto.insert(BOOL_TYPE_HASH, IRType::Bool(ctx.bool_type())); + sto.insert(BOOL_TYPE_HASH, IRType::Bool(OwnedIntType::new(&ctx.inkwell_ctx, bool))); return sto; } - pub fn insert(&mut self, hash: u64, t: IRType<'a>) { - self.map.put(hash, t); + pub fn insert(&mut self, hash: u64, t: IRType) { + self.map.insert(SelfHash { hash }, Rc::new(t)); } - pub fn get(&self, hash: u64) -> Option<&IRType<'a>> { - return self.map.get(hash); + pub fn get(&self, hash: u64) -> Option> { + return self.map.get(&SelfHash { hash }).cloned(); } } \ No newline at end of file diff --git a/ir/src/types/typing.rs b/ir/src/types/typing.rs index 43bdb5d..aba58f7 100644 --- a/ir/src/types/typing.rs +++ b/ir/src/types/typing.rs @@ -1,30 +1,48 @@ //! IR Type structures -use std::{cell::Ref, collections::HashMap}; +use std::{cell::Ref, collections::HashMap, mem::transmute, ops::Add, rc::Rc}; -use inkwell::types::IntType; +use commons::err::{PositionlessError, PositionlessResult}; +use inkwell::{AddressSpace, builder::Builder, context::Context, types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType, IntType, PointerType, StringRadix}, values::{BasicValueEnum, GlobalValue, IntValue, PointerValue}}; + +use crate::{ctx::IRContext, irstruct::structs::IRStructuredType, utils::OwnedType, values::IRValue}; + +pub type OwnedIntType = OwnedType>; +pub type OwnedPointerType = OwnedType>; +pub type OwnedTypeEnum = OwnedType>; +pub type OwnedMetadataTypeEnum = OwnedType>; + +pub type OwnedValueEnum = OwnedType>; +pub type OwnedIntValue = OwnedType>; +pub type OwnedPointerValue = OwnedType>; + +pub type OwnedGlobalValue = OwnedType>; /// Types of IR variables -pub enum IRType<'a> { - Signed8(IntType<'a>), - Signed16(IntType<'a>), - Signed32(IntType<'a>), - Signed64(IntType<'a>), - Signed128(IntType<'a>), - - Unsigned8(IntType<'a>), - Unsigned16(IntType<'a>), - Unsigned32(IntType<'a>), - Unsigned64(IntType<'a>), - Unsigned128(IntType<'a>), - - Bool(IntType<'a>), +#[derive(Clone)] +pub enum IRType { + Signed8(OwnedIntType), + Signed16(OwnedIntType), + Signed32(OwnedIntType), + Signed64(OwnedIntType), + Signed128(OwnedIntType), + + Unsigned8(OwnedIntType), + Unsigned16(OwnedIntType), + Unsigned32(OwnedIntType), + Unsigned64(OwnedIntType), + Unsigned128(OwnedIntType), + + StaticString(OwnedPointerType), + Pointer(OwnedPointerType), + + Bool(OwnedIntType), - Struct(HashMap>>), // fields - Layout(HashMap>>) // fields + Struct(Rc), + Layout(Rc) } -impl IRType<'_> { +impl IRType { /// Gets the size in bits of a given IR element pub fn get_bitsize(&self) -> usize { match self { @@ -33,14 +51,15 @@ impl IRType<'_> { IRType::Signed32(_) | IRType::Unsigned32(_) => return 32, IRType::Signed64(_) | IRType::Unsigned64(_) => return 64, IRType::Signed128(_) | IRType::Unsigned128(_) => return 128, + IRType::Pointer(_) | IRType::StaticString(_) => return 64, IRType::Struct(v) => { let mut sz: usize = 0; // TODO: add bool compacting - for (_, ir_type) in v { - sz += ir_type.get_bitsize(); + for t in &v.field_types { + sz += t.get_bitsize(); } return sz; @@ -49,8 +68,8 @@ impl IRType<'_> { IRType::Layout(v) => { let mut sz: usize = 0; - for (_, ir_type) in v { - sz += ir_type.get_bitsize(); + for t in &v.field_types { + sz += t.get_bitsize(); } return sz; @@ -103,4 +122,126 @@ impl IRType<'_> { return -2_i128.pow(self.get_bitsize() as u32) - 1; } + + pub fn get_inkwell_basetype(&self) -> PositionlessResult { + match self { + IRType::Unsigned8(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Unsigned16(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Unsigned32(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Unsigned64(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Unsigned128(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Signed8(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Signed16(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Signed32(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Signed64(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + IRType::Signed128(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + + IRType::Bool(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + + IRType::StaticString(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + + IRType::Pointer(v) => Ok(OwnedTypeEnum::new(&v.owned, BasicTypeEnum::from(v.inner))), + + IRType::Struct(a) => Ok(OwnedTypeEnum::new(&a.owned, BasicTypeEnum::from(a.inkwell_type))), + IRType::Layout(a) => Ok(OwnedTypeEnum::new(&a.owned, BasicTypeEnum::from(a.inkwell_type))), + + _ => Err(PositionlessError::new("Given IR type doesn't have any Inkwell type!!!")) + } + } + + pub fn get_inkwell_instance_basetype(&self, ctx: &IRContext) -> PositionlessResult { + match self { + IRType::Struct(_) | IRType::Layout(_) => Ok(OwnedTypeEnum::new(&ctx.inkwell_ctx, ctx.ptr_type.into())), + _ => self.get_inkwell_basetype() + } + } + + pub fn get_inkwell_base_metadatatype(&self) -> PositionlessResult { + match self { + IRType::Unsigned8(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Unsigned16(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Unsigned32(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Unsigned64(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Unsigned128(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Signed8(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Signed16(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Signed32(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Signed64(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + IRType::Signed128(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + + IRType::Bool(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + + IRType::StaticString(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + + IRType::Pointer(v) => Ok(OwnedMetadataTypeEnum::new(&v.owned, BasicMetadataTypeEnum::from(v.inner))), + + IRType::Struct(a) => Ok(OwnedMetadataTypeEnum::new(&a.owned, BasicMetadataTypeEnum::from(a.inkwell_type))), + IRType::Layout(a) => Ok(OwnedMetadataTypeEnum::new(&a.owned, BasicMetadataTypeEnum::from(a.inkwell_type))), + + _ => Err(PositionlessError::new("Given IR type doesn't have any Inkwell type!!!")) + } + } + + pub fn get_inkwell_inttype(&self) -> PositionlessResult<&OwnedIntType> { + match self { + IRType::Unsigned8(v) => Ok(v), + IRType::Unsigned16(v) => Ok(v), + IRType::Unsigned32(v) => Ok(v), + IRType::Unsigned64(v) => Ok(v), + IRType::Unsigned128(v) => Ok(v), + IRType::Signed8(v) => Ok(v), + IRType::Signed16(v) => Ok(v), + IRType::Signed32(v) => Ok(v), + IRType::Signed64(v) => Ok(v), + IRType::Signed128(v) => Ok(v), + + _ => return Err(PositionlessError::new("get_inkwell_inttype was used with a non int typed IRType!")) + } + } + + pub fn get_inkwell_pointertype(ctx: &IRContext) -> OwnedPointerType { + return OwnedPointerType::new(&ctx.inkwell_ctx, ctx.ptr_type); + } + + /// Checks if the given type instance is the same type as the given one without having to use `PartialEq` + pub fn is_same(&self, t: &Rc) -> bool { + return match(self, t.as_ref()) { + (IRType::Signed8(_), IRType::Signed8(_)) => true, + (IRType::Signed16(_), IRType::Signed16(_)) => true, + (IRType::Signed32(_), IRType::Signed32(_)) => true, + (IRType::Signed64(_), IRType::Signed64(_)) => true, + (IRType::Signed128(_), IRType::Signed128(_)) => true, + + (IRType::Unsigned8(_), IRType::Unsigned8(_)) => true, + (IRType::Unsigned16(_), IRType::Unsigned16(_)) => true, + (IRType::Unsigned32(_), IRType::Unsigned32(_)) => true, + (IRType::Unsigned64(_), IRType::Unsigned64(_)) => true, + (IRType::Unsigned128(_), IRType::Unsigned128(_)) => true, + + (IRType::Bool(_), IRType::Bool(_)) => true, + + (IRType::StaticString(_), IRType::StaticString(_)) => true, + + (IRType::Struct(a), IRType::Struct(b)) => a.name == b.name && a.is_layout == b.is_layout, + (IRType::Layout(a), IRType::Layout(b)) => a.name == b.name && a.is_layout == b.is_layout, + + _ => false + } + } + + pub fn get_structured_type_descriptor(&self) -> PositionlessResult> { + return match self { + IRType::Struct(e) => Ok(e.clone()), + IRType::Layout(e) => Ok(e.clone()), + _ => Err(PositionlessError::new("Given IRType doesn't have a structured type descriptor!")) + } + } + + pub fn has_structured_type_descriptor(&self) -> bool { + return match self { + IRType::Struct(_) | IRType::Layout(_) => true, + _ => false + } + } + } \ No newline at end of file diff --git a/ir/src/utils.rs b/ir/src/utils.rs new file mode 100644 index 0000000..ccd44b7 --- /dev/null +++ b/ir/src/utils.rs @@ -0,0 +1,76 @@ +//! Codebase wide utilities. Are mostly used to escape the Inkwell lifecycle hell + +use std::{hash::Hash, mem::transmute, ops::{Deref, DerefMut}, rc::Rc}; + +use inkwell::context::Context; + +/// A type containing a counted reference to the Inkwell context. +/// This allows for the type to have the 'static lifecycle safely, allowing to safely use without annoying lifecycles. +#[derive(Clone, Debug)] +pub struct OwnedType { + pub inner: T, + pub owned: Rc +} + +impl OwnedType { + pub fn new(ctx: &Rc, inner: K) -> Self { + return OwnedType { inner: unsafe { transmute(inner)} , owned: ctx.clone() } + } + + pub fn new_ref(ctx: &Rc, inner: &K) -> Self { + return OwnedType { inner: unsafe { transmute(K::clone(inner)) }, owned: ctx.clone() } + } + + pub fn new_ownership(ctx: Rc, inner: K) -> Self { + return OwnedType { inner: unsafe {transmute(inner) }, owned: ctx } + } +} + +impl Deref for OwnedType { + type Target = T; + + fn deref(&self) -> &Self::Target { + return &self.inner; + } +} + +/// Warning: unsafe temporary struct +pub struct LateInit { + inner: Option +} + +#[derive(Eq, PartialEq)] +pub struct SelfHash { + pub hash: u64 +} + +impl Hash for SelfHash { + fn hash(&self, state: &mut H) { + state.write_u64(self.hash); + } +} + +impl Deref for LateInit { + type Target = K; + + fn deref(&self) -> &Self::Target { + return &self.inner.as_ref().unwrap(); + } +} + +impl DerefMut for LateInit { + fn deref_mut(&mut self) -> &mut Self::Target { + let m = self.inner.as_mut(); + return m.unwrap(); + } +} + +impl LateInit { + pub fn new() -> Self { + return LateInit { inner: None }; + } + + pub fn fill(&mut self, inner: K) { + self.inner = Some(inner); + } +} \ No newline at end of file diff --git a/ir/src/values.rs b/ir/src/values.rs new file mode 100644 index 0000000..1b64110 --- /dev/null +++ b/ir/src/values.rs @@ -0,0 +1,86 @@ +//! IR value representation definitons + +use std::{cell::{Ref, RefCell}, rc::Rc}; + +use commons::{err::{PositionlessError, PositionlessResult}}; +use inkwell::{types::StringRadix, values::{BasicValueEnum, IntValue}}; + +use crate::{ctx::IRContext, irstruct::ptr::IRPointer, types::typing::{IRType, OwnedIntType, OwnedIntValue, OwnedValueEnum}}; + +/// The new IR value system. Allows for a close interaction with inkwell rather than a more AST-side one. +/// # Safety +/// IRValue enforces a strict typing system for values. An instance of `IRType` is required for every gather and will fail if the provided type isn't the variable's. +#[derive(Clone)] +pub struct IRValue { + inkwell_val: OwnedValueEnum, + pub t: Rc, +} + +impl IRValue { + /// Creates a new untracked instance + pub fn new(inkwell_val: OwnedValueEnum, t: Rc) -> Self { + return IRValue { inkwell_val, t: t.clone() } + } + + pub fn from_unsigned(ctx: &IRContext, t: Rc, v: u128) -> PositionlessResult { + if !t.is_numeric_type() || t.is_signed() { + return Err(PositionlessError::new("The given type cannot be applied to make an unsigned!")); + } + + let int_type = t.get_inkwell_inttype()?; + let val = match int_type.const_int_from_string(&v.to_string(), StringRadix::Decimal) { + Some(v) => v, + None => return Err(PositionlessError::new("const_int_from_string failed!")) + }; + + return Ok(IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx, val.into()), t)); + } + + pub fn from_signed(ctx: &IRContext, t: Rc, v: i128) -> PositionlessResult { + if !t.is_numeric_type() || !t.is_signed() { + return Err(PositionlessError::new("The given type cannot be applied to make a signed!")); + } + + let int_type = t.get_inkwell_inttype()?; + let val = match int_type.const_int_from_string(&v.to_string(), StringRadix::Decimal) { + Some(v) => v, + None => return Err(PositionlessError::new("const_int_from_string failed!")) + }; + + return Ok(IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx, val.into()), t)); + } + + pub fn from_bool(val: bool, ctx: &IRContext, t: Rc) -> PositionlessResult { + let inkwell_type = match t.as_ref() { + IRType::Bool(ty) => ty, + _ => return Err(PositionlessError::new("from_bool got fed a non-boolean IRType instance! t != IRType::Bool!")) + }; + + return Ok(IRValue::new(OwnedValueEnum::new(&ctx.inkwell_ctx, inkwell_type.const_int(val as u64, false).into()),t)); + } + + /// Typeless obtain. Can be considered as an unsafe handle. Doesn't perform type checking + pub fn obtain(&self) -> OwnedValueEnum { + return self.inkwell_val.clone(); + } + + /// Obtains the value as an integer value. Returns None if the value is incompatible with integers + pub fn obtain_as_int(&self, ctx: &IRContext, t: Rc) -> Option { + println!("is same as: {}", self.t.is_same(&t)); + + if !self.t.is_numeric_type() || !self.t.is_same(&t) { + return None; + } + + return Some(OwnedIntValue::new(&ctx.inkwell_ctx, self.inkwell_val.into_int_value())); + } + + /// Obtains the value as an bool value. Returns None if the value is incompatible with booleans + pub fn obtain_as_bool(&self) -> Option { + return match self.t.as_ref() { + IRType::Bool(v) => Some(OwnedIntValue::new(&v.owned, self.inkwell_val.into_int_value())), + _ => None + } + } + +} \ No newline at end of file diff --git a/lexer/src/lexer.rs b/lexer/src/lexer.rs index 7bbdf0b..5eb8e7d 100644 --- a/lexer/src/lexer.rs +++ b/lexer/src/lexer.rs @@ -8,6 +8,7 @@ use commons::Position; use crate::{LexerParseResult, LexerParsingError, token::{LexerToken, LexerTokenType}, toks::{comp::ComparingOperator, math::MathOperator}}; +const SHADOWFUNC_KEYWORD_HASH: u64 = 8856473617513302734; const FUNC_KEYWORD_HASH: u64 = 17439195341824537259; const RET_KEYWORD_HASH: u64 = 9222097151127739705; const VAR_KEYWORD_HASH: u64 = 10000921911505692860; @@ -20,6 +21,7 @@ const IF_KEYWORD_HASH: u64 = 14565880314940941169; const ELSE_KEYWORD_HASH: u64 = 15870633062462684568; const WHILE_KEYWORD_HASH: u64 = 10666076348663826897; const FOR_KEYWORD_HASH: u64 = 8246706989536534387; +const STATIC_KEYWORD_HASH: u64 = 15057913784433987235; /// Parses a file into a set of lexer tokens. /// @@ -246,7 +248,7 @@ fn parse_string_token(str: &String, ind: &mut usize, start_pos: Position) -> Lex end = start + i + c.len_utf8(); } - let slice = &str[*ind..end]; + let slice = &str[*ind + 1..end - 1]; *ind = end; @@ -277,6 +279,7 @@ fn parse_keyword(str: &String, ind: &mut usize, start_pos: Position) -> LexerTok let token_type = match hash { FUNC_KEYWORD_HASH => LexerTokenType::Function, + SHADOWFUNC_KEYWORD_HASH => LexerTokenType::ShadowFunction, RET_KEYWORD_HASH => LexerTokenType::Return, STRUCT_KEYWORD_HASH => LexerTokenType::Struct, LAYOUT_KEYWORD_HASH => LexerTokenType::Layout, @@ -288,6 +291,7 @@ fn parse_keyword(str: &String, ind: &mut usize, start_pos: Position) -> LexerTok ELSE_KEYWORD_HASH => LexerTokenType::Else, WHILE_KEYWORD_HASH => LexerTokenType::While, FOR_KEYWORD_HASH => LexerTokenType::For, + STATIC_KEYWORD_HASH => LexerTokenType::Static, _ => LexerTokenType::KEYWORD(slice.to_string(), hash) }; diff --git a/lexer/src/token.rs b/lexer/src/token.rs index b1a6387..ae10fd3 100644 --- a/lexer/src/token.rs +++ b/lexer/src/token.rs @@ -11,12 +11,15 @@ use crate::{LexerParseResult, LexerParsingError, toks::{comp::ComparingOperator, pub enum LexerTokenType { /// Represent the func keyword Function, + ShadowFunction, Var, Struct, Layout, Lay, - + + Static, + /// 0: the operator /// 1: does the operator affect the original variable! MathOperator(MathOperator, bool), diff --git a/parser/src/ast/control/ifelse.rs b/parser/src/ast/control/ifelse.rs index 6a60e69..6216e30 100644 --- a/parser/src/ast/control/ifelse.rs +++ b/parser/src/ast/control/ifelse.rs @@ -2,7 +2,7 @@ //! Parsing for if and else statements //! -use commons::err::PositionedResult; +use commons::err::{PositionedResult}; use lexer::token::{LexerToken, LexerTokenType}; use crate::{ast::{func::parse_node_body, parse_ast_value, tree::ASTTreeNode}}; @@ -32,21 +32,24 @@ pub fn parse_if_statement(tokens: &Vec, ind: &mut usize) -> Position Err(e) => return Err(e) }; - let mut else_statement = None; + let mut depth = 1; + let mut branches: Vec> = vec![]; if tokens[*ind].tok_type == LexerTokenType::Else { - else_statement = Some(parse_else_statement(tokens, ind)?); + parse_else_statement(tokens, ind, &mut depth, &mut branches)?; } - return Ok(Box::new(ASTTreeNode::IfStatement { cond, body, else_statement })); + return Ok(Box::new(ASTTreeNode::IfStatement { cond, body, branches, depth })); } -pub fn parse_else_statement(tokens: &Vec, ind: &mut usize) -> PositionedResult> { +pub fn parse_else_statement(tokens: &Vec, ind: &mut usize, depth: &mut usize, branches: &mut Vec>) -> PositionedResult { *ind += 1; let mut cond = None; + *depth += 1; + if tokens[*ind].tok_type == LexerTokenType::If { *ind += 1; cond = Some(parse_condition_member(tokens, ind)?); @@ -60,14 +63,15 @@ pub fn parse_else_statement(tokens: &Vec, ind: &mut usize) -> Positi }; if cond.is_some() { - let mut else_statement = None; + branches.push(Box::new(ASTTreeNode::IfElseStatement { cond, body })); if tokens[*ind].tok_type == LexerTokenType::Else { - else_statement = Some(parse_else_statement(tokens, ind)?); + parse_else_statement(tokens, ind, depth, branches)?; } - return Ok(Box::new(ASTTreeNode::IfElseStatement { cond, body, else_statement: else_statement })); + return Ok(true); } - return Ok(Box::new(ASTTreeNode::ElseStatement { body })); + branches.push(Box::new(ASTTreeNode::ElseStatement { body })); + return Ok(true); } diff --git a/parser/src/ast/func/call.rs b/parser/src/ast/func/call.rs index c42cb2d..110e548 100644 --- a/parser/src/ast/func/call.rs +++ b/parser/src/ast/func/call.rs @@ -18,7 +18,11 @@ pub fn parse_function_call(tokens: &Vec, ind: &mut usize) -> Positio while tokens[*ind].tok_type != LexerTokenType::ParenClose { vals.push(parse_ast_value(tokens, ind)?); - + + if tokens[*ind].tok_type == LexerTokenType::ParenClose { + break; + } + tokens[*ind].expects(LexerTokenType::Comma)?; *ind += 1; diff --git a/parser/src/ast/func/decl.rs b/parser/src/ast/func/decl.rs index 5df13e1..61ee611 100644 --- a/parser/src/ast/func/decl.rs +++ b/parser/src/ast/func/decl.rs @@ -1,9 +1,30 @@ -use commons::err::PositionedResult; +use commons::err::{PositionedError, PositionedResult}; use lexer::token::{LexerToken, LexerTokenType}; use utils::hash::WithHash; use crate::{ast::{func::{parse_function_arguments, parse_node_body}, tree::ASTTreeNode}}; +pub fn parse_shadow_function_declaration(tokens: &Vec, ind: &mut usize) -> PositionedResult> { + *ind += 1; + let function_name = tokens[*ind].expects_keyword()?; + + *ind += 1; + tokens[*ind].expects(LexerTokenType::ParenOpen)?; + + let args = parse_function_arguments(tokens, ind)?; + + *ind += 1; + + let mut retType = None; + + if tokens[*ind].is_keyword() { + retType = Some(tokens[*ind].expects_keyword()?.1); + *ind += 1; + } + + return Ok(Box::new(ASTTreeNode::ShadowFunctionDeclaration { func_name: WithHash::new(function_name.0), args, returnType: retType })) +} + pub fn parse_function_declaraction(tokens: &Vec, ind: &mut usize) -> PositionedResult> { *ind += 1; let function_name = tokens[*ind].expects_keyword()?; @@ -15,9 +36,16 @@ pub fn parse_function_declaraction(tokens: &Vec, ind: &mut usize) -> *ind += 1; + let mut retType = None; + + if tokens[*ind].is_keyword() { + retType = Some(tokens[*ind].expects_keyword()?.1); + *ind += 1; + } + tokens[*ind].expects(LexerTokenType::BracketOpen)?; let body = parse_node_body(tokens, ind)?; - return Ok(Box::new(ASTTreeNode::FunctionDeclaration { func_name: WithHash::new(function_name.0), args, body })); + return Ok(Box::new(ASTTreeNode::FunctionDeclaration { func_name: WithHash::new(function_name.0), args, body, returnType: retType })); } \ No newline at end of file diff --git a/parser/src/ast/func/mod.rs b/parser/src/ast/func/mod.rs index af1294b..b4cdb36 100644 --- a/parser/src/ast/func/mod.rs +++ b/parser/src/ast/func/mod.rs @@ -3,7 +3,7 @@ use commons::err::PositionedResult; use lexer::token::{LexerToken, LexerTokenType}; -use crate::{ast::{parse_ast_node_in_body, tree::{ASTTreeNode, FunctionDeclarationArgument}}}; +use crate::ast::{parse_ast_node_in_body, parse_ast_value, tree::{ASTTreeNode, FunctionDeclarationArgument}}; pub mod decl; pub mod call; @@ -56,4 +56,12 @@ pub fn parse_function_arguments(tokens: &Vec, ind: &mut usize) -> Po tokens[*ind].expects(LexerTokenType::ParenClose)?; Ok(args) -} \ No newline at end of file +} + +pub fn parse_function_return_statement(tokens: &Vec, ind: &mut usize) -> PositionedResult> { + *ind += 1; + + let val = parse_ast_value(tokens, ind)?; + + return Ok(Box::new(ASTTreeNode::ReturnStatement { val: Some(val) })) +} diff --git a/parser/src/ast/math.rs b/parser/src/ast/math.rs index 49961ca..5d5279c 100644 --- a/parser/src/ast/math.rs +++ b/parser/src/ast/math.rs @@ -17,4 +17,4 @@ pub fn parse_math_operation(tokens: &Vec, ind: &mut usize, original: let right_member = parse_ast_value(tokens, ind)?; return Ok(Box::new(ASTTreeNode::MathResult { lval: original, rval: right_member, operator: oper.0, assigns: oper.1 })) -} \ No newline at end of file +} diff --git a/parser/src/ast/mod.rs b/parser/src/ast/mod.rs index 9bf9a25..1f60a18 100644 --- a/parser/src/ast/mod.rs +++ b/parser/src/ast/mod.rs @@ -21,7 +21,7 @@ use commons::err::PositionedResult; use lexer::token::{LexerToken, LexerTokenType}; use utils::hash::WithHash; -use crate::{ast::{control::{forloop::parse_for_loop, ifelse::parse_if_statement, whileblock::parse_while_block}, func::{call::parse_function_call, decl::parse_function_declaraction}, literals::{parse_integer_literal, parse_string_literal}, math::parse_math_operation, tree::ASTTreeNode, types::parse_type_declaration, var::decl::parse_variable_declaration}}; +use crate::ast::{control::{forloop::parse_for_loop, ifelse::parse_if_statement, whileblock::parse_while_block}, func::{call::parse_function_call, decl::{parse_function_declaraction, parse_shadow_function_declaration}, parse_function_return_statement}, literals::{parse_integer_literal, parse_string_literal}, math::parse_math_operation, tree::ASTTreeNode, types::parse_type_declaration, var::{decl::parse_variable_declaration, staticdecl::parse_static_function_declaration}}; pub mod tree; pub mod func; @@ -196,10 +196,18 @@ pub fn parse_ast_node(tokens: &Vec, ind: &mut usize) -> PositionedRe return parse_function_declaraction(tokens, ind); }, + LexerTokenType::ShadowFunction => { + return parse_shadow_function_declaration(tokens, ind); + } + LexerTokenType::Struct => { return parse_type_declaration(tokens, ind, false); }, + LexerTokenType::Static => { + return parse_static_function_declaration(tokens, ind); + } + LexerTokenType::Layout => { return parse_type_declaration(tokens, ind, true); }, @@ -228,6 +236,10 @@ pub fn parse_ast_node_in_body(tokens: &Vec, ind: &mut usize) -> Posi LexerTokenType::For => { return parse_for_loop(tokens, ind); + }, + + LexerTokenType::Return => { + return parse_function_return_statement(tokens, ind); } LexerTokenType::KEYWORD(str, _) => { diff --git a/parser/src/ast/tree.rs b/parser/src/ast/tree.rs index 804577d..406f319 100644 --- a/parser/src/ast/tree.rs +++ b/parser/src/ast/tree.rs @@ -5,8 +5,6 @@ use lexer::toks::{comp::ComparingOperator, math::MathOperator}; use utils::hash::{TypeHash, WithHash}; -use crate::ast::func; - #[derive(Debug, PartialEq, Clone)] pub struct FunctionDeclarationArgument { pub name: WithHash, @@ -39,18 +37,22 @@ pub enum ASTTreeNode { VarValueChange { var: Box, value: Box }, VarIncrement { var: Box, increment_by: Option> }, // Default is by 1 - IfStatement { cond: Box, body: Vec>, else_statement: Option> }, - IfElseStatement { cond: Option>, body: Vec>, else_statement: Option> }, + IfStatement { cond: Box, body: Vec>, branches: Vec>, depth: usize }, + IfElseStatement { cond: Option>, body: Vec> }, ElseStatement { body: Vec> }, + ReturnStatement { val: Option> }, + + StaticVariableDeclaration { name: WithHash, var_type: TypeHash, val: Box }, + WhileBlock { cond: Box, body: Vec> }, ForBlock { initial_state: Box, cond: Box, increment: Box, body: Vec> }, - Return { value: Option> }, - FunctionCall { func: WithHash, args: Vec> }, - FunctionDeclaration { func_name: WithHash, args: Vec, body: Vec> }, - + FunctionDeclaration { func_name: WithHash, args: Vec, body: Vec>, returnType: Option }, + + ShadowFunctionDeclaration { func_name: WithHash, args: Vec, returnType: Option }, + StructLRVariable { l: Box, r: Box,}, StructLRFunction { l: Box, r: Box, } } @@ -65,15 +67,23 @@ impl ASTTreeNode { } pub fn is_tree_permissible(&self) -> bool { - return matches!(self, ASTTreeNode::FunctionDeclaration { .. } | ASTTreeNode::StructLayoutDeclaration { .. }) + return matches!(self, ASTTreeNode::FunctionDeclaration { .. } | ASTTreeNode::StaticVariableDeclaration { .. } | ASTTreeNode::ShadowFunctionDeclaration { .. }| ASTTreeNode::StructLayoutDeclaration { .. }) } pub fn get_tree_name(&self) -> Option> { match self { - ASTTreeNode::FunctionDeclaration { func_name, args, body } => { + ASTTreeNode::FunctionDeclaration { func_name, args, body, returnType } => { return Some(WithHash::new(func_name.val.to_string())); }, + ASTTreeNode::ShadowFunctionDeclaration { func_name, args, returnType } => { + return Some(WithHash::new(func_name.val.to_string())) + } + + ASTTreeNode::StaticVariableDeclaration { name, var_type, val } => { + return Some(WithHash::new(name.val.clone())); + }, + ASTTreeNode::StructLayoutDeclaration { name, layout, members } => { return Some(WithHash::new(name.val.to_string())); }, diff --git a/parser/src/ast/var/mod.rs b/parser/src/ast/var/mod.rs index 96ed48d..3ff32b2 100644 --- a/parser/src/ast/var/mod.rs +++ b/parser/src/ast/var/mod.rs @@ -1,3 +1,4 @@ //! AST parsing for variable related elements (variable declarations, modifications, ...) -pub mod decl; \ No newline at end of file +pub mod decl; +pub mod staticdecl; \ No newline at end of file diff --git a/parser/src/ast/var/staticdecl.rs b/parser/src/ast/var/staticdecl.rs new file mode 100644 index 0000000..d15b21d --- /dev/null +++ b/parser/src/ast/var/staticdecl.rs @@ -0,0 +1,22 @@ +use commons::err::PositionedResult; +use lexer::token::{LexerToken, LexerTokenType}; +use utils::hash::WithHash; + +use crate::ast::{parse_ast_value, tree::ASTTreeNode, var}; + +pub fn parse_static_function_declaration(tokens: &Vec, ind: &mut usize) -> PositionedResult> { + *ind += 1; + + let var_type = tokens[*ind].expects_keyword()?; + *ind += 1; + + let var_name = tokens[*ind].expects_keyword()?; + *ind += 1; + + tokens[*ind].expects(LexerTokenType::EqualSign)?; + *ind += 1; + + let val = parse_ast_value(tokens, ind)?; + + return Ok(Box::new(ASTTreeNode::StaticVariableDeclaration { name: WithHash::new(var_name.0), val, var_type: var_type.1 })) +} \ No newline at end of file diff --git a/parser/src/ctx/mod.rs b/parser/src/ctx/mod.rs index 18a7088..85a268e 100644 --- a/parser/src/ctx/mod.rs +++ b/parser/src/ctx/mod.rs @@ -4,12 +4,13 @@ use crate::ast::tree::ASTTreeNode; #[derive(Debug)] pub struct ParserCtx { - pub map: HashMap> + pub map: HashMap>, + pub iter_order: Vec } impl ParserCtx { pub fn new() -> Self { - return ParserCtx { map: HashMap::new() } + return ParserCtx { map: HashMap::new(), iter_order: Vec::new() } } pub fn insert(&mut self, name: String, node: Box) -> bool { @@ -17,6 +18,8 @@ impl ParserCtx { return false; } + self.iter_order.push(name.clone()); + self.map.insert(name, node); return true; } diff --git a/test-main/Cargo.toml b/test-main/Cargo.toml index 3ed57f7..9aae5a2 100644 --- a/test-main/Cargo.toml +++ b/test-main/Cargo.toml @@ -5,4 +5,6 @@ edition = "2024" [dependencies] lexer = { path = "../lexer" } -parser = { path = "../parser" } \ No newline at end of file +parser = { path = "../parser" } +ir = { path = "../ir" } +inkwell = { version = "0.8.0", features = ["llvm21-1"]} diff --git a/test-main/src/main.rs b/test-main/src/main.rs index 8119647..4a6b0db 100644 --- a/test-main/src/main.rs +++ b/test-main/src/main.rs @@ -1,7 +1,10 @@ -use std::{env}; +use core::{fmt, hash}; +use std::{env, hash::{DefaultHasher, Hash, Hasher}, rc::Rc}; +use inkwell::{context::Context, module::Module}; +use ir::{conv::parse_ir_node_toplevel, ctx::IRContext, irstruct::{funcs::IRFunction, ptr::IRPointer, staticvars::IRStaticVariable, structs::IRStructuredType}, refs::IRValueRef, types::{POINTER_TYPE_HASH, SIGNED32_TYPE_HASH, UNSIGNED32_TYPE_HASH, storage::IRTypeStorage, typing::IRType}, values::IRValue}; use lexer::lexer::lexer_parse_file; -use parser::{ast::parse_ast_node, parse_ast_ctx}; +use parser::{ast::func, parse_ast_ctx}; fn main() { let args: Vec = env::args().collect(); @@ -9,8 +12,21 @@ fn main() { let lexer_res = lexer_parse_file(file_path).expect("Bad lexer!"); - let ctx = parse_ast_ctx(&lexer_res); + let ctx = parse_ast_ctx(&lexer_res).unwrap(); - println!("{:#?}", ctx); + let context = Rc::new(Context::create()); + + let mut hasher= DefaultHasher::new(); + "ptr".hash(&mut hasher); + + println!("{}", hasher.finish()); + + let mut irctx = IRContext::new(context); + + for entry in ctx.iter_order { + parse_ir_node_toplevel(&mut irctx, ctx.map.get(&entry).unwrap().clone()).unwrap(); + } + + irctx.module.print_to_file("output.ll").unwrap(); } diff --git a/utils/src/hash.rs b/utils/src/hash.rs index bac5f7a..1acdc0d 100644 --- a/utils/src/hash.rs +++ b/utils/src/hash.rs @@ -14,7 +14,7 @@ pub type TypeHash = u64; #[derive(Debug, PartialEq, Clone)] pub struct WithHash { pub val: K, - hash: u64 + pub hash: u64 } impl WithHash {