diff --git a/compiler/astoir_hir/src/ctx.rs b/compiler/astoir_hir/src/ctx.rs index f8dc5eac..a7aa0802 100644 --- a/compiler/astoir_hir/src/ctx.rs +++ b/compiler/astoir_hir/src/ctx.rs @@ -1,6 +1,6 @@ //! The context definitions for the AstoIR HIR layer. -use std::{collections::HashMap}; +use std::collections::{HashMap, HashSet}; use astoir_typing::{complete::{ComplexType}, storage::TypeStorage}; use compiler_errors::{IR_ALREADY_EXISTING_ELEM, IR_FIND_ELEMENT, IR_OUTSIDE_ERA_HIGHER, IR_OUTSIDE_ERA_LOWER, errs::{BaseResult, base::BaseError}}; @@ -62,14 +62,14 @@ impl HIRBranchedContext { } /// Introduces a new variable in the current branch era. - pub fn introduce_variable(&mut self, hash: u64, t: ComplexType) -> BaseResult { + pub fn introduce_variable(&mut self, hash: u64, t: ComplexType, has_default: bool) -> BaseResult { let identity = SelfHash { hash }; if self.hash_to_ind.contains_key(&identity) { return Err(BaseError::err(IR_ALREADY_EXISTING_ELEM!().to_string())); } - let var: HIRBranchedVariable = HIRBranchedVariable { introduced_in_era: self.current_branch, variable_type: t }; + let var: HIRBranchedVariable = HIRBranchedVariable { introduced_in_era: self.current_branch, variable_type: t, has_default, introduced_values: HashSet::new() }; self.variables.push(var); let ind: usize = self.current_element_index; @@ -80,6 +80,18 @@ impl HIRBranchedContext { return Ok(ind); } + pub fn introduce_variable_assign(&mut self, ind: usize) -> bool { + let var = &mut self.variables[ind]; + + if var.has_default { + return true; + } + + var.introduced_values.insert(self.current_branch); + + return true; + } + /// 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; @@ -88,15 +100,17 @@ impl HIRBranchedContext { return false; } - if !self.ending_eras.contains_key(&start_branch) { + return self.is_era_alive(start_branch); + } + + 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) // this means that the variable is still alive and we are still inside of the branch start_branch return true; } - let end = self.ending_eras[&start_branch]; - - return end <= self.current_branch; + return false; } pub fn is_dropped_before(&self, ind: usize) -> bool { @@ -109,6 +123,22 @@ impl HIRBranchedContext { return self.ending_eras[&start_branch] < self.current_branch; } + pub fn has_variable_value(&self, ind: usize) -> bool { + let var = &self.variables[ind]; + + if var.has_default { + return true; + } + + for era in var.introduced_values.iter() { + if self.is_era_alive(*era) { + return true; + } + } + + return false; + } + pub fn get_ending_era(&self, ind: usize) -> usize { return self.ending_eras[&self.variables[ind].introduced_in_era]; } @@ -140,7 +170,10 @@ impl HIRBranchedContext { #[derive(Debug)] pub struct HIRBranchedVariable { pub introduced_in_era: usize, - pub variable_type: ComplexType + pub variable_type: ComplexType, + + pub has_default: bool, + pub introduced_values: HashSet // TODO: try to potentially reduce this } #[derive(Debug)] diff --git a/compiler/astoir_hir/src/nodes.rs b/compiler/astoir_hir/src/nodes.rs index 898b5be3..2d81c39d 100644 --- a/compiler/astoir_hir/src/nodes.rs +++ b/compiler/astoir_hir/src/nodes.rs @@ -1,6 +1,7 @@ //! The nodes inside of the AstoIR HIR. use astoir_typing::{complete::{ComplexType, ConcreteType}, hashes::{BOOLEAN_TYPE, STATIC_STR}, structs::StructTypeContainer}; +use compiler_errors::errs::{BaseResult, base::BaseError}; use lexer::toks::{comp::ComparingOperator, math::MathOperator}; use crate::{ctx::{HIRBranchedContext, HIRContext}, structs::{HIRIfBranch, StructLRUStep}}; @@ -47,6 +48,14 @@ impl HIRNode { return false; } + + pub fn as_variable_reference(&self) -> BaseResult<(usize, bool)> { + if let HIRNode::VariableReference { index, is_static } = self { + return Ok((*index, *is_static)) + } + + return Err(BaseError::err("Tried using as_variable_reference on a non var ref".to_string())) + } pub fn get_node_type(&self, context: &HIRContext, curr_ctx: &HIRBranchedContext) -> Option { match self { diff --git a/compiler/astoir_hir_lowering/src/func.rs b/compiler/astoir_hir_lowering/src/func.rs index 5de306d8..83696383 100644 --- a/compiler/astoir_hir_lowering/src/func.rs +++ b/compiler/astoir_hir_lowering/src/func.rs @@ -65,7 +65,7 @@ pub fn lower_ast_function_declaration(context: &mut HIRContext, node: Box {}, Err(e) => return Err(CompilerError::from_base(e, &node.start, &node.end)) } diff --git a/compiler/astoir_hir_lowering/src/lib.rs b/compiler/astoir_hir_lowering/src/lib.rs index 3e47d47f..ad9477de 100644 --- a/compiler/astoir_hir_lowering/src/lib.rs +++ b/compiler/astoir_hir_lowering/src/lib.rs @@ -2,7 +2,7 @@ use ast::{ctx::ParserCtx, tree::{ASTTreeNode, ASTTreeNodeKind}}; use astoir_hir::{ctx::{HIRBranchedContext, HIRContext}, nodes::HIRNode}; use compiler_errors::{IR_INVALID_NODE_TYPE, IR_TYPE_WRONG_KIND, errs::{CompilerResult, ErrorKind, normal::CompilerError}}; -use crate::{control::{lower_ast_for_block, lower_ast_if_statement, lower_ast_while_block}, func::{lower_ast_function_call, lower_ast_function_declaration, lower_ast_shadow_function_declaration}, math::lower_ast_math_operation, structs::lower_ast_struct_declaration, values::lower_ast_value, var::lower_ast_variable_declaration}; +use crate::{control::{lower_ast_for_block, lower_ast_if_statement, lower_ast_while_block}, func::{lower_ast_function_call, lower_ast_function_declaration, lower_ast_shadow_function_declaration}, math::lower_ast_math_operation, structs::lower_ast_struct_declaration, values::lower_ast_value, var::{lower_ast_variable_assign, lower_ast_variable_declaration}}; pub mod literals; pub mod var; @@ -18,6 +18,7 @@ pub fn lower_ast_body_node(context: &mut HIRContext, curr_ctx: &mut HIRBranchedC match node.kind.clone() { ASTTreeNodeKind::VarDeclaration { .. } => return lower_ast_variable_declaration(context, curr_ctx, node), ASTTreeNodeKind::FunctionCall { .. } => return lower_ast_function_call(context, curr_ctx, node), + ASTTreeNodeKind::VarValueChange { .. } => return lower_ast_variable_assign(context, curr_ctx, node), ASTTreeNodeKind::MathResult { .. } => return lower_ast_math_operation(context, curr_ctx, node, true), diff --git a/compiler/astoir_hir_lowering/src/values.rs b/compiler/astoir_hir_lowering/src/values.rs index 9a2349f1..8fe84a2b 100644 --- a/compiler/astoir_hir_lowering/src/values.rs +++ b/compiler/astoir_hir_lowering/src/values.rs @@ -138,7 +138,7 @@ pub fn lower_ast_value(context: &HIRContext, curr_ctx: &HIRBranchedContext, node }, ASTTreeNodeKind::VariableReference(_) => { - return lower_ast_variable_reference(context, curr_ctx, node) + return lower_ast_variable_reference(context, curr_ctx, node, true) }, _ => make_invalid_type_err!(node) diff --git a/compiler/astoir_hir_lowering/src/var.rs b/compiler/astoir_hir_lowering/src/var.rs index e7508bf8..859726b8 100644 --- a/compiler/astoir_hir_lowering/src/var.rs +++ b/compiler/astoir_hir_lowering/src/var.rs @@ -1,6 +1,6 @@ use ast::{tree::{ASTTreeNode, ASTTreeNodeKind}}; use astoir_hir::{ctx::{HIRBranchedContext, HIRContext, VariableKind, get_variable}, nodes::HIRNode}; -use compiler_errors::{IR_INVALID_NODE_TYPE, IR_VALUE_TYPE_TRANSMUTE, errs::{CompilerResult, ErrorKind, normal::CompilerError}}; +use compiler_errors::{IR_INVALID_NODE_TYPE, IR_VALUE_TYPE_TRANSMUTE, VARIABLE_REQ_VALUE, errs::{CompilerResult, ErrorKind, normal::CompilerError}}; use crate::{types::lower_ast_type, values::lower_ast_value}; @@ -11,7 +11,7 @@ pub fn lower_ast_variable_declaration(context: &HIRContext, curr_ctx: &mut HIRBr Err(e) => return Err(CompilerError::from_base(e, &node.start, &node.end)) }; - let name_ind = match curr_ctx.introduce_variable(var_name.hash, lowered.clone()) { + let name_ind = match curr_ctx.introduce_variable(var_name.hash, lowered.clone(), value.is_some()) { Ok(v) => v, Err(e) => return Err(CompilerError::from_base(e, &node.start, &node.end)) }; @@ -38,7 +38,7 @@ pub fn lower_ast_variable_declaration(context: &HIRContext, curr_ctx: &mut HIRBr return Err(CompilerError::from_ast(ErrorKind::Error, IR_INVALID_NODE_TYPE!().to_string(), &node.start, &node.end)) } -pub fn lower_ast_variable_reference(context: &HIRContext, curr_ctx: &HIRBranchedContext, node: Box) -> CompilerResult> { +pub fn lower_ast_variable_reference(context: &HIRContext, curr_ctx: &HIRBranchedContext, node: Box, requires_value: bool) -> CompilerResult> { if let ASTTreeNodeKind::VariableReference(str) = node.kind.clone() { let var = match get_variable(context, curr_ctx, str.hash) { Ok(v) => v, @@ -49,8 +49,34 @@ pub fn lower_ast_variable_reference(context: &HIRContext, curr_ctx: &HIRBranched return Ok(Box::new(HIRNode::VariableReference { index: var.2, is_static: true })) } + if requires_value { + if !curr_ctx.has_variable_value(var.2) { + return Err(CompilerError::from_ast(ErrorKind::Error, VARIABLE_REQ_VALUE!().to_string(), &node.start, &node.end)) + } + } + return Ok(Box::new(HIRNode::VariableReference { index: var.2, is_static: false })) } return Err(CompilerError::from_ast(ErrorKind::Error, IR_INVALID_NODE_TYPE!().to_string(), &node.start, &node.end)) } + +pub fn lower_ast_variable_assign(context: &HIRContext, curr_ctx: &mut HIRBranchedContext, node: Box) -> CompilerResult> { + if let ASTTreeNodeKind::VarValueChange { var, value } = node.kind.clone() { + let value = lower_ast_value(context, curr_ctx, value)?; + let variable_reference = lower_ast_variable_reference(context, curr_ctx, var, false)?; + + let var = match variable_reference.as_variable_reference() { + Ok(v) => v, + Err(e) => return Err(CompilerError::from_base(e, &node.start, &node.end)) + }; + + if !var.1 { + curr_ctx.introduce_variable_assign(var.0); + } + + return Ok(Box::new(HIRNode::VarAssigment { variable: var.0, val: value })) + } + + return Err(CompilerError::from_ast(ErrorKind::Error, IR_INVALID_NODE_TYPE!().to_string(), &node.start, &node.end)) +} \ No newline at end of file diff --git a/compiler/compiler_errors/src/errors.rs b/compiler/compiler_errors/src/errors.rs index 5074858b..ecad30d1 100644 --- a/compiler/compiler_errors/src/errors.rs +++ b/compiler/compiler_errors/src/errors.rs @@ -214,6 +214,13 @@ macro_rules! IR_REQ_VARIABLE_ASSIGN { }; } +#[macro_export] +macro_rules! VARIABLE_REQ_VALUE { + () => { + "The variable doesn't have any value here! Every variable must have a value at every point where it is used." + }; +} + #[macro_export] macro_rules! IR_VALUE_TYPE_TRANSMUTE { () => { diff --git a/compiler/compiler_errors/src/errs/mod.rs b/compiler/compiler_errors/src/errs/mod.rs index 18a89fca..1c624d6c 100644 --- a/compiler/compiler_errors/src/errs/mod.rs +++ b/compiler/compiler_errors/src/errs/mod.rs @@ -25,6 +25,7 @@ pub struct ErrorStorage { pub fn dump_errors() { ERR_STORAGE.with_borrow(|f| { + for err in &f.errs { println!("{}", err.err); diff --git a/compiler/compiler_main/src/cmds/astoir.rs b/compiler/compiler_main/src/cmds/astoir.rs index 56c49563..a56d7de4 100644 --- a/compiler/compiler_main/src/cmds/astoir.rs +++ b/compiler/compiler_main/src/cmds/astoir.rs @@ -18,16 +18,18 @@ pub fn parse_astoir_command(arguments: Vec) { for i in 3..arguments.len() { let lexer = lexer_parse_file(&arguments[i]).unwrap(); - let ast = parse_ast_ctx(&lexer).unwrap(); + let ast = parse_ast_ctx(&lexer); + + dump_errors(); match level { IRLevel::HIR => { - let ctx = run_astoir_hir(ast).unwrap(); + let ctx = run_astoir_hir(ast.unwrap()); let res_path = arguments[i].clone() + ".qfhir"; dump_errors(); - fs::write(res_path, format!("{:#?}", ctx)).unwrap() + fs::write(res_path, format!("{:#?}", ctx.unwrap())).unwrap() } } } diff --git a/examples/test.qf b/examples/test.qf deleted file mode 100644 index 777141bc..00000000 --- a/examples/test.qf +++ /dev/null @@ -1,13 +0,0 @@ -func main(si32 myTestArg, si32 age) { - var si32 test = test.abc().test; - - var si32 test2 = test.abs() >= test.def(); - - if(test2 >= test) { - var si32 age = 0; - } else if(test2 == test) { - var si32 age = 63; - } else { - var si32 age = 68; - } -} \ No newline at end of file