From 9368d6dcd04fd47806d68fcb8250417f97314229 Mon Sep 17 00:00:00 2001 From: Shadow Cat Date: Sun, 4 May 2025 14:21:27 -0400 Subject: [PATCH] getting closer --- src/ir/arch/riscv64.rs | 6 +- src/ir/lower/program.rs | 18 +- src/ir/upper/error.rs | 28 +- src/ir/upper/instr.rs | 38 +-- src/ir/upper/kind.rs | 82 +----- src/ir/upper/mod.rs | 1 + src/ir/upper/program.rs | 22 +- src/ir/upper/resolve.rs | 431 +++++++++++++++++++--------- src/ir/upper/ty.rs | 72 +++-- src/parser/v3/lower/arch/riscv64.rs | 4 +- src/parser/v3/lower/asm.rs | 8 +- src/parser/v3/lower/block.rs | 10 +- src/parser/v3/lower/def.rs | 4 +- src/parser/v3/lower/expr.rs | 6 +- src/parser/v3/lower/func.rs | 16 +- src/parser/v3/lower/map.rs | 4 +- 16 files changed, 423 insertions(+), 327 deletions(-) diff --git a/src/ir/arch/riscv64.rs b/src/ir/arch/riscv64.rs index 90f322e..b9da0a8 100644 --- a/src/ir/arch/riscv64.rs +++ b/src/ir/arch/riscv64.rs @@ -1,10 +1,10 @@ -use crate::{compiler::arch::riscv::*, ir::VarInst}; +use crate::{compiler::arch::riscv::*, ir::UIdent}; -pub type RV64Instruction = LinkerInstruction; +pub type RV64Instruction = LinkerInstruction; #[derive(Copy, Clone)] pub enum RegRef { - Var(VarInst), + Var(UIdent), Reg(Reg), } diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs index 16c38f4..d89e367 100644 --- a/src/ir/lower/program.rs +++ b/src/ir/lower/program.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; -use crate::ir::{AsmBlockArgType, Size, StructTy, SymbolSpace, Type, UFunc, UInstrInst, VarOffset}; -StructTy +use crate::ir::{AsmBlockArgType, Size, LStructInst, SymbolSpace, Type, UFunc, UInstrInst, VarOffset}; +LStructInst use super::{ IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, UInstruction, UProgram, VarID, }; @@ -42,14 +42,14 @@ impl LProgram { } } -pub struct StructInst { +pub struct LStructInst { offsets: Vec, types: Vec, order: HashMap, size: Size, } -impl StructInst { +impl LStructInst { pub fn offset(&self, name: &str) -> Option { Some(self.offsets[*self.order.get(name)?]) } @@ -82,7 +82,7 @@ pub struct LFunctionBuilderData<'a> { instrs: Vec, stack: HashMap, subvar_map: HashMap, - struct_insts: HashMap, + struct_insts: HashMap, makes_call: bool, loopp: Option, } @@ -376,10 +376,10 @@ impl LFunctionBuilderData<'_> { pub fn addr_size(&self) -> Size { 64StructTy } - pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst { + pub fn struct_inst(&mut self, p: &UProgram, ty: &LStructInst) -> &LStructInst { // normally I'd let Some(..) here and return, but polonius does not exist :grief: if self.struct_insts.get(ty).is_none() { - let StructInst { id, args } = ty; + let LStructInst { id, args } = ty; let struc = p.expect(*id); let mut types = Vec::new(); let mut sizes = struc @@ -412,7 +412,7 @@ impl LFunctionBuilderData<'_> { } self.struct_insts.insert( ty.clone(), - StructInst { + LStructInst { offsets, order, types, @@ -423,7 +423,7 @@ impl LFunctionBuilderData<'_> { self.struct_insts.get(ty).unwrap() } - pub fn field_offset(&mut self, p: &UProgram, sty: &StructInst, field: &str) -> Option { + pub fn field_offset(&mut self, p: &UProgram, sty: &LStructInst, field: &str) -> Option { let inst = self.struct_inst(p, sty); Some(inst.offset(field)?) } diff --git a/src/ir/upper/error.rs b/src/ir/upper/error.rs index 0d3908e..8388c80 100644 --- a/src/ir/upper/error.rs +++ b/src/ir/upper/error.rs @@ -3,7 +3,7 @@ use crate::{ ir::ID, }; -use super::{KindTy, Origin, StructID, TypeID, UProgram}; +use super::{KindTy, Origin, Res, StructID, TypeID, UProgram}; pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec) { for err in errs { @@ -82,18 +82,18 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec) origin, found, expected, - id, } => output.err(CompilerMsg::new( { - let name = match found { - KindTy::Type => &p.type_name(ID::new(id)), - KindTy::Var => &p.vars[id].name, - KindTy::Struct => &p.structs[id].name, + let name = match &found { + Res::Fn(fty) => &p.fns[fty.id].name, + Res::Type(id) => &p.type_name(id), + Res::Var(id) => &p.vars[id].name, + Res::Struct(sty) => &p.structs[sty.id].name, }; format!( "Expected {}, found {} '{}'", expected.str(), - found.str(), + found.kind_str(), name ) }, @@ -106,12 +106,20 @@ pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec) } } +#[derive(Debug, Clone)] pub enum ResErr { + UnknownModule { + origin: Origin, + name: String, + }, + UnknownMember { + origin: Origin, + name: String, + }, KindMismatch { origin: Origin, expected: KindTy, - found: KindTy, - id: usize, + found: Res, }, UnexpectedField { origin: Origin, @@ -158,6 +166,7 @@ pub enum ResErr { }, } +#[derive(Debug, Clone)] pub enum ControlFlowOp { Break, Continue, @@ -172,6 +181,7 @@ impl ControlFlowOp { } } +#[derive(Debug, Clone)] pub struct TypeMismatch { pub dst: TypeID, pub src: TypeID, diff --git a/src/ir/upper/instr.rs b/src/ir/upper/instr.rs index d27a8cb..79596fc 100644 --- a/src/ir/upper/instr.rs +++ b/src/ir/upper/instr.rs @@ -1,53 +1,53 @@ use std::{collections::HashMap, fmt::Write}; -use super::{arch::riscv64::RV64Instruction, DataID, FnID, Origin, UFunc, VarInst, VarInstID}; +use super::{arch::riscv64::RV64Instruction, DataID, FnID, Origin, UFunc, UIdent, IdentID}; use crate::{compiler::arch::riscv::Reg, util::Padder}; #[derive(Clone)] pub enum UInstruction { Mv { - dst: VarInstID, - src: VarInstID, + dst: IdentID, + src: IdentID, }, Ref { - dst: VarInstID, - src: VarInstID, + dst: IdentID, + src: IdentID, }, Deref { - dst: VarInstID, - src: VarInstID, + dst: IdentID, + src: IdentID, }, LoadData { - dst: VarInstID, + dst: IdentID, src: DataID, }, LoadSlice { - dst: VarInstID, + dst: IdentID, src: DataID, }, LoadFn { - dst: VarInstID, + dst: IdentID, src: FnID, }, Call { - dst: VarInstID, - f: VarInstID, - args: Vec, + dst: IdentID, + f: IdentID, + args: Vec, }, AsmBlock { instructions: Vec, args: Vec, }, Ret { - src: VarInstID, + src: IdentID, }, Construct { - dst: VarInstID, - struc: VarInstID, - fields: HashMap, + dst: IdentID, + struc: IdentID, + fields: HashMap, }, If { - cond: VarInstID, + cond: IdentID, body: Vec, }, Loop { @@ -71,7 +71,7 @@ impl std::fmt::Debug for UInstrInst { #[derive(Debug, Clone)] pub struct AsmBlockArg { - pub var: VarInstID, + pub var: IdentID, pub reg: Reg, pub ty: AsmBlockArgType, } diff --git a/src/ir/upper/kind.rs b/src/ir/upper/kind.rs index c23cfa9..6f1088d 100644 --- a/src/ir/upper/kind.rs +++ b/src/ir/upper/kind.rs @@ -1,4 +1,4 @@ -use super::{Type, UInstrInst, UInstruction}; +use super::{FnInst, ResErr, StructInst, Type, UInstrInst, UInstruction}; use crate::{ common::FileSpan, ir::{Len, ID}, @@ -7,57 +7,9 @@ use std::{collections::HashMap, fmt::Debug}; pub type NamePath = Vec; -// "effective" (externally visible) kinds -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum KindTy { - Type, - Var, - Struct, - Fn, -} - -impl KindTy { - pub fn str(&self) -> &'static str { - match self { - KindTy::Type => "type", - KindTy::Var => "variable", - KindTy::Fn => "function", - KindTy::Struct => "struct", - } - } -} - -pub trait Kind { - fn ty() -> KindTy; -} - -impl Kind for UFunc { - fn ty() -> KindTy { - KindTy::Fn - } -} - -impl Kind for UVar { - fn ty() -> KindTy { - KindTy::Var - } -} - -impl Kind for UStruct { - fn ty() -> KindTy { - KindTy::Struct - } -} - -impl Kind for Type { - fn ty() -> KindTy { - KindTy::Type - } -} - pub type FnID = ID; pub type VarID = ID; -pub type VarInstID = ID; +pub type IdentID = ID; pub type TypeID = ID; pub type GenericID = ID; pub type StructID = ID; @@ -99,31 +51,33 @@ pub struct UVar { pub origin: Origin, pub ty: TypeID, pub parent: Option, - pub children: Vec, + pub children: HashMap, } -/// these are more like "expressions", need to find good name /// eg. a::b::c::.d.e #[derive(Clone, Debug)] -pub struct VarInst { - pub status: VarStatus, +pub struct UIdent { + pub status: IdentStatus, pub origin: Origin, } #[derive(Clone, Debug)] -pub enum VarStatus { +pub enum IdentStatus { Var(VarID), - Struct(StructID, Vec), + Struct(StructInst), + Fn(FnInst), + Type(TypeID), Unres { path: ModPath, - name: String, + mem: MemberID, gargs: Vec, fields: Vec, }, - Partial { - v: VarID, + PartialVar { + id: VarID, fields: Vec, }, + Failed(ResErr), Cooked, } @@ -209,13 +163,3 @@ impl<'a> Iterator for InstrIter<'a> { } } -impl VarInst { - pub fn id(&self) -> Option { - match &self.status { - VarStatus::Var(id) => Some(*id), - VarStatus::Unres { .. } => None, - VarStatus::Partial { .. } => None, - VarStatus::Cooked => None, - } - } -} diff --git a/src/ir/upper/mod.rs b/src/ir/upper/mod.rs index 4f118f2..810e8a3 100644 --- a/src/ir/upper/mod.rs +++ b/src/ir/upper/mod.rs @@ -12,3 +12,4 @@ pub use kind::*; pub use program::*; pub use ty::*; pub use error::*; +pub use resolve::*; diff --git a/src/ir/upper/program.rs b/src/ir/upper/program.rs index 9ac302b..f7472b5 100644 --- a/src/ir/upper/program.rs +++ b/src/ir/upper/program.rs @@ -11,7 +11,7 @@ pub struct UProgram { pub data: Vec, pub generics: Vec, pub vars: Vec, - pub vars_insts: Vec, + pub idents: Vec, pub types: Vec, pub vfmap: HashMap, @@ -39,7 +39,7 @@ impl UProgram { Self { fns: Vec::new(), vars: Vec::new(), - vars_insts: Vec::new(), + idents: Vec::new(), structs: Vec::new(), types: Vec::new(), generics: Vec::new(), @@ -66,8 +66,8 @@ impl UProgram { push_id(&mut self.types, t) } - pub fn def_var_inst(&mut self, i: VarInst) -> VarInstID { - push_id(&mut self.vars_insts, i) + pub fn def_var_inst(&mut self, i: UIdent) -> IdentID { + push_id(&mut self.idents, i) } pub fn def_generic(&mut self, g: UGeneric) -> GenericID { @@ -85,12 +85,12 @@ impl UProgram { pub fn type_name(&self, ty: impl Typed) -> String { match ty.ty(self) { Type::Struct(ty) => { - format!("{}{}", self.structs[ty.id].name, self.gparams_str(&ty.args)) + format!("{}{}", self.structs[ty.id].name, self.gparams_str(&ty.gargs)) } Type::FnRef(ty) => { format!( "fn{}({}) -> {}", - &self.gparams_str(&ty.args), + &self.gparams_str(&ty.gargs), &self.type_list_str(self.fns[ty.id].args.iter().map(|v| self.vars[v].ty)), &self.type_name(self.fns[ty.id].ret) ) @@ -146,21 +146,21 @@ impl<'a> UModuleBuilder<'a> { temp: 0, } } - pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> VarInstID { + pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> IdentID { self.temp_var_inner(origin, ty) } - fn temp_var_inner(&mut self, origin: Origin, ty: impl Typable) -> VarInstID { + fn temp_var_inner(&mut self, origin: Origin, ty: impl Typable) -> IdentID { let var = UVar { name: format!("temp{}", self.temp), ty: ty.ty(self), origin, parent: None, - children: Vec::new(), + children: HashMap::new(), }; let id = self.p.def_var(var); self.temp += 1; - self.def_var_inst(VarInst { - status: VarStatus::Var(id), + self.def_var_inst(UIdent { + status: IdentStatus::Var(id), origin, }) } diff --git a/src/ir/upper/resolve.rs b/src/ir/upper/resolve.rs index 7ae9d6f..92fa051 100644 --- a/src/ir/upper/resolve.rs +++ b/src/ir/upper/resolve.rs @@ -1,9 +1,11 @@ use super::{ - report_errs, ControlFlowOp, DataID, Kind, MemberTy, Origin, ResErr, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID, VarInst, VarInstID, VarStatus + inst_fn_ty, inst_struct_ty, report_errs, ControlFlowOp, DataID, FnInst, IdentID, IdentStatus, + MemberTy, Origin, ResErr, StructInst, Type, TypeID, TypeMismatch, UData, UFunc, UGeneric, + UIdent, UInstrInst, UInstruction, UModule, UProgram, UStruct, UVar, VarID, }; use crate::{ common::{CompilerMsg, CompilerOutput}, - ir::{inst_fn_var, inst_struct_ty, KindTy, ID}, + ir::{inst_fn_var, ID}, }; use std::{ collections::HashSet, @@ -21,7 +23,7 @@ impl UProgram { changed: false, types: &mut self.types, s: Sources { - insts: &mut self.vars_insts, + idents: &mut self.idents, vars: &mut self.vars, fns: &self.fns, structs: &self.structs, @@ -44,13 +46,12 @@ impl UProgram { } // this currently works bc expressions create temporary variables // although you can't do things like loop {return 3} (need to analyze control flow) - if !matches!(data.types[f.ret], Type::Unit) { - if f.instructions + if !matches!(data.types[f.ret], Type::Unit) + && f.instructions .last() .is_none_or(|i| !matches!(i.i, UInstruction::Ret { .. })) - { - data.errs.push(ResErr::NoReturn { fid }); - } + { + data.errs.push(ResErr::NoReturn { fid }); } } while !data.unfinished.is_empty() && data.changed { @@ -60,7 +61,23 @@ impl UProgram { resolve_instr(&mut data, ctx); } } - let errs = data.errs; + let mut errs = data.errs; + for ident in &self.idents { + match &ident.status { + IdentStatus::Unres { + path, + mem, + gargs, + fields, + } => errs.push(ResErr::UnknownModule { + origin: path.path[0].origin, + name: path.path[0].name.clone(), + }), + IdentStatus::PartialVar { id, fields } => todo!(), + IdentStatus::Failed(err) => errs.push(err.clone()), + _ => (), + } + } report_errs(self, output, errs); for var in &self.vars { match &self.types[var.ty] { @@ -93,13 +110,8 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option< let mut res = InstrRes::Finished; match &ctx.i.i { UInstruction::Call { dst, f, args } => { - let fty = data.res_id(f, ctx)?; - let Type::FnRef(ftyy) = data.types[fty].clone() else { - let origin = f.origin(data); - data.errs.push(ResErr::NotCallable { origin, ty: fty }); - return None; - }; - let f = &data.s.fns[ftyy.id]; + let fi = data.res_id::(f, ctx)?; + let f = &data.s.fns[fi.id]; for (src, dest) in args.iter().zip(&f.args) { res |= data.match_types(dest, src, src); } @@ -109,14 +121,14 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option< res |= data.match_types(dst, src, src); } UInstruction::Ref { dst, src } => { - let dstid = data.res_id(dst, ctx)?; + let dstid = data.res_ty_id::(dst, ctx)?; let Type::Ref(dest_ty) = data.types[dstid] else { compiler_error() }; res |= data.match_types(dest_ty, src, src); } UInstruction::Deref { dst, src } => { - let srcid = data.res_id(src, ctx)?; + let srcid = data.res_ty_id::(src, ctx)?; let Type::Ref(src_ty) = data.types[srcid] else { let origin = src.origin(data); data.errs.push(ResErr::CannotDeref { origin, ty: srcid }); @@ -148,11 +160,8 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option< res |= data.match_types(ctx.ret, src, src); } UInstruction::Construct { dst, struc, fields } => { - let id = data.res_id(dst, ctx, KindTy::Struct)?; - let Type::Struct(sty) = &data.types[id] else { - return None; - }; - let sid = sty.id; + let si = data.res_id::(dst, ctx)?; + let sid = si.id; let st = &data.s.structs[sid]; let mut used = HashSet::new(); for (name, field) in &st.fields { @@ -180,7 +189,7 @@ pub fn resolve_instr<'a>(data: &mut ResData<'a>, ctx: ResolveCtx<'a>) -> Option< } } UInstruction::If { cond, body } => { - if let Some(id) = data.res_id(cond, ctx, KindTy::Var) { + if let Some(id) = data.res_ty_id::(cond, ctx) { if !matches!(data.types[id], Type::Bits(64)) { let origin = cond.origin(data); data.errs.push(ResErr::CondType { origin, ty: id }); @@ -262,7 +271,7 @@ pub fn match_types(data: &mut TypeResData, dst: impl TypeIDed, src: impl TypeIDe if dest.id != src.id { return error(); } - match_all(data, dest.args.iter().cloned(), src.args.iter().cloned()) + match_all(data, dest.gargs.iter().cloned(), src.gargs.iter().cloned()) } // ( // Type::Fn { @@ -327,7 +336,7 @@ fn match_all( } struct Sources<'a> { - insts: &'a mut [VarInst], + idents: &'a mut [UIdent], vars: &'a mut Vec, fns: &'a [UFunc], structs: &'a [UStruct], @@ -353,12 +362,12 @@ struct TypeResData<'a> { impl<'a> ResData<'a> { pub fn match_types( &mut self, - dst: impl ResID, - src: impl ResID, + dst: impl Resolvable, + src: impl Resolvable, origin: impl HasOrigin, ) -> InstrRes { - let dst = dst.try_id(&mut self.s, self.types, &mut self.errs, KindTy::Type)?; - let src = src.try_id(&mut self.s, self.types, &mut self.errs, KindTy::Type)?; + let dst = dst.try_res(&mut self.s, self.types, &mut self.errs)?; + let src = src.try_res(&mut self.s, self.types, &mut self.errs)?; let res = match_types( &mut TypeResData { changed: &mut self.changed, @@ -382,15 +391,24 @@ impl<'a> ResData<'a> { } } } - pub fn try_res_id(&mut self, x: impl ResID) -> Result, InstrRes> { - x.try_id(&mut self.s, &mut self.types, &mut self.errs) - .map(|id| resolve_refs(self.types, id)) + pub fn try_res_id(&mut self, x: impl Resolvable) -> Result { + x.try_res(&mut self.s, &mut self.types, &mut self.errs) } - pub fn res_id<'b: 'a, K>( + pub fn res_ty_id<'b: 'a, K: ResKind>( &mut self, - x: impl ResID, + x: impl Resolvable, ctx: ResolveCtx<'b>, - ) -> Option> { + ) -> Option + where + K::Res: TypeIDed, + { + self.res_id::(x, ctx).map(|i| i.type_id(&self.s)) + } + pub fn res_id<'b: 'a, K: ResKind>( + &mut self, + x: impl Resolvable, + ctx: ResolveCtx<'b>, + ) -> Option { match self.try_res_id(x) { Ok(id) => return Some(id), Err(InstrRes::Unfinished) => self.unfinished.push(ctx), @@ -433,166 +451,293 @@ impl FromResidual> for InstrRes { } } -trait ResID { - fn try_id( +trait Resolvable { + fn try_res( &self, s: &mut Sources, types: &mut Vec, errs: &mut Vec, - ) -> Result, InstrRes>; + ) -> Result; } -impl ResID for T { - fn try_id( +impl Resolvable for T { + fn try_res( &self, s: &mut Sources, _: &mut Vec, errs: &mut Vec, - kind: KindTy, ) -> Result { Ok(self.type_id(s)) } } -impl VarInst { - pub fn resolve(&mut self, s: &mut Sources) { - match &self.status { - VarStatus::Var(id) => self.status = VarStatus::Cooked, - VarStatus::Struct(id, ids) => todo!(), - VarStatus::Unres { path, name, gargs, fields } => todo!(), - VarStatus::Partial { v, fields } => todo!(), - VarStatus::Cooked => todo!(), - } - } -} - -impl ResID for VarInstID { - fn try_id( - &self, - s: &mut Sources, - types: &mut Vec, - errs: &mut Vec, - ) -> Result, InstrRes> { - let kind = K::ty(); - let inst = &mut s.insts[self]; - let (id, fields) = match &mut inst.status { - VarStatus::Var(id) => { - return Ok(s.vars[id].ty) - }, - VarStatus::Unres { +impl IdentID { + pub fn resolve(self, s: &mut Sources) -> Result { + let ident = &mut s.idents[self]; + Ok(match &mut ident.status { + IdentStatus::Var(id) => Res::Var(*id), + IdentStatus::Struct(sty) => Res::Struct(sty.clone()), + IdentStatus::Fn(fty) => Res::Fn(fty.clone()), + IdentStatus::Type(ty) => Res::Type(*ty), + IdentStatus::Unres { path, - name, + mem, gargs, fields, } => { let mut mid = path.id; - let mut depth = 0; + let mut count = 0; for mem in &path.path { let Some(&child) = s.modules[mid].children.get(&mem.name) else { break; }; - depth += 1; + count += 1; mid = child; } - path.path.drain(0..depth); + path.path.drain(0..count); path.id = mid; if path.path.len() != 0 { return Err(InstrRes::Unfinished); } - let Some(mem) = s.modules[mid].members.get(name) else { + let Some(mem) = s.modules[mid].members.get(&mem.name) else { return Err(InstrRes::Unfinished); }; - let vid = match mem.id { + match mem.id { MemberTy::Fn(id) => { - if kind == KindTy::Fn { - return Ok(id.0.into()); - } - if !matches!(kind, KindTy::Var | KindTy::Fn) { - errs.push(ResErr::KindMismatch { - origin: inst.origin, - expected: kind, - found: KindTy::Fn, - id: id.0, + if fields.len() > 0 { + ident.status = IdentStatus::Failed(ResErr::UnexpectedField { + origin: ident.origin, }); return Err(InstrRes::Finished); } - inst_fn_var( + let fty = FnInst { id, - s.fns, - gargs, - inst.origin, - s.vars, - types, - s.generics, - errs, - ) + gargs: gargs.clone(), + }; + ident.status = IdentStatus::Fn(fty.clone()); + Res::Fn(fty) + } + MemberTy::Struct(id) => { + if fields.len() > 0 { + ident.status = IdentStatus::Failed(ResErr::UnexpectedField { + origin: ident.origin, + }); + return Err(InstrRes::Finished); + } + let sty = StructInst { + id, + gargs: gargs.clone(), + }; + ident.status = IdentStatus::Struct(sty.clone()); + Res::Struct(sty) } MemberTy::Var(id) => { - if !matches!(kind, KindTy::Var | KindTy::Any) { - errs.push(ResErr::KindMismatch { - origin: inst.origin, - expected: kind, - found: KindTy::Var, - id: id.0, - }); - return Err(InstrRes::Finished); - } if !gargs.is_empty() { - errs.push(ResErr::GenericCount { - origin: inst.origin, + ident.status = IdentStatus::Failed(ResErr::GenericCount { + origin: ident.origin, expected: 0, found: gargs.len(), }); - } - id - } - MemberTy::Struct(id) => { - if !matches!(kind, KindTy::Struct | KindTy::Type | KindTy::Any) { - errs.push(ResErr::KindMismatch { - origin: inst.origin, - expected: kind, - found: KindTy::Struct, - id: id.0, - }); return Err(InstrRes::Finished); } - if fields.len() > 0 { - errs.push(ResErr::UnexpectedField { - origin: inst.origin, - }); - return Err(InstrRes::Finished); - } - return Ok(inst_struct_ty( - id, s.structs, gargs, types, s.generics, errs, - )); + ident.status = IdentStatus::PartialVar { + id, + fields: fields.clone(), + }; + return self.resolve(s); } - }; - if fields.len() > 0 { - inst.status = VarStatus::Partial{v: vid, fields} } } - VarStatus::Partial { v, fields } => (*v, fields), - VarStatus::Cooked => return Err(InstrRes::Finished), - }; - // I feel like this clone is not necessary but idk how - inst.status = VarStatus::Partial { - v: id, - fields: fields.clone(), - }; - // let VarStatus::Partial { v, fields } = inst.status - todo!() + IdentStatus::PartialVar { id, fields } => { + let mut fiter = fields.iter(); + let mut next = fiter.next(); + let mut count = 0; + while let Some(mem) = next + && let Some(&cid) = s.vars[*id].children.get(&mem.name) + { + *id = cid; + next = fiter.next(); + count += 1; + } + fields.drain(0..count); + if fields.len() != 0 { + return Err(InstrRes::Unfinished); + } + let id = *id; + ident.status = IdentStatus::Var(id); + Res::Var(id) + } + IdentStatus::Cooked => return Err(InstrRes::Finished), + IdentStatus::Failed(_) => return Err(InstrRes::Finished), + }) } } -impl ResID for &VarInstID { - fn try_id( +impl Resolvable for IdentID { + fn try_res( &self, s: &mut Sources, types: &mut Vec, errs: &mut Vec, - kind: KindTy, - ) -> Result, InstrRes> { - (*self).try_id(s, types, errs, kind) + ) -> Result { + let origin = s.idents[self].origin; + let res = self.resolve(s)?; + match K::from_res(res.clone(), types, s, origin, errs) { + Some(res) => Ok(res), + None => { + errs.push(ResErr::KindMismatch { + origin, + expected: K::ty(), + found: res, + }); + Err(InstrRes::Finished) + } + } + } +} + +// "effective" (externally visible) kinds +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KindTy { + Type, + Var, + Struct, + Fn, +} + +impl KindTy { + pub fn str(&self) -> &'static str { + match self { + KindTy::Type => "type", + KindTy::Var => "variable", + KindTy::Fn => "function", + KindTy::Struct => "struct", + } + } +} + +#[derive(Debug, Clone)] +pub enum Res { + Var(VarID), + Fn(FnInst), + Struct(StructInst), + Type(TypeID), +} + +impl Res { + pub fn kind(&self) -> KindTy { + match self { + Res::Var(..) => KindTy::Var, + Res::Fn(..) => KindTy::Fn, + Res::Struct(..) => KindTy::Struct, + Res::Type(..) => KindTy::Type, + } + } + pub fn kind_str(&self) -> &'static str { + self.kind().str() + } +} + +pub trait ResKind { + type Res; + fn ty() -> KindTy; + fn from_res( + res: Res, + types: &mut Vec, + s: &mut Sources, + origin: Origin, + errs: &mut Vec, + ) -> Option; +} + +impl ResKind for UFunc { + type Res = FnInst; + fn ty() -> KindTy { + KindTy::Fn + } + fn from_res( + res: Res, + _: &mut Vec, + _: &mut Sources, + _: Origin, + _: &mut Vec, + ) -> Option { + match res { + Res::Fn(fi) => Some(fi), + _ => None, + } + } +} + +impl ResKind for UVar { + type Res = VarID; + fn ty() -> KindTy { + KindTy::Var + } + fn from_res( + res: Res, + types: &mut Vec, + s: &mut Sources, + origin: Origin, + errs: &mut Vec, + ) -> Option { + Some(match res { + Res::Fn(fty) => inst_fn_var(&fty, s.fns, origin, s.vars, types, s.generics, errs), + Res::Var(id) => id, + Res::Struct(_) => return None, + Res::Type(_) => return None, + }) + } +} + +impl ResKind for UStruct { + type Res = StructInst; + fn ty() -> KindTy { + KindTy::Struct + } + fn from_res( + res: Res, + _: &mut Vec, + _: &mut Sources, + _: Origin, + _: &mut Vec, + ) -> Option { + match res { + Res::Struct(si) => Some(si), + _ => None, + } + } +} + +impl ResKind for Type { + type Res = TypeID; + fn ty() -> KindTy { + KindTy::Type + } + fn from_res( + res: Res, + types: &mut Vec, + s: &mut Sources, + _: Origin, + errs: &mut Vec, + ) -> Option { + Some(match res { + Res::Fn(fty) => inst_fn_ty(&fty, s.fns, types, s.generics, errs), + Res::Var(id) => id.type_id(s), + Res::Struct(si) => inst_struct_ty(&si, s.structs, types, s.generics, errs), + Res::Type(id) => id, + }) + } +} + +impl Resolvable for &IdentID { + fn try_res( + &self, + s: &mut Sources, + types: &mut Vec, + errs: &mut Vec, + ) -> Result { + Resolvable::::try_res(*self, s, types, errs) } } @@ -637,8 +782,8 @@ trait HasOrigin { fn origin(&self, data: &ResData) -> Origin; } -impl HasOrigin for &VarInstID { +impl HasOrigin for &IdentID { fn origin(&self, data: &ResData) -> Origin { - data.s.insts[*self].origin + data.s.idents[*self].origin } } diff --git a/src/ir/upper/ty.rs b/src/ir/upper/ty.rs index 3032681..66c75a4 100644 --- a/src/ir/upper/ty.rs +++ b/src/ir/upper/ty.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use super::{ - push_id, FnID, GenericID, Len, ModPath, Origin, ResErr, StructID, TypeCache, TypeID, UFunc, - UGeneric, UProgram, UStruct, UVar, VarID, + push_id, FnID, GenericID, Len, ModPath, Origin, ResErr, StructID, TypeID, UFunc, UGeneric, + UProgram, UStruct, UVar, VarID, }; #[derive(Debug, Clone, Hash, Eq, PartialEq)] @@ -11,23 +11,23 @@ pub struct FieldRef { pub name: String, } -#[derive(Clone, Eq, PartialEq, Hash)] -pub struct StructTy { +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct StructInst { pub id: StructID, - pub args: Vec, + pub gargs: Vec, } -#[derive(Clone, Eq, PartialEq, Hash)] -pub struct FnTy { +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct FnInst { pub id: FnID, - pub args: Vec, + pub gargs: Vec, } #[derive(Clone)] pub enum Type { Bits(u32), - Struct(StructTy), - FnRef(FnTy), + Struct(StructInst), + FnRef(FnInst), // this can be added for constraints later (F: fn(...) -> ...) // Fn { args: Vec, ret: TypeID }, Ref(TypeID), @@ -79,17 +79,16 @@ impl Type { } pub fn inst_fn_var( - id: FnID, + fi: &FnInst, fns: &[UFunc], - gargs: &[TypeID], origin: Origin, vars: &mut Vec, types: &mut Vec, generics: &[UGeneric], errs: &mut Vec, ) -> VarID { - let ty = inst_fn_ty(id, fns, gargs, types, generics, errs); - let name = fns[id].name.clone(); + let ty = inst_fn_ty(fi, fns, types, generics, errs); + let name = fns[fi.id].name.clone(); push_id( vars, UVar { @@ -97,39 +96,37 @@ pub fn inst_fn_var( origin, ty, parent: None, - children: Vec::new(), + children: HashMap::new(), }, ) } pub fn inst_fn_ty( - id: FnID, + fi: &FnInst, fns: &[UFunc], - gargs: &[TypeID], types: &mut Vec, generics: &[UGeneric], errs: &mut Vec, ) -> TypeID { - let f = &fns[id]; - let ty = Type::FnRef(FnTy { - id, - args: inst_generics(&f.gargs, gargs, types, generics, errs), + let f = &fns[fi.id]; + let ty = Type::FnRef(FnInst { + id: fi.id, + gargs: inst_generics(&f.gargs, &fi.gargs, types, generics, errs), }); push_id(types, ty) } pub fn inst_struct_var( - id: StructID, + si: &StructInst, structs: &[UStruct], - gargs: &[TypeID], origin: Origin, vars: &mut Vec, types: &mut Vec, generics: &[UGeneric], errs: &mut Vec, ) -> VarID { - let ty = inst_struct_ty(id, structs, gargs, types, generics, errs); - let name = structs[id].name.clone(); + let ty = inst_struct_ty(si, structs, types, generics, errs); + let name = structs[si.id].name.clone(); push_id( vars, UVar { @@ -137,23 +134,22 @@ pub fn inst_struct_var( origin, ty, parent: None, - children: Vec::new(), + children: HashMap::new(), }, ) } pub fn inst_struct_ty( - id: StructID, + si: &StructInst, structs: &[UStruct], - gargs: &[TypeID], types: &mut Vec, generics: &[UGeneric], errs: &mut Vec, ) -> TypeID { - let s = &structs[id]; - let ty = Type::Struct(StructTy { - id, - args: inst_generics(&s.gargs, gargs, types, generics, errs), + let s = &structs[si.id]; + let ty = Type::Struct(StructInst { + id: si.id, + gargs: inst_generics(&s.gargs, &si.gargs, types, generics, errs), }); push_id(types, ty) } @@ -204,18 +200,18 @@ pub fn inst_type_ins( ) -> TypeID { let ty = match types[id].clone() { Type::Bits(_) => return id, - Type::Struct(struct_ty) => Type::Struct(StructTy { + Type::Struct(struct_ty) => Type::Struct(StructInst { id: struct_ty.id, - args: struct_ty - .args + gargs: struct_ty + .gargs .iter() .map(|id| inst_type(*id, types, gmap)) .collect(), }), - Type::FnRef(fn_ty) => Type::FnRef(FnTy { + Type::FnRef(fn_ty) => Type::FnRef(FnInst { id: fn_ty.id, - args: fn_ty - .args + gargs: fn_ty + .gargs .iter() .map(|id| inst_type(*id, types, gmap)) .collect(), diff --git a/src/parser/v3/lower/arch/riscv64.rs b/src/parser/v3/lower/arch/riscv64.rs index 1390164..e9ead4b 100644 --- a/src/parser/v3/lower/arch/riscv64.rs +++ b/src/parser/v3/lower/arch/riscv64.rs @@ -3,7 +3,7 @@ use crate::{ compiler::arch::riscv::*, ir::{ arch::riscv64::{RV64Instruction, RegRef}, - VarInst, + UIdent, }, }; @@ -166,7 +166,7 @@ impl RV64Instruction { } } -pub fn arg_to_var(node: &Node, ctx: &mut FnLowerCtx) -> Option { +pub fn arg_to_var(node: &Node, ctx: &mut FnLowerCtx) -> Option { let PAsmArg::Ref(node) = node.inner.as_ref()? else { ctx.err_at( node.origin, diff --git a/src/parser/v3/lower/asm.rs b/src/parser/v3/lower/asm.rs index ffa654b..be8b14c 100644 --- a/src/parser/v3/lower/asm.rs +++ b/src/parser/v3/lower/asm.rs @@ -1,15 +1,15 @@ use crate::{ compiler::arch::riscv::Reg, ir::{ - arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, Type, UInstruction, VarInst, - VarInstID, + arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, Type, UInstruction, UIdent, + IdentID, }, parser::PAsmBlockArg, }; use super::{FnLowerCtx, FnLowerable, PAsmBlock, PInstruction, PUAsmBlockArg}; -type PLAsmBlockArg = PAsmBlockArg; +type PLAsmBlockArg = PAsmBlockArg; impl FnLowerable for PInstruction { type Output = RV64Instruction; @@ -20,7 +20,7 @@ impl FnLowerable for PInstruction { } impl FnLowerable for PAsmBlock { - type Output = VarInstID; + type Output = IdentID; fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let mut args = Vec::new(); diff --git a/src/parser/v3/lower/block.rs b/src/parser/v3/lower/block.rs index a111c27..d8a875f 100644 --- a/src/parser/v3/lower/block.rs +++ b/src/parser/v3/lower/block.rs @@ -1,13 +1,13 @@ use crate::{ - ir::{Type, UInstruction, UVar, VarInst, VarInstID}, + ir::{Type, UInstruction, UVar, UIdent, IdentID}, parser::{PConstStatement, PStatementLike}, }; use super::{FnLowerCtx, FnLowerable, Import, PBlock, PStatement}; impl FnLowerable for PBlock { - type Output = VarInstID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = IdentID; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let mut last = None; let mut statements = Vec::new(); let mut fn_nodes = Vec::new(); @@ -74,8 +74,8 @@ impl FnLowerable for PBlock { } impl FnLowerable for PStatement { - type Output = VarInst; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = UIdent; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { match self { PStatement::Let(def, e) => { let def = def.lower(ctx.b, ctx.output)?; diff --git a/src/parser/v3/lower/def.rs b/src/parser/v3/lower/def.rs index 9be5731..2293f3e 100644 --- a/src/parser/v3/lower/def.rs +++ b/src/parser/v3/lower/def.rs @@ -1,4 +1,4 @@ -use crate::ir::{UProgram, UVar, VarID, VarInst}; +use crate::ir::{UProgram, UVar, VarID, UIdent}; use super::{CompilerOutput, Node, PVarDef}; @@ -10,7 +10,7 @@ impl Node { Some(ty) => ty.lower(program, output), None => program.infer(self.origin), }; - Some(VarInst { + Some(UIdent { id: program.def_searchable(name, Some(UVar { ty }), self.origin), origin: self.origin, }) diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs index 6f34bdc..ac506a8 100644 --- a/src/parser/v3/lower/expr.rs +++ b/src/parser/v3/lower/expr.rs @@ -1,12 +1,12 @@ use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp}; use crate::{ - ir::{Type, UData, UInstruction, VarInst, VarInstID}, + ir::{Type, UData, UInstruction, UIdent, IdentID}, parser::InfixOp, }; impl FnLowerable for PExpr { - type Output = VarInstID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = IdentID; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let mut e = self; let mut path = Vec::new(); while let PExpr::Member(node, ident) = e { diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs index 9c5bb94..75efa99 100644 --- a/src/parser/v3/lower/func.rs +++ b/src/parser/v3/lower/func.rs @@ -7,7 +7,7 @@ use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, P use crate::{ ir::{ FnID, GenericID, ModPath, Origin, Typable, Type, UFunc, UInstrInst, UInstruction, - UModuleBuilder, VarID, VarInst, VarInstID, VarStatus, + UModuleBuilder, VarID, UIdent, IdentID, IdentStatus, }, parser, util::NameStack, @@ -68,7 +68,7 @@ impl PFunction { let res = self.body.lower(&mut ctx); let mut instructions = ctx.instructions; if let Some(src) = res { - let origin = b.vars_insts[src].origin; + let origin = b.idents[src].origin; instructions.push(UInstrInst { origin, i: UInstruction::Ret { src }, @@ -99,13 +99,13 @@ pub struct FnLowerCtx<'a, 'b> { } impl<'a, 'b> FnLowerCtx<'a, 'b> { - pub fn var(&mut self, node: &Node) -> VarInstID { - let inst = VarInst { + pub fn var(&mut self, node: &Node) -> IdentID { + let inst = UIdent { status: if let Some(n) = node.as_ref() { if let Some(&var) = self.var_stack.search(&n.0) { - VarStatus::Var(var) + IdentStatus::Var(var) } else { - VarStatus::Unres { + IdentStatus::Unres { path: ModPath { id: self.b.module, path: Vec::new(), @@ -116,7 +116,7 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> { } } } else { - VarStatus::Cooked + IdentStatus::Cooked }, origin: node.origin, }; @@ -128,7 +128,7 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> { pub fn err_at(&mut self, span: FileSpan, msg: String) { self.output.err(CompilerMsg::new(msg, span)) } - pub fn temp(&mut self, ty: T) -> VarInstID { + pub fn temp(&mut self, ty: T) -> IdentID { self.b.temp_var(self.origin, ty) } pub fn push(&mut self, i: UInstruction) { diff --git a/src/parser/v3/lower/map.rs b/src/parser/v3/lower/map.rs index 6f00185..2c78b65 100644 --- a/src/parser/v3/lower/map.rs +++ b/src/parser/v3/lower/map.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; -use crate::{ir::VarInstID, parser::PMap}; +use crate::{ir::IdentID, parser::PMap}; use super::{FnLowerCtx, FnLowerable}; impl FnLowerable for PMap { - type Output = HashMap; + type Output = HashMap; fn lower(&self, ctx: &mut FnLowerCtx) -> Option { Some( self.0