diff --git a/reid/examples/reid/array.reid b/reid/examples/reid/array.reid index 3613554..6de6d1a 100644 --- a/reid/examples/reid/array.reid +++ b/reid/examples/reid/array.reid @@ -9,7 +9,7 @@ fn main() -> u16 { let mut list = array(); - // list[1] = 5; + list[3] = 5; return list[3]; } diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index b4488be..aa688d6 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -5,7 +5,7 @@ use reid_lib::{ TerminatorKind as Term, Type, }; -use crate::mir::{self, types::ReturnType, NamedVariableRef, TypeKind}; +use crate::mir::{self, types::ReturnType, IndexedVariableReference, NamedVariableRef, TypeKind}; /// Context that contains all of the given modules as complete codegenerated /// LLIR that can then be finally compiled into LLVM IR. @@ -153,6 +153,42 @@ impl<'ctx, 'a> Scope<'ctx, 'a> { } } +impl IndexedVariableReference { + fn get_stack_value(&self, scope: &mut Scope) -> Option { + use StackValueKind as Kind; + + match &self.kind { + mir::IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => { + scope.stack_values.get(name).cloned() + } + mir::IndexedVariableReferenceKind::Index(inner, idx) => { + let inner_val = inner.get_stack_value(scope)?; + let inner_instr = match inner_val.0 { + Kind::Immutable(val) => val, + Kind::Mutable(val) => val, + }; + + match inner_val.1 { + Type::ArrayPtr(inner_ty, _) => { + let gep_instr = scope + .block + .build(Instr::ArrayGEP(inner_instr, vec![*idx as u32])) + .unwrap(); + Some(StackValue( + match inner_val.0 { + Kind::Immutable(_) => Kind::Immutable(gep_instr), + Kind::Mutable(_) => Kind::Mutable(gep_instr), + }, + *inner_ty, + )) + } + _ => panic!("Tried to codegen indexing a non-indexable value!"), + } + } + } + } +} + impl mir::Statement { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option { match &self.0 { @@ -163,14 +199,17 @@ impl mir::Statement { StackValue( match mutable { false => StackValueKind::Immutable(value), - true => StackValueKind::Mutable({ - let alloca = scope - .block - .build(Instr::Alloca(name.clone(), ty.get_type())) - .unwrap(); - scope.block.build(Instr::Store(alloca, value)).unwrap(); - alloca - }), + true => match ty { + TypeKind::Array(_, _) => StackValueKind::Mutable(value), + _ => StackValueKind::Mutable({ + let alloca = scope + .block + .build(Instr::Alloca(name.clone(), ty.get_type())) + .unwrap(); + scope.block.build(Instr::Store(alloca, value)).unwrap(); + alloca + }), + }, }, ty.get_type(), ), @@ -178,20 +217,19 @@ impl mir::Statement { None } mir::StmtKind::Set(var, val) => { - todo!("Re-think how set needs to work with arrays"); - // if let Some(StackValue(kind, _)) = scope.stack_values.get(&var.1).cloned() { - // match kind { - // StackValueKind::Immutable(_) => { - // panic!("Tried to mutate an immutable variable") - // } - // StackValueKind::Mutable(ptr) => { - // let expression = val.codegen(scope).unwrap(); - // Some(scope.block.build(Instr::Store(ptr, expression)).unwrap()) - // } - // } - // } else { - // panic!("") - // } + if let Some(StackValue(kind, _)) = var.get_stack_value(scope) { + match kind { + StackValueKind::Immutable(_) => { + panic!("Tried to mutate an immutable variable") + } + StackValueKind::Mutable(ptr) => { + let expression = val.codegen(scope).unwrap(); + Some(scope.block.build(Instr::Store(ptr, expression)).unwrap()) + } + } + } else { + panic!("") + } } // mir::StmtKind::If(if_expression) => if_expression.codegen(scope), mir::StmtKind::Import(_) => todo!(), @@ -267,9 +305,10 @@ impl mir::Expression { .expect("Variable reference not found?!"); Some(match v.0 { StackValueKind::Immutable(val) => val.clone(), - StackValueKind::Mutable(val) => { - scope.block.build(Instr::Load(val, v.1.clone())).unwrap() - } + StackValueKind::Mutable(val) => match v.1 { + Type::ArrayPtr(_, _) => val, + _ => scope.block.build(Instr::Load(val, v.1.clone())).unwrap(), + }, }) } mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)), diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index e8ddb4c..1ed8cae 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -7,7 +7,7 @@ use TypeKind::*; use VagueType::*; use super::{ - pass::{Pass, PassState, ScopeFunction, ScopeVariable}, + pass::{Pass, PassState, ScopeFunction, ScopeVariable, Storage}, typerefs::TypeRefs, types::ReturnType, }; @@ -169,41 +169,46 @@ impl Block { None } StmtKind::Set(variable_reference, expression) => { - todo!("Re-think how set needs to work with arrays") - // if let Some(var) = state.scope.variables.get(&variable_reference.1).cloned() { - // // Typecheck expression and coerce to variable type - // let res = expression.typecheck(&mut state, &hints, Some(&var.ty)); + if let Some(var) = state + .ok( + variable_reference.get_variable(&state.scope.variables), + variable_reference.meta, + ) + .flatten() + { + // Typecheck expression and coerce to variable type + let res = expression.typecheck(&mut state, &hints, Some(&var.ty)); - // // If expression resolution itself was erronous, resolve as - // // Unknown. - // let expr_ty = state.or_else(res, Vague(Unknown), expression.1); + // If expression resolution itself was erronous, resolve as + // Unknown. + let expr_ty = state.or_else(res, Vague(Unknown), expression.1); - // // Make sure the expression and variable type to really - // // be the same - // let res_t = state.or_else( - // expr_ty.collapse_into(&variable_reference.0.resolve_hinted(&hints)), - // Vague(Unknown), - // variable_reference.2 + expression.1, - // ); + // Make sure the expression and variable type to really + // be the same + let res_t = state.or_else( + expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)), + Vague(Unknown), + variable_reference.meta + expression.1, + ); - // // Update typing to be more accurate - // variable_reference.0 = res_t; + // Update typing to be more accurate + variable_reference.update_type(&res_t); - // if !var.mutable { - // state.ok::<_, Infallible>( - // Err(ErrorKind::VariableNotMutable(variable_reference.1.clone())), - // variable_reference.2, - // ); - // } + if !var.mutable { + state.ok::<_, Infallible>( + Err(ErrorKind::VariableNotMutable(variable_reference.get_name())), + variable_reference.meta, + ); + } - // None - // } else { - // state.ok::<_, Infallible>( - // Err(ErrorKind::VariableNotDefined(variable_reference.1.clone())), - // variable_reference.2, - // ); - // None - // } + None + } else { + state.ok::<_, Infallible>( + Err(ErrorKind::VariableNotDefined(variable_reference.get_name())), + variable_reference.meta, + ); + None + } } StmtKind::Import(_) => todo!(), // TODO StmtKind::Expression(expression) => { @@ -438,6 +443,32 @@ impl Expression { } } +impl IndexedVariableReference { + fn get_variable( + &self, + storage: &Storage, + ) -> Result, ErrorKind> { + match &self.kind { + IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => { + Ok(storage.get(&name).cloned()) + } + IndexedVariableReferenceKind::Index(inner_ref, _) => { + if let Some(var) = inner_ref.get_variable(storage)? { + match &var.ty { + TypeKind::Array(inner_ty, _) => Ok(Some(ScopeVariable { + ty: *inner_ty.clone(), + mutable: var.mutable, + })), + _ => Err(ErrorKind::TriedIndexingNonArray(var.ty.clone())), + } + } else { + Ok(None) + } + } + } + } +} + impl Literal { /// Try to coerce this literal, ie. convert it to a more specific type in /// regards to the given hint if any. diff --git a/reid/src/mir/typeinference.rs b/reid/src/mir/typeinference.rs index b38ff6d..0b036fe 100644 --- a/reid/src/mir/typeinference.rs +++ b/reid/src/mir/typeinference.rs @@ -13,8 +13,8 @@ use super::{ typecheck::ErrorKind, typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, types::{pick_return, ReturnType}, - Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module, - ReturnKind, StmtKind, + Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, + IndexedVariableReference, Module, NamedVariableRef, ReturnKind, StmtKind, TypeKind::*, VagueType::*, }; @@ -113,24 +113,23 @@ impl Block { } } StmtKind::Set(var, expr) => { - todo!("Re-think how set needs to work with arrays") - // // Get the TypeRef for this variable declaration - // let var_ref = inner_hints.find_hint(&var.1); + // Get the TypeRef for this variable declaration + let var_ref = var.find_hint(&inner_hints)?; - // // If ok, update the MIR type to this TypeRef - // if let Some((_, var_ref)) = &var_ref { - // var.0 = var_ref.as_type() - // } + // If ok, update the MIR type to this TypeRef + if let Some((_, var_ref)) = &var_ref { + var.update_type(&var_ref.as_type()); + } - // // Infer hints for the expression itself - // let inferred = expr.infer_types(&mut state, &inner_hints); - // let expr_ty_ref = state.ok(inferred, expr.1); + // Infer hints for the expression itself + let inferred = expr.infer_types(&mut state, &inner_hints); + let expr_ty_ref = state.ok(inferred, expr.1); - // // Try to narrow the variable type declaration with the - // // expression - // if let (Some((_, mut var_ref)), Some(expr_ty_ref)) = (var_ref, expr_ty_ref) { - // var_ref.narrow(&expr_ty_ref); - // } + // Try to narrow the variable type declaration with the + // expression + if let (Some((_, mut var_ref)), Some(expr_ty_ref)) = (var_ref, expr_ty_ref) { + var_ref.narrow(&expr_ty_ref); + } } StmtKind::Import(_) => todo!(), StmtKind::Expression(expr) => { @@ -161,6 +160,33 @@ impl Block { } } +impl IndexedVariableReference { + fn find_hint<'s>( + &self, + hints: &'s ScopeTypeRefs, + ) -> Result)>, ErrorKind> { + match &self.kind { + super::IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => { + Ok(hints.find_hint(&name)) + } + super::IndexedVariableReferenceKind::Index(inner, _) => { + if let Some((mutable, inner_ref)) = inner.find_hint(hints)? { + let inner_ty = inner_ref.as_type(); + match inner_ty { + Array(type_kind, _) => Ok(hints + .from_type(&type_kind) + .clone() + .map(|t_ref| (mutable, t_ref))), + _ => Err(ErrorKind::TriedIndexingNonArray(inner_ty.clone())), + } + } else { + Ok(None) + } + } + } + } +} + impl Expression { fn infer_types<'s>( &mut self, diff --git a/reid/src/mir/types.rs b/reid/src/mir/types.rs index c96228d..9c7d801 100644 --- a/reid/src/mir/types.rs +++ b/reid/src/mir/types.rs @@ -1,4 +1,8 @@ -use super::*; +use super::{ + pass::{ScopeVariable, Storage}, + typecheck::ErrorKind, + *, +}; #[derive(Debug, Clone)] pub enum ReturnTypeOther { @@ -160,3 +164,23 @@ pub fn pick_return(lhs: (ReturnKind, T), rhs: (ReturnKind, T)) -> (ReturnKind (_, _) => (Soft, lhs.1), } } + +impl IndexedVariableReference { + pub fn get_name(&self) -> String { + match &self.kind { + IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => name.clone(), + IndexedVariableReferenceKind::Index(inner, idx) => { + format!("{}[{}]", inner.get_name(), idx) + } + } + } + + pub fn update_type(&mut self, new_ty: &TypeKind) { + match &mut self.kind { + IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => { + *ty = new_ty.clone(); + } + IndexedVariableReferenceKind::Index(inner, _) => inner.update_type(new_ty), + } + } +}