diff --git a/.gitignore b/.gitignore index 57f3b0e7..a10bf95e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ out out.* *.qf -*.qfmir *.llvm +*.air !examples/**.qf \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index dec2b97b..a4e0e32d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,7 @@ dependencies = [ "ast", "ast_parser", "astoir", + "astoir_mir", "clap", "compiler_utils", "diagnostics", diff --git a/compiler/ast/src/lib.rs b/compiler/ast/src/lib.rs index 3725aeeb..19193580 100644 --- a/compiler/ast/src/lib.rs +++ b/compiler/ast/src/lib.rs @@ -4,5 +4,6 @@ pub mod ctx; pub mod operators; +pub mod ranges; pub mod tree; pub mod types; diff --git a/compiler/ast/src/operators.rs b/compiler/ast/src/operators.rs index 6da2475d..46c673d7 100644 --- a/compiler/ast/src/operators.rs +++ b/compiler/ast/src/operators.rs @@ -72,15 +72,23 @@ pub fn parse_compare_operator( _ => false, }; + if eq { + *ind += 1; + } + let op = match tokens[*ind].tok_type { LexerTokenType::EqualSign => { - tokens[*ind + 1].expects(LexerTokenType::EqualSign)?; + if !eq { + tokens[*ind + 1].expects(LexerTokenType::EqualSign)?; + } ComparingOperator::Equal } LexerTokenType::ExclamationMark => { - tokens[*ind + 1].expects(LexerTokenType::EqualSign)?; + if !eq { + tokens[*ind + 1].expects(LexerTokenType::EqualSign)?; + } ComparingOperator::NotEqual } @@ -106,5 +114,7 @@ pub fn parse_compare_operator( } }; + *ind += 1; + return Ok(op); } diff --git a/compiler/ast/src/ranges.rs b/compiler/ast/src/ranges.rs new file mode 100644 index 00000000..5a97a11f --- /dev/null +++ b/compiler/ast/src/ranges.rs @@ -0,0 +1,7 @@ +use crate::tree::ASTTreeNode; + +#[derive(Debug, PartialEq, Clone)] +pub struct ASTRange { + pub min: Box, + pub max: Box, +} diff --git a/compiler/ast/src/tree.rs b/compiler/ast/src/tree.rs index dc0e6789..76d7fd1e 100644 --- a/compiler/ast/src/tree.rs +++ b/compiler/ast/src/tree.rs @@ -15,7 +15,7 @@ use diagnostics::{ diagnostic::{Diagnostic, Span, SpanKind, SpanPosition}, }; -use crate::types::ASTType; +use crate::{ranges::ASTRange, types::ASTType}; #[derive(Debug, PartialEq, Clone)] pub struct FunctionDeclarationArgument { @@ -78,7 +78,13 @@ pub enum ASTTreeNodeKind { VariableReference(HashedString), - PointerGrab(Box), + Dereference(Box), + + DereferenceModify { + pointer: Box, + val: Box, + }, + ReferenceGrab(Box), StructInitializer { @@ -166,6 +172,7 @@ pub enum ASTTreeNodeKind { cond: Box, body: Vec>, }, + ForBlock { initial_state: Box, cond: Box, @@ -173,6 +180,12 @@ pub enum ASTTreeNodeKind { body: Vec>, }, + RangedForBlock { + var: Box, + range: ASTRange, + body: Vec>, + }, + FunctionCall { func: HashedString, args: Vec>, @@ -185,7 +198,7 @@ pub enum ASTTreeNodeKind { requires_this: bool, }, - ShadowFunctionDeclaration { + ExternFunctionDeclaration { func_name: HashedString, args: Vec, return_type: Option, @@ -222,7 +235,7 @@ impl ASTTreeNodeKind { ASTTreeNodeKind::FunctionDeclaration { .. } | ASTTreeNodeKind::EnumDeclaration { .. } | ASTTreeNodeKind::StaticVariableDeclaration { .. } - | ASTTreeNodeKind::ShadowFunctionDeclaration { .. } + | ASTTreeNodeKind::ExternFunctionDeclaration { .. } | ASTTreeNodeKind::StructLayoutDeclaration { .. } ); } @@ -239,7 +252,7 @@ impl ASTTreeNodeKind { return Some(HashedString::new(func_name.val.to_string())); } - ASTTreeNodeKind::ShadowFunctionDeclaration { + ASTTreeNodeKind::ExternFunctionDeclaration { func_name, args: _, return_type: _, @@ -349,7 +362,8 @@ impl Display for ASTTreeNodeKind { Self::BooleanBasedConditionMember { .. } => "boolean condition", Self::MathResult { .. } => "math operation", Self::VariableReference(_) => "variable reference", - Self::PointerGrab(_) => "pointer grabbing", + Self::DereferenceModify { .. } => "modifying dereference", + Self::Dereference(_) => "dereference", Self::ReferenceGrab(_) => "reference", Self::StructInitializer { .. } => "struct value initializer", Self::ArrayVariableInitializerValue { .. } @@ -364,10 +378,10 @@ impl Display for ASTTreeNodeKind { Self::ReturnStatement { .. } => "return statement", Self::StaticVariableDeclaration { .. } => "static variable declaration", Self::WhileBlock { .. } => "while block", - Self::ForBlock { .. } => "for block", + Self::ForBlock { .. } | Self::RangedForBlock { .. } => "for block", Self::FunctionCall { .. } => "function call", Self::FunctionDeclaration { .. } => "function declaration", - Self::ShadowFunctionDeclaration { .. } => "shadow function declaration", + Self::ExternFunctionDeclaration { .. } => "extern function declaration", Self::StructLRFunction { .. } => "struct LRU function usage", Self::StructLRVariable { .. } => "struct LRU variable usage", Self::StructLayoutDeclaration { .. } => "struct / layout declaration", diff --git a/compiler/ast_parser/src/control/for_loop.rs b/compiler/ast_parser/src/control/for_loop.rs index 3ff2c66e..19c5e4a1 100644 --- a/compiler/ast_parser/src/control/for_loop.rs +++ b/compiler/ast_parser/src/control/for_loop.rs @@ -4,8 +4,8 @@ use lexer::token::{LexerToken, LexerTokenType}; use ast::tree::{ASTTreeNode, ASTTreeNodeKind}; use crate::{ - functions::parse_node_body, parser::parse_ast_node_in_body, value::parse_ast_value, - variables::decl::parse_variable_declaration, + functions::parse_node_body, parser::parse_ast_node_in_body, ranges::parse_value_range, + value::parse_ast_value, variables::decl::parse_variable_declaration, }; pub fn parse_for_loop( @@ -14,11 +14,18 @@ pub fn parse_for_loop( ) -> DiagnosticResult> { let start = tokens[*ind].pos.clone(); + if tokens[*ind + 1].tok_type != LexerTokenType::ParenOpen { + return parse_for_ranged_loop(tokens, ind); + } + *ind += 1; tokens[*ind].expects(LexerTokenType::ParenOpen)?; + *ind += 1; + + tokens[*ind].expects(LexerTokenType::Var)?; - let initial = parse_variable_declaration(tokens, ind)?; + let initial = parse_variable_declaration(tokens, ind, true)?; tokens[*ind].expects(LexerTokenType::Comma)?; @@ -50,3 +57,32 @@ pub fn parse_for_loop( end, ))); } + +pub fn parse_for_ranged_loop( + tokens: &Vec, + ind: &mut usize, +) -> DiagnosticResult> { + let start = tokens[*ind].pos.clone(); + + let var = parse_variable_declaration(tokens, ind, false)?; + + tokens[*ind].expects(LexerTokenType::EqualSign)?; + *ind += 1; + + tokens[*ind].expects(LexerTokenType::AngelBracketClose)?; + *ind += 1; + + let range = parse_value_range(tokens, ind)?; + + tokens[*ind].expects(LexerTokenType::BracketOpen)?; + + let body = parse_node_body(tokens, ind)?; + + let end: compiler_utils::Position = tokens[*ind - 1].get_end_pos(); + + Ok(Box::new(ASTTreeNode::new( + ASTTreeNodeKind::RangedForBlock { var, range, body }, + start, + end, + ))) +} diff --git a/compiler/ast_parser/src/functions/mod.rs b/compiler/ast_parser/src/functions/mod.rs index 67413bcc..60a7b345 100644 --- a/compiler/ast_parser/src/functions/mod.rs +++ b/compiler/ast_parser/src/functions/mod.rs @@ -17,6 +17,24 @@ pub mod arguments; pub mod returns; pub mod shadow; +pub fn parse_function_return_type( + tokens: &Vec, + ind: &mut usize, +) -> DiagnosticResult> { + if tokens[*ind].tok_type == LexerTokenType::Minus { + *ind += 1; + + tokens[*ind].expects(LexerTokenType::AngelBracketClose)?; + *ind += 1; + + let ty = parse_type(tokens, ind)?; + + return Ok(Some(ty)); + } else { + return Ok(None); + } +} + pub fn parse_function_declaraction( tokens: &Vec, ind: &mut usize, @@ -34,12 +52,7 @@ pub fn parse_function_declaraction( *ind += 1; - let mut ret_type = None; - - if tokens[*ind].is_keyword() { - ret_type = Some(parse_type(tokens, ind)?); - //*ind += 1; - } + let ret_type = parse_function_return_type(tokens, ind)?; tokens[*ind].expects(LexerTokenType::BracketOpen)?; @@ -108,20 +121,13 @@ pub fn parse_node_body( let mut tok: &LexerToken = &tokens[*ind]; let mut body: Vec> = Vec::new(); - let mut stock = 1; - while tok.tok_type != LexerTokenType::EndOfFile && tok.tok_type != LexerTokenType::BracketClose { - if tok.tok_type == LexerTokenType::BracketClose { - stock -= 1; - } - - if stock == 0 { - break; - } + if tok.tok_type == LexerTokenType::SemiCollon { + *ind += 1; + tok = &tokens[*ind]; - if tok.tok_type == LexerTokenType::BracketOpen { - stock += 1; + continue; } let n = parse_ast_node_in_body(tokens, ind)?; diff --git a/compiler/ast_parser/src/functions/shadow.rs b/compiler/ast_parser/src/functions/shadow.rs index c7edaa45..b9a78f69 100644 --- a/compiler/ast_parser/src/functions/shadow.rs +++ b/compiler/ast_parser/src/functions/shadow.rs @@ -5,9 +5,9 @@ use compiler_utils::hash::HashedString; use diagnostics::DiagnosticResult; use lexer::token::{LexerToken, LexerTokenType}; -use crate::{functions::arguments::parse_function_arguments, types::parse_type}; +use crate::functions::{arguments::parse_function_arguments, parse_function_return_type}; -pub fn parse_shadow_function_declaration( +pub fn parse_extern_function_definition( tokens: &Vec, ind: &mut usize, ) -> DiagnosticResult> { @@ -23,19 +23,11 @@ pub fn parse_shadow_function_declaration( *ind += 1; - let mut ret_type = None; - let end; - - if tokens[*ind].is_keyword() { - ret_type = Some(parse_type(tokens, ind)?); - - end = tokens[*ind].get_end_pos().clone(); - } else { - end = tokens[*ind - 1].get_end_pos().clone(); - } + let ret_type = parse_function_return_type(tokens, ind)?; + let end = tokens[*ind].get_end_pos(); return Ok(Box::new(ASTTreeNode::new( - ASTTreeNodeKind::ShadowFunctionDeclaration { + ASTTreeNodeKind::ExternFunctionDeclaration { func_name: HashedString::new(function_name.0), args: args.0, return_type: ret_type, diff --git a/compiler/ast_parser/src/lib.rs b/compiler/ast_parser/src/lib.rs index f0379bfb..f1011516 100644 --- a/compiler/ast_parser/src/lib.rs +++ b/compiler/ast_parser/src/lib.rs @@ -15,6 +15,8 @@ pub mod functions; pub mod literals; pub mod math; pub mod parser; +pub mod pointers; +pub mod ranges; pub mod structs; pub mod types; pub mod unwraps; diff --git a/compiler/ast_parser/src/math.rs b/compiler/ast_parser/src/math.rs index 92d4e235..68eca92e 100644 --- a/compiler/ast_parser/src/math.rs +++ b/compiler/ast_parser/src/math.rs @@ -31,8 +31,6 @@ pub fn parse_math_operation( .into()); } - println!("{:#?}", tokens[*ind].tok_type); - let right_member = parse_ast_value(tokens, ind)?; let start = original.start.clone(); diff --git a/compiler/ast_parser/src/parser.rs b/compiler/ast_parser/src/parser.rs index 84f207dc..2b5fbd1c 100644 --- a/compiler/ast_parser/src/parser.rs +++ b/compiler/ast_parser/src/parser.rs @@ -15,8 +15,9 @@ use crate::{ }, functions::{ parse_function_call, parse_function_declaraction, returns::parse_function_return_statement, - shadow::parse_shadow_function_declaration, + shadow::parse_extern_function_definition, }, + pointers::parse_deref_modify, structs::{enums::parse_enum_declaration, parse_type_declaration}, use_statements::parse_use_statement, value::parse_ast_value_post_l, @@ -39,8 +40,8 @@ pub fn parse_ast_node( return parse_function_declaraction(tokens, ind, None); } - LexerTokenType::ShadowFunction => { - return parse_shadow_function_declaration(tokens, ind); + LexerTokenType::ExternFunc => { + return parse_extern_function_definition(tokens, ind); } LexerTokenType::Struct => { @@ -76,7 +77,7 @@ pub fn parse_ast_node_in_body( ) -> DiagnosticResult> { match &tokens[*ind].tok_type { LexerTokenType::Var => { - return parse_variable_declaration(tokens, ind); + return parse_variable_declaration(tokens, ind, true); } LexerTokenType::If => { @@ -91,6 +92,8 @@ pub fn parse_ast_node_in_body( return parse_for_loop(tokens, ind); } + LexerTokenType::Asterisk => return parse_deref_modify(tokens, ind), + LexerTokenType::Return => { return parse_function_return_statement(tokens, ind); } @@ -98,6 +101,7 @@ pub fn parse_ast_node_in_body( LexerTokenType::Keyword(str, _) => { if tokens[*ind + 1].tok_type == LexerTokenType::ParenOpen { let call = parse_function_call(tokens, ind); + return parse_ast_value_post_l(tokens, ind, call, true); } diff --git a/compiler/ast_parser/src/pointers.rs b/compiler/ast_parser/src/pointers.rs new file mode 100644 index 00000000..157388c5 --- /dev/null +++ b/compiler/ast_parser/src/pointers.rs @@ -0,0 +1,30 @@ +use ast::tree::{ASTTreeNode, ASTTreeNodeKind}; +use diagnostics::DiagnosticResult; +use lexer::token::{LexerToken, LexerTokenType}; + +use crate::value::{parse_ast_value, parse_ast_value_full}; + +pub fn parse_deref_modify( + tokens: &Vec, + ind: &mut usize, +) -> DiagnosticResult> { + *ind += 1; // * + + let pointer = parse_ast_value_full(tokens, ind, false)?; + + tokens[*ind].expects(LexerTokenType::EqualSign)?; + *ind += 1; // = + + let val = parse_ast_value(tokens, ind)?; + + let deref = Box::new(ASTTreeNode::new( + ASTTreeNodeKind::DereferenceModify { + pointer, + val: val.clone(), + }, + val.start.clone(), + val.end, + )); + + Ok(deref) +} diff --git a/compiler/ast_parser/src/ranges.rs b/compiler/ast_parser/src/ranges.rs new file mode 100644 index 00000000..8e45aad3 --- /dev/null +++ b/compiler/ast_parser/src/ranges.rs @@ -0,0 +1,50 @@ +use ast::{ + ranges::ASTRange, + tree::{ASTTreeNode, ASTTreeNodeKind}, +}; +use compiler_utils::hash; +use diagnostics::DiagnosticResult; +use lexer::token::{LexerToken, LexerTokenType}; + +use crate::value::parse_ast_value; + +pub fn parse_value_range(tokens: &Vec, ind: &mut usize) -> DiagnosticResult { + tokens[*ind].expects(LexerTokenType::ArrayOpen)?; + *ind += 1; + + let min; + let mut got_first_dot = false; + + if tokens[*ind].tok_type == LexerTokenType::Dot { + min = Box::new(ASTTreeNode::new( + ASTTreeNodeKind::IntegerLit { + val: 0, + hash: hash!("s64"), + }, + tokens[*ind].pos.clone(), + tokens[*ind].get_end_pos(), + )); + + got_first_dot = true; + + *ind += 1; + } else { + min = parse_ast_value(tokens, ind)?; + } + + tokens[*ind].expects(LexerTokenType::Dot)?; + *ind += 1; + + if !got_first_dot { + tokens[*ind].expects(LexerTokenType::Dot)?; + *ind += 1; + } + + let max = parse_ast_value(tokens, ind)?; + + tokens[*ind].expects(LexerTokenType::ArrayClose)?; + + *ind += 1; + + Ok(ASTRange { min, max }) +} diff --git a/compiler/ast_parser/src/use_statements.rs b/compiler/ast_parser/src/use_statements.rs index 20327639..4ddf79e5 100644 --- a/compiler/ast_parser/src/use_statements.rs +++ b/compiler/ast_parser/src/use_statements.rs @@ -22,6 +22,9 @@ pub fn parse_use_statement( tokens[*ind].expects(LexerTokenType::Collon)?; *ind += 1; + + tokens[*ind].expects(LexerTokenType::Collon)?; + *ind += 1; } tokens[*ind].expects(LexerTokenType::ArrayOpen)?; diff --git a/compiler/ast_parser/src/value.rs b/compiler/ast_parser/src/value.rs index 1e453cf2..07c5574e 100644 --- a/compiler/ast_parser/src/value.rs +++ b/compiler/ast_parser/src/value.rs @@ -125,10 +125,14 @@ pub fn parse_ast_value_post_l( | LexerTokenType::Minus | LexerTokenType::Asterisk | LexerTokenType::Divide => { - let o = &original?; + let o = &original.clone()?; let k = Box::new(ASTTreeNode::clone(o.as_ref())); - return Ok(parse_math_operation(tokens, ind, k, invoked_on_body)?); + if !invoked_on_body { + return Ok(parse_math_operation(tokens, ind, k, invoked_on_body)?); + } else { + return original; + } } LexerTokenType::ArrayOpen => { @@ -215,14 +219,23 @@ pub fn parse_ast_condition_if_statement_value( /// - Math operation results (both with or without value changing) /// - Boolean negation result /// - Boolean compare result + pub fn parse_ast_value( tokens: &Vec, ind: &mut usize, +) -> DiagnosticResult> { + parse_ast_value_full(tokens, ind, true) +} + +pub fn parse_ast_value_full( + tokens: &Vec, + ind: &mut usize, + allow_lparsing: bool, ) -> DiagnosticResult> { match &tokens[*ind].tok_type { LexerTokenType::ExclamationMark => { *ind += 1; - let ast = parse_ast_value(tokens, ind)?; + let ast = parse_ast_value_full(tokens, ind, allow_lparsing)?; if ast.kind.is_function_call() || ast.kind.is_var_access() { let end = ast.end.clone(); @@ -248,17 +261,27 @@ pub fn parse_ast_value( return parse_ast_array_init(tokens, ind); } - LexerTokenType::Asterisk => return parse_ast_pointer(tokens, ind), + LexerTokenType::Asterisk => return parse_ast_dereference(tokens, ind), LexerTokenType::Ampersand => return parse_ast_reference(tokens, ind), LexerTokenType::IntLit(_, _) => { let int = parse_integer_literal(tokens, ind); - return parse_ast_value_post_l(tokens, ind, int, false); + + if allow_lparsing { + return parse_ast_value_post_l(tokens, ind, int, false); + } else { + return int; + } } LexerTokenType::StringLit(_) => { let str = parse_string_literal(tokens, ind); - return parse_ast_value_post_l(tokens, ind, str, false); + + if allow_lparsing { + return parse_ast_value_post_l(tokens, ind, str, false); + } else { + return str; + } } LexerTokenType::BracketOpen => { @@ -268,7 +291,12 @@ pub fn parse_ast_value( LexerTokenType::Keyword(str, _) => { if tokens[*ind + 1].tok_type == LexerTokenType::ParenOpen { let call = parse_function_call(tokens, ind); - return parse_ast_value_post_l(tokens, ind, call, false); + + if allow_lparsing { + return parse_ast_value_post_l(tokens, ind, call, false); + } else { + return call; + } } let n = Ok(make_node!( @@ -281,7 +309,11 @@ pub fn parse_ast_value( let chain = parse_ast_value_dotacess(tokens, ind, n); - return parse_ast_value_post_l(tokens, ind, chain, false); + if allow_lparsing { + return parse_ast_value_post_l(tokens, ind, chain, false); + } else { + return chain; + } } LexerTokenType::Unwrap | LexerTokenType::UnwrapUnsafe => parse_unwrap_value(tokens, ind), @@ -339,7 +371,7 @@ pub fn parse_ast_array_init( ))); } -pub fn parse_ast_pointer( +pub fn parse_ast_dereference( tokens: &Vec, ind: &mut usize, ) -> DiagnosticResult> { @@ -351,7 +383,7 @@ pub fn parse_ast_pointer( let value = parse_ast_value(tokens, ind)?; return Ok(Box::new(ASTTreeNode::new( - ASTTreeNodeKind::PointerGrab(value), + ASTTreeNodeKind::Dereference(value), start, tokens[*ind].get_end_pos(), ))); diff --git a/compiler/ast_parser/src/variables/decl.rs b/compiler/ast_parser/src/variables/decl.rs index 827ee269..c9240a15 100644 --- a/compiler/ast_parser/src/variables/decl.rs +++ b/compiler/ast_parser/src/variables/decl.rs @@ -9,6 +9,7 @@ use crate::{types::parse_type, value::parse_ast_value}; pub fn parse_variable_declaration( tokens: &Vec, ind: &mut usize, + allow_value: bool, ) -> DiagnosticResult> { let start = tokens[*ind].pos.clone(); @@ -23,7 +24,7 @@ pub fn parse_variable_declaration( let mut val: Option> = None; let end; - if tokens[*ind].tok_type == LexerTokenType::EqualSign { + if tokens[*ind].tok_type == LexerTokenType::EqualSign && allow_value { *ind += 1; val = Some(parse_ast_value(tokens, ind)?); diff --git a/compiler/astoir_hir/src/ctx.rs b/compiler/astoir_hir/src/ctx.rs index f978dac3..bf8871f6 100644 --- a/compiler/astoir_hir/src/ctx.rs +++ b/compiler/astoir_hir/src/ctx.rs @@ -30,25 +30,41 @@ pub type HIRFunctionImpl = Box; /// Every variable has a specific branch period called era in which they are allowed to live in. An era can simply be defined as a branch index. /// /// Every branch index stores an end branch index from when it ends (inside of `ending_eras`). This end branch index will be used to calculate when the era of a variable ends. -/// -/// #[derive(Debug, Clone)] pub struct HIRBranchedContext { pub hash_to_ind: HashMap, // TODO: add a layer system to this so you are able to put multiple variables with the same name. pub ending_eras: HashMap, pub variables: Vec, // index is the resolved indec + pub ending_points: Vec, + + pub return_type: Option, pub current_branch: usize, pub current_element_index: usize, } +#[derive(Debug, Clone)] +pub struct HIRBranchedEndingPoint { + pub introduced_in_era: usize, + pub kind: EndingPointKind, +} + +#[derive(Debug, Clone)] +pub enum EndingPointKind { + Return, + Crash, + NoneReturn, +} + impl HIRBranchedContext { - pub fn new() -> Self { + pub fn new(return_type: Option) -> Self { HIRBranchedContext { hash_to_ind: HashMap::new(), ending_eras: HashMap::new(), - variables: Vec::new(), + ending_points: vec![], + variables: vec![], + return_type, current_branch: 0, current_element_index: 0, } @@ -168,17 +184,59 @@ impl HIRBranchedContext { return true; } + pub fn introduce_ending_point(&mut self, kind: EndingPointKind) { + self.ending_points.push(HIRBranchedEndingPoint { + introduced_in_era: self.current_branch, + kind, + }) + } + /// Determines if the element with the given index is still alive in the current branch. pub fn is_alive(&self, ind: usize) -> bool { let start_branch = self.variables[ind].introduced_in_era; - if start_branch > self.current_element_index { + if start_branch > self.current_branch { return false; } return self.is_era_alive(start_branch); } + /// Checks if the code is currently alive on the given branch. Alive meaning before an ending point has taken effect. + /// This function can also be used to detect unreachable code by using this function on the current branch + pub fn is_code_alive(&self, branch: usize) -> bool { + for ending in &self.ending_points { + let end = match self.ending_eras.get(&ending.introduced_in_era) { + Some(v) => *v, + None => ending.introduced_in_era, + }; + + if branch >= end { + return false; + } + } + + true + } + + /// Determines if the current function meets the ending point requirement. + /// The requirement is that every single branch should have an ending point that affects it. + /// This function uses `is_code_alive` to check if the code ended on each branch before the current branch. + /// This function should only be ran at the end of body parsing + pub fn meets_ending_point(&self) -> bool { + if !self.is_code_alive(self.current_branch) { + return true; + } + + for i in 0..self.current_branch { + if self.is_code_alive(i) { + return false; + } + } + + return true; + } + pub fn is_era_alive(&self, era: usize) -> bool { if !self.ending_eras.contains_key(&era) { // If the era hasn't ended yet, (the ending era isn't added for branch start_branch) @@ -237,7 +295,13 @@ impl HIRBranchedContext { return Err(make_doesnt_exist_in_era(origin, &hash).into()); } - panic!("Dropped unalived variable") + println!( + "Variable dropped before! Information dump: introduced {}, ending era {}", + self.variables[ind].introduced_in_era, + self.ending_eras[&self.variables[ind].introduced_in_era] + ); + + panic!("Dropped unalived variable {} -> hash {}", ind, hash); } self.variables[ind].usage_count += 1; @@ -253,7 +317,7 @@ impl HIRBranchedContext { return !var.requires_address && var.mutation_count <= 1 && !var.variable_type.can_use_index_access() - && false; + && !var.variable_type.is_struct(); } } diff --git a/compiler/astoir_hir/src/nodes.rs b/compiler/astoir_hir/src/nodes.rs index d9bc8ce1..c0e23a6d 100644 --- a/compiler/astoir_hir/src/nodes.rs +++ b/compiler/astoir_hir/src/nodes.rs @@ -21,7 +21,7 @@ use diagnostics::{ use crate::{ ctx::{HIRBranchedContext, HIRContext}, resolve::resolve_to_type, - structs::{HIRIfBranch, StructLRUStep}, + structs::{HIRIfBranch, HIRRange, StructLRUStep}, }; #[derive(Debug, Clone)] @@ -129,7 +129,12 @@ pub enum HIRNodeKind { index: usize, }, - PointerGrab { + DereferenceModify { + pointer: Box, + val: Box, + }, + + Dereference { val: Box, }, ReferenceGrab { @@ -201,7 +206,7 @@ pub enum HIRNodeKind { requires_this: bool, }, - ShadowFunctionDeclaration { + ExternFunctionDeclaration { func_name: usize, arguments: Vec<(u64, Type)>, return_type: Option, @@ -223,6 +228,12 @@ pub enum HIRNodeKind { body: Vec>, }, + RangedForBlock { + variable: Box, + range: HIRRange, + body: Vec>, + }, + IfStatement { branches: Vec, }, @@ -259,6 +270,13 @@ impl HIRNode { return false; } + pub fn is_ending_point(&self) -> bool { + match self.kind { + HIRNodeKind::ReturnStatement { .. } => true, + _ => false, + } + } + pub fn get_variable_represent(&self) -> (usize, bool) { match &self.kind { HIRNodeKind::VariableReference { index, is_static } => return (*index, *is_static), @@ -424,19 +442,23 @@ impl HIRNode { return Some(curr_ctx.variables[*index].variable_type.clone()); } - HIRNodeKind::PointerGrab { val } => { + HIRNodeKind::Dereference { val } => { + let ty = val.get_node_type(context, curr_ctx).unwrap(); + + if ty.is_generic_direct() { + None + } else { + Some(*ty.get_inner_type()) + } + } + + HIRNodeKind::ReferenceGrab { val } => { return Some(Type::Pointer( false, Box::new(val.get_node_type(context, curr_ctx).unwrap()), )); } - HIRNodeKind::ReferenceGrab { val } => { - return Some(Type::Reference(Box::new( - val.get_node_type(context, curr_ctx).unwrap(), - ))); - } - HIRNodeKind::UnwrapCondition { .. } => { return Some(Type::Generic(RawType::Boolean, vec![], vec![])); } diff --git a/compiler/astoir_hir/src/structs.rs b/compiler/astoir_hir/src/structs.rs index 5c3725a1..0c688b31 100644 --- a/compiler/astoir_hir/src/structs.rs +++ b/compiler/astoir_hir/src/structs.rs @@ -28,6 +28,12 @@ pub enum HIRIfBranch { }, } +#[derive(Clone, Debug)] +pub struct HIRRange { + pub min: Box, + pub max: Box, +} + #[derive(Debug)] pub struct HIRStructContainer { pub function_impls: Vec>, diff --git a/compiler/astoir_hir_lowering/src/control.rs b/compiler/astoir_hir_lowering/src/control.rs index 373ac77a..490fedfc 100644 --- a/compiler/astoir_hir_lowering/src/control.rs +++ b/compiler/astoir_hir_lowering/src/control.rs @@ -4,11 +4,12 @@ use astoir_hir::{ nodes::{HIRNode, HIRNodeKind}, structs::HIRIfBranch, }; +use compiler_typing::{raw::RawType, tree::Type}; use diagnostics::DiagnosticResult; use crate::{ bools::lower_ast_condition, lower_ast_body, math::lower_ast_math_operation, - var::lower_ast_variable_declaration, + values::lower_ast_range, var::lower_ast_variable_declaration, }; pub fn lower_ast_for_block( @@ -25,7 +26,8 @@ pub fn lower_ast_for_block( { let branch = curr_ctx.start_branch(); - let initial = lower_ast_variable_declaration(context, curr_ctx, initial_state)?; + let initial = + lower_ast_variable_declaration(context, curr_ctx, initial_state, false, None)?; let condition = lower_ast_condition(context, curr_ctx, cond)?; let incrementation = lower_ast_math_operation(context, curr_ctx, increment, true)?; @@ -49,6 +51,38 @@ pub fn lower_ast_for_block( panic!("Invalid node passed!"); } +pub fn lower_ast_for_ranged_block( + context: &mut HIRContext, + curr_ctx: &mut HIRBranchedContext, + node: Box, +) -> DiagnosticResult> { + if let ASTTreeNodeKind::RangedForBlock { var, range, body } = node.kind.clone() { + let branch = curr_ctx.start_branch(); + + let ty = Type::Generic(RawType::Integer(64, false), vec![], vec![]); + + let initial = + lower_ast_variable_declaration(context, curr_ctx, var, true, Some(ty.clone()))?; + + let range = lower_ast_range(context, curr_ctx, range, ty, &*node)?; + let body = lower_ast_body(context, curr_ctx, body, false)?; + + curr_ctx.end_branch(branch); + + return Ok(Box::new(HIRNode::new( + HIRNodeKind::RangedForBlock { + variable: initial, + range, + body, + }, + &node.start, + &node.end, + ))); + } + + panic!("Invalid node!") +} + pub fn lower_ast_while_block( context: &mut HIRContext, curr_ctx: &mut HIRBranchedContext, diff --git a/compiler/astoir_hir_lowering/src/func.rs b/compiler/astoir_hir_lowering/src/func.rs index c0ea4054..8067795e 100644 --- a/compiler/astoir_hir_lowering/src/func.rs +++ b/compiler/astoir_hir_lowering/src/func.rs @@ -5,7 +5,10 @@ use astoir_hir::{ }; use compiler_global_scope::key::EntryKey; use compiler_typing::TypedGlobalScopeEntry; -use diagnostics::{DiagnosticResult, builders::make_already_in_scope}; +use diagnostics::{ + DiagnosticResult, + builders::{make_already_in_scope, make_ending_point_missing}, +}; use crate::{lower_ast_body, types::lower_ast_type, values::lower_ast_value}; @@ -83,7 +86,7 @@ pub fn lower_ast_function_declaration( arguments.push((arg.name.hash, t)); } - let mut curr_ctx = HIRBranchedContext::new(); + let mut curr_ctx = HIRBranchedContext::new(ret_type.clone()); let branch = curr_ctx.start_branch(); @@ -115,10 +118,8 @@ pub fn lower_ast_function_declaration( curr_ctx.end_branch(branch); - for var in 0..curr_ctx.variables.len() { - if curr_ctx.is_eligible_for_ssa(var) { - println!("* Function variable {} is eligible for SSA treatment!", var); - } + if !curr_ctx.meets_ending_point() { + return Err(make_ending_point_missing(&*body[body.len() - 1]).into()); } let implementation = Box::new(HIRNode::new( @@ -159,11 +160,11 @@ pub fn lower_ast_function_declaration( panic!("Invalid node passed!"); } -pub fn lower_ast_shadow_function_declaration( +pub fn lower_ast_extern_function_declaration( context: &mut HIRContext, node: Box, ) -> DiagnosticResult> { - if let ASTTreeNodeKind::ShadowFunctionDeclaration { + if let ASTTreeNodeKind::ExternFunctionDeclaration { func_name, args, return_type, @@ -198,7 +199,7 @@ pub fn lower_ast_shadow_function_declaration( )?; return Ok(Box::new(HIRNode::new( - HIRNodeKind::ShadowFunctionDeclaration { + HIRNodeKind::ExternFunctionDeclaration { func_name: ind, arguments, return_type: ret_type, diff --git a/compiler/astoir_hir_lowering/src/lib.rs b/compiler/astoir_hir_lowering/src/lib.rs index 863a7b46..18996db2 100644 --- a/compiler/astoir_hir_lowering/src/lib.rs +++ b/compiler/astoir_hir_lowering/src/lib.rs @@ -3,24 +3,31 @@ use ast::{ tree::{ASTTreeNode, ASTTreeNodeKind}, }; use astoir_hir::{ - ctx::{HIRBranchedContext, HIRContext}, + ctx::{EndingPointKind, HIRBranchedContext, HIRContext}, nodes::{HIRNode, HIRNodeKind}, }; -use diagnostics::{DiagnosticResult, DiagnosticSpanOrigin, move_current_diagnostic_pos}; +use diagnostics::{ + DiagnosticResult, DiagnosticSpanOrigin, + builders::{make_ret_type_kind, make_unreachable_code}, + move_current_diagnostic_pos, +}; use prelude::apply_prelude; use crate::{ arrays::lower_ast_array_modify, - control::{lower_ast_for_block, lower_ast_if_statement, lower_ast_while_block}, + control::{ + lower_ast_for_block, lower_ast_for_ranged_block, lower_ast_if_statement, + lower_ast_while_block, + }, enums::lower_ast_enum, func::{ - lower_ast_function_call, lower_ast_function_declaration, - lower_ast_shadow_function_declaration, + lower_ast_extern_function_declaration, lower_ast_function_call, + lower_ast_function_declaration, }, math::lower_ast_math_operation, structs::lower_ast_struct_declaration, uses::handle_ast_use_statement, - values::lower_ast_value, + values::{lower_ast_pointer_modify, lower_ast_value}, var::{lower_ast_variable_assign, lower_ast_variable_declaration}, }; @@ -46,7 +53,7 @@ pub fn lower_ast_body_node( move_current_diagnostic_pos(node.get_pos()); match node.kind.clone() { ASTTreeNodeKind::VarDeclaration { .. } => { - return lower_ast_variable_declaration(context, curr_ctx, node); + return lower_ast_variable_declaration(context, curr_ctx, node, false, None); } ASTTreeNodeKind::FunctionCall { .. } => { return lower_ast_function_call(context, curr_ctx, node); @@ -65,10 +72,26 @@ pub fn lower_ast_body_node( ASTTreeNodeKind::ReturnStatement { val } => { let v; + if val.is_none() != curr_ctx.return_type.is_none() { + return Err(make_ret_type_kind(&*node).into()); + } + if val.is_none() { + curr_ctx.introduce_ending_point(EndingPointKind::NoneReturn); + v = None; } else { - v = Some(lower_ast_value(context, curr_ctx, val.unwrap())?) + curr_ctx.introduce_ending_point(EndingPointKind::Return); + + let k = Box::new(lower_ast_value(context, curr_ctx, val.unwrap())?.use_as( + context, + curr_ctx, + curr_ctx.return_type.clone().unwrap(), + &*node, + None, + )?); + + v = Some(k) } return Ok(Box::new(HIRNode::new( @@ -79,6 +102,9 @@ pub fn lower_ast_body_node( } ASTTreeNodeKind::ForBlock { .. } => return lower_ast_for_block(context, curr_ctx, node), + ASTTreeNodeKind::RangedForBlock { .. } => { + return lower_ast_for_ranged_block(context, curr_ctx, node); + } ASTTreeNodeKind::WhileBlock { .. } => { return lower_ast_while_block(context, curr_ctx, node); } @@ -86,6 +112,10 @@ pub fn lower_ast_body_node( return lower_ast_if_statement(context, curr_ctx, node); } + ASTTreeNodeKind::DereferenceModify { .. } => { + return lower_ast_pointer_modify(context, curr_ctx, node); + } + _ => panic!("Invalid node type"), } } @@ -107,7 +137,17 @@ pub fn lower_ast_body( } for n in nodes { - hir_nodes.push(lower_ast_body_node(context, curr_ctx, n)?); + let is_code_dead_pre = !curr_ctx.is_code_alive(curr_ctx.current_branch); + + let node = lower_ast_body_node(context, curr_ctx, n)?; + + if !curr_ctx.is_code_alive(curr_ctx.current_branch) { + if is_code_dead_pre || !node.is_ending_point() { + return Err(make_unreachable_code(&*node).into()); + } + } + + hir_nodes.push(node); } if introduce_era { @@ -128,8 +168,8 @@ pub fn lower_ast_toplevel( return Ok(true); } - ASTTreeNodeKind::ShadowFunctionDeclaration { .. } => { - lower_ast_shadow_function_declaration(context, node)?; + ASTTreeNodeKind::ExternFunctionDeclaration { .. } => { + lower_ast_extern_function_declaration(context, node)?; return Ok(true); } diff --git a/compiler/astoir_hir_lowering/src/structs.rs b/compiler/astoir_hir_lowering/src/structs.rs index 3dcd4cfc..82528523 100644 --- a/compiler/astoir_hir_lowering/src/structs.rs +++ b/compiler/astoir_hir_lowering/src/structs.rs @@ -62,7 +62,7 @@ fn lower_ast_struct_function_decl( ret_type = None; } - let mut curr_ctx = HIRBranchedContext::new(); + let mut curr_ctx = HIRBranchedContext::new(None); // TODO: remove type reference let body = lower_ast_body(context, &mut curr_ctx, body, true)?; let ind = container diff --git a/compiler/astoir_hir_lowering/src/values.rs b/compiler/astoir_hir_lowering/src/values.rs index c96a61ea..4a8ed030 100644 --- a/compiler/astoir_hir_lowering/src/values.rs +++ b/compiler/astoir_hir_lowering/src/values.rs @@ -1,14 +1,20 @@ -use ast::tree::{ASTTreeNode, ASTTreeNodeKind}; +use ast::{ + ranges::ASTRange, + tree::{ASTTreeNode, ASTTreeNodeKind}, +}; use astoir_hir::{ ctx::{HIRBranchedContext, HIRContext, get_variable}, nodes::{HIRNode, HIRNodeKind}, - structs::StructLRUStep, + structs::{HIRRange, StructLRUStep}, }; use compiler_global_scope::key::EntryKey; use compiler_typing::tree::Type; use diagnostics::{ - DiagnosticResult, - builders::{make_invalid_pointing, make_struct_missing_field, make_struct_missing_func}, + DiagnosticResult, DiagnosticSpanOrigin, + builders::{ + make_expected_simple_error, make_invalid_pointing, make_struct_missing_field, + make_struct_missing_func, + }, }; use crate::{ @@ -215,8 +221,7 @@ pub fn lower_ast_value( return lower_ast_variable_reference(context, curr_ctx, node, true); } - ASTTreeNodeKind::PointerGrab(_) => return lower_ast_pointer(context, curr_ctx, node), - + ASTTreeNodeKind::Dereference(_) => return lower_ast_pointer(context, curr_ctx, node), ASTTreeNodeKind::ReferenceGrab(_) => return lower_ast_reference(context, curr_ctx, node), ASTTreeNodeKind::UnwrapCondition { .. } => { @@ -231,6 +236,30 @@ pub fn lower_ast_value( } } +pub fn lower_ast_range( + context: &mut HIRContext, + curr_ctx: &mut HIRBranchedContext, + range: ASTRange, + ty: Type, + origin: &K, +) -> DiagnosticResult { + let min = Box::new( + lower_ast_value(context, curr_ctx, range.min.clone())?.use_as( + context, + curr_ctx, + ty.clone(), + origin, + None, + )?, + ); + let max = Box::new( + lower_ast_value(context, curr_ctx, range.max)? + .use_as(context, curr_ctx, ty, origin, None)?, + ); + + Ok(HIRRange { min, max }) +} + pub fn lower_ast_array_init( context: &mut HIRContext, curr_ctx: &mut HIRBranchedContext, @@ -269,19 +298,23 @@ pub fn lower_ast_pointer( curr_ctx: &mut HIRBranchedContext, node: Box, ) -> DiagnosticResult> { - if let ASTTreeNodeKind::PointerGrab(val) = node.kind.clone() { + if let ASTTreeNodeKind::Dereference(val) = node.kind.clone() { let val = lower_ast_value(context, curr_ctx, val)?; - if !val.is_variable_representative() { + let ty = val.get_node_type(context, curr_ctx); + + if ty.is_none() || !ty.unwrap().is_pointer() { return Err(make_invalid_pointing(&*node).into()); } - let r = val.get_variable_represent(); + // TODO: add deref counter perhaps? - curr_ctx.introduce_variable_refer(r.0); + //let r = val.get_variable_represent(); + + //curr_ctx.introduce_variable_refer(r.0); return Ok(Box::new(HIRNode::new( - HIRNodeKind::PointerGrab { val }, + HIRNodeKind::Dereference { val }, &node.start, &node.end, ))); @@ -290,6 +323,54 @@ pub fn lower_ast_pointer( panic!("Invalid node") } +pub fn lower_ast_pointer_modify( + context: &mut HIRContext, + curr_ctx: &mut HIRBranchedContext, + node: Box, +) -> DiagnosticResult> { + if let ASTTreeNodeKind::DereferenceModify { pointer, val } = node.kind.clone() { + let ptr = lower_ast_value(context, curr_ctx, pointer)?; + let ty = ptr.get_node_type(context, curr_ctx); + + let val = lower_ast_value(context, curr_ctx, val)?; + let val_type = val.get_node_type(context, curr_ctx).unwrap(); + + if ty.is_none() || !ty.clone().unwrap().is_pointer() { + return Err(make_invalid_pointing(&*node).into()); + } + + if !ty + .clone() + .unwrap() + .get_inner_type() + .can_transmute(&val_type, &context.global_scope.scope) + { + return Err(make_expected_simple_error(&*val, &ty.clone().unwrap(), &val_type).into()); + } + + let val = val.use_as( + context, + curr_ctx, + *ty.clone().unwrap().get_inner_type(), + &*val, + None, + )?; + + return Ok(Box::new(HIRNode::new( + HIRNodeKind::DereferenceModify { + pointer: ptr, + val: Box::new(val), + }, + &node.start, + &node.end, + ))); + } + + panic!("Invalid node") +} + +//pub fn lower_ast_pointer_modify() + pub fn lower_ast_reference( context: &mut HIRContext, curr_ctx: &mut HIRBranchedContext, diff --git a/compiler/astoir_hir_lowering/src/var.rs b/compiler/astoir_hir_lowering/src/var.rs index c22dbf19..1071d321 100644 --- a/compiler/astoir_hir_lowering/src/var.rs +++ b/compiler/astoir_hir_lowering/src/var.rs @@ -4,7 +4,11 @@ use astoir_hir::{ nodes::{HIRNode, HIRNodeKind}, }; use compiler_global_scope::key::EntryKey; -use diagnostics::{DiagnosticResult, builders::make_variable_uninit}; +use compiler_typing::tree::Type; +use diagnostics::{ + DiagnosticResult, + builders::{make_expected_simple_error, make_variable_uninit}, +}; use crate::{arrays::lower_ast_array_index_access, types::lower_ast_type, values::lower_ast_value}; @@ -12,6 +16,8 @@ pub fn lower_ast_variable_declaration( context: &mut HIRContext, curr_ctx: &mut HIRBranchedContext, node: Box, + force_default: bool, + enforce_type: Option, ) -> DiagnosticResult> { if let ASTTreeNodeKind::VarDeclaration { var_name, @@ -28,8 +34,17 @@ pub fn lower_ast_variable_declaration( let lowered = lower_ast_type(context, var_type, &*node)?; - let name_ind = - curr_ctx.introduce_variable(var_name.hash, lowered.clone(), value.is_some())?; + if let Some(enforce_type) = enforce_type { + if lowered != enforce_type { + return Err(make_expected_simple_error(&*node, &enforce_type, &lowered).into()); + } + } + + let name_ind = curr_ctx.introduce_variable( + var_name.hash, + lowered.clone(), + value.is_some() || force_default, + )?; let default_val; diff --git a/compiler/astoir_mir/src/blocks/mod.rs b/compiler/astoir_mir/src/blocks/mod.rs index 0e1109f1..67400512 100644 --- a/compiler/astoir_mir/src/blocks/mod.rs +++ b/compiler/astoir_mir/src/blocks/mod.rs @@ -1,11 +1,13 @@ -use std::{collections::HashMap, fmt::Display}; +use std::collections::HashMap; use diagnostics::{DiagnosticResult, unsure_panic}; use crate::{ + DisplayAstoIR, blocks::refer::MIRBlockReference, builder::build_phi, ctx::MIRContext, + fmt::DisplayWithCtx, inst_writer::BlockPosition, insts::MIRInstruction, vals::{base::BaseMIRValue, refer::MIRVariableReference}, @@ -109,6 +111,19 @@ impl MIRBlock { return ind; } + pub fn propagate_variables( + base: MIRBlockReference, + target: MIRBlockReference, + ctx: &mut MIRContext, + ) { + let variables = ctx.blocks[base].variables.clone(); + let target_block = &mut ctx.blocks[target]; + + for (ind, hint) in variables { + target_block.variables.insert(ind, hint); + } + } + pub fn get_variable_ref(&self, var_ind: usize) -> DiagnosticResult { let var = &self.variables[&var_ind]; @@ -183,8 +198,8 @@ impl MIRBlock { } } -impl Display for MIRBlock { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl DisplayAstoIR for MIRBlock { + fn format(&self, f: &mut std::fmt::Formatter<'_>, ctx: &MIRContext) -> std::fmt::Result { writeln!(f, "%block_{}", self.self_ref)?; if !self.merge_blocks.is_empty() { @@ -196,18 +211,24 @@ impl Display for MIRBlock { } for inst in &self.instructions { - write!(f, " {}", inst)?; + write!(f, " {}", DisplayWithCtx::new(ctx, inst))?; } Ok(()) } } -impl Display for MIRBlockHeldInstruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl DisplayAstoIR for MIRBlockHeldInstruction { + fn format(&self, f: &mut std::fmt::Formatter<'_>, ctx: &MIRContext) -> std::fmt::Result { match self { - Self::Valued(a, b) => write!(f, "#{} = {}", *b, a), - Self::Valueless(a) => write!(f, "{}", a), + Self::Valued(a, b) => writeln!( + f, + "({}) #{} = {}", + a.get_return_type(ctx), + b, + DisplayWithCtx::new(ctx, a) + ), + Self::Valueless(a) => writeln!(f, "(void) {}", DisplayWithCtx::new(ctx, a)), } } } diff --git a/compiler/astoir_mir/src/builder.rs b/compiler/astoir_mir/src/builder.rs index 6cea1cca..bf296a86 100644 --- a/compiler/astoir_mir/src/builder.rs +++ b/compiler/astoir_mir/src/builder.rs @@ -35,7 +35,9 @@ pub fn build_stack_alloc( } pub fn build_load(ctx: &mut MIRContext, ptr: MIRPointerValue) -> DiagnosticResult { - let res = ctx.append_inst(MIRInstruction::Load { value: ptr }).get()?; + let res = ctx + .append_inst(MIRInstruction::Load { value: ptr.clone() }) + .get()?; return Ok(res); } @@ -60,7 +62,8 @@ pub fn build_store( return build_store_fallback(ctx, ptr, val.clone(), storage); } - unsure_panic!("cannot put this value onto this pointer since it's not the type"); + //println!("Expected {}({}) got {}({})", hint, base, val.vtype, val); + unsure_panic!("cannot put this value onto this pointer since it's not the type."); } ctx.append_inst(MIRInstruction::Store { @@ -71,6 +74,17 @@ pub fn build_store( return Ok(()); } +pub fn build_pointer_deref( + ctx: &mut MIRContext, + val: MIRPointerValue, +) -> DiagnosticResult { + let res = ctx + .append_inst(MIRInstruction::DerefPointer { ptr: val }) + .get()?; + + Ok(res) +} + pub fn build_downcast_int( ctx: &mut MIRContext, val: MIRIntValue, diff --git a/compiler/astoir_mir/src/ctx.rs b/compiler/astoir_mir/src/ctx.rs index c08baeff..b87f2c85 100644 --- a/compiler/astoir_mir/src/ctx.rs +++ b/compiler/astoir_mir/src/ctx.rs @@ -1,14 +1,16 @@ -use std::{collections::HashMap, fmt::Display}; +use std::collections::HashMap; use diagnostics::DiagnosticResult; use crate::{ + DisplayAstoIR, blocks::{ MIRBlock, MIRBlockHeldInstruction, hints::{HintStorage, MIRValueHint}, refer::MIRBlockReference, }, builder::build_phi, + fmt::DisplayWithCtx, funcs::MIRFunction, inst_writer::{BlockPosition, InstructionWriterPosition}, insts::{MIRInstruction, val::InstructionValue}, @@ -152,14 +154,14 @@ impl MIRContext { } } -impl Display for MIRContext { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl DisplayAstoIR for MIRContext { + fn format(&self, f: &mut std::fmt::Formatter<'_>, ctx: &MIRContext) -> std::fmt::Result { for func in &self.functions { writeln!(f, "{}", func.1)?; } for block in &self.blocks { - writeln!(f, "{}", block)?; + writeln!(f, "{}", DisplayWithCtx::new(ctx, block))?; } Ok(()) diff --git a/compiler/astoir_mir/src/fmt.rs b/compiler/astoir_mir/src/fmt.rs new file mode 100644 index 00000000..5aafd95b --- /dev/null +++ b/compiler/astoir_mir/src/fmt.rs @@ -0,0 +1,20 @@ +use std::fmt::Display; + +use crate::{DisplayAstoIR, ctx::MIRContext}; + +pub struct DisplayWithCtx<'a, K: DisplayAstoIR> { + value: &'a K, + ctx: &'a MIRContext, +} + +impl<'a, K: DisplayAstoIR> DisplayWithCtx<'a, K> { + pub fn new(ctx: &'a MIRContext, value: &'a K) -> Self { + Self { value, ctx } + } +} + +impl<'a, K: DisplayAstoIR> Display for DisplayWithCtx<'a, K> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.value.format(f, self.ctx) + } +} diff --git a/compiler/astoir_mir/src/insts/mod.rs b/compiler/astoir_mir/src/insts/mod.rs index eddd8639..2a125d2d 100644 --- a/compiler/astoir_mir/src/insts/mod.rs +++ b/compiler/astoir_mir/src/insts/mod.rs @@ -1,12 +1,12 @@ //! The definitions for instructions within the MIR. -use std::fmt::Display; - use compiler_typing::{raw::RawType, tree::Type}; use crate::{ + DisplayAstoIR, blocks::refer::MIRBlockReference, ctx::MIRContext, + fmt::DisplayWithCtx, vals::{base::BaseMIRValue, float::MIRFloatValue, int::MIRIntValue, ptr::MIRPointerValue}, }; @@ -22,6 +22,11 @@ pub enum MIRInstruction { Load { value: MIRPointerValue, }, + + DerefPointer { + ptr: MIRPointerValue, + }, + Store { variable: MIRPointerValue, value: BaseMIRValue, @@ -315,13 +320,21 @@ impl MIRInstruction { pub fn get_return_type(&self, ctx: &MIRContext) -> Type { match self { - Self::StackAlloc { .. } => return Type::GenericLowered(RawType::Pointer), + Self::StackAlloc { alloc_size: _, t } => { + return Type::Pointer(false, Box::new(t.clone())); + } Self::Load { value } => { let base: BaseMIRValue = value.clone().into(); let hint = ctx.ssa_hints.get_hint(base.get_ssa_index()); - return hint.as_pointer(); + return hint.get_type(); + } + + Self::DerefPointer { ptr } => { + let base: BaseMIRValue = ptr.clone().into(); + + *base.vtype.get_inner_type() } Self::DowncastInteger { val, size } => { @@ -493,18 +506,19 @@ impl MIRInstruction { _ => panic!( "Tried using get_return_type on non returning type! {}", - self + DisplayWithCtx::new(ctx, self) ), } } } -impl Display for MIRInstruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl DisplayAstoIR for MIRInstruction { + fn format(&self, f: &mut std::fmt::Formatter<'_>, _ctx: &MIRContext) -> std::fmt::Result { match self { Self::StackAlloc { alloc_size, t: _ } => writeln!(f, "stkalloc {}", *alloc_size)?, Self::Load { value } => writeln!(f, "load {}", value)?, Self::Store { variable, value } => writeln!(f, "store d{} s{}", variable, value)?, + Self::DerefPointer { ptr } => writeln!(f, "ptrderef {}", ptr)?, Self::MemoryCopy { src, dest, sz } => { writeln!(f, "unsmemcopy s{} d{} {}b", src, dest, sz)? diff --git a/compiler/astoir_mir/src/lib.rs b/compiler/astoir_mir/src/lib.rs index ee4987c9..dc258d05 100644 --- a/compiler/astoir_mir/src/lib.rs +++ b/compiler/astoir_mir/src/lib.rs @@ -1,10 +1,17 @@ //! The MIR layer of the AstoIR. //! The MIR layer represents a block based representation of the program. Uses low level instructions near Assembly //! + +use crate::ctx::MIRContext; pub mod blocks; pub mod builder; pub mod ctx; +pub mod fmt; pub mod funcs; pub mod inst_writer; pub mod insts; pub mod vals; + +pub trait DisplayAstoIR { + fn format(&self, f: &mut std::fmt::Formatter<'_>, ctx: &MIRContext) -> std::fmt::Result; +} diff --git a/compiler/astoir_mir/src/vals/arrays.rs b/compiler/astoir_mir/src/vals/arrays.rs index ac331232..c08641da 100644 --- a/compiler/astoir_mir/src/vals/arrays.rs +++ b/compiler/astoir_mir/src/vals/arrays.rs @@ -28,8 +28,6 @@ impl Into for MIRArrayValue { impl Display for MIRArrayValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#{}", self.base.get_ssa_index())?; - - Ok(()) + self.base.fmt(f) } } diff --git a/compiler/astoir_mir/src/vals/base.rs b/compiler/astoir_mir/src/vals/base.rs index 9e64b697..1206a618 100644 --- a/compiler/astoir_mir/src/vals/base.rs +++ b/compiler/astoir_mir/src/vals/base.rs @@ -59,7 +59,7 @@ impl PartialEq for BaseMIRValue { impl Display for BaseMIRValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#{}", self.val_index)?; + write!(f, "#{} ({})", self.val_index, self.vtype)?; Ok(()) } diff --git a/compiler/astoir_mir/src/vals/float.rs b/compiler/astoir_mir/src/vals/float.rs index 7822ba07..9426fd9f 100644 --- a/compiler/astoir_mir/src/vals/float.rs +++ b/compiler/astoir_mir/src/vals/float.rs @@ -34,8 +34,6 @@ impl Into for MIRFloatValue { impl Display for MIRFloatValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#{}", self.base.get_ssa_index())?; - - Ok(()) + self.base.fmt(f) } } diff --git a/compiler/astoir_mir/src/vals/int.rs b/compiler/astoir_mir/src/vals/int.rs index 8ecb2369..b3164a66 100644 --- a/compiler/astoir_mir/src/vals/int.rs +++ b/compiler/astoir_mir/src/vals/int.rs @@ -42,8 +42,6 @@ impl Into for MIRIntValue { impl Display for MIRIntValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#{}", self.base.get_ssa_index())?; - - Ok(()) + self.base.fmt(f) } } diff --git a/compiler/astoir_mir/src/vals/ptr.rs b/compiler/astoir_mir/src/vals/ptr.rs index cca9bb7b..d2df76fc 100644 --- a/compiler/astoir_mir/src/vals/ptr.rs +++ b/compiler/astoir_mir/src/vals/ptr.rs @@ -31,8 +31,6 @@ impl Into for MIRPointerValue { impl Display for MIRPointerValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#{}", self.base.get_ssa_index())?; - - Ok(()) + self.base.fmt(f) } } diff --git a/compiler/astoir_mir/src/vals/refer.rs b/compiler/astoir_mir/src/vals/refer.rs index 3c3d6aa1..cfb4a200 100644 --- a/compiler/astoir_mir/src/vals/refer.rs +++ b/compiler/astoir_mir/src/vals/refer.rs @@ -59,14 +59,16 @@ impl MIRVariableReference { storage: &TypedGlobalScope, ) -> DiagnosticResult { if self.is_pointer_ref() { - let mut ptr_ref = self.as_pointer_ref()?; - let hint = ctx - .ssa_hints - .get_hint(BaseMIRValue::from(ptr_ref.clone().into()).get_ssa_index()); + let ptr_ref = self.as_pointer_ref()?; - if hint.get_type().is_technically_pointer() { - ptr_ref = build_load(ctx, ptr_ref)?.as_ptr()?; - } + //let _hint = ctx + // .ssa_hints + // .get_hint(BaseMIRValue::from(ptr_ref.clone().into()).get_ssa_index()); + + //if hint.get_type().is_technically_pointer() { + // ptr_ref = build_load(ctx, ptr_ref)?.as_ptr()?; + // println!("Triggered {}", val); + //} build_store(ctx, storage, ptr_ref, val)?; diff --git a/compiler/astoir_mir/src/vals/structs.rs b/compiler/astoir_mir/src/vals/structs.rs index a6f02e57..9f645007 100644 --- a/compiler/astoir_mir/src/vals/structs.rs +++ b/compiler/astoir_mir/src/vals/structs.rs @@ -31,8 +31,6 @@ impl Into for MIRStructValue { impl Display for MIRStructValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#{}", self.base.get_ssa_index())?; - - Ok(()) + self.base.fmt(f) } } diff --git a/compiler/astoir_mir_lowering/src/body.rs b/compiler/astoir_mir_lowering/src/body.rs index 493d33ac..f6e967d0 100644 --- a/compiler/astoir_mir_lowering/src/body.rs +++ b/compiler/astoir_mir_lowering/src/body.rs @@ -8,12 +8,15 @@ use diagnostics::{ use crate::{ MIRLoweringContext, arrays::lower_hir_array_modify, - control::{forloop::lower_hir_for_loop, ifstatement::lower_hir_if_statement}, + control::{ + forloop::{lower_hir_for_loop, lower_hir_ranged_for_loop}, + ifstatement::lower_hir_if_statement, + }, funcs::lower_hir_function_call, introductions::handle_var_introduction_queue, math::lower_hir_math_operation, values::lower_hir_value, - vars::{lower_hir_variable_assignment, lower_hir_variable_declaration}, + vars::{lower_hir_deref_modify, lower_hir_variable_assignment, lower_hir_variable_declaration}, }; pub fn lower_hir_body_member( @@ -30,7 +33,10 @@ pub fn lower_hir_body_member( return match node.kind.clone() { HIRNodeKind::VarAssigment { .. } => lower_hir_variable_assignment(block, node, ctx), - HIRNodeKind::VarDeclaration { .. } => lower_hir_variable_declaration(block, node, ctx), + HIRNodeKind::VarDeclaration { .. } => { + let _ = lower_hir_variable_declaration(block, node, ctx, None)?; + Ok(true) + } HIRNodeKind::MathOperation { left: _, right: _, @@ -47,6 +53,12 @@ pub fn lower_hir_body_member( HIRNodeKind::ArrayIndexModify { .. } => lower_hir_array_modify(block, node, ctx), + HIRNodeKind::RangedForBlock { .. } => { + let _ = lower_hir_ranged_for_loop(block, node, ctx)?; + + Ok(true) + } + HIRNodeKind::ForBlock { .. } => lower_hir_for_loop(block, node, ctx), HIRNodeKind::IfStatement { .. } => lower_hir_if_statement(block, node, ctx), HIRNodeKind::FunctionCall { .. } => { @@ -70,6 +82,12 @@ pub fn lower_hir_body_member( return Ok(true); } + HIRNodeKind::DereferenceModify { .. } => { + let _ = lower_hir_deref_modify(block, node, ctx)?; + + return Ok(true); + } + _ => panic!("Invalid node"), }; } diff --git a/compiler/astoir_mir_lowering/src/casts.rs b/compiler/astoir_mir_lowering/src/casts.rs index 033e1968..782f8616 100644 --- a/compiler/astoir_mir_lowering/src/casts.rs +++ b/compiler/astoir_mir_lowering/src/casts.rs @@ -3,6 +3,7 @@ use astoir_mir::{ blocks::{hints::MIRValueHint, refer::MIRBlockReference}, vals::base::BaseMIRValue, }; +use compiler_typing::raw::RawType; use diagnostics::DiagnosticResult; use crate::{MIRLoweringContext, lower_hir_type, values::lower_hir_value}; @@ -39,7 +40,26 @@ pub fn lower_cast( return Ok(value); } - panic!("Bad castt {:#?} -> {:#?}", old_type, new_type); + if old_type.is_generic_direct() + && new_type.is_generic_direct() + && old_type.as_generic() == RawType::StaticString + && new_type.as_generic() == RawType::Pointer + { + match ctx.mir_ctx.ssa_hints.vec[value.get_ssa_index()] { + MIRValueHint::Pointer(_) => { + ctx.mir_ctx.ssa_hints.vec[value.get_ssa_index()] = + MIRValueHint::Pointer(new_type) + } + MIRValueHint::Value(_) => { + ctx.mir_ctx.ssa_hints.vec[value.get_ssa_index()] = MIRValueHint::Value(new_type) + } + _ => panic!("constant enum cast"), + } + + return Ok(value); + } + + panic!("Bad cast {:#?} -> {:#?}", old_type, new_type); } panic!("Invalid node or cast!") diff --git a/compiler/astoir_mir_lowering/src/control/forloop.rs b/compiler/astoir_mir_lowering/src/control/forloop.rs index 22f8d0f8..f16ddef9 100644 --- a/compiler/astoir_mir_lowering/src/control/forloop.rs +++ b/compiler/astoir_mir_lowering/src/control/forloop.rs @@ -3,9 +3,14 @@ use astoir_hir::nodes::{HIRNode, HIRNodeKind}; use astoir_mir::{ blocks::{MIRBlock, refer::MIRBlockReference}, - builder::{build_conditional_branch, build_unconditional_branch}, + builder::{ + build_comp_lt, build_conditional_branch, build_int_add, build_unconditional_branch, + build_unsigned_int_const, + }, +}; +use diagnostics::{ + DiagnosticResult, DiagnosticSpanOrigin, MaybeDiagnostic, move_current_diagnostic_pos, }; -use diagnostics::{DiagnosticResult, DiagnosticSpanOrigin, move_current_diagnostic_pos}; use crate::{ MIRLoweringContext, body::lower_hir_body, math::lower_hir_math_operation, @@ -32,23 +37,39 @@ pub fn lower_hir_for_loop( ctx.mir_ctx.blocks[header_ref].merge_blocks.push(block); ctx.mir_ctx.blocks[header_ref].merge_blocks.push(body_ref); + // Initial State + move_current_diagnostic_pos(initial_state.get_pos()); - lower_hir_variable_declaration(block, initial_state, ctx)?; + lower_hir_variable_declaration(block, initial_state, ctx, None)?; + + MIRBlock::propagate_variables(block, body_ref, &mut ctx.mir_ctx); + MIRBlock::propagate_variables(block, header_ref, &mut ctx.mir_ctx); + MIRBlock::propagate_variables(block, cond_ref, &mut ctx.mir_ctx); + + build_unconditional_branch(&mut ctx.mir_ctx, cond_ref)?; + + // Body reference ctx.mir_ctx.writer.move_end(body_ref); lower_hir_body(body_ref, body, ctx)?; + // Incrementation + move_current_diagnostic_pos(incrementation.get_pos()); lower_hir_math_operation(body_ref, incrementation, ctx)?; build_unconditional_branch(&mut ctx.mir_ctx, header_ref)?; + // Header + ctx.mir_ctx.writer.move_end(header_ref); ctx.mir_ctx.resolve_ssa(header_ref)?; build_unconditional_branch(&mut ctx.mir_ctx, cond_ref)?; + // Condition + ctx.mir_ctx.writer.move_end(cond_ref); move_current_diagnostic_pos(condition.get_pos()); @@ -57,6 +78,86 @@ pub fn lower_hir_for_loop( build_conditional_branch(&mut ctx.mir_ctx, cond_val.as_int()?, body_ref, exit_ref)?; ctx.mir_ctx.writer.move_end(exit_ref); + + return Ok(true); + } + + panic!("Invalid node") +} + +pub fn lower_hir_ranged_for_loop( + block: MIRBlockReference, + node: Box, + ctx: &mut MIRLoweringContext, +) -> MaybeDiagnostic { + if let HIRNodeKind::RangedForBlock { + variable, + range, + body, + } = node.kind.clone() + { + move_current_diagnostic_pos(node.get_pos()); + + let header_ref = MIRBlock::new_merge(block, &mut ctx.mir_ctx, false); + let cond_ref = MIRBlock::new_merge(header_ref, &mut ctx.mir_ctx, false); + let exit_ref = MIRBlock::new_merge(block, &mut ctx.mir_ctx, false); + let body_ref = MIRBlock::new_merge(header_ref, &mut ctx.mir_ctx, false); + + ctx.mir_ctx.blocks[header_ref].merge_blocks.push(block); + ctx.mir_ctx.blocks[header_ref].merge_blocks.push(body_ref); + + // Initial state + + let min = lower_hir_value(block, range.min, ctx)?; + let max = lower_hir_value(block, range.max, ctx)?; + + let v = lower_hir_variable_declaration(block, variable, ctx, Some(min.clone()))?; + + MIRBlock::propagate_variables(block, body_ref, &mut ctx.mir_ctx); + MIRBlock::propagate_variables(block, header_ref, &mut ctx.mir_ctx); + MIRBlock::propagate_variables(block, cond_ref, &mut ctx.mir_ctx); + + build_unconditional_branch(&mut ctx.mir_ctx, cond_ref)?; + + // Body reference + + ctx.mir_ctx.writer.move_end(body_ref); + lower_hir_body(body_ref, body, ctx)?; + + // Incrementation + + let val = v.read(body_ref, &mut ctx.mir_ctx)?; + let increment = build_unsigned_int_const(&mut ctx.mir_ctx, 1, min.as_int()?.size)?; + let incremented = build_int_add(&mut ctx.mir_ctx, val.as_int()?, increment, false, false)?; + + v.write( + body_ref, + &mut ctx.mir_ctx, + incremented.base, + &ctx.hir_ctx.global_scope.scope, + )?; + + build_unconditional_branch(&mut ctx.mir_ctx, header_ref)?; + + // Header + + ctx.mir_ctx.writer.move_end(header_ref); + ctx.mir_ctx.resolve_ssa(header_ref)?; + + build_unconditional_branch(&mut ctx.mir_ctx, cond_ref)?; + + // Condition + + ctx.mir_ctx.writer.move_end(cond_ref); + + let val = v.read(cond_ref, &mut ctx.mir_ctx)?.as_int()?; + let cond_val = build_comp_lt(&mut ctx.mir_ctx, val, max.as_int()?)?; + + build_conditional_branch(&mut ctx.mir_ctx, cond_val, body_ref, exit_ref)?; + + ctx.mir_ctx.writer.move_end(exit_ref); + + return Ok(()); } panic!("Invalid node") diff --git a/compiler/astoir_mir_lowering/src/funcs.rs b/compiler/astoir_mir_lowering/src/funcs.rs index 56fe7c66..6c46db9d 100644 --- a/compiler/astoir_mir_lowering/src/funcs.rs +++ b/compiler/astoir_mir_lowering/src/funcs.rs @@ -83,11 +83,11 @@ pub fn lower_hir_function_decl( panic!("Invalid node") } -pub fn lower_hir_shadow_decl( +pub fn lower_hir_extern_decl( node: Box, ctx: &mut MIRLoweringContext, ) -> DiagnosticResult { - if let HIRNodeKind::ShadowFunctionDeclaration { + if let HIRNodeKind::ExternFunctionDeclaration { func_name, arguments, return_type, diff --git a/compiler/astoir_mir_lowering/src/lib.rs b/compiler/astoir_mir_lowering/src/lib.rs index 6434ec17..ecc8451e 100644 --- a/compiler/astoir_mir_lowering/src/lib.rs +++ b/compiler/astoir_mir_lowering/src/lib.rs @@ -11,7 +11,7 @@ use compiler_typing::{ use compiler_utils::utils::indexed::IndexStorage; use diagnostics::{DiagnosticResult, unsure_panic}; -use crate::funcs::{lower_hir_function_decl, lower_hir_shadow_decl}; +use crate::funcs::{lower_hir_extern_decl, lower_hir_function_decl}; pub mod arrays; pub mod body; @@ -37,7 +37,7 @@ pub fn lower_hir_top_level( ) -> DiagnosticResult { return match node.kind { HIRNodeKind::FunctionDeclaration { .. } => lower_hir_function_decl(node, ctx), - HIRNodeKind::ShadowFunctionDeclaration { .. } => lower_hir_shadow_decl(node, ctx), + HIRNodeKind::ExternFunctionDeclaration { .. } => lower_hir_extern_decl(node, ctx), HIRNodeKind::StructDeclaration { .. } => { // Since Struct declarations are already fulled lowered in HIR, we do need handling here! diff --git a/compiler/astoir_mir_lowering/src/math.rs b/compiler/astoir_mir_lowering/src/math.rs index af6c0343..faa04c1c 100644 --- a/compiler/astoir_mir_lowering/src/math.rs +++ b/compiler/astoir_mir_lowering/src/math.rs @@ -29,7 +29,7 @@ pub fn lower_hir_math_operation( operation, } = node.clone().kind { - if operation.assigns && !left.is_variable_reference() { + if !operation.assigns && !left.is_variable_reference() { return Err(make_math_operation_req_assign(&*node).into()); } diff --git a/compiler/astoir_mir_lowering/src/values/mod.rs b/compiler/astoir_mir_lowering/src/values/mod.rs index 331537e5..75d99b61 100644 --- a/compiler/astoir_mir_lowering/src/values/mod.rs +++ b/compiler/astoir_mir_lowering/src/values/mod.rs @@ -2,7 +2,7 @@ use astoir_hir::nodes::{HIRNode, HIRNodeKind}; use astoir_mir::{ blocks::refer::MIRBlockReference, builder::{build_static_array_const, build_static_array_one_const}, - vals::base::BaseMIRValue, + vals::{base::BaseMIRValue, refer::MIRVariableReference}, }; use diagnostics::{ DiagnosticResult, DiagnosticSpanOrigin, move_current_diagnostic_pos, unsure_panic, @@ -47,10 +47,17 @@ pub fn lower_hir_value( .as_pointer_ref()? .into()); } - HIRNodeKind::PointerGrab { val } => { - return Ok(lower_hir_variable_reference(block, &val, ctx)? - .as_pointer_ref()? - .into()); + HIRNodeKind::Dereference { val } => { + let ptr = lower_hir_variable_reference(block, &val, ctx)? + .read(block, &mut ctx.mir_ctx)? + .as_ptr()?; + + let var = MIRVariableReference::PointerReference(ptr); + let val = var.read(block, &mut ctx.mir_ctx)?; + + //let val = build_pointer_deref(&mut ctx.mir_ctx, ptr)?; + + Ok(val) } HIRNodeKind::BooleanCondition { .. } => { return Ok(lowering_hir_boolean_condition(block, node, ctx)?.into()); @@ -84,7 +91,6 @@ pub fn lower_hir_value( return Ok(res.unwrap()); } - _ => panic!("Invalid node {:#?}", node), } } diff --git a/compiler/astoir_mir_lowering/src/vars.rs b/compiler/astoir_mir_lowering/src/vars.rs index a613c93c..43b2c829 100644 --- a/compiler/astoir_mir_lowering/src/vars.rs +++ b/compiler/astoir_mir_lowering/src/vars.rs @@ -7,7 +7,9 @@ use astoir_mir::{ vals::{base::BaseMIRValue, refer::MIRVariableReference}, }; use compiler_typing::{SizedType, TypedGlobalScopeEntry}; -use diagnostics::{DiagnosticResult, builders::make_expected_simple_error_originless}; +use diagnostics::{ + DiagnosticResult, MaybeDiagnostic, builders::make_expected_simple_error_originless, +}; use crate::{MIRLoweringContext, lower_hir_type, values::lower_hir_value}; @@ -15,7 +17,8 @@ pub fn lower_hir_variable_declaration( block_id: MIRBlockReference, node: Box, ctx: &mut MIRLoweringContext, -) -> DiagnosticResult { + override_val: Option, +) -> DiagnosticResult { if let HIRNodeKind::VarDeclaration { variable, var_type, @@ -75,6 +78,8 @@ pub fn lower_hir_variable_declaration( }, ); } + + return Ok(MIRVariableReference::SSAReference(variable)); } else { let lowered = lower_hir_type(ctx, var_type)?; @@ -92,6 +97,17 @@ pub fn lower_hir_variable_declaration( }, ); + if !default_val.is_some() && override_val.is_some() { + let val = override_val.unwrap(); + + build_store( + &mut ctx.mir_ctx, + &ctx.hir_ctx.global_scope.scope, + ptr.clone(), + val, + )?; + } + if default_val.is_some() { let val = lower_hir_value(block_id, default_val.unwrap(), ctx)?; @@ -102,9 +118,9 @@ pub fn lower_hir_variable_declaration( val, )?; } - } - return Ok(true); + return Ok(MIRVariableReference::PointerReference(ptr.clone())); + } } panic!("Invalid node") @@ -113,7 +129,7 @@ pub fn lower_hir_variable_declaration( pub fn lower_hir_variable_reference( block: MIRBlockReference, node: &Box, - ctx: &MIRLoweringContext, + ctx: &mut MIRLoweringContext, ) -> DiagnosticResult { if let HIRNodeKind::VariableReference { index, @@ -127,6 +143,35 @@ pub fn lower_hir_variable_reference( panic!("Invalid node") } +pub fn lower_hir_deref_modify( + block: MIRBlockReference, + node: Box, + ctx: &mut MIRLoweringContext, +) -> MaybeDiagnostic { + if let HIRNodeKind::DereferenceModify { pointer, val } = node.kind.clone() { + let ptr = lower_hir_value(block, pointer, ctx)?.as_ptr()?; + let val = lower_hir_value(block, val, ctx)?; + + println!( + "ptr: {}, val: {}", + BaseMIRValue::from(ptr.clone().into()).vtype, + val.vtype + ); + + let var = MIRVariableReference::PointerReference(ptr); + var.write( + block, + &mut ctx.mir_ctx, + val, + &ctx.hir_ctx.global_scope.scope, + )?; + + return Ok(()); + } + + panic!("Invalid node") +} + /// Lowers the HIR variable reference as if to obtain it's value. Requires a load pub fn lower_hir_variable_reference_value( block: MIRBlockReference, diff --git a/compiler/compiler_main/Cargo.toml b/compiler/compiler_main/Cargo.toml index 4122199a..59ca4105 100644 --- a/compiler/compiler_main/Cargo.toml +++ b/compiler/compiler_main/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] astoir = { path = "../astoir" } +astoir_mir = { path = "../astoir_mir" } ast = { path = "../ast" } ast_parser = { path = "../ast_parser" } lexer = { path = "../lexer" } diff --git a/compiler/compiler_main/src/cmds/build.rs b/compiler/compiler_main/src/cmds/build.rs index c6a238c3..fab8abe4 100644 --- a/compiler/compiler_main/src/cmds/build.rs +++ b/compiler/compiler_main/src/cmds/build.rs @@ -2,8 +2,12 @@ use std::{fs, path::PathBuf}; use ast_parser::parse_ast_ctx; use astoir::run_astoir_mir; +use astoir_mir::fmt::DisplayWithCtx; use lexer::lexer::lexer_parse_file; +#[cfg(feature = "llvm")] +use llvm_ir_bridge::bridge_llvm; + use crate::quietlyquit_if_errors; pub fn build_mir(path: String, out: PathBuf) { @@ -16,5 +20,28 @@ pub fn build_mir(path: String, out: PathBuf) { let mir = run_astoir_mir(ast.unwrap()); quietlyquit_if_errors!(); - fs::write(out, format!("{}", mir.unwrap())).unwrap(); + let mir = mir.unwrap(); + + fs::write(out, format!("{}", DisplayWithCtx::new(&mir, &mir))).unwrap(); +} + +#[cfg(feature = "llvm")] +pub fn build_llvm(path: String, out: PathBuf) { + let lexer = lexer_parse_file(&path); + quietlyquit_if_errors!(); + + let ast = parse_ast_ctx(&lexer.unwrap()); + quietlyquit_if_errors!(); + + let mir = run_astoir_mir(ast.unwrap()); + quietlyquit_if_errors!(); + + let llvm = bridge_llvm(&mir.unwrap()); + + llvm.module.print_to_file(out).unwrap(); +} + +#[cfg(not(feature = "llvm"))] +pub fn build_llvm(_path: String, _out: PathBuf) { + println!("LLVM bridge is disabled in this version of the compiler.") } diff --git a/compiler/compiler_main/src/main.rs b/compiler/compiler_main/src/main.rs index c0e5855b..7a9ac7ce 100644 --- a/compiler/compiler_main/src/main.rs +++ b/compiler/compiler_main/src/main.rs @@ -1,14 +1,13 @@ -use std::{ - fs, - path::PathBuf, - time::Instant, -}; +use std::{fs, path::PathBuf, time::Instant}; use clap::Parser; use crate::{ cli::{Bridge, CLICommand, Cli, OutputFormat}, - cmds::{build::build_mir, check::run_check}, + cmds::{ + build::{build_llvm, build_mir}, + check::run_check, + }, version::{GIT_HASH, VERSION}, }; @@ -74,7 +73,15 @@ fn main() { } } - _ => todo!(), + Bridge::LLVM => { + for i in input { + let mut outfile = PathBuf::from(i.file_name().unwrap()); + outfile.add_extension("ll"); + + let output_path = out.join(outfile); + build_llvm(i.to_str().unwrap().to_string(), output_path); + } + } } } diff --git a/compiler/compiler_typing/src/raw.rs b/compiler/compiler_typing/src/raw.rs index 6d48971d..65c3bdc6 100644 --- a/compiler/compiler_typing/src/raw.rs +++ b/compiler/compiler_typing/src/raw.rs @@ -140,6 +140,14 @@ impl RawType { } } + pub fn is_struct(&self) -> bool { + match self { + Self::Struct(_, _) => true, + Self::LoweredStruct(_, _) => true, + _ => false, + } + } + pub fn has_trait(&self, t: Trait, raw_type: &Type) -> bool { match t { Trait::Integer => self.is_integer(), diff --git a/compiler/compiler_typing/src/tree.rs b/compiler/compiler_typing/src/tree.rs index 1ac498dc..bf5113bf 100644 --- a/compiler/compiler_typing/src/tree.rs +++ b/compiler/compiler_typing/src/tree.rs @@ -54,6 +54,23 @@ impl Type { } } + pub fn is_generic_direct(&self) -> bool { + match self { + Self::Generic(_, _, _) => true, + Self::GenericLowered(_) => true, + _ => false, + } + } + + pub fn is_struct(&self) -> bool { + match self { + Self::GenericLowered(inner) => inner.is_struct(), + Self::Generic(inner, _, _) => inner.is_struct(), + + _ => false, + } + } + pub fn is_ptr(&self) -> bool { match self { Self::Pointer(_, _) => true, @@ -115,6 +132,9 @@ impl Type { return base == base2; } + (Self::Pointer(_, _), Self::GenericLowered(base)) => return *base == RawType::Pointer, + (Self::GenericLowered(base), Self::Pointer(_, _)) => return *base == RawType::Pointer, + _ => false, } } diff --git a/compiler/diagnostics/src/builders.rs b/compiler/diagnostics/src/builders.rs index f5980cfd..8e1674e4 100644 --- a/compiler/diagnostics/src/builders.rs +++ b/compiler/diagnostics/src/builders.rs @@ -4,12 +4,13 @@ use crate::{ DiagnosticSpanOrigin, diagnostic::{Diagnostic, Level, Span, SpanKind, SpanPosition}, errors::{ - ALREADY_IN_SCOPE, ASSIGN_DIFF_TYPE_IR, BOUND_MISSING, CANNOT_FIND, DIFF_SIZE_SPECIFIERS, - DIFF_TYPE_SPECIFIERS, ENUM_PARENT_FIELDS, ERA_NOT_EXIST, EXPECTED_FREE, EXPECTED_TOKEN, - EXPECTED_TYPE, FIELD_MISSING, FIELD_STRUCT_INIT, FIND_TYPE, FIND_TYPE_FIELD, - FIND_TYPE_FUNCTION, FIND_VAR, FUNC_MISSING, INDEX_USAGE, INVALID_POINTING, - INVALID_TYPE_REQ, IR_CAST, IR_INSTRUCTION_HELD_VAL, MATH_OPERATION_ASSIGNS, NOT_FOUND_USE, - TRAIT_MISSING, TYPE_NOT_PART, UNEXPECTED_TOKEN, VARIABLE_UNINIT, + ALREADY_IN_SCOPE, ASSIGN_DIFF_TYPE_IR, BOUND_MISSING, CANNOT_FIND, CODE_UNREACHABLE, + DIFF_SIZE_SPECIFIERS, DIFF_TYPE_SPECIFIERS, ENDING_POINT_MISSING, ENUM_PARENT_FIELDS, + ERA_NOT_EXIST, EXPECTED_FREE, EXPECTED_TOKEN, EXPECTED_TYPE, FIELD_MISSING, + FIELD_STRUCT_INIT, FIND_TYPE, FIND_TYPE_FIELD, FIND_TYPE_FUNCTION, FIND_VAR, FUNC_MISSING, + INDEX_USAGE, INVALID_POINTING, INVALID_TYPE_REQ, IR_CAST, IR_INSTRUCTION_HELD_VAL, + MATH_OPERATION_ASSIGNS, NOT_FOUND_USE, RET_TYPE_NOT_MATCH, TRAIT_MISSING, TYPE_NOT_PART, + UNEXPECTED_TOKEN, VARIABLE_UNINIT, }, get_current_diagnostic_pos, warnings::UNUSED_VAR, @@ -641,3 +642,42 @@ pub fn make_cannot_find( vec![], ) } + +pub fn make_ending_point_missing(origin: &K) -> Diagnostic { + origin.make_simple_diagnostic( + ENDING_POINT_MISSING.0, + Level::Error, + ENDING_POINT_MISSING.1.to_string(), + None, + vec![], + vec![ + "an ending point (eg: return statement) is missing on a function that must return" + .to_string(), + ], + vec!["try adding a ret statement".to_string()], + ) +} + +pub fn make_unreachable_code(origin: &K) -> Diagnostic { + origin.make_simple_diagnostic( + CODE_UNREACHABLE.0, + Level::Error, + CODE_UNREACHABLE.1.to_string(), + None, + vec![], + vec!["an ending point (eg: return statement) was previously introduced, this code is then unreachable".to_string()], + vec!["move this code before the ending point".to_string()], + ) +} + +pub fn make_ret_type_kind(origin: &K) -> Diagnostic { + origin.make_simple_diagnostic( + RET_TYPE_NOT_MATCH.0, + Level::Error, + RET_TYPE_NOT_MATCH.1.to_string(), + None, + vec![], + vec![], + vec![], + ) +} diff --git a/compiler/diagnostics/src/errors.rs b/compiler/diagnostics/src/errors.rs index 8f6e25d2..e7f1def7 100644 --- a/compiler/diagnostics/src/errors.rs +++ b/compiler/diagnostics/src/errors.rs @@ -39,7 +39,7 @@ declare_error!( 10, "functions are not supported in layouts" ); -declare_error!(INVALID_POINTING, 11, "cannot point to a non-variable"); +declare_error!(INVALID_POINTING, 11, "cannot dereference non-pointer"); declare_error!( TRAIT_MISSING, 12, @@ -103,3 +103,10 @@ declare_error!(INVALID_TYPE_REQ, 30, "this operation requires a {} type"); declare_error!(TYPE_NOT_PART, 31, "type {} is not part of type {}"); declare_error!(NOT_FOUND_USE, 32, "element {} was not found in {}"); declare_error!(CANNOT_FIND, 33, "cannot find {} in the current scope"); +declare_error!(ENDING_POINT_MISSING, 34, "missing ending point."); +declare_error!(CODE_UNREACHABLE, 35, "unreachable code."); +declare_error!( + RET_TYPE_NOT_MATCH, + 36, + "different return type kinds. one is empty and one is not." +); diff --git a/compiler/lexer/src/lexer.rs b/compiler/lexer/src/lexer.rs index 202ba992..45be7020 100644 --- a/compiler/lexer/src/lexer.rs +++ b/compiler/lexer/src/lexer.rs @@ -11,13 +11,12 @@ use diagnostics::diagnostic::SpanPosition; use crate::token::{LexerToken, LexerTokenType}; -const SHADOWFUNC_KEYWORD_HASH: u64 = hash!("shadowfunc"); +const EXTERNFUNC_KEYWORD_HASH: u64 = hash!("externfunc"); const FUNC_KEYWORD_HASH: u64 = hash!("func"); const RET_KEYWORD_HASH: u64 = hash!("ret"); const VAR_KEYWORD_HASH: u64 = hash!("var"); const STRUCT_KEYWORD_HASH: u64 = hash!("struct"); const LAYOUT_KEYWORD_HASH: u64 = hash!("layout"); -const LAY_KEYWORD_HASH: u64 = hash!("lay"); const FALSE_KEYWORD_HASH: u64 = hash!("false"); const TRUE_KEYWORD_HASH: u64 = hash!("true"); const IF_KEYWORD_HASH: u64 = hash!("if"); @@ -179,6 +178,10 @@ pub fn lexer_parse(contents: String, file_path: &String) -> DiagnosticResult tokens.push(LexerToken::make_single_sized(pos, LexerTokenType::Minus)), '/' => tokens.push(LexerToken::make_single_sized(pos, LexerTokenType::Divide)), '~' => tokens.push(LexerToken::make_single_sized(pos, LexerTokenType::Tidle)), + ';' => tokens.push(LexerToken::make_single_sized( + pos, + LexerTokenType::SemiCollon, + )), '%' => tokens.push(LexerToken::make_single_sized( pos, LexerTokenType::PercentSign, @@ -352,11 +355,10 @@ 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, + EXTERNFUNC_KEYWORD_HASH => LexerTokenType::ExternFunc, RET_KEYWORD_HASH => LexerTokenType::Return, STRUCT_KEYWORD_HASH => LexerTokenType::Struct, LAYOUT_KEYWORD_HASH => LexerTokenType::Layout, - LAY_KEYWORD_HASH => LexerTokenType::Lay, TRUE_KEYWORD_HASH => LexerTokenType::True, FALSE_KEYWORD_HASH => LexerTokenType::False, VAR_KEYWORD_HASH => LexerTokenType::Var, diff --git a/compiler/lexer/src/token.rs b/compiler/lexer/src/token.rs index c61ee5e7..e60a45f3 100644 --- a/compiler/lexer/src/token.rs +++ b/compiler/lexer/src/token.rs @@ -16,7 +16,7 @@ use diagnostics::{ pub enum LexerTokenType { /// Represent the func keyword Function, - ShadowFunction, + ExternFunc, Comment(String), GlobalComment(String), @@ -59,6 +59,7 @@ pub enum LexerTokenType { Dot, Ampersand, Collon, + SemiCollon, Plus, Minus, @@ -194,6 +195,7 @@ impl Display for LexerTokenType { Self::ArrayOpen => "[", Self::Asterisk => "*", Self::Collon => ":", + Self::SemiCollon => ";", Self::BracketClose => "}", Self::BracketOpen => "{", Self::Comma => ",", @@ -216,7 +218,7 @@ impl Display for LexerTokenType { Self::ParenClose => ")", Self::ParenOpen => "(", Self::Return => "ret", - Self::ShadowFunction => "shadowfunc", + Self::ExternFunc => "externfunc", Self::Static => "static", Self::StringLit(_) => "string literal", Self::Var => "var", diff --git a/compiler/llvm_ir_bridge/src/ctx.rs b/compiler/llvm_ir_bridge/src/ctx.rs index 203b7726..f6ab09ec 100644 --- a/compiler/llvm_ir_bridge/src/ctx.rs +++ b/compiler/llvm_ir_bridge/src/ctx.rs @@ -14,7 +14,7 @@ pub struct LLVMBridgeContext { pub blocks: HashMap, pub values: HashMap, pub completed_blocks: HashSet, - pub functions: Vec, + pub functions: HashMap, pub types: LLVMTypeStorage, @@ -32,7 +32,7 @@ impl LLVMBridgeContext { blocks: HashMap::new(), completed_blocks: HashSet::new(), types: LLVMTypeStorage::new(&ctx), - functions: vec![], + functions: HashMap::new(), void_type: unsafe { transmute::>(ctx.void_type()) }, values: HashMap::new(), ctx: ctx.clone(), diff --git a/compiler/llvm_ir_bridge/src/funcs.rs b/compiler/llvm_ir_bridge/src/funcs.rs index 60d1a013..8c7428ae 100644 --- a/compiler/llvm_ir_bridge/src/funcs.rs +++ b/compiler/llvm_ir_bridge/src/funcs.rs @@ -11,6 +11,8 @@ use crate::{ pub fn bridge_llvm_functions(mir: &MIRContext, bridge: &mut LLVMBridgeContext) { for func in &mir.functions { let mut args = vec![]; + let ind = func.0; + let func = func.1; if !func.blocks.is_empty() { @@ -35,6 +37,6 @@ pub fn bridge_llvm_functions(mir: &MIRContext, bridge: &mut LLVMBridgeContext) { ); } - bridge.functions.push(LLVMFunction::new(ff)); + bridge.functions.insert(*ind, LLVMFunction::new(ff)); } } diff --git a/compiler/llvm_ir_bridge/src/insts.rs b/compiler/llvm_ir_bridge/src/insts.rs index ad7edc20..a1f8abd8 100644 --- a/compiler/llvm_ir_bridge/src/insts.rs +++ b/compiler/llvm_ir_bridge/src/insts.rs @@ -49,6 +49,23 @@ pub fn bridge_llvm_instruction( Some(res.into()) } + MIRInstruction::DerefPointer { ptr } => { + let base = BaseMIRValue::from(ptr.into()); + + let res = llvm_to_base!( + bridge.builder.build_load( + bridge + .types + .convert(mir.ssa_hints.get_hint(base.get_ssa_index()).get_type()) + .inner, + bridge.values[&base.get_ssa_index()].into_pointer_value(), + &format!("{}", instruction.as_valuedindex()) + ) + ); + + Some(res.into()) + } + MIRInstruction::Store { variable, value } => { let base = BaseMIRValue::from(variable.into()); let ptr = bridge.values[&base.get_ssa_index()].into_pointer_value(); @@ -888,7 +905,7 @@ pub fn bridge_llvm_instruction( function, arguments, } => { - let func = bridge.functions[function].clone().inner; + let func = bridge.functions[&function].clone().inner; let mut args = vec![]; @@ -902,7 +919,7 @@ pub fn bridge_llvm_instruction( } MIRInstruction::FuncArgumentGrab { ind, argtype: _ } => { - let func = bridge.functions[func].clone().inner; + let func = bridge.functions[&func].clone().inner; func.get_nth_param(ind as u32) } diff --git a/examples/control.qf b/examples/control.qf new file mode 100644 index 00000000..7fd1e2fb --- /dev/null +++ b/examples/control.qf @@ -0,0 +1,17 @@ +func multiply_number(s32 a, s32 b) -> s32 { + mut s32 res = 0; + + for s32 i => [0..b] { + res += b; + } + + return res; +} + +func check_number(s32 test) -> bool { + if(test <= 53) { + return true; + } + + return false; +} \ No newline at end of file diff --git a/examples/extern.qf b/examples/extern.qf new file mode 100644 index 00000000..28d488df --- /dev/null +++ b/examples/extern.qf @@ -0,0 +1,5 @@ +externfunc printf(ptr fmt, ...); + +func main() -> s32 { + printf("Hello World! From %d", 52) +} \ No newline at end of file diff --git a/examples/helloworld.qf b/examples/helloworld.qf new file mode 100644 index 00000000..a0e0550b --- /dev/null +++ b/examples/helloworld.qf @@ -0,0 +1,11 @@ +use std::[print] + +func main() -> s32 { + mut s32 test2 = 69; + + test2 = 120; // Mutable + + var s32 test3 = 69; // Not mutable + + print("Hello world!"); +} \ No newline at end of file diff --git a/examples/math.qf b/examples/math.qf new file mode 100644 index 00000000..22f79965 --- /dev/null +++ b/examples/math.qf @@ -0,0 +1,11 @@ +func main() -> s32 { + var s32 add = 1 + 1 + var s32 sub = 1 - 1 + var s32 mul = 1 * 1 + var s32 div = 1 / 1 + var s32 mod = 1 \ 1 + var s32 or = 1 -- 1 + var s32 and = 1 ++ 1 + var s32 xor = 1 !! 1 + var s32 xnor = 1 ?? 1 +} \ No newline at end of file diff --git a/examples/pointers.qf b/examples/pointers.qf new file mode 100644 index 00000000..8ba4a885 --- /dev/null +++ b/examples/pointers.qf @@ -0,0 +1,11 @@ +// In arguments, mut can only be used on pointers to decide +// if a pointer is mutable or immutable +func move_from_pointer(mut s32* a, mut s32* b) { + var s32 origin = *a // Gets the value of a + var s32 second = *b // gets the value of b + + var s32*[] myPointerArray; // Represents a pointer based array. That can use indexing like an array + + *b = origin // Changes the value of b + *a = second // Changes the value of a +} diff --git a/examples/structs.qf b/examples/structs.qf new file mode 100644 index 00000000..c85fb792 --- /dev/null +++ b/examples/structs.qf @@ -0,0 +1,14 @@ +struct my_struct { + s32 field_a + bool field_b +} + +decl my_struct { + func test(self) -> bool { + return self.field_b && self.field_a >= 50; + } + + func new() -> my_struct { + return { field_a: 0, field_b: false } + } +} \ No newline at end of file diff --git a/examples/type_params.qf b/examples/type_params.qf new file mode 100644 index 00000000..32a27088 --- /dev/null +++ b/examples/type_params.qf @@ -0,0 +1,13 @@ +// Type parameters are only available on structs and functions but can only be used for pointers and storage. Any other operation (eg: math) is forbidden + +struct vector { + K*[] pointer + u0 counter +} + +decl vector { + func add(self, K v) { + self.pointer[self.counter] = v + self.counter += 1 + } +} \ No newline at end of file