From 6583d47ef80614b560b76452676a16221181e15a Mon Sep 17 00:00:00 2001 From: shadow cat Date: Sun, 4 May 2025 04:12:56 -0400 Subject: [PATCH] the light is getting closer --- src/ir/id.rs | 28 ++ src/ir/lower/program.rs | 20 +- src/ir/upper/assoc.rs | 31 -- src/ir/upper/error.rs | 186 ++++++++++ src/ir/upper/inst.rs | 35 -- src/ir/upper/instr.rs | 51 ++- src/ir/upper/kind.rs | 126 +++++-- src/ir/upper/mod.rs | 7 +- src/ir/upper/program.rs | 210 +++++------ src/ir/upper/resolve.rs | 676 +++++++++++++++++++++++++---------- src/ir/upper/ty.rs | 187 ++++++++-- src/ir/upper/validate.rs | 169 --------- src/parser/v3/lower/asm.rs | 7 +- src/parser/v3/lower/block.rs | 6 +- src/parser/v3/lower/expr.rs | 67 ++-- src/parser/v3/lower/func.rs | 88 +++-- src/parser/v3/lower/map.rs | 22 ++ src/parser/v3/lower/mod.rs | 1 + src/parser/v3/lower/struc.rs | 51 +-- src/parser/v3/lower/ty.rs | 17 +- src/parser/v3/nodes/func.rs | 6 +- src/parser/v3/nodes/struc.rs | 2 +- src/util/name_stack.rs | 8 +- 23 files changed, 1261 insertions(+), 740 deletions(-) delete mode 100644 src/ir/upper/assoc.rs create mode 100644 src/ir/upper/error.rs delete mode 100644 src/ir/upper/inst.rs delete mode 100644 src/ir/upper/validate.rs create mode 100644 src/parser/v3/lower/map.rs diff --git a/src/ir/id.rs b/src/ir/id.rs index 01c8d20..b718caa 100644 --- a/src/ir/id.rs +++ b/src/ir/id.rs @@ -79,6 +79,20 @@ impl IndexMut<&ID> for Vec { } } +impl Index<&mut ID> for Vec { + type Output = T; + + fn index(&self, i: &mut ID) -> &Self::Output { + &self[i.0] + } +} + +impl IndexMut<&mut ID> for Vec { + fn index_mut(&mut self, i: &mut ID) -> &mut Self::Output { + &mut self[i.0] + } +} + impl Index> for [T] { type Output = T; @@ -106,3 +120,17 @@ impl IndexMut<&ID> for [T] { &mut self[i.0] } } + +impl Index<&mut ID> for [T] { + type Output = T; + + fn index(&self, i: &mut ID) -> &Self::Output { + &self[i.0] + } +} + +impl IndexMut<&mut ID> for [T] { + fn index_mut(&mut self, i: &mut ID) -> &mut Self::Output { + &mut self[i.0] + } +} diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs index b9a73c2..16c38f4 100644 --- a/src/ir/lower/program.rs +++ b/src/ir/lower/program.rs @@ -1,9 +1,7 @@ use std::collections::HashMap; -use crate::ir::{ - AsmBlockArgType, FnID, Size, GenericTy, SymbolSpace, Type, UFunc, UInstrInst, VarOffset, -}; - +use crate::ir::{AsmBlockArgType, Size, StructTy, SymbolSpace, Type, UFunc, UInstrInst, VarOffset}; +StructTy use super::{ IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, UInstruction, UProgram, VarID, }; @@ -16,11 +14,15 @@ pub struct LProgram { // NOTE: there are THREE places here where I specify size (8) impl LProgram { - pub fn create(p: &UProgram, start: FnID) -> Result { + pub fn create(p: &UProgram) -> Result { + let start = p + .names + .id::(&[], "crate") + .ok_or("no start method found")?; let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]); let entry = ssbuilder.func(&start); while let Some((sym, i)) = ssbuilder.pop_fn() { - let f = &p.fns[i]; + let f = p.fns[i.0].as_ref().unwrap(); let mut fbuilder = LFunctionBuilder::new(p, &mut ssbuilder); for i in &f.instructions { fbuilder.insert_instr(i); @@ -29,7 +31,7 @@ impl LProgram { fbuilder.instrs.push(LInstruction::Ret { src: None }); } let res = fbuilder.finish(f); - ssbuilder.write_fn(sym, res, Some(f.name.clone())); + ssbuilder.write_fn(sym, res, Some(p.names.path(i).to_string())); } let sym_space = ssbuilder.finish().expect("we failed the mission"); Ok(Self { sym_space, entry }) @@ -372,9 +374,9 @@ impl LFunctionBuilderData<'_> { Some(VarOffset { id: var, offset }) } pub fn addr_size(&self) -> Size { - 64 + 64StructTy } - pub fn struct_inst(&mut self, p: &UProgram, ty: &GenericTy) -> &StructInst { + pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst { // 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; diff --git a/src/ir/upper/assoc.rs b/src/ir/upper/assoc.rs deleted file mode 100644 index d81d443..0000000 --- a/src/ir/upper/assoc.rs +++ /dev/null @@ -1,31 +0,0 @@ - -// #[derive(Debug, Clone, Copy)] -// pub struct Ident { -// id: usize, -// kind: usize, -// } -// -// // this isn't really a map... but also keeps track of "side data" -// #[derive(Debug, Clone, Copy)] -// pub struct Idents { -// pub latest: Ident, -// pub kinds: [Option; NAMED_KINDS], -// } -// -// impl Idents { -// pub fn new(latest: Ident) -> Self { -// let mut s = Self { -// latest, -// kinds: [None; NAMED_KINDS], -// }; -// s.insert(latest); -// s -// } -// pub fn insert(&mut self, i: Ident) { -// self.latest = i; -// self.kinds[i.kind] = Some(i.id); -// } -// pub fn get(&self) -> Option> { -// self.kinds[K::INDEX].map(|i| i.into()) -// } -// } diff --git a/src/ir/upper/error.rs b/src/ir/upper/error.rs new file mode 100644 index 0000000..0d3908e --- /dev/null +++ b/src/ir/upper/error.rs @@ -0,0 +1,186 @@ +use crate::{ + common::{CompilerMsg, CompilerOutput}, + ir::ID, +}; + +use super::{KindTy, Origin, StructID, TypeID, UProgram}; + +pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, errs: Vec) { + for err in errs { + match err { + ResErr::Type { + dst, + src, + errs, + origin, + } => { + let mut msg = type_assign_err(p, dst, src); + for inner in errs { + if inner.dst != dst && inner.src != src { + msg.push_str("\n "); + msg.push_str(&type_assign_err(p, inner.dst, inner.src)); + } + } + output.err(CompilerMsg::new(msg, origin)); + } + ResErr::NotCallable { origin, ty } => { + output.err(CompilerMsg::new( + format!("Cannot call type '{}'", p.type_name(ty)), + origin, + )); + } + ResErr::CannotDeref { origin, ty } => { + output.err(CompilerMsg::new( + format!("Cannot dereference type '{}'", p.type_name(ty)), + origin, + )); + } + ResErr::CondType { origin, ty } => { + output.err(CompilerMsg::new( + format!("Condition types must be '64'; found '{}'", p.type_name(ty)), + origin, + )); + } + ResErr::BadControlFlow { origin, op } => { + output.err(CompilerMsg::new( + format!("Cannot {} here (outside of loop)", op.str()), + origin, + )); + } + ResErr::MissingField { origin, id, name } => { + output.err(CompilerMsg::new( + format!( + "Missing field '{name}' in creation of struct '{}'", + p.structs[id].name + ), + origin, + )); + } + ResErr::UnknownField { origin, id, name } => { + output.err(CompilerMsg::new( + format!("Unknown field '{name}' in struct '{}'", p.structs[id].name), + origin, + )); + } + ResErr::NoReturn { fid } => output.err(CompilerMsg::new( + format!("Function must return a value"), + p.fns[fid].origin, + )), + ResErr::GenericCount { + origin, + expected, + found, + } => output.err(CompilerMsg::new( + if expected == 0 { + format!("No generic arguments expected") + } else { + format!("Expected {expected} generic arguments, found {found}") + }, + origin, + )), + ResErr::KindMismatch { + 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, + }; + format!( + "Expected {}, found {} '{}'", + expected.str(), + found.str(), + name + ) + }, + origin, + )), + ResErr::UnexpectedField { origin } => { + output.err(CompilerMsg::new(format!("Unexpected fields here"), origin)) + } + } + } +} + +pub enum ResErr { + KindMismatch { + origin: Origin, + expected: KindTy, + found: KindTy, + id: usize, + }, + UnexpectedField { + origin: Origin, + }, + GenericCount { + origin: Origin, + expected: usize, + found: usize, + }, + NotCallable { + origin: Origin, + ty: TypeID, + }, + CannotDeref { + origin: Origin, + ty: TypeID, + }, + CondType { + origin: Origin, + ty: TypeID, + }, + NoReturn { + fid: usize, + }, + BadControlFlow { + op: ControlFlowOp, + origin: Origin, + }, + MissingField { + origin: Origin, + id: StructID, + name: String, + }, + UnknownField { + origin: Origin, + id: StructID, + name: String, + }, + Type { + dst: TypeID, + src: TypeID, + errs: Vec, + origin: Origin, + }, +} + +pub enum ControlFlowOp { + Break, + Continue, +} + +impl ControlFlowOp { + pub fn str(&self) -> &'static str { + match self { + ControlFlowOp::Break => "break", + ControlFlowOp::Continue => "continue", + } + } +} + +pub struct TypeMismatch { + pub dst: TypeID, + pub src: TypeID, +} + +pub fn type_assign_err(p: &UProgram, dst: TypeID, src: TypeID) -> String { + format!( + "Cannot assign type {} to {}", + p.type_name(src), + p.type_name(dst) + ) +} diff --git a/src/ir/upper/inst.rs b/src/ir/upper/inst.rs deleted file mode 100644 index cc977a8..0000000 --- a/src/ir/upper/inst.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::ir::VarID; -use std::fmt::Debug; - -use super::{MemberID, ModPath, Origin, UInstruction}; - -#[derive(Clone)] -pub struct VarInst { - pub status: VarStatus, - pub origin: Origin, -} - -#[derive(Clone)] -pub enum VarStatus { - Res(VarID), - Unres { mid: ModPath, fields: Vec }, - Partial { v: VarID, fields: Vec }, -} - -#[derive(Clone)] -pub struct VarParent { - id: VarID, - path: Vec, -} - -#[derive(Clone)] -pub struct UInstrInst { - pub i: UInstruction, - pub origin: Origin, -} - -impl Debug for UInstrInst { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.i) - } -} diff --git a/src/ir/upper/instr.rs b/src/ir/upper/instr.rs index 6546a07..d27a8cb 100644 --- a/src/ir/upper/instr.rs +++ b/src/ir/upper/instr.rs @@ -1,52 +1,53 @@ use std::{collections::HashMap, fmt::Write}; -use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UFunc, UInstrInst}; +use super::{arch::riscv64::RV64Instruction, DataID, FnID, Origin, UFunc, VarInst, VarInstID}; use crate::{compiler::arch::riscv::Reg, util::Padder}; #[derive(Clone)] pub enum UInstruction { Mv { - dst: VarInst, - src: VarInst, + dst: VarInstID, + src: VarInstID, }, Ref { - dst: VarInst, - src: VarInst, + dst: VarInstID, + src: VarInstID, }, Deref { - dst: VarInst, - src: VarInst, + dst: VarInstID, + src: VarInstID, }, LoadData { - dst: VarInst, + dst: VarInstID, src: DataID, }, LoadSlice { - dst: VarInst, + dst: VarInstID, src: DataID, }, LoadFn { - dst: VarInst, + dst: VarInstID, src: FnID, }, Call { - dst: VarInst, - f: VarInst, - args: Vec, + dst: VarInstID, + f: VarInstID, + args: Vec, }, AsmBlock { instructions: Vec, args: Vec, }, Ret { - src: VarInst, + src: VarInstID, }, Construct { - dst: VarInst, - fields: HashMap, + dst: VarInstID, + struc: VarInstID, + fields: HashMap, }, If { - cond: VarInst, + cond: VarInstID, body: Vec, }, Loop { @@ -56,9 +57,21 @@ pub enum UInstruction { Continue, } +#[derive(Clone)] +pub struct UInstrInst { + pub i: UInstruction, + pub origin: Origin, +} + +impl std::fmt::Debug for UInstrInst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.i) + } +} + #[derive(Debug, Clone)] pub struct AsmBlockArg { - pub var: VarInst, + pub var: VarInstID, pub reg: Reg, pub ty: AsmBlockArgType, } @@ -85,7 +98,7 @@ impl std::fmt::Debug for UInstruction { } => write!(f, "{dest:?} <- {func:?}({args:?})")?, Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}")?, Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?, - Self::Construct { dst: dest, fields } => write!(f, "{dest:?} <- {fields:?}")?, + Self::Construct { dst: dest, struc, fields } => write!(f, "{dest:?} <- {struc:?}{fields:?}")?, Self::If { cond, body } => { write!(f, "if {cond:?}:")?; if !body.is_empty() { diff --git a/src/ir/upper/kind.rs b/src/ir/upper/kind.rs index b4748a6..c23cfa9 100644 --- a/src/ir/upper/kind.rs +++ b/src/ir/upper/kind.rs @@ -7,19 +7,76 @@ 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 TypeID = ID; +pub type GenericID = ID; +pub type StructID = ID; +pub type DataID = ID; +pub type ModID = ID; + #[derive(Clone)] pub struct UFunc { pub name: String, pub origin: Origin, pub args: Vec, - pub gargs: Vec, + pub gargs: Vec, pub ret: TypeID, pub instructions: Vec, } #[derive(Clone)] pub struct StructField { - pub ty: Type, + pub ty: TypeID, } #[derive(Clone)] @@ -27,7 +84,7 @@ pub struct UStruct { pub name: String, pub origin: Origin, pub fields: HashMap, - pub generics: Vec, + pub gargs: Vec, } #[derive(Clone)] @@ -45,15 +102,40 @@ pub struct UVar { pub children: Vec, } -#[derive(Clone, PartialEq, Eq, Hash)] +/// 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 origin: Origin, +} + +#[derive(Clone, Debug)] +pub enum VarStatus { + Var(VarID), + Struct(StructID, Vec), + Unres { + path: ModPath, + name: String, + gargs: Vec, + fields: Vec, + }, + Partial { + v: VarID, + fields: Vec, + }, + Cooked, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MemberID { pub name: String, pub origin: Origin, } -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ModPath { - pub m: ModID, + pub id: ModID, pub path: Vec, } @@ -66,25 +148,26 @@ pub struct VarOffset { #[derive(Clone)] pub struct UData { pub name: String, - pub ty: Type, + pub ty: TypeID, pub content: Vec, } #[derive(Clone)] pub struct UModule { pub name: String, - pub members: HashMap, + pub members: HashMap, pub children: HashMap, pub parent: Option, } -pub struct ModMissing { - pub import_all: Vec, - pub vars: Vec, +#[derive(Clone)] +pub struct Member { + pub id: MemberTy, + // pub visibility: Visibility } #[derive(Clone)] -pub enum Member { +pub enum MemberTy { Fn(FnID), Struct(StructID), Var(VarID), @@ -126,12 +209,13 @@ impl<'a> Iterator for InstrIter<'a> { } } -pub const NAMED_KINDS: usize = 5; - -pub type FnID = ID; -pub type VarID = ID; -pub type TypeID = ID; -pub type GenericID = ID; -pub type StructID = ID; -pub type DataID = ID; -pub type ModID = ID>; +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 34277d0..4f118f2 100644 --- a/src/ir/upper/mod.rs +++ b/src/ir/upper/mod.rs @@ -1,17 +1,14 @@ -mod assoc; -mod inst; mod instr; mod kind; mod program; mod ty; -mod validate; mod resolve; +mod error; use super::*; -use assoc::*; -pub use inst::*; pub use instr::*; pub use kind::*; pub use program::*; pub use ty::*; +pub use error::*; diff --git a/src/ir/upper/program.rs b/src/ir/upper/program.rs index feafad3..9ac302b 100644 --- a/src/ir/upper/program.rs +++ b/src/ir/upper/program.rs @@ -7,14 +7,18 @@ use std::{ pub struct UProgram { pub fns: Vec, pub structs: Vec, - pub modules: Vec>, + pub modules: Vec, pub data: Vec, pub generics: Vec, pub vars: Vec, + pub vars_insts: Vec, pub types: Vec, - pub unres_vars: Vec, - pub unres_tys: Vec, + pub vfmap: HashMap, + pub tc: TypeCache, +} + +pub struct TypeCache { pub unit: TypeID, pub error: TypeID, } @@ -28,196 +32,164 @@ pub struct UModuleBuilder<'a> { impl UProgram { pub fn new() -> Self { let mut types = Vec::new(); - let unit = Self::push_id(&mut types, Type::Unit); - let error = Self::push_id(&mut types, Type::Error); + let tc = TypeCache { + unit: push_id(&mut types, Type::Unit), + error: push_id(&mut types, Type::Error), + }; Self { fns: Vec::new(), vars: Vec::new(), + vars_insts: Vec::new(), structs: Vec::new(), types: Vec::new(), generics: Vec::new(), data: Vec::new(), modules: Vec::new(), - unres_vars: Vec::new(), - unres_tys: Vec::new(), - error, - unit, + vfmap: HashMap::new(), + tc, } } - pub fn inst_type(&mut self, ty: TypeID, gs: Vec) -> TypeID { - let ty = match &self.types[ty] { - Type::Ref(id) => Type::Ref(self.inst_type(*id, gs)), - Type::Generic(id) => return gs[id.0], - Type::Bits(b) => Type::Bits(*b), - Type::Struct(struct_ty) => Type::Struct(struct_ty.clone()), - Type::Fn() => todo!(), - Type::Deref(id) => todo!(), - Type::Slice(id) => todo!(), - Type::Array(id, _) => todo!(), - Type::Unit => todo!(), - Type::Unres(mod_path) => todo!(), - Type::Infer => todo!(), - Type::Error => todo!(), - }; - self.def_ty(ty) - } - pub fn infer(&mut self) -> TypeID { self.def_ty(Type::Infer) } - pub fn set_type(id: TypeID, ty: Type) {} - pub fn def_var(&mut self, v: UVar) -> VarID { - Self::push_id(&mut self.vars, v) + push_id(&mut self.vars, v) } pub fn def_fn(&mut self, f: UFunc) -> FnID { - Self::push_id(&mut self.fns, f) + push_id(&mut self.fns, f) } pub fn def_ty(&mut self, t: Type) -> TypeID { - Self::push_id(&mut self.types, t) + 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_generic(&mut self, g: UGeneric) -> GenericID { - Self::push_id(&mut self.generics, g) + push_id(&mut self.generics, g) } pub fn def_data(&mut self, d: UData) -> DataID { - Self::push_id(&mut self.data, d) + push_id(&mut self.data, d) } pub fn def_struct(&mut self, s: UStruct) -> StructID { - Self::push_id(&mut self.structs, s) + push_id(&mut self.structs, s) } - fn push_id(v: &mut Vec, t: T) -> ID { - let id = ID::new(v.len()); - v.push(t); - id - } - - pub fn type_name(&self, ty: T) -> String { - let mut str = String::new(); + pub fn type_name(&self, ty: impl Typed) -> String { match ty.ty(self) { Type::Struct(ty) => { - str += &self.structs[ty.id].name; - let args = &ty.args; - if let Some(arg) = args.first() { - str = str + "<" + &self.type_name(arg); - } - for arg in args.iter().skip(1) { - str = str + ", " + &self.type_name(arg); - } - if !args.is_empty() { - str += ">"; - } + format!("{}{}", self.structs[ty.id].name, self.gparams_str(&ty.args)) } - Type::Fn { args, ret } => { - str += "fn("; - if let Some(arg) = args.first() { - str += &self.type_name(arg); - } - for arg in args.iter().skip(1) { - str = str + ", " + &self.type_name(arg); - } - str += ") -> "; - str += &self.type_name(ret); + Type::FnRef(ty) => { + format!( + "fn{}({}) -> {}", + &self.gparams_str(&ty.args), + &self.type_list_str(self.fns[ty.id].args.iter().map(|v| self.vars[v].ty)), + &self.type_name(self.fns[ty.id].ret) + ) } - Type::Ref(t) => { - str += &self.type_name(t); - str += "&"; - } - Type::Deref(t) => { - str += &self.type_name(t); - str += "^"; - } - Type::Unres(_) => { - str += "{unresolved}"; - } - Type::Bits(size) => str += &format!("b{}", size), - Type::Array(t, len) => str += &format!("[{}; {len}]", self.type_name(t)), - Type::Unit => str += "()", - Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)), - Type::Error => str += "{error}", - Type::Infer => str += "{inferred}", - Type::Placeholder => str += "{placeholder}", + Type::Ref(t) => format!("{}&", self.type_name(t)), + Type::Deref(t) => format!("{}^", self.type_name(t)), + Type::Unres(_) => "{unresolved}".to_string(), + Type::Bits(size) => format!("b{}", size), + Type::Array(t, len) => format!("[{}; {len}]", self.type_name(t)), + Type::Unit => "()".to_string(), + Type::Slice(t) => format!("&[{}]", self.type_name(t)), + Type::Error => "{error}".to_string(), + Type::Infer => "{inferred}".to_string(), + Type::Generic(id) => self.generics[id].name.clone(), + } + } + + pub fn type_list_str(&self, mut args: impl Iterator) -> String { + let mut str = String::new(); + if let Some(arg) = args.next() { + str += &self.type_name(arg); + } + for arg in args { + str = str + ", " + &self.type_name(arg); + } + str + } + + pub fn gparams_str(&self, args: &[TypeID]) -> String { + let mut str = String::new(); + if !args.is_empty() { + str += "<"; + } + str += &self.type_list_str(args.iter().cloned()); + if !args.is_empty() { + str += ">"; } str } } +pub fn push_id(v: &mut Vec, t: T) -> ID { + let id = ID::new(v.len()); + v.push(t); + id +} + impl<'a> UModuleBuilder<'a> { - pub fn new(program: &'a mut UProgram, id: ModID, error: TypeID) -> Self { + pub fn new(program: &'a mut UProgram, id: ModID) -> Self { Self { p: program, module: id, - error, - name_stack: Vec::new(), temp: 0, } } - pub fn push(&mut self) { - self.name_stack.push(HashMap::new()); - } - pub fn pop(&mut self) { - self.name_stack.pop(); - } - pub fn get_idents(&self, name: &str) -> Option { - for map in self.name_stack.iter().rev() { - let res = map.get(name); - if res.is_some() { - return res.cloned(); - } - } - None - } - - pub fn def_var(&mut self, name: &str, v: UVar, origin: Origin) -> VarID { - let id = self.p.def_var(name, v, origin); - self.name_on_stack(id, name.to_string()); - id - } - - pub fn temp_var(&mut self, origin: Origin, ty: T) -> VarInst { + pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> VarInstID { self.temp_var_inner(origin, ty) } - fn temp_var_inner(&mut self, origin: Origin, ty: T) -> VarInst { - let t = self.temp; - let v = self - .p - .def_var(&format!("temp{}", t), UVar { ty: ty.ty(self) }, origin); + fn temp_var_inner(&mut self, origin: Origin, ty: impl Typable) -> VarInstID { + let var = UVar { + name: format!("temp{}", self.temp), + ty: ty.ty(self), + origin, + parent: None, + children: Vec::new(), + }; + let id = self.p.def_var(var); self.temp += 1; - VarInst { id: v, origin } + self.def_var_inst(VarInst { + status: VarStatus::Var(id), + origin, + }) } } // I'm done with names... -pub trait Typer { +pub trait Typed { fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type; } -impl Typer for &Type { +impl Typed for &Type { fn ty(&self, _: &UProgram) -> &Type { self } } -impl Typer for TypeID { +impl Typed for TypeID { fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type { &p.types[self] } } -impl Typer for &TypeID { +impl Typed for &TypeID { fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type { &p.types[*self] } } -impl Typer for &Box { +impl Typed for &Box { fn ty<'a>(&'a self, _: &'a UProgram) -> &'a Type { &**self } diff --git a/src/ir/upper/resolve.rs b/src/ir/upper/resolve.rs index 101841e..7ae9d6f 100644 --- a/src/ir/upper/resolve.rs +++ b/src/ir/upper/resolve.rs @@ -1,60 +1,67 @@ -use super::{Origin, GenericTy, Type, TypeID, TypeIDed, UInstruction, UProgram, UStruct, UVar}; -use crate::common::{CompilerMsg, CompilerOutput}; -use std::{collections::HashMap, ops::BitOrAssign}; +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 +}; +use crate::{ + common::{CompilerMsg, CompilerOutput}, + ir::{inst_fn_var, inst_struct_ty, KindTy, ID}, +}; +use std::{ + collections::HashSet, + convert::Infallible, + ops::{BitOrAssign, FromResidual}, +}; + +// dawg this file is way too long impl UProgram { pub fn resolve(&mut self, output: &mut CompilerOutput) { let mut unfinished = Vec::new(); - let mut unfinished_new = Vec::new(); - let data = &mut ResData { + let mut data = ResData { + unfinished: Vec::new(), changed: false, types: &mut self.types, - vars: &self.vars, - structs: &self.structs, + s: Sources { + insts: &mut self.vars_insts, + vars: &mut self.vars, + fns: &self.fns, + structs: &self.structs, + generics: &self.generics, + data: &self.data, + modules: &self.modules, + }, errs: Vec::new(), }; - for f in &self.fns { - for i in f.flat_iter() { - if resolve_instr(data, &i.i).unfinished() { - unfinished.push(i); + for (fid, f) in self.fns.iter().enumerate() { + for i in &f.instructions { + resolve_instr( + &mut data, + ResolveCtx { + ret: f.ret, + breakable: false, + i, + }, + ); + } + // 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 + .last() + .is_none_or(|i| !matches!(i.i, UInstruction::Ret { .. })) + { + data.errs.push(ResErr::NoReturn { fid }); } } } - while !unfinished.is_empty() && data.changed { + while !data.unfinished.is_empty() && data.changed { data.changed = false; - for &i in &unfinished { - if resolve_instr(data, &i.i).unfinished() { - unfinished_new.push(i); - } - } - std::mem::swap(&mut unfinished, &mut unfinished_new); - unfinished_new.clear(); - } - for err in &data.errs { - match err { - &ResErr::Type { - dst, - src, - ref errs, - origin, - } => { - let mut msg = type_assign_err(self, dst, src); - for inner in errs { - if inner.dst != dst && inner.src != src { - msg.push_str("\n "); - msg.push_str(&type_assign_err(self, inner.dst, inner.src)); - } - } - output.err(CompilerMsg::new(msg, origin)); - } - &ResErr::NotCallable { origin, ty } => { - output.err(CompilerMsg::new( - format!("Cannot call type {}", self.type_name(ty)), - origin, - )); - } + std::mem::swap(&mut data.unfinished, &mut unfinished); + for ctx in unfinished.drain(..) { + resolve_instr(&mut data, ctx); } } + let errs = data.errs; + report_errs(self, output, errs); for var in &self.vars { match &self.types[var.ty] { Type::Error => output.err(CompilerMsg::new( @@ -75,163 +82,205 @@ impl UProgram { } } -pub fn type_assign_err(p: &mut UProgram, dst: TypeID, src: TypeID) -> String { - format!( - "Cannot assign type {} to {}", - p.type_name(src), - p.type_name(dst) - ) +#[derive(Clone, Copy)] +struct ResolveCtx<'a> { + ret: TypeID, + breakable: bool, + i: &'a UInstrInst, } -pub fn resolve_instr(data: &mut ResData, i: &UInstruction) -> InstrRes { - let mut uf = InstrRes::Finished; - match &i { +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 ftyid = data.vars[f.id].ty; - let fty = &data.types[ftyid]; - let Type::Fn { args: fargs, ret } = fty else { - data.errs.push(ResErr::NotCallable { - origin: f.origin, - ty: ftyid, - }); - return InstrRes::Finished; + 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; }; - uf |= data.match_types(dst, ret, dst.origin); - for (src, dest) in args.iter().zip(fargs) { - uf |= data.match_types(dest, src, src.origin); + let f = &data.s.fns[ftyy.id]; + for (src, dest) in args.iter().zip(&f.args) { + res |= data.match_types(dest, src, src); } + res |= data.match_types(dst, f.ret, dst); } UInstruction::Mv { dst, src } => { - uf |= data.match_types(dst, src, src.origin); + res |= data.match_types(dst, src, src); } UInstruction::Ref { dst, src } => { - let Type::Ref(dest_ty) = data.types[data.vars[dst.id].ty] else { - // TODO: this is probably a compiler error / should never happen - panic!("how could this happen to me (you)"); + let dstid = data.res_id(dst, ctx)?; + let Type::Ref(dest_ty) = data.types[dstid] else { + compiler_error() }; - uf |= data.match_types(dest_ty, src, src.origin); + res |= data.match_types(dest_ty, src, src); + } + UInstruction::Deref { dst, src } => { + let srcid = data.res_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 }); + return None; + }; + res |= data.match_types(dst, src_ty, src); } UInstruction::LoadData { dst, src } => { - // TODO + res |= data.match_types(dst, src, dst); } UInstruction::LoadSlice { dst, src } => { - // TODO + let dstid = data.res_id(src, ctx)?; + let srcid = data.res_id(src, ctx)?; + let Type::Slice(dstty) = data.types[dstid] else { + compiler_error() + }; + let Type::Array(srcty, _) = data.types[srcid] else { + compiler_error() + }; + res |= data.match_types(dstty, srcty, dst); } UInstruction::LoadFn { dst, src } => { - // TODO + // TODO: validate size with enabled targets } UInstruction::AsmBlock { instructions, args } => { // TODO } - UInstruction::Ret { .. } => {} - UInstruction::Construct { dst, fields } => { - let dest_ty = get(vars, dst.id)?; - let Type::Struct(sty) = dest_ty else {}; - let id = sty.id; - let Some(struc) = get(id) else {}; - let mut new = HashMap::new(); - for (name, field) in &struc.fields { - let Some(src) = fields.get(name) else { - continue; - }; - let src_ty = get(vars, src.id)?; - if let Some(ty) = match_types(vars, types, &field.ty, src_ty) { - if let Type::Generic { id } = field.ty { - new.insert(id, ty.clone()); - } - set(vars, src.id, ty); + UInstruction::Ret { src } => { + 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 st = &data.s.structs[sid]; + let mut used = HashSet::new(); + for (name, field) in &st.fields { + if let Some(src) = fields.get(name) { + used.insert(name); + res |= data.match_types(field.ty, src, src); + } else { + let origin = dst.origin(data); + data.errs.push(ResErr::MissingField { + origin, + id: sid, + name: name.clone(), + }); } } - let mut args: Vec<_> = struc - .generics - .iter() - .map(|&id| Type::Generic { id }) - .collect(); - for (i, g) in struc.generics.iter().enumerate() { - if let Some(ty) = new.remove(g) { - args[i] = ty; + for (name, _) in fields { + if !used.contains(name) { + let origin = dst.origin(data); + data.errs.push(ResErr::UnknownField { + origin, + id: sid, + name: name.clone(), + }); } } - set(vars, dst.id, Type::Struct(GenericTy { id, args })); } UInstruction::If { cond, body } => { + if let Some(id) = data.res_id(cond, ctx, KindTy::Var) { + if !matches!(data.types[id], Type::Bits(64)) { + let origin = cond.origin(data); + data.errs.push(ResErr::CondType { origin, ty: id }); + } + } for i in body { - uf |= resolve_instr(data, &i.i); + resolve_instr( + data, + ResolveCtx { + ret: ctx.ret, + breakable: ctx.breakable, + i, + }, + ); + } + } + UInstruction::Loop { body } => { + for i in body { + resolve_instr( + data, + ResolveCtx { + ret: ctx.ret, + breakable: true, + i, + }, + ); + } + } + UInstruction::Break => { + if !ctx.breakable { + data.errs.push(ResErr::BadControlFlow { + op: ControlFlowOp::Break, + origin: ctx.i.origin, + }); + } + } + UInstruction::Continue => { + if !ctx.breakable { + data.errs.push(ResErr::BadControlFlow { + op: ControlFlowOp::Continue, + origin: ctx.i.origin, + }); } } - UInstruction::Loop { body } => {} - UInstruction::Break => {} - UInstruction::Continue => {} } - uf + match res { + InstrRes::Finished => (), + InstrRes::Unfinished => data.unfinished.push(ctx), + } + return None; } -pub fn match_types( - data: &mut TypeResData, - dst: T1, - src: T2, -) -> MatchRes { - let dst = dst.type_id(data.vars); - let src = src.type_id(data.vars); +fn compiler_error() -> ! { + // TODO: this is probably a compiler error / should never happen + panic!("how could this happen to me (you)"); +} + +pub fn match_types(data: &mut TypeResData, dst: impl TypeIDed, src: impl TypeIDed) -> MatchRes { + let dst = data.res_id(dst); + let src = data.res_id(src); if dst == src { return MatchRes::Finished; } let error = || MatchRes::Error(vec![TypeMismatch { dst, src }]); - match (&data.types[dst], &data.types[src]) { + match (data.types[dst].clone(), data.types[src].clone()) { (Type::Error, _) | (_, Type::Error) => MatchRes::Finished, - (Type::Placeholder, _) | (_, Type::Placeholder) => MatchRes::Unfinished, (Type::Infer, Type::Infer) => MatchRes::Unfinished, (Type::Infer, x) => { *data.changed = true; - data.types[dst] = x.clone(); + data.types[dst] = x; MatchRes::Finished } (x, Type::Infer) => { *data.changed = true; - data.types[src] = x.clone(); + data.types[src] = x; MatchRes::Finished } (Type::Struct(dest), Type::Struct(src)) => { if dest.id != src.id { return error(); } - let mut finished = true; - let mut errors = Vec::new(); - let dargs = dest.args.clone(); - let sargs = dest.args.clone(); - for (darg, sarg) in dargs.iter().zip(&sargs) { - match match_types(data, darg, sarg) { - MatchRes::Unfinished => finished = false, - MatchRes::Error(errs) => errors.extend(errs), - MatchRes::Finished => (), - } - } - if finished { - if errors.is_empty() { - MatchRes::Finished - } else { - MatchRes::Error(errors) - } - } else { - MatchRes::Unfinished - } + match_all(data, dest.args.iter().cloned(), src.args.iter().cloned()) } - ( - Type::Fn { - args: dest_args, - ret: dest_ret, - }, - Type::Fn { - args: src_args, - ret: src_ret, - }, - ) => { - // TODO - MatchRes::Finished - } - (&Type::Ref(dest), &Type::Ref(src)) => match_types(data, dest, src), - (&Type::Slice(dest), &Type::Slice(src)) => match_types(data, dest, src), - (&Type::Array(dest, dlen), &Type::Array(src, slen)) => { + // ( + // Type::Fn { + // args: dst_args, + // ret: dst_ret, + // }, + // Type::Fn { + // args: src_args, + // ret: src_ret, + // }, + // ) => { + // let dst = dst_args.into_iter().chain(once(dst_ret)); + // let src = src_args.into_iter().chain(once(src_ret)); + // match_all(data, dst, src) + // } + (Type::Ref(dest), Type::Ref(src)) => match_types(data, dest, src), + (Type::Slice(dest), Type::Slice(src)) => match_types(data, dest, src), + (Type::Array(dest, dlen), Type::Array(src, slen)) => { if dlen == slen { match_types(data, dest, src) } else { @@ -242,49 +291,79 @@ pub fn match_types( } } -struct ResData<'a> { - changed: bool, - types: &'a mut [Type], - vars: &'a [UVar], +pub fn resolve_refs(types: &[Type], id: TypeID) -> TypeID { + if let Type::Deref(rid) = types[id] + && let Type::Ref(nid) = types[rid] + { + nid + } else { + id + } +} + +fn match_all( + data: &mut TypeResData, + dst: impl Iterator, + src: impl Iterator, +) -> MatchRes { + let mut finished = true; + let mut errors = Vec::new(); + for (dst, src) in dst.zip(src) { + match match_types(data, dst, src) { + MatchRes::Unfinished => finished = false, + MatchRes::Error(errs) => errors.extend(errs), + MatchRes::Finished => (), + } + } + if finished { + if errors.is_empty() { + MatchRes::Finished + } else { + MatchRes::Error(errors) + } + } else { + MatchRes::Unfinished + } +} + +struct Sources<'a> { + insts: &'a mut [VarInst], + vars: &'a mut Vec, + fns: &'a [UFunc], structs: &'a [UStruct], + generics: &'a [UGeneric], + data: &'a [UData], + modules: &'a [UModule], +} + +struct ResData<'a> { + unfinished: Vec>, + changed: bool, + types: &'a mut Vec, + s: Sources<'a>, errs: Vec, } struct TypeResData<'a> { changed: &'a mut bool, types: &'a mut [Type], - vars: &'a [UVar], - structs: &'a [UStruct], -} - -enum ResErr { - NotCallable { - origin: Origin, - ty: TypeID, - }, - Type { - dst: TypeID, - src: TypeID, - errs: Vec, - origin: Origin, - }, + sources: &'a Sources<'a>, } impl<'a> ResData<'a> { - pub fn match_types( - &'a mut self, - dst: T1, - src: T2, - origin: Origin, + pub fn match_types( + &mut self, + dst: impl ResID, + src: impl ResID, + origin: impl HasOrigin, ) -> InstrRes { - let dst = dst.type_id(self.vars); - let src = src.type_id(self.vars); + 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 res = match_types( &mut TypeResData { changed: &mut self.changed, types: self.types, - vars: self.vars, - structs: self.structs, + sources: &self.s, }, dst, src, @@ -295,7 +374,7 @@ impl<'a> ResData<'a> { MatchRes::Error(es) => { self.errs.push(ResErr::Type { errs: es, - origin, + origin: origin.origin(self), dst, src, }); @@ -303,11 +382,28 @@ 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 res_id<'b: 'a, K>( + &mut self, + x: impl ResID, + ctx: ResolveCtx<'b>, + ) -> Option> { + match self.try_res_id(x) { + Ok(id) => return Some(id), + Err(InstrRes::Unfinished) => self.unfinished.push(ctx), + Err(InstrRes::Finished) => (), + } + None + } } -pub struct TypeMismatch { - dst: TypeID, - src: TypeID, +impl TypeResData<'_> { + pub fn res_id(&self, x: impl TypeIDed) -> TypeID { + resolve_refs(self.types, x.type_id(self.sources)) + } } pub enum MatchRes { @@ -316,6 +412,7 @@ pub enum MatchRes { Error(Vec), } +#[derive(Debug, Clone, Copy)] pub enum InstrRes { Finished, Unfinished, @@ -330,11 +427,218 @@ impl BitOrAssign for InstrRes { } } -impl InstrRes { - pub fn unfinished(&self) -> bool { - match self { - Self::Finished => false, - Self::Unfinished => true, +impl FromResidual> for InstrRes { + fn from_residual(_: Option) -> Self { + Self::Unfinished + } +} + +trait ResID { + fn try_id( + &self, + s: &mut Sources, + types: &mut Vec, + errs: &mut Vec, + ) -> Result, InstrRes>; +} + +impl ResID for T { + fn try_id( + &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 { + path, + name, + gargs, + fields, + } => { + let mut mid = path.id; + let mut depth = 0; + for mem in &path.path { + let Some(&child) = s.modules[mid].children.get(&mem.name) else { + break; + }; + depth += 1; + mid = child; + } + path.path.drain(0..depth); + path.id = mid; + if path.path.len() != 0 { + return Err(InstrRes::Unfinished); + } + let Some(mem) = s.modules[mid].members.get(name) else { + return Err(InstrRes::Unfinished); + }; + let vid = 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, + }); + return Err(InstrRes::Finished); + } + inst_fn_var( + id, + s.fns, + gargs, + inst.origin, + s.vars, + types, + s.generics, + errs, + ) + } + 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, + 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, + )); + } + }; + 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!() + } +} + +impl ResID for &VarInstID { + fn try_id( + &self, + s: &mut Sources, + types: &mut Vec, + errs: &mut Vec, + kind: KindTy, + ) -> Result, InstrRes> { + (*self).try_id(s, types, errs, kind) + } +} + +pub trait TypeIDed { + fn type_id(&self, s: &Sources) -> TypeID; +} + +impl TypeIDed for TypeID { + fn type_id(&self, _: &Sources) -> TypeID { + *self + } +} + +impl TypeIDed for VarID { + fn type_id(&self, s: &Sources) -> TypeID { + s.vars[self].ty + } +} + +impl TypeIDed for DataID { + fn type_id(&self, s: &Sources) -> TypeID { + s.data[self].ty + } +} + +impl TypeIDed for &T { + fn type_id(&self, s: &Sources) -> TypeID { + (*self).type_id(s) + } +} + +impl FromResidual> for InstrRes { + fn from_residual(residual: std::result::Result) -> Self { + match residual { + Ok(_) => unreachable!(), + Err(r) => r, + } + } +} + +trait HasOrigin { + fn origin(&self, data: &ResData) -> Origin; +} + +impl HasOrigin for &VarInstID { + fn origin(&self, data: &ResData) -> Origin { + data.s.insts[*self].origin + } +} diff --git a/src/ir/upper/ty.rs b/src/ir/upper/ty.rs index 0b7c288..3032681 100644 --- a/src/ir/upper/ty.rs +++ b/src/ir/upper/ty.rs @@ -1,5 +1,9 @@ -use super::{GenericID, Len, ModPath, TypeID, UFunc, UProgram, UStruct, UVar, VarID, VarInst}; -use crate::ir::ID; +use std::collections::HashMap; + +use super::{ + push_id, FnID, GenericID, Len, ModPath, Origin, ResErr, StructID, TypeCache, TypeID, UFunc, + UGeneric, UProgram, UStruct, UVar, VarID, +}; #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub struct FieldRef { @@ -8,16 +12,24 @@ pub struct FieldRef { } #[derive(Clone, Eq, PartialEq, Hash)] -pub struct GenericTy { - pub id: ID, +pub struct StructTy { + pub id: StructID, + pub args: Vec, +} + +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct FnTy { + pub id: FnID, pub args: Vec, } #[derive(Clone)] pub enum Type { Bits(u32), - Struct(GenericTy), - Fn(GenericTy), + Struct(StructTy), + FnRef(FnTy), + // this can be added for constraints later (F: fn(...) -> ...) + // Fn { args: Vec, ret: TypeID }, Ref(TypeID), Deref(TypeID), Slice(TypeID), @@ -66,36 +78,157 @@ impl Type { } } -pub trait TypeIDed { - fn type_id(&self, vars: &[UVar]) -> TypeID; +pub fn inst_fn_var( + id: FnID, + 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(); + push_id( + vars, + UVar { + name, + origin, + ty, + parent: None, + children: Vec::new(), + }, + ) } -impl TypeIDed for TypeID { - fn type_id(&self, _: &[UVar]) -> TypeID { - *self - } +pub fn inst_fn_ty( + id: FnID, + 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), + }); + push_id(types, ty) } -impl TypeIDed for &TypeID { - fn type_id(&self, _: &[UVar]) -> TypeID { - **self - } +pub fn inst_struct_var( + id: StructID, + 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(); + push_id( + vars, + UVar { + name, + origin, + ty, + parent: None, + children: Vec::new(), + }, + ) } -impl TypeIDed for VarID { - fn type_id(&self, vars: &[UVar]) -> TypeID { - vars[self].ty - } +pub fn inst_struct_ty( + id: StructID, + 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), + }); + push_id(types, ty) } -impl TypeIDed for VarInst { - fn type_id(&self, vars: &[UVar]) -> TypeID { - self.id.type_id(vars) +pub fn inst_generics( + source: &[GenericID], + args: &[TypeID], + types: &mut Vec, + // will be needed when constraints are added + _generics: &[UGeneric], + errs: &mut Vec, +) -> Vec { + if source.len() != args.len() { + // don't want unequal lengths to be inferred further + return source.iter().map(|_| push_id(types, Type::Error)).collect(); } + let mut gargs = Vec::new(); + let mut gmap = HashMap::new(); + for &gid in source { + let id = push_id(types, Type::Error); + gmap.insert(gid, id); + gargs.push(id); + } + for (gid, &ty) in source.iter().zip(args) { + inst_type_ins( + |types, ty| { + let id = gmap[gid]; + types[id] = ty; + id + }, + ty, + types, + &gmap, + ); + } + gargs } -impl TypeIDed for &VarInst { - fn type_id(&self, vars: &[UVar]) -> TypeID { - self.id.type_id(vars) - } +pub fn inst_type(id: TypeID, types: &mut Vec, gmap: &HashMap) -> TypeID { + inst_type_ins(push_id, id, types, gmap) +} + +pub fn inst_type_ins( + insert: impl Fn(&mut Vec, Type) -> TypeID, + id: TypeID, + types: &mut Vec, + gmap: &HashMap, +) -> TypeID { + let ty = match types[id].clone() { + Type::Bits(_) => return id, + Type::Struct(struct_ty) => Type::Struct(StructTy { + id: struct_ty.id, + args: struct_ty + .args + .iter() + .map(|id| inst_type(*id, types, gmap)) + .collect(), + }), + Type::FnRef(fn_ty) => Type::FnRef(FnTy { + id: fn_ty.id, + args: fn_ty + .args + .iter() + .map(|id| inst_type(*id, types, gmap)) + .collect(), + }), + Type::Ref(id) => Type::Ref(inst_type(id, types, gmap)), + Type::Deref(id) => Type::Deref(inst_type(id, types, gmap)), + Type::Slice(id) => Type::Slice(inst_type(id, types, gmap)), + Type::Array(id, len) => Type::Array(inst_type(id, types, gmap), len), + Type::Unit => Type::Unit, + Type::Unres(mod_path) => Type::Unres(mod_path.clone()), + Type::Generic(gid) => return gmap.get(&gid).cloned().unwrap_or_else(|| id), + Type::Infer => Type::Infer, + Type::Error => Type::Error, + }; + insert(types, ty) } diff --git a/src/ir/upper/validate.rs b/src/ir/upper/validate.rs deleted file mode 100644 index 8a49c42..0000000 --- a/src/ir/upper/validate.rs +++ /dev/null @@ -1,169 +0,0 @@ -use super::{Type, UInstrInst, UInstruction, UProgram}; -use crate::common::{CompilerMsg, CompilerOutput, FileSpan}; - -impl UProgram { - pub fn validate(&self, output: &mut CompilerOutput) { - for (id, f) in self.iter_fns() { - self.validate_fn( - &f.instructions, - self.origins.get(id), - &f.ret, - output, - true, - false, - ); - } - } - - pub fn validate_fn( - &self, - instructions: &[UInstrInst], - origin: FileSpan, - ret: &Type, - output: &mut CompilerOutput, - needs_ret: bool, - breakable: bool, - ) { - let mut no_ret = true; - for i in instructions { - match &i.i { - UInstruction::Mv { dst: dest, src } => { - let dest = self.expect(dest.id); - let src = self.expect(src.id); - output.check_assign(self, &src.ty, &dest.ty, i.origin); - } - UInstruction::Ref { dst: dest, src } => { - let dest = self.expect(dest.id); - let src = self.expect(src.id); - output.check_assign(self, &src.ty.clone().rf(), &dest.ty, i.origin); - } - UInstruction::LoadData { dst: dest, src } => { - let dest = self.expect(dest.id); - let src = self.expect(*src); - output.check_assign(self, &src.ty, &dest.ty, i.origin); - } - UInstruction::LoadSlice { dst: dest, src } => { - let dest = self.expect(dest.id); - let src = self.expect(*src); - let Type::Array(srcty, ..) = &src.ty else { - todo!() - }; - output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.origin); - } - UInstruction::LoadFn { dst: dest, src } => todo!(), - UInstruction::Call { dst: dest, f, args } => { - let destty = &self.expect(dest.id).ty; - let f = self.expect(f.id); - let Type::Fn { args: argtys, ret } = &f.ty else { - output.err(CompilerMsg { - msg: format!("Type {} is not callable", self.type_name(&f.ty)), - spans: vec![dest.origin], - }); - continue; - }; - output.check_assign(self, ret, destty, dest.origin); - if args.len() != argtys.len() { - output.err(CompilerMsg { - msg: "Wrong number of arguments to function".to_string(), - spans: vec![dest.origin], - }); - } - for (dst_ty, src) in argtys.iter().zip(args) { - let src_var = self.expect(src.id); - output.check_assign(self, &src_var.ty, dst_ty, src.origin); - } - } - UInstruction::AsmBlock { instructions, args } => { - for arg in args { - // TODO: validate size with enabled targets - // maybe should happen in lowering? but I think it could happen here - // if let Some(size) = self.size_of_var(arg.var.id) - // && size != 64 - // { - // output.err(CompilerMsg { - // msg: format!("asm block args must be size 64, is size {}", size), - // spans: vec![arg.var.span], - // }); - // } - } - } - UInstruction::Ret { src } => { - let srcty = &self.expect(src.id).ty; - output.check_assign(self, srcty, ret, src.origin); - no_ret = false; - } - UInstruction::Construct { dst: dest, fields } => { - let dest_def = self.expect(dest.id); - let sty = match &dest_def.ty { - Type::Struct(sty) => sty, - _ => { - output.err(CompilerMsg { - msg: format!( - "Type {} cannot be constructed", - self.type_name(&dest_def.ty) - ), - spans: vec![dest.origin], - }); - continue; - } - }; - let def = self.expect(sty.id); - for (name, field) in &def.fields { - if let Some(var) = fields.get(name) { - let mut fty = &field.ty; - if let Type::Generic { id } = fty { - for (g, a) in def.generics.iter().zip(&sty.args) { - if *g == *id { - fty = a; - } - } - } - let ety = &self.expect(var.id).ty; - output.check_assign(self, ety, fty, var.origin); - } else { - output.err(CompilerMsg { - msg: format!("field '{}' missing from struct", name), - spans: vec![dest.origin], - }); - } - } - } - UInstruction::If { cond, body } => { - let cond = self.expect(cond.id); - output.check_assign(self, &cond.ty, &Type::Bits(64), i.origin); - self.validate_fn(body, origin, ret, output, false, breakable); - } - UInstruction::Loop { body } => { - self.validate_fn(body, origin, ret, output, false, true); - } - UInstruction::Break => { - if !breakable { - output.err(CompilerMsg { - msg: "Can't break here (outside of loop)".to_string(), - spans: vec![i.origin], - }); - } - // TODO - } - UInstruction::Continue => { - if !breakable { - output.err(CompilerMsg { - msg: "Can't continue here (outside of loop)".to_string(), - spans: vec![i.origin], - }); - } - // TODO - } - } - } - if needs_ret && no_ret && *ret != Type::Unit { - output.err(CompilerMsg { - msg: format!( - "Function implicitly returns () at the end, must return {}", - self.type_name(ret) - ), - spans: vec![origin], - }); - } - } -} diff --git a/src/parser/v3/lower/asm.rs b/src/parser/v3/lower/asm.rs index eb6f081..ffa654b 100644 --- a/src/parser/v3/lower/asm.rs +++ b/src/parser/v3/lower/asm.rs @@ -1,14 +1,15 @@ use crate::{ compiler::arch::riscv::Reg, ir::{ - arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, Type, UInstruction, VarInst + arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, Type, UInstruction, VarInst, + VarInstID, }, parser::PAsmBlockArg, }; use super::{FnLowerCtx, FnLowerable, PAsmBlock, PInstruction, PUAsmBlockArg}; -type PLAsmBlockArg = PAsmBlockArg; +type PLAsmBlockArg = PAsmBlockArg; impl FnLowerable for PInstruction { type Output = RV64Instruction; @@ -19,7 +20,7 @@ impl FnLowerable for PInstruction { } impl FnLowerable for PAsmBlock { - type Output = VarInst; + type Output = VarInstID; 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 5c8d490..a111c27 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}, + ir::{Type, UInstruction, UVar, VarInst, VarInstID}, parser::{PConstStatement, PStatementLike}, }; use super::{FnLowerCtx, FnLowerable, Import, PBlock, PStatement}; impl FnLowerable for PBlock { - type Output = VarInst; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = VarInstID; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let mut last = None; let mut statements = Vec::new(); let mut fn_nodes = Vec::new(); diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs index 5e6f928..6f34bdc 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}, + ir::{Type, UData, UInstruction, VarInst, VarInstID}, parser::InfixOp, }; impl FnLowerable for PExpr { - type Output = VarInst; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = VarInstID; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let mut e = self; let mut path = Vec::new(); while let PExpr::Member(node, ident) = e { @@ -20,40 +20,40 @@ impl FnLowerable for PExpr { Some(match e { PExpr::Lit(l) => match l { super::PLiteral::String(s) => { - let dest = ctx.b.temp_var(ctx.origin, Type::Bits(8).slice(ctx.b.p)); + let dst = ctx.temp_var(ctx.origin, Type::Bits(8).slice(ctx.p)); let data = s.as_bytes().to_vec(); - let src = ctx.b.def_data(UData { + let src = ctx.def_data(UData { name: format!("string \"{}\"", s.replace("\n", "\\n")), - ty: Type::Bits(8).arr(ctx.b.p, data.len() as u32), + ty: ctx.def_ty(Type::Bits(8).arr(ctx.b.p, data.len() as u32)), content: data, }); - ctx.push(UInstruction::LoadSlice { dst: dest, src }); - dest + ctx.push(UInstruction::LoadSlice { dst, src }); + dst } super::PLiteral::Char(c) => { - let ty = Type::Bits(8); - let dest = ctx.b.temp_var(ctx.origin, ty.clone()); - let src = ctx.b.def_data(UData { + let ty = ctx.def_ty(Type::Bits(8)); + let dst = ctx.temp_var(ctx.origin, ty.clone()); + let src = ctx.def_data(UData { name: format!("char '{c}'"), ty, content: c.to_string().as_bytes().to_vec(), }); - ctx.push(UInstruction::LoadData { dst: dest, src }); - dest + ctx.push(UInstruction::LoadData { dst, src }); + dst } super::PLiteral::Number(n) => { // TODO: temp - let ty = Type::Bits(64); - let dest = ctx.b.temp_var(ctx.origin, ty.clone()); - let src = ctx.b.def_data(UData { + let ty = ctx.def_ty(Type::Bits(64)); + let dst = ctx.temp_var(ctx.origin, ty.clone()); + let src = ctx.def_data(UData { name: format!("num {n:?}"), ty, content: n.whole.parse::().unwrap().to_le_bytes().to_vec(), }); - ctx.push(UInstruction::LoadData { dst: dest, src }); - dest + ctx.push(UInstruction::LoadData { dst, src }); + dst } - super::PLiteral::Unit => ctx.b.temp_var(ctx.origin, Type::Unit), + super::PLiteral::Unit => ctx.temp_var(ctx.origin, Type::Unit), }, PExpr::Ident(i) => ctx.var(i), PExpr::BinaryOp(op, e1, e2) => match op { @@ -79,14 +79,17 @@ impl FnLowerable for PExpr { PostfixOp::Ref => { let ty = Type::Ref(ctx.b.infer()); let dest = ctx.temp(ty); - ctx.push(UInstruction::Ref { dst: dest, src: res }); + ctx.push(UInstruction::Ref { + dst: dest, + src: res, + }); dest } PostfixOp::Deref => { let ty = Type::Deref(ctx.b.infer()); - let dest = ctx.temp(ty); - ctx.push(UInstruction::Deref { dst: dest, src: res }); - dest + let dst = ctx.temp(ty); + ctx.push(UInstruction::Deref { dst, src: res }); + dst } PostfixOp::Not => todo!(), } @@ -102,7 +105,7 @@ impl FnLowerable for PExpr { } let dest = ctx.temp(Type::Infer); ctx.push(UInstruction::Call { - dst: VarInst { status: , origin: () }, + dst: dest, f: fe, args: nargs, }); @@ -110,26 +113,28 @@ impl FnLowerable for PExpr { } PExpr::Group(e) => e.lower(ctx)?, PExpr::Construct(e, map) => { - let dest = ctx.temp(Type::Placeholder); - ctx.push(UInstruction::Construct { dst: dest, fields: () }); - dest + let dst = ctx.temp(Type::Infer); + let struc = e.lower(ctx)?; + let fields = map.lower(ctx)?; + ctx.push(UInstruction::Construct { dst, struc, fields }); + dst } PExpr::If(cond, body) => { let cond = cond.lower(ctx)?; - ctx.b.push(); + ctx.var_stack.push(); let mut body_ctx = ctx.branch(); body.lower(&mut body_ctx); let body = body_ctx.instructions; - ctx.b.pop(); + ctx.var_stack.pop(); ctx.push(UInstruction::If { cond, body }); return None; } PExpr::Loop(body) => { - ctx.b.push(); + ctx.var_stack.push(); let mut body_ctx = ctx.branch(); body.lower(&mut body_ctx); let body = body_ctx.instructions; - ctx.b.pop(); + ctx.var_stack.pop(); ctx.push(UInstruction::Loop { body }); return None; } diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs index d4e1bc5..9c5bb94 100644 --- a/src/parser/v3/lower/func.rs +++ b/src/parser/v3/lower/func.rs @@ -1,12 +1,16 @@ -use std::collections::HashMap; +use std::{ + collections::HashMap, + ops::{Deref, DerefMut}, +}; use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Imports, Node, PFunction}; use crate::{ ir::{ - FnID, Origin, Typable, Type, UFunc, UInstrInst, UInstruction, UModuleBuilder, UVar, VarID, - VarInst, VarStatus, + FnID, GenericID, ModPath, Origin, Typable, Type, UFunc, UInstrInst, UInstruction, + UModuleBuilder, VarID, VarInst, VarInstID, VarStatus, }, - parser, util::NameStack, + parser, + util::NameStack, }; impl Node { @@ -32,13 +36,9 @@ impl PFunction { ) -> Option { let header = self.header.as_ref()?; let name = header.name.as_ref()?.0.clone(); - let (generic_args, args, ret) = if let Some(header) = self.header.as_ref() { + let (generics, args, ret) = if let Some(header) = self.header.as_ref() { ( - header - .gargs - .iter() - .map(|a| Some(a.lower(b, output))) - .collect(), + header.gargs.iter().flat_map(|a| a.lower(b)).collect(), header .args .iter() @@ -50,27 +50,32 @@ impl PFunction { }, ) } else { - (Vec::new(), Vec::new(), b.error) + (Vec::new(), Vec::new(), b.tc.error) }; + let gargs = generics.iter().map(|g| g.1).collect(); + let generics = generics.into_iter().collect(); let instructions = { - let mut var_stack = Vec::new(); + let mut var_stack = NameStack::new(); let mut ctx = FnLowerCtx { instructions: Vec::new(), var_stack: &mut var_stack, b, output, origin: self.body.origin, + generics: &generics, imports, }; - if let Some(src) = self.body.lower(&mut ctx) { - ctx.instructions.push(UInstrInst { - origin: src.origin, + let res = self.body.lower(&mut ctx); + let mut instructions = ctx.instructions; + if let Some(src) = res { + let origin = b.vars_insts[src].origin; + instructions.push(UInstrInst { + origin, i: UInstruction::Ret { src }, }); } - ctx.instructions + instructions }; - let gargs = args.iter().map(|a| b.vars[a].ty).collect(); let f = UFunc { origin, gargs, @@ -90,18 +95,32 @@ pub struct FnLowerCtx<'a, 'b> { pub origin: FileSpan, pub imports: &'a mut Imports, pub var_stack: &'a mut NameStack, + pub generics: &'a HashMap, } impl<'a, 'b> FnLowerCtx<'a, 'b> { - pub fn var(&mut self, node: &Node) -> VarInst { - if let Some(n) = node.as_ref() { - if let Some(&var) = self.var_stack.search(&n.0) { - return VarInst { - status: VarStatus::Res(var), - origin: node.origin, + pub fn var(&mut self, node: &Node) -> VarInstID { + let inst = VarInst { + status: if let Some(n) = node.as_ref() { + if let Some(&var) = self.var_stack.search(&n.0) { + VarStatus::Var(var) + } else { + VarStatus::Unres { + path: ModPath { + id: self.b.module, + path: Vec::new(), + }, + name: n.0.clone(), + gargs: Vec::new(), + fields: Vec::new(), + } } - } - } + } else { + VarStatus::Cooked + }, + origin: node.origin, + }; + self.def_var_inst(inst) } pub fn err(&mut self, msg: String) { self.output.err(CompilerMsg::new(msg, self.origin)) @@ -109,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: Type) -> VarInst { + pub fn temp(&mut self, ty: T) -> VarInstID { self.b.temp_var(self.origin, ty) } pub fn push(&mut self, i: UInstruction) { @@ -118,10 +137,11 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> { pub fn push_at(&mut self, i: UInstruction, span: FileSpan) { self.instructions.push(UInstrInst { i, origin: span }); } - pub fn branch(&'a mut self) -> FnLowerCtx<'a, 'b> { + pub fn branch<'c>(&'c mut self) -> FnLowerCtx<'c, 'b> { FnLowerCtx { b: self.b, instructions: Vec::new(), + generics: self.generics, var_stack: self.var_stack, output: self.output, origin: self.origin, @@ -129,3 +149,17 @@ impl<'a, 'b> FnLowerCtx<'a, 'b> { } } } + +impl<'b> Deref for FnLowerCtx<'_, 'b> { + type Target = UModuleBuilder<'b>; + + fn deref(&self) -> &Self::Target { + self.b + } +} + +impl DerefMut for FnLowerCtx<'_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.b + } +} diff --git a/src/parser/v3/lower/map.rs b/src/parser/v3/lower/map.rs new file mode 100644 index 0000000..6f00185 --- /dev/null +++ b/src/parser/v3/lower/map.rs @@ -0,0 +1,22 @@ +use std::collections::HashMap; + +use crate::{ir::VarInstID, parser::PMap}; + +use super::{FnLowerCtx, FnLowerable}; + +impl FnLowerable for PMap { + type Output = HashMap; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + Some( + self.0 + .iter() + .flat_map(|n| { + let def = n.as_ref()?; + let name = def.name.as_ref()?.to_string(); + let expr = def.val.as_ref()?.lower(ctx)?; + Some((name, expr)) + }) + .collect(), + ) + } +} diff --git a/src/parser/v3/lower/mod.rs b/src/parser/v3/lower/mod.rs index b7b4b23..98b65b8 100644 --- a/src/parser/v3/lower/mod.rs +++ b/src/parser/v3/lower/mod.rs @@ -6,6 +6,7 @@ mod expr; mod func; mod struc; mod ty; +mod map; use super::*; use crate::ir::{Type, UFunc, UModuleBuilder}; diff --git a/src/parser/v3/lower/struc.rs b/src/parser/v3/lower/struc.rs index 9b5d949..8870613 100644 --- a/src/parser/v3/lower/struc.rs +++ b/src/parser/v3/lower/struc.rs @@ -1,52 +1,18 @@ use crate::{ common::{CompilerOutput, FileSpan}, - ir::{StructField, StructID, UInstruction, UModuleBuilder, UProgram, UStruct, VarInst}, - parser::{Node, PMap, PStruct, PStructFields}, + ir::{StructField, StructID, UModuleBuilder, UProgram, UStruct}, + parser::{Node, PStruct, PStructFields}, }; -use super::{FnLowerCtx, FnLowerable}; - -impl FnLowerable for PMap { - type Output = VarInst; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - let ty = self.name.lower(ctx.b, ctx.output); - let fields = match &self.fields { - PConstructFields::Named(nodes) => nodes - .iter() - .flat_map(|n| { - let def = n.as_ref()?; - let name = def.name.as_ref()?.to_string(); - let expr = def.val.as_ref()?.lower(ctx)?; - Some((name, expr)) - }) - .collect(), - PConstructFields::Tuple(nodes) => nodes - .iter() - .enumerate() - .flat_map(|(i, n)| { - let expr = n.as_ref()?.lower(ctx)?; - let name = format!("{i}"); - Some((name, expr)) - }) - .collect(), - PConstructFields::None => Default::default(), - }; - let id = ctx.temp(ty); - ctx.push(UInstruction::Construct { dst: id, fields }); - Some(id) - } -} - impl PStruct { pub fn lower( &self, id: StructID, - p: &mut UModuleBuilder, + b: &mut UModuleBuilder, output: &mut CompilerOutput, span: FileSpan, ) -> Option<()> { - p.push(); - let generics = self.generics.iter().flat_map(|a| a.lower(p)).collect(); + let generics = self.generics.iter().flat_map(|a| a.lower(b)).collect(); let fields = match &self.fields { PStructFields::Named(nodes) => nodes .iter() @@ -54,7 +20,7 @@ impl PStruct { let def = n.as_ref()?; let name = def.name.as_ref()?.to_string(); let tynode = def.ty.as_ref()?; - let ty = tynode.lower(p, output); + let ty = tynode.lower(b, output); Some((name, ty)) }) .collect(), @@ -62,7 +28,7 @@ impl PStruct { .iter() .enumerate() .flat_map(|(i, n)| { - let ty = n.as_ref()?.lower(p, output, span); + let ty = n.as_ref()?.lower(b, output, span); Some((format!("{i}"), ty)) }) .collect(), @@ -72,13 +38,12 @@ impl PStruct { .map(|(name, ty)| (name, StructField { ty })) .collect(); let name = self.name.as_ref()?.to_string(); - p.def_data(UStruct { + b.def_data(UStruct { name, - generics, + gargs: generics, fields, origin: span, }); - p.pop(); Some(()) } } diff --git a/src/parser/v3/lower/ty.rs b/src/parser/v3/lower/ty.rs index 4c330e8..88dd54a 100644 --- a/src/parser/v3/lower/ty.rs +++ b/src/parser/v3/lower/ty.rs @@ -54,7 +54,7 @@ impl PType { name: id.0.clone(), origin, }); - let ty = Type::Unres(ModPath { m: p.module, path }); + let ty = Type::Unres(ModPath { id: p.module, path }); return p.def_ty(ty); } let ty = match ty { @@ -65,7 +65,7 @@ impl PType { origin, }); path.reverse(); - Type::Unres(ModPath { m: p.module, path }) + Type::Unres(ModPath { id: p.module, path }) } PType::Ref(node) => node.lower(p, output).rf(), PType::Generic(node, nodes) => todo!(), @@ -75,12 +75,15 @@ impl PType { } impl Node { - pub fn lower(&self, p: &mut UProgram) -> Option { + pub fn lower(&self, p: &mut UProgram) -> Option<(String, GenericID)> { let s = self.as_ref()?; let name = s.name.as_ref()?.to_string(); - Some(p.def_generic(UGeneric { - name, - origin: self.origin, - })) + Some(( + name.clone(), + p.def_generic(UGeneric { + name, + origin: self.origin, + }), + )) } } diff --git a/src/parser/v3/nodes/func.rs b/src/parser/v3/nodes/func.rs index 3870edd..ba1a8ce 100644 --- a/src/parser/v3/nodes/func.rs +++ b/src/parser/v3/nodes/func.rs @@ -1,13 +1,13 @@ use super::{ - util::parse_list, Node, PBlock, PIdent, PType, PVarDef, Parsable, ParseResult, ParserCtx, - Symbol, + util::parse_list, Node, PBlock, PGenericDef, PIdent, PType, PVarDef, Parsable, ParseResult, + ParserCtx, Symbol, }; use std::fmt::Debug; pub struct PFunctionHeader { pub name: Node, pub args: Vec>, - pub gargs: Vec>, + pub gargs: Vec>, pub ret: Option>, } diff --git a/src/parser/v3/nodes/struc.rs b/src/parser/v3/nodes/struc.rs index 08ecf2f..d3ee8ac 100644 --- a/src/parser/v3/nodes/struc.rs +++ b/src/parser/v3/nodes/struc.rs @@ -14,7 +14,7 @@ pub struct PStruct { pub fields: PStructFields, } -pub struct PMap(Vec>); +pub struct PMap(pub Vec>); #[derive(Debug)] pub enum PStructFields { diff --git a/src/util/name_stack.rs b/src/util/name_stack.rs index da44d8e..00e1079 100644 --- a/src/util/name_stack.rs +++ b/src/util/name_stack.rs @@ -4,7 +4,7 @@ pub struct NameStack(Vec>); impl NameStack { pub fn new() -> Self { - Self(Vec::new()) + Self(vec![HashMap::new()]) } pub fn search(&self, name: &str) -> Option<&T> { for level in self.0.iter().rev() { @@ -14,4 +14,10 @@ impl NameStack { } None } + pub fn push(&mut self) { + self.0.push(HashMap::new()); + } + pub fn pop(&mut self) { + self.0.pop(); + } }