From 31c16a263b9dd67ab58d8152f8e90666fbdf2b07 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Fri, 11 Apr 2025 01:57:10 -0400 Subject: [PATCH] huge refactor, can now define structs out of order --- README.md | 1 + data/test.lang | 4 +- src/compiler/arch/riscv/compile.rs | 4 +- src/compiler/mod.rs | 4 +- src/ir/id.rs | 57 ++++--- src/ir/lower/func.rs | 6 +- src/ir/lower/program.rs | 129 +++++++-------- src/ir/upper/def.rs | 82 ---------- src/ir/upper/error.rs | 7 +- src/ir/upper/inst.rs | 8 +- src/ir/upper/{func.rs => instr.rs} | 27 +--- src/ir/upper/kind.rs | 160 +++++++++++++++++++ src/ir/upper/mod.rs | 8 +- src/ir/upper/program.rs | 244 ++++++++++++++--------------- src/ir/upper/ty.rs | 124 ++++++++++++++- src/ir/upper/validate.rs | 83 +++++----- src/main.rs | 69 ++++---- src/parser/v3/lower/asm.rs | 4 +- src/parser/v3/lower/block.rs | 11 +- src/parser/v3/lower/def.rs | 34 ++-- src/parser/v3/lower/expr.rs | 83 +++++----- src/parser/v3/lower/func.rs | 124 +++++++-------- src/parser/v3/lower/module.rs | 24 +-- src/parser/v3/lower/struc.rs | 34 ++-- 24 files changed, 765 insertions(+), 566 deletions(-) delete mode 100644 src/ir/upper/def.rs rename src/ir/upper/{func.rs => instr.rs} (85%) create mode 100644 src/ir/upper/kind.rs diff --git a/README.md b/README.md index 7fb22bb..9f31e6a 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,4 @@ todo: - iterators? - borrow checking - basic optimization: use registers, remove temp var moves +- Cow str diff --git a/data/test.lang b/data/test.lang index 4a56d5d..fd635ae 100644 --- a/data/test.lang +++ b/data/test.lang @@ -31,7 +31,7 @@ fn start() { }; println("after"); print(tester()); - let test = Test { + let test: Test = Test { a: 10, b: 4, c: 0, @@ -59,7 +59,7 @@ fn structer(test: Test) { print_dec(test.c); println(""); - let test2 = Test2 { + let test2: Test2 = Test2 { a: 3, b: test, c: test, diff --git a/src/compiler/arch/riscv/compile.rs b/src/compiler/arch/riscv/compile.rs index d14f19c..393207c 100644 --- a/src/compiler/arch/riscv/compile.rs +++ b/src/compiler/arch/riscv/compile.rs @@ -4,7 +4,7 @@ use crate::{ compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedFunction, UnlinkedProgram}, ir::{ arch::riscv64::{RV64Instruction as AI, RegRef}, - IRLInstruction as IRI, IRLProgram, Len, Size, + LInstruction as IRI, LProgram, Len, Size, }, }; @@ -47,7 +47,7 @@ fn mov_mem( } } -pub fn compile(program: &IRLProgram) -> UnlinkedProgram
  • { +pub fn compile(program: &LProgram) -> UnlinkedProgram
  • { let mut fns = Vec::new(); let mut data = Vec::new(); let mut dbg = DebugInfo::new(program.labels().to_vec()); diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 1db9c44..db94d01 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -7,8 +7,8 @@ mod target; use arch::riscv; pub use program::*; -use crate::ir::IRLProgram; +use crate::ir::LProgram; -pub fn compile(program: &IRLProgram) -> UnlinkedProgram { +pub fn compile(program: &LProgram) -> UnlinkedProgram { arch::riscv::compile(program) } diff --git a/src/ir/id.rs b/src/ir/id.rs index 0b06019..98fd4da 100644 --- a/src/ir/id.rs +++ b/src/ir/id.rs @@ -1,46 +1,51 @@ -use std::fmt::Debug; - -#[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub struct StructID(pub usize); -#[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub struct VarID(pub usize); -#[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub struct FnID(pub usize); -#[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub struct DataID(pub usize); -#[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub struct FieldID(pub usize); +use std::{fmt::Debug, marker::PhantomData}; // I had an idea for why these were different... now I don't pub type Size = u32; pub type Len = u32; -impl Debug for VarID { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "var{}", self.0) +pub struct ID(pub usize, PhantomData); + +impl ID { + pub fn new(i: usize) -> Self { + Self(i, PhantomData) } } -impl Debug for StructID { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "ty{}", self.0) +pub trait Named { + const NAME: &str; +} + +impl From for ID { + fn from(value: usize) -> Self { + Self(value, PhantomData) } } -impl Debug for FnID { +impl Debug for ID { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "fn{}", self.0) + write!(f, "{}{}", K::NAME, self.0) } } -impl Debug for DataID { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "data{}", self.0) +impl PartialEq for ID { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 } } -impl Debug for FieldID { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "field{}", self.0) +impl Eq for ID {} + +impl std::hash::Hash for ID { + fn hash(&self, state: &mut H) { + self.0.hash(state); } } + +impl Clone for ID { + fn clone(&self) -> Self { + Self(self.0.clone(), PhantomData) + } +} + +impl Copy for ID {} diff --git a/src/ir/lower/func.rs b/src/ir/lower/func.rs index 6e86538..ee6431e 100644 --- a/src/ir/lower/func.rs +++ b/src/ir/lower/func.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; #[derive(Debug)] pub struct IRLFunction { - pub instructions: Vec, + pub instructions: Vec, pub stack: HashMap, pub subvar_map: HashMap, pub args: Vec<(VarID, Size)>, @@ -14,7 +14,7 @@ pub struct IRLFunction { } #[derive(Debug)] -pub enum IRLInstruction { +pub enum LInstruction { Mv { dest: VarID, dest_offset: Size, @@ -59,7 +59,7 @@ pub enum IRLInstruction { Mark(Symbol), } -impl IRLInstruction { +impl LInstruction { pub fn is_ret(&self) -> bool { matches!(self, Self::Ret { .. }) } diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs index eada48b..e4b5ed4 100644 --- a/src/ir/lower/program.rs +++ b/src/ir/lower/program.rs @@ -1,41 +1,38 @@ use std::collections::HashMap; -use crate::ir::{AsmBlockArgType, IRUFunction, IRUInstrInst, Size, SymbolSpace, VarOffset}; +use crate::ir::{AsmBlockArgType, UInstrInst, Size, SymbolSpace, UFunc, VarOffset}; use super::{ - IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, SymbolSpaceBuilder, Type, + IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, Type, UInstruction, UProgram, VarID, }; -pub struct IRLProgram { +pub struct LProgram { sym_space: SymbolSpace, entry: Symbol, } // NOTE: there are THREE places here where I specify size (8) -impl IRLProgram { - pub fn create(p: &IRUProgram) -> Result { - let mut start = None; - for (i, f) in p.iter_fns() { - if f.name == "start" { - start = Some(i); - } - } - let start = start.ok_or("no start method found")?; +impl LProgram { + pub fn create(p: &UProgram) -> Result { + let start = p + .names + .lookup::("start") + .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.0].as_ref().unwrap(); - let mut fbuilder = IRLFunctionBuilder::new(p, &mut ssbuilder); + let mut fbuilder = LFunctionBuilder::new(p, &mut ssbuilder); for i in &f.instructions { fbuilder.insert_instr(i); } if fbuilder.instrs.last().is_none_or(|i| !i.is_ret()) { - fbuilder.instrs.push(IRLInstruction::Ret { src: None }); + 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.get(i).to_string())); } let sym_space = ssbuilder.finish().expect("we failed the mission"); Ok(Self { sym_space, entry }) @@ -46,10 +43,10 @@ impl IRLProgram { } } -pub struct IRLFunctionBuilder<'a> { - program: &'a IRUProgram, +pub struct LFunctionBuilder<'a> { + program: &'a UProgram, builder: &'a mut SymbolSpaceBuilder, - instrs: Vec, + instrs: Vec, stack: HashMap, subvar_map: HashMap, makes_call: bool, @@ -62,8 +59,8 @@ pub struct LoopCtx { bot: Symbol, } -impl<'a> IRLFunctionBuilder<'a> { - pub fn new(program: &'a IRUProgram, builder: &'a mut SymbolSpaceBuilder) -> Self { +impl<'a> LFunctionBuilder<'a> { + pub fn new(program: &'a UProgram, builder: &'a mut SymbolSpaceBuilder) -> Self { Self { instrs: Vec::new(), stack: HashMap::new(), @@ -92,50 +89,56 @@ impl<'a> IRLFunctionBuilder<'a> { self.subvar_map.insert(i, off); } } - pub fn insert_instr(&mut self, i: &IRUInstrInst) -> Option> { + pub fn insert_instr(&mut self, i: &UInstrInst) -> Option> { match &i.i { - IRUInstruction::Mv { dest, src } => { + UInstruction::Mv { dest, src } => { self.alloc_stack(dest.id)?; self.map_subvar(src.id); - self.instrs.push(IRLInstruction::Mv { + self.instrs.push(LInstruction::Mv { dest: dest.id, dest_offset: 0, src: src.id, src_offset: 0, }); } - IRUInstruction::Ref { dest, src } => { + UInstruction::Ref { dest, src } => { self.alloc_stack(dest.id)?; self.map_subvar(src.id); - self.instrs.push(IRLInstruction::Ref { + self.instrs.push(LInstruction::Ref { dest: dest.id, src: src.id, }); } - IRUInstruction::LoadData { dest, src } => { + UInstruction::LoadData { dest, src } => { self.alloc_stack(dest.id)?; - let data = &self.program.data[src.0]; - let ddef = self.program.get_data(*src); - let sym = self.builder.ro_data(src, data, Some(ddef.label.clone())); - self.instrs.push(IRLInstruction::LoadData { + let data = self.program.expect(*src); + let sym = self.builder.ro_data( + src, + &data.content, + Some(self.program.names.get(dest.id).to_string()), + ); + self.instrs.push(LInstruction::LoadData { dest: dest.id, offset: 0, - len: data.len() as Len, + len: data.content.len() as Len, src: sym, }); } - IRUInstruction::LoadSlice { dest, src } => { + UInstruction::LoadSlice { dest, src } => { self.alloc_stack(dest.id)?; - let data = &self.program.data[src.0]; - let def = self.program.get_data(*src); - let Type::Array(_, len) = &def.ty else { + let data = self.program.expect(*src); + let Type::Array(_, len) = &data.ty else { return Some(Some(format!( "tried to load {} as slice", - self.program.type_name(&def.ty) + self.program.type_name(&data.ty) ))); }; - let sym = self.builder.ro_data(src, data, Some(def.label.clone())); - self.instrs.push(IRLInstruction::LoadAddr { + let sym = self.builder.ro_data( + src, + &data.content, + Some(self.program.names.get(dest.id).to_string()), + ); + self.instrs.push(LInstruction::LoadAddr { dest: dest.id, offset: 0, src: sym, @@ -144,23 +147,23 @@ impl<'a> IRLFunctionBuilder<'a> { let sym = self .builder .anon_ro_data(&(*len as u64).to_le_bytes(), Some(format!("len: {}", len))); - self.instrs.push(IRLInstruction::LoadData { + self.instrs.push(LInstruction::LoadData { dest: dest.id, offset: 8, len: 8, src: sym, }); } - IRUInstruction::LoadFn { dest, src } => { + UInstruction::LoadFn { dest, src } => { self.alloc_stack(dest.id)?; let sym = self.builder.func(src); - self.instrs.push(IRLInstruction::LoadAddr { + self.instrs.push(LInstruction::LoadAddr { dest: dest.id, offset: 0, src: sym, }); } - IRUInstruction::Call { dest, f, args } => { + UInstruction::Call { dest, f, args } => { self.alloc_stack(dest.id); self.makes_call = true; let fid = &self.program.fn_map[&f.id]; @@ -171,7 +174,7 @@ impl<'a> IRLFunctionBuilder<'a> { } else { None }; - let call = IRLInstruction::Call { + let call = LInstruction::Call { dest, f: sym, args: args @@ -184,7 +187,7 @@ impl<'a> IRLFunctionBuilder<'a> { }; self.instrs.push(call); } - IRUInstruction::AsmBlock { instructions, args } => { + UInstruction::AsmBlock { instructions, args } => { let mut inputs = Vec::new(); let mut outputs = Vec::new(); for a in args { @@ -199,15 +202,15 @@ impl<'a> IRLFunctionBuilder<'a> { } } } - self.instrs.push(IRLInstruction::AsmBlock { + self.instrs.push(LInstruction::AsmBlock { instructions: instructions.clone(), inputs, outputs, }) } - IRUInstruction::Ret { src } => { + UInstruction::Ret { src } => { self.map_subvar(src.id); - self.instrs.push(IRLInstruction::Ret { + self.instrs.push(LInstruction::Ret { src: if self.program.size_of_var(src.id).expect("unsized var") == 0 { None } else { @@ -215,9 +218,9 @@ impl<'a> IRLFunctionBuilder<'a> { }, }) } - IRUInstruction::Construct { dest, fields } => { + UInstruction::Construct { dest, fields } => { self.alloc_stack(dest.id)?; - let ty = &self.program.get_var(dest.id).ty; + let ty = &self.program.expect(dest.id).ty; let &Type::Struct { id, ref args } = ty else { return Some(Some(format!( "Failed to contruct type {}", @@ -226,7 +229,7 @@ impl<'a> IRLFunctionBuilder<'a> { }; for (&fid, var) in fields { self.map_subvar(var.id); - self.instrs.push(IRLInstruction::Mv { + self.instrs.push(LInstruction::Mv { dest: dest.id, src: var.id, dest_offset: self.program.field_offset(id, fid).expect("field offset"), @@ -234,19 +237,19 @@ impl<'a> IRLFunctionBuilder<'a> { }) } } - IRUInstruction::If { cond, body } => { + UInstruction::If { cond, body } => { self.map_subvar(cond.id); let sym = self.builder.reserve(); - self.instrs.push(IRLInstruction::Branch { + self.instrs.push(LInstruction::Branch { to: *sym, cond: cond.id, }); for i in body { self.insert_instr(i); } - self.instrs.push(IRLInstruction::Mark(*sym)); + self.instrs.push(LInstruction::Mark(*sym)); } - IRUInstruction::Loop { body } => { + UInstruction::Loop { body } => { let top = self.builder.reserve(); let bot = self.builder.reserve(); let old = self.loopp; @@ -254,21 +257,21 @@ impl<'a> IRLFunctionBuilder<'a> { bot: *bot, top: *top, }); - self.instrs.push(IRLInstruction::Mark(*top)); + self.instrs.push(LInstruction::Mark(*top)); for i in body { self.insert_instr(i); } - self.instrs.push(IRLInstruction::Jump(*top)); - self.instrs.push(IRLInstruction::Mark(*bot)); + self.instrs.push(LInstruction::Jump(*top)); + self.instrs.push(LInstruction::Mark(*bot)); self.loopp = old; } - IRUInstruction::Break => { - self.instrs.push(IRLInstruction::Jump( + UInstruction::Break => { + self.instrs.push(LInstruction::Jump( self.loopp.expect("Tried to break outside of loop").bot, )); } - IRUInstruction::Continue => { - self.instrs.push(IRLInstruction::Jump( + UInstruction::Continue => { + self.instrs.push(LInstruction::Jump( self.loopp.expect("Tried to break outside of loop").top, )); } @@ -276,7 +279,7 @@ impl<'a> IRLFunctionBuilder<'a> { Some(None) } - pub fn finish(self, f: &IRUFunction) -> IRLFunction { + pub fn finish(self, f: &UFunc) -> IRLFunction { IRLFunction { instructions: self.instrs, makes_call: self.makes_call, @@ -292,7 +295,7 @@ impl<'a> IRLFunctionBuilder<'a> { } } -impl std::ops::Deref for IRLProgram { +impl std::ops::Deref for LProgram { type Target = SymbolSpace; fn deref(&self) -> &Self::Target { diff --git a/src/ir/upper/def.rs b/src/ir/upper/def.rs deleted file mode 100644 index c581b72..0000000 --- a/src/ir/upper/def.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::{ - common::FileSpan, - ir::{FieldID, Len, StructID, VarID}, -}; - -use super::Type; -use std::{collections::HashMap, fmt::Debug}; - -#[derive(Clone)] -pub struct FnDef { - pub name: String, - pub args: Vec, - pub ret: Type, - pub origin: Origin, -} - -#[derive(Clone)] -pub struct StructField { - pub name: String, - pub ty: Type, -} - -#[derive(Clone)] -pub struct StructDef { - pub name: String, - pub fields: Vec, - pub field_map: HashMap, - pub origin: Origin, -} - -#[derive(Clone)] -pub struct VarDef { - pub name: String, - pub parent: Option, - pub ty: Type, - pub origin: Origin, -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -pub struct VarOffset { - pub id: VarID, - pub offset: Len, -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -pub struct FieldRef { - pub var: VarID, - // this is technically redundant bc you can get it from the var... - // but it makes things a lot easier, and you'd have to recheck the fields anyways - pub struc: StructID, - pub field: FieldID, -} - -#[derive(Clone)] -pub struct DataDef { - pub ty: Type, - pub origin: Origin, - pub label: String, -} - -pub type Origin = FileSpan; - -impl FnDef { - pub fn ty(&self) -> Type { - Type::Fn { - args: self.args.iter().map(|a| a.ty.clone()).collect(), - ret: Box::new(self.ret.clone()), - } - } -} - -impl StructDef { - pub fn field(&self, id: FieldID) -> &StructField { - &self.fields[id.0] - } - pub fn get_field(&self, name: &str) -> Option<&StructField> { - self.field_map.get(name).map(|id| self.field(*id)) - } - pub fn iter_fields(&self) -> impl Iterator { - self.fields.iter().enumerate().map(|(i, f)| (FieldID(i), f)) - } -} diff --git a/src/ir/upper/error.rs b/src/ir/upper/error.rs index f2ffe52..0a9ebe1 100644 --- a/src/ir/upper/error.rs +++ b/src/ir/upper/error.rs @@ -1,9 +1,9 @@ use crate::common::{CompilerMsg, CompilerOutput, FileSpan}; -use super::{IRUProgram, Type}; +use super::{Type, UProgram}; impl CompilerOutput { - pub fn check_assign(&mut self, p: &IRUProgram, src: &Type, dest: &Type, span: FileSpan) { + pub fn check_assign(&mut self, p: &UProgram, src: &Type, dest: &Type, span: FileSpan) -> bool { // TODO: spans if src != dest { self.err(CompilerMsg { @@ -14,6 +14,9 @@ impl CompilerOutput { ), spans: vec![span], }); + true + } else { + false } } } diff --git a/src/ir/upper/inst.rs b/src/ir/upper/inst.rs index 6e93092..e6d9987 100644 --- a/src/ir/upper/inst.rs +++ b/src/ir/upper/inst.rs @@ -1,7 +1,7 @@ use crate::{common::FileSpan, ir::VarID}; use std::fmt::Debug; -use super::IRUInstruction; +use super::UInstruction; #[derive(Clone, Copy)] pub struct VarInst { @@ -9,8 +9,8 @@ pub struct VarInst { pub span: FileSpan, } -pub struct IRUInstrInst { - pub i: IRUInstruction, +pub struct UInstrInst { + pub i: UInstruction, pub span: FileSpan, } @@ -20,7 +20,7 @@ impl Debug for VarInst { } } -impl Debug for IRUInstrInst { +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/func.rs b/src/ir/upper/instr.rs similarity index 85% rename from src/ir/upper/func.rs rename to src/ir/upper/instr.rs index 58eec34..3e1d0a4 100644 --- a/src/ir/upper/func.rs +++ b/src/ir/upper/instr.rs @@ -1,18 +1,9 @@ use std::{collections::HashMap, fmt::Write}; -use super::{ - arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, Type, VarID, -}; +use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, UInstrInst, UFunc}; use crate::{compiler::arch::riscv::Reg, ir::FieldID, util::Padder}; -pub struct IRUFunction { - pub name: String, - pub args: Vec, - pub ret: Type, - pub instructions: Vec, -} - -pub enum IRUInstruction { +pub enum UInstruction { Mv { dest: VarInst, src: VarInst, @@ -51,10 +42,10 @@ pub enum IRUInstruction { }, If { cond: VarInst, - body: Vec, + body: Vec, }, Loop { - body: Vec, + body: Vec, }, Break, Continue, @@ -73,7 +64,7 @@ pub enum AsmBlockArgType { Out, } -impl std::fmt::Debug for IRUInstruction { +impl std::fmt::Debug for UInstruction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}")?, @@ -86,9 +77,7 @@ impl std::fmt::Debug for IRUInstruction { f: func, args, } => write!(f, "{dest:?} <- {func:?}({args:?})")?, - Self::AsmBlock { args, instructions } => { - write!(f, "asm {args:?} {instructions:#?}")? - } + Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}")?, Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?, Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?, Self::If { cond, body } => { @@ -126,9 +115,9 @@ impl std::fmt::Debug for IRUInstruction { } } -impl std::fmt::Debug for IRUFunction { +impl std::fmt::Debug for UFunc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}{:?}", &self.name, self.args)?; + write!(f, "{:?}", self.args)?; if !self.instructions.is_empty() { f.write_str("{\n ")?; let mut padder = Padder::new(f); diff --git a/src/ir/upper/kind.rs b/src/ir/upper/kind.rs new file mode 100644 index 0000000..3720519 --- /dev/null +++ b/src/ir/upper/kind.rs @@ -0,0 +1,160 @@ +use crate::{ + common::FileSpan, + ir::{Len, Named, ID}, +}; + +use super::{Type, UInstrInst, UProgram}; +use std::{collections::HashMap, fmt::Debug}; + +pub const NAMED_KINDS: usize = 4; + +pub struct UFunc { + pub args: Vec, + pub ret: Type, + pub origin: Origin, + pub instructions: Vec, +} + +#[derive(Clone)] +pub struct StructField { + pub name: String, + pub ty: Type, +} + +#[derive(Clone)] +pub struct UStruct { + pub fields: Vec, + pub field_map: HashMap, + pub origin: Origin, +} + +#[derive(Clone)] +pub struct UVar { + pub parent: Option, + pub ty: Type, + pub origin: Origin, +} + +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub struct VarOffset { + pub id: VarID, + pub offset: Len, +} + +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub struct FieldRef { + pub var: VarID, + // this is technically redundant bc you can get it from the var... + // but it makes things a lot easier, and you'd have to recheck the fields anyways + pub struc: StructID, + pub field: FieldID, +} + +#[derive(Clone)] +pub struct UData { + pub ty: Type, + pub origin: Origin, + pub content: Vec, +} + +pub type Origin = FileSpan; + +impl UFunc { + pub fn ty(&self, program: &UProgram) -> Type { + Type::Fn { + args: self + .args + .iter() + .map(|a| program.expect(*a).ty.clone()) + .collect(), + ret: Box::new(self.ret.clone()), + } + } +} + +impl UStruct { + pub fn field(&self, id: FieldID) -> &StructField { + &self.fields[id.0] + } + pub fn get_field(&self, name: &str) -> Option<&StructField> { + self.field_map.get(name).map(|id| self.field(*id)) + } + pub fn iter_fields(&self) -> impl Iterator { + self.fields + .iter() + .enumerate() + .map(|(i, f)| (FieldID::new(i), f)) + } +} + +pub type StructID = ID; +pub type VarID = ID; +pub type DataID = ID; +pub type FieldID = ID; +pub type FnID = ID; + +impl Kind for UFunc { + const INDEX: usize = 0; + fn from_program_mut(program: &mut UProgram) -> &mut Vec> { + &mut program.fns + } + fn from_program(program: &UProgram) -> &Vec> { + &program.fns + } +} +impl Named for UFunc { + const NAME: &str = "func"; +} + +impl Kind for UVar { + const INDEX: usize = 1; + fn from_program_mut(program: &mut UProgram) -> &mut Vec> { + &mut program.vars + } + fn from_program(program: &UProgram) -> &Vec> { + &program.vars + } +} +impl Named for UVar { + const NAME: &str = "var"; +} + +impl Kind for UStruct { + const INDEX: usize = 2; + fn from_program_mut(program: &mut UProgram) -> &mut Vec> { + &mut program.structs + } + fn from_program(program: &UProgram) -> &Vec> { + &program.structs + } +} +impl Named for UStruct { + const NAME: &str = "struct"; +} + +impl Kind for UData { + const INDEX: usize = 3; + fn from_program_mut(program: &mut UProgram) -> &mut Vec> { + &mut program.data + } + fn from_program(program: &UProgram) -> &Vec> { + &program.data + } +} +impl Named for UData { + const NAME: &str = "data"; +} + +impl Named for StructField { + const NAME: &str = "field"; +} + +pub trait Kind { + const INDEX: usize; + fn from_program_mut(program: &mut UProgram) -> &mut Vec> + where + Self: Sized; + fn from_program(program: &UProgram) -> &Vec> + where + Self: Sized; +} diff --git a/src/ir/upper/mod.rs b/src/ir/upper/mod.rs index 56992f9..3ca1b7d 100644 --- a/src/ir/upper/mod.rs +++ b/src/ir/upper/mod.rs @@ -1,5 +1,5 @@ -mod def; -mod func; +mod kind; +mod instr; mod ty; mod program; mod validate; @@ -7,8 +7,8 @@ mod error; mod inst; use super::*; -pub use def::*; -pub use func::*; +pub use kind::*; +pub use instr::*; pub use ty::*; pub use program::*; pub use inst::*; diff --git a/src/ir/upper/program.rs b/src/ir/upper/program.rs index e3ac8f5..5325460 100644 --- a/src/ir/upper/program.rs +++ b/src/ir/upper/program.rs @@ -2,40 +2,67 @@ use std::{collections::HashMap, fmt::Debug}; use super::{inst::VarInst, *}; -pub struct IRUProgram { - pub fn_defs: Vec, - pub var_defs: Vec, - pub struct_defs: Vec, - pub data_defs: Vec, - pub fns: Vec>, - pub data: Vec>, +pub struct UProgram { + pub fns: Vec>, + pub vars: Vec>, + pub structs: Vec>, + pub data: Vec>, + pub start: Option, + pub names: NameMap, + // todo: these feel weird raw pub fn_map: HashMap, + pub inv_fn_map: Vec, pub temp: usize, - pub stack: Vec>, + pub name_stack: Vec>, } -impl IRUProgram { +pub struct NameMap { + names: [Vec; NAMED_KINDS], + inv_names: [HashMap; NAMED_KINDS], +} + +impl NameMap { + pub fn new() -> Self { + Self { + names: core::array::from_fn(|_| Vec::new()), + inv_names: core::array::from_fn(|_| HashMap::new()), + } + } + pub fn get(&self, id: ID) -> &str { + &self.names[K::INDEX][id.0] + } + pub fn lookup(&self, name: &str) -> Option> { + Some(ID::new(*self.inv_names[K::INDEX].get(name)?)) + } + pub fn push(&mut self, name: String) { + self.inv_names[K::INDEX].insert(name.clone(), self.names[K::INDEX].len()); + self.names[K::INDEX].push(name); + } +} + +impl UProgram { pub fn new() -> Self { Self { - fn_defs: Vec::new(), - var_defs: Vec::new(), - struct_defs: Vec::new(), - data_defs: Vec::new(), - data: Vec::new(), - fn_map: HashMap::new(), fns: Vec::new(), + vars: Vec::new(), + structs: Vec::new(), + data: Vec::new(), + start: None, + names: NameMap::new(), + fn_map: HashMap::new(), + inv_fn_map: Vec::new(), temp: 0, - stack: vec![HashMap::new()], + name_stack: vec![HashMap::new()], } } pub fn push(&mut self) { - self.stack.push(HashMap::new()); + self.name_stack.push(HashMap::new()); } pub fn pop(&mut self) { - self.stack.pop(); + self.name_stack.pop(); } - pub fn get(&self, name: &str) -> Option { - for map in self.stack.iter().rev() { + 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(); @@ -43,43 +70,29 @@ impl IRUProgram { } None } - pub fn get_var(&self, id: VarID) -> &VarDef { - &self.var_defs[id.0] + pub fn get(&self, id: ID) -> Option<&K> { + K::from_program(self)[id.0].as_ref() } - pub fn get_fn(&self, id: FnID) -> &FnDef { - &self.fn_defs[id.0] + pub fn get_mut(&mut self, id: ID) -> Option<&mut K> { + K::from_program_mut(self)[id.0].as_mut() } - pub fn get_data(&self, id: DataID) -> &DataDef { - &self.data_defs[id.0] + pub fn expect(&self, id: ID) -> &K { + self.get(id) + .unwrap_or_else(|| panic!("{id:?} not defined yet!")) } - pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> { - Some(&self.fn_defs[self.fn_map.get(&id)?.0]) + pub fn expect_mut(&mut self, id: ID) -> &mut K { + self.get_mut(id) + .unwrap_or_else(|| panic!("{id:?} not defined yet!")) } - pub fn get_struct(&self, id: StructID) -> &StructDef { - &self.struct_defs[id.0] - } - pub fn alias_fn(&mut self, name: &str, id: FnID) { - self.insert(name, Ident::Fn(id)); - } - pub fn named_var(&mut self, def: VarDef) -> VarID { - // TODO: this is stupid - let id = self.def_var(def.clone()); - self.name_var(&def, id); - id - } - pub fn name_var(&mut self, def: &VarDef, var: VarID) { - self.insert(&def.name, Ident::Var(var)); - } - pub fn def_var(&mut self, var: VarDef) -> VarID { - let i = self.var_defs.len(); - self.var_defs.push(var); - VarID(i) + pub fn get_fn_var(&self, id: VarID) -> Option<&UFunc> { + self.fns[self.fn_map.get(&id)?.0].as_ref() } pub fn size_of_type(&self, ty: &Type) -> Option { // TODO: target matters Some(match ty { Type::Bits(b) => *b, - Type::Struct { id, args } => self.struct_defs[id.0] + Type::Struct { id, args } => self.structs[id.0] + .as_ref()? .fields .iter() .try_fold(0, |sum, f| Some(sum + self.size_of_type(&f.ty)?))?, @@ -92,9 +105,8 @@ impl IRUProgram { Type::Unit => 0, }) } - pub fn struct_layout() {} pub fn size_of_var(&self, var: VarID) -> Option { - self.size_of_type(&self.var_defs[var.0].ty) + self.size_of_type(&self.get(var)?.ty) } pub fn temp_subvar(&mut self, origin: Origin, ty: Type, parent: FieldRef) -> VarInst { self.temp_var_inner(origin, ty, Some(parent)) @@ -104,12 +116,10 @@ impl IRUProgram { } fn temp_var_inner(&mut self, origin: Origin, ty: Type, parent: Option) -> VarInst { - let v = self.def_var(VarDef { - name: format!("temp{}", self.temp), - parent, - origin, - ty, - }); + let v = self.def( + format!("temp{}", self.temp), + Some(UVar { parent, origin, ty }), + ); self.temp += 1; VarInst { id: v, @@ -117,44 +127,29 @@ impl IRUProgram { } } - pub fn def_fn(&mut self, def: FnDef) -> FnID { - let i = self.fn_defs.len(); - let id = FnID(i); - let var_def = VarDef { - name: def.name.clone(), - parent: None, - origin: def.origin, - ty: def.ty(), - }; - - let vid = self.def_var(var_def); - self.insert(&def.name, Ident::Var(vid)); - self.fn_map.insert(vid, id); - - self.insert(&def.name, Ident::Fn(id)); - self.fn_defs.push(def); - self.fns.push(None); + pub fn write(&mut self, id: ID, k: K) { + K::from_program_mut(self)[id.0] = Some(k); + } + pub fn def(&mut self, name: String, k: Option) -> ID { + self.names.push::(name); + let vec = K::from_program_mut(self); + let id = ID::new(vec.len()); + vec.push(k); id } - pub fn def_struct(&mut self, def: StructDef) -> StructID { - let i = self.struct_defs.len(); - let id = StructID(i); - self.insert(&def.name, Ident::Type(id)); - self.struct_defs.push(def); + + pub fn def_searchable(&mut self, name: String, k: Option) -> ID { + let id = self.def(name.clone(), k); + self.name_on_stack(id, name); id } - pub fn def_data(&mut self, def: DataDef, bytes: Vec) -> DataID { - let i = self.data.len(); - self.data_defs.push(def); - self.data.push(bytes); - DataID(i) - } + pub fn type_name(&self, ty: &Type) -> String { let mut str = String::new(); match ty { Type::Struct { id: base, args } => { - str += &self.get_struct(*base).name; + str += self.names.get(*base); if let Some(arg) = args.first() { str = str + "<" + &self.type_name(arg); } @@ -188,81 +183,82 @@ impl IRUProgram { } str } - fn insert(&mut self, name: &str, id: Ident) { - let idx = self.stack.len() - 1; - let last = &mut self.stack[idx]; - if let Some(l) = last.get_mut(name) { - l.insert(id); + fn name_on_stack(&mut self, id: ID, name: String) { + let idx = self.name_stack.len() - 1; + let last = &mut self.name_stack[idx]; + if let Some(l) = last.get_mut(&name) { + l.insert(id.into()); } else { - last.insert(name.to_string(), Idents::new(id)); + last.insert(name, Idents::new(id.into())); } } - pub fn write_fn(&mut self, id: FnID, f: IRUFunction) { - self.fns[id.0] = Some(f); - } - pub fn iter_vars(&self) -> impl Iterator { - self.var_defs.iter().enumerate().map(|(i, v)| (VarID(i), v)) - } - pub fn iter_fns(&self) -> impl Iterator { - self.fns - .iter() - .enumerate() - .flat_map(|(i, f)| Some((FnID(i), f.as_ref()?))) - } pub fn var_offset(&self, var: VarID) -> Option { let mut current = VarOffset { id: var, offset: 0 }; - while let Some(parent) = self.var_defs[current.id.0].parent { + while let Some(parent) = self.get(current.id)?.parent { current.id = parent.var; current.offset += self.field_offset(parent.struc, parent.field)?; } Some(current) } pub fn field_offset(&self, struct_id: StructID, field: FieldID) -> Option { - let struc = self.get_struct(struct_id); + let struc = self.get(struct_id)?; let mut offset = 0; for i in 0..field.0 { offset += self.size_of_type(&struc.fields[i].ty)?; } Some(offset) } + pub fn iter_vars(&self) -> impl Iterator { + self.vars + .iter() + .flatten() + .enumerate() + .map(|(i, x)| (ID::new(i), x)) + } + pub fn iter_fns(&self) -> impl Iterator { + self.fns + .iter() + .flatten() + .enumerate() + .map(|(i, x)| (ID::new(i), x)) + } } #[derive(Debug, Clone, Copy)] -pub enum Ident { - Var(VarID), - Fn(FnID), - Type(StructID), +pub struct Ident { + id: usize, + kind: usize, +} + +impl From> for Ident { + fn from(id: ID) -> Self { + Self { + id: id.0, + kind: K::INDEX, + } + } } #[derive(Debug, Clone, Copy)] pub struct Idents { pub latest: Ident, - pub var: Option, - pub func: Option, - pub struc: Option, + pub kinds: [Option; NAMED_KINDS], } impl Idents { fn new(latest: Ident) -> Self { let mut s = Self { latest, - var: None, - func: None, - struc: None, + kinds: [None; NAMED_KINDS], }; s.insert(latest); s } fn insert(&mut self, i: Ident) { self.latest = i; - match i { - Ident::Var(v) => { - self.var = Some(v); - } - Ident::Fn(f) => { - self.func = Some(f); - } - Ident::Type(t) => self.struc = Some(t), - } + 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/ty.rs b/src/ir/upper/ty.rs index 0a949d0..0fab315 100644 --- a/src/ir/upper/ty.rs +++ b/src/ir/upper/ty.rs @@ -1,4 +1,6 @@ -use super::{IRUProgram, Len, StructID}; +use crate::common::CompilerOutput; + +use super::{Len, StructID, UInstruction, UProgram, UVar}; #[derive(Clone, PartialEq)] pub enum Type { @@ -25,13 +27,121 @@ impl Type { } } -// should impl instead -pub fn resolve_types(ns: &IRUProgram) { - for (i, f) in ns.iter_fns() { - for inst in &f.instructions { - match &inst.i { - _ => todo!(), +impl UProgram { + pub fn resolve_types(&mut self) { + // I LOVE RUST + let mut vars = self.vars.clone(); + for f in self.fns.iter().flatten() { + for i in &f.instructions { + self.resolve_instr_types(&mut vars, &i.i); } } + self.vars = vars; + } + + pub fn resolve_instr_types(&self, vars: &mut Vec>, i: &UInstruction) { + match &i { + UInstruction::Call { dest, f, args } => { + let ret = self.get_fn_var(f.id).expect("bruh").ret.clone(); + vars[dest.id.0].as_mut().expect("bruh").ty = ret; + } + UInstruction::Mv { dest, src } => { + let dest_ty = &vars[dest.id.0].as_ref().unwrap().ty; + let src_ty = &vars[src.id.0].as_ref().unwrap().ty; + if let Some(ty) = match_types(dest_ty, src_ty) { + vars[dest.id.0] + .as_mut() + .expect("PARTIAL BORROWING WOULD BE REALLY COOL") + .ty = ty.clone(); + vars[src.id.0] + .as_mut() + .expect("PARTIAL BORROWING WOULD BE REALLY COOL") + .ty = ty; + } + } + UInstruction::Ref { dest, src } => { + // TODO + } + UInstruction::LoadData { dest, src } => { + // TODO + } + UInstruction::LoadSlice { dest, src } => { + // TODO + } + UInstruction::LoadFn { dest, src } => { + // TODO + } + UInstruction::AsmBlock { instructions, args } => { + // TODO + } + UInstruction::Ret { .. } => {} + UInstruction::Construct { dest, fields } => { + // TODO + } + UInstruction::If { cond, body } => { + for i in body { + self.resolve_instr_types(vars, &i.i); + } + } + UInstruction::Loop { body } => { + for i in body { + self.resolve_instr_types(vars, &i.i); + } + } + UInstruction::Break => {} + UInstruction::Continue => {} + } + } +} + +pub fn match_types(dest: &Type, src: &Type) -> Option { + if dest == src { + return None; + } + match (dest, src) { + (Type::Error, x) | (x, Type::Error) => None, + (Type::Infer, x) | (x, Type::Infer) => Some(x.clone()), + ( + Type::Struct { + id: dest_id, + args: dest_args, + }, + Type::Struct { + id: src_id, + args: src_args, + }, + ) => { + if dest_id != src_id { + return None; + } + None + // TODO + // let mut args = Vec::new(); + // for (darg, sarg) in dest_args.iter().zip(src_args) { + // } + // Some(Type::Struct { id: *dest_id, args }) + } + ( + Type::Fn { + args: dest_args, + ret: dest_ret, + }, + Type::Fn { + args: src_args, + ret: src_ret, + }, + ) => { + // TODO + None + } + (Type::Ref(dest), Type::Ref(src)) => Some(match_types(dest, src)?), + (Type::Slice(dest), Type::Slice(src)) => Some(match_types(dest, src)?), + (Type::Array(dest, dlen), Type::Array(src, slen)) => { + if dlen != slen { + return None; + } + match_types(dest, src) + } + _ => None, } } diff --git a/src/ir/upper/validate.rs b/src/ir/upper/validate.rs index 0cd88b9..2e658be 100644 --- a/src/ir/upper/validate.rs +++ b/src/ir/upper/validate.rs @@ -1,26 +1,27 @@ // TODO: move this into ir, not parser -use super::{IRUInstrInst, IRUInstruction, IRUProgram, Type}; +use super::{Type, UInstrInst, UInstruction, UProgram}; use crate::common::{CompilerMsg, CompilerOutput, FileSpan}; -impl IRUProgram { +impl UProgram { pub fn validate(&self) -> CompilerOutput { let mut output = CompilerOutput::new(); - for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) { - self.validate_fn( - &f.instructions, - fd.origin, - &fd.ret, - &mut output, - true, - false, - ); + for f in self.fns.iter().flatten() { + self.validate_fn(&f.instructions, f.origin, &f.ret, &mut output, true, false); + } + for (id, var) in self.iter_vars() { + if var.ty == Type::Error { + output.err(CompilerMsg { + msg: format!("Var {:?} is error type!", id), + spans: vec![var.origin], + }); + } } output } pub fn validate_fn( &self, - instructions: &[IRUInstrInst], + instructions: &[UInstrInst], origin: FileSpan, ret: &Type, output: &mut CompilerOutput, @@ -30,31 +31,31 @@ impl IRUProgram { let mut no_ret = true; for i in instructions { match &i.i { - IRUInstruction::Mv { dest, src } => { - let dest = self.get_var(dest.id); - let src = self.get_var(src.id); + UInstruction::Mv { dest, src } => { + let dest = self.expect(dest.id); + let src = self.expect(src.id); output.check_assign(self, &src.ty, &dest.ty, i.span); } - IRUInstruction::Ref { dest, src } => { + UInstruction::Ref { dest, src } => { // TODO } - IRUInstruction::LoadData { dest, src } => { - let dest = self.get_var(dest.id); - let src = self.get_data(*src); + UInstruction::LoadData { dest, src } => { + let dest = self.expect(dest.id); + let src = self.expect(*src); output.check_assign(self, &src.ty, &dest.ty, i.span); } - IRUInstruction::LoadSlice { dest, src } => { - let dest = self.get_var(dest.id); - let src = self.get_data(*src); + UInstruction::LoadSlice { 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.span); } - IRUInstruction::LoadFn { dest, src } => todo!(), - IRUInstruction::Call { dest, f, args } => { - let destty = &self.get_var(dest.id).ty; - let f = self.get_var(f.id); + UInstruction::LoadFn { dest, src } => todo!(), + UInstruction::Call { 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 { todo!() }; @@ -65,21 +66,21 @@ impl IRUProgram { spans: vec![dest.span], }); } - for (argv, argt) in args.iter().zip(argtys) { - let dest = self.get_var(argv.id); - output.check_assign(self, argt, &dest.ty, argv.span); + 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.span); } } - IRUInstruction::AsmBlock { instructions, args } => { + UInstruction::AsmBlock { instructions, args } => { // TODO } - IRUInstruction::Ret { src } => { - let srcty = &self.get_var(src.id).ty; + UInstruction::Ret { src } => { + let srcty = &self.expect(src.id).ty; output.check_assign(self, srcty, ret, src.span); no_ret = false; } - IRUInstruction::Construct { dest, fields } => { - let dest_def = self.get_var(dest.id); + UInstruction::Construct { dest, fields } => { + let dest_def = self.expect(dest.id); let tyid = match &dest_def.ty { Type::Struct { id, args } => *id, _ => { @@ -90,10 +91,10 @@ impl IRUProgram { continue; } }; - let def = self.get_struct(tyid); + let def = self.expect(tyid); for (id, field) in def.iter_fields() { if let Some(var) = fields.get(&id) { - let ety = &self.get_var(var.id).ty; + let ety = &self.expect(var.id).ty; output.check_assign(self, &field.ty, ety, var.span); } else { output.err(CompilerMsg { @@ -103,15 +104,15 @@ impl IRUProgram { } } } - IRUInstruction::If { cond, body } => { - let cond = self.get_var(cond.id); + UInstruction::If { cond, body } => { + let cond = self.expect(cond.id); output.check_assign(self, &cond.ty, &Type::Bits(64), i.span); self.validate_fn(body, origin, ret, output, false, breakable); } - IRUInstruction::Loop { body } => { + UInstruction::Loop { body } => { self.validate_fn(body, origin, ret, output, false, true); } - IRUInstruction::Break => { + UInstruction::Break => { if !breakable { output.err(CompilerMsg { msg: "Can't break here (outside of loop)".to_string(), @@ -120,7 +121,7 @@ impl IRUProgram { } // TODO } - IRUInstruction::Continue => { + UInstruction::Continue => { if !breakable { output.err(CompilerMsg { msg: "Can't continue here (outside of loop)".to_string(), diff --git a/src/main.rs b/src/main.rs index ddd68a0..0c5953e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,9 @@ // dawg what #![feature(str_as_str)] -use ir::{IRLProgram, IRUProgram}; +use ir::{LProgram, UProgram}; use parser::{NodeParsable, PModule, PStatement, ParserCtx}; +use util::Labelable; use std::{ fs::{create_dir_all, OpenOptions}, io::{stdout, BufRead, BufReader}, @@ -37,37 +38,45 @@ fn main() { fn run_file(file: &str, gdb: bool, asm: bool) { let mut ctx = ParserCtx::from(file); let res = PModule::parse_node(&mut ctx); - if ctx.output.errs.is_empty() { - println!("Parsed:"); - println!("{:#?}", res.node); - if let Some(module) = res.node.as_ref() { - let mut program = IRUProgram::new(); - module.lower(&mut program, &mut ctx.output); - if ctx.output.errs.is_empty() { - // println!("vars:"); - // for (id, def) in namespace.iter_vars() { - // println!(" {id:?} = {}: {}", def.name, namespace.type_name(&def.ty)); - // } - // for (id, f) in namespace.iter_fns() { - // println!("{id:?} = {:#?}", f.unwrap()); - // } - let output = program.validate(); - output.write_for(&mut stdout(), file); - if output.errs.is_empty() { - let program = IRLProgram::create(&program).expect("morir"); - let unlinked = compiler::compile(&program); - if asm { - println!("{:?}", unlinked); - } else { - let bin = unlinked.link().to_elf(); - println!("compiled"); - save_run(&bin, gdb); - } - } - } + let mut output = ctx.output; + 'outer: { + if !output.errs.is_empty() { + break 'outer; + } + // println!("Parsed:"); + // println!("{:#?}", res.node); + let Some(module) = res.node.as_ref() else { + break 'outer; + }; + let mut program = UProgram::new(); + module.lower(&mut program, &mut output); + if !output.errs.is_empty() { + break 'outer; + } + program.resolve_types(); + // println!("vars:"); + // for (id, def) in program.iter_vars() { + // println!(" {id:?} = {}: {}", program.names.get(id), program.type_name(&def.ty)); + // } + // for (id, f) in program.iter_fns() { + // println!("{}:{id:?} = {:#?}", program.names.get(id), f); + // } + output = program.validate(); + if !output.errs.is_empty() { + break 'outer; + } + output.write_for(&mut stdout(), file); + let program = LProgram::create(&program).expect("morir"); + let unlinked = compiler::compile(&program); + if asm { + println!("{:?}", unlinked); + } else { + let bin = unlinked.link().to_elf(); + println!("compiled"); + save_run(&bin, gdb); } } - ctx.output.write_for(&mut stdout(), file); + output.write_for(&mut stdout(), file); } fn save_run(binary: &[u8], run_gdb: bool) { diff --git a/src/parser/v3/lower/asm.rs b/src/parser/v3/lower/asm.rs index 239fb09..ebe3c2f 100644 --- a/src/parser/v3/lower/asm.rs +++ b/src/parser/v3/lower/asm.rs @@ -1,7 +1,7 @@ use crate::{ compiler::arch::riscv::Reg, ir::{ - arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, IRUInstruction, Type, VarInst, + arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, UInstruction, Type, VarInst, }, parser::PAsmBlockArg, }; @@ -48,7 +48,7 @@ impl FnLowerable for PAsmBlock { } } } - let block = IRUInstruction::AsmBlock { + let block = UInstruction::AsmBlock { instructions: { let mut v = Vec::new(); for i in &self.instructions { diff --git a/src/parser/v3/lower/block.rs b/src/parser/v3/lower/block.rs index b3f7701..a649c83 100644 --- a/src/parser/v3/lower/block.rs +++ b/src/parser/v3/lower/block.rs @@ -1,4 +1,4 @@ -use crate::ir::{IRUInstruction, Type, VarInst}; +use crate::ir::{Type, UInstruction, VarInst}; use super::{FnLowerCtx, FnLowerable, PBlock, PStatement}; @@ -23,17 +23,20 @@ impl FnLowerable for PStatement { let def = def.lower(ctx.program, ctx.output)?; let res = e.lower(ctx); if let Some(res) = res { - ctx.program.name_var(&def, res.id); + ctx.push(UInstruction::Mv { + dest: def, + src: res, + }); } None } super::PStatement::Return(e) => { if let Some(e) = e { let src = e.lower(ctx)?; - ctx.push_at(IRUInstruction::Ret { src }, src.span); + ctx.push_at(UInstruction::Ret { src }, src.span); } else { let src = ctx.temp(Type::Unit); - ctx.push_at(IRUInstruction::Ret { src }, src.span); + ctx.push_at(UInstruction::Ret { src }, src.span); } None } diff --git a/src/parser/v3/lower/def.rs b/src/parser/v3/lower/def.rs index 82e2c31..45cff8a 100644 --- a/src/parser/v3/lower/def.rs +++ b/src/parser/v3/lower/def.rs @@ -1,26 +1,35 @@ -use crate::ir::{IRUProgram, Origin, Type, VarDef}; +use crate::ir::{Type, UProgram, UStruct, UVar, VarInst}; use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef}; impl Node { - pub fn lower(&self, program: &mut IRUProgram, output: &mut CompilerOutput) -> Option { + pub fn lower(&self, program: &mut UProgram, output: &mut CompilerOutput) -> Option { let s = self.as_ref()?; - let name = s.name.as_ref()?.to_string(); + let name = s + .name + .as_ref() + .map(|n| n.to_string()) + .unwrap_or("{error}".to_string()); let ty = match &s.ty { Some(ty) => ty.lower(program, output), None => Type::Infer, }; - Some(VarDef { - name, - ty, - parent: None, - origin: self.span, + Some(VarInst { + id: program.def_searchable( + name, + Some(UVar { + ty, + parent: None, + origin: self.span, + }), + ), + span: self.span, }) } } impl Node { - pub fn lower(&self, namespace: &mut IRUProgram, output: &mut CompilerOutput) -> Type { + pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type { self.as_ref() .map(|t| t.lower(namespace, output, self.span)) .unwrap_or(Type::Error) @@ -30,14 +39,17 @@ impl Node { impl PType { pub fn lower( &self, - namespace: &mut IRUProgram, + namespace: &mut UProgram, output: &mut CompilerOutput, span: FileSpan, ) -> Type { let Some(name) = self.name.as_ref() else { return Type::Error; }; - match namespace.get(&name).and_then(|ids| ids.struc) { + match namespace + .get_idents(name) + .and_then(|ids| ids.get::()) + { Some(id) => { let args = self .args diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs index 69e52bc..76f82d5 100644 --- a/src/parser/v3/lower/expr.rs +++ b/src/parser/v3/lower/expr.rs @@ -1,6 +1,6 @@ use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp}; use crate::{ - ir::{DataDef, FieldRef, IRUInstruction, Type, VarInst}, + ir::{FieldRef, Type, UData, UInstruction, VarInst}, parser::PInfixOp, }; @@ -12,55 +12,53 @@ impl FnLowerable for PExpr { super::PLiteral::String(s) => { let dest = ctx.program.temp_var(l.span, Type::Bits(8).slice()); let data = s.as_bytes().to_vec(); - let src = ctx.program.def_data( - DataDef { + let src = ctx.program.def( + format!("string \"{}\"", s.replace("\n", "\\n")), + Some(UData { ty: Type::Bits(8).arr(data.len() as u32), origin: l.span, - label: format!("string \"{}\"", s.replace("\n", "\\n")), - }, - data, + content: data, + }), ); - ctx.push(IRUInstruction::LoadSlice { dest, src }); + ctx.push(UInstruction::LoadSlice { dest, src }); dest } super::PLiteral::Char(c) => { let ty = Type::Bits(8); let dest = ctx.program.temp_var(l.span, ty.clone()); - let src = ctx.program.def_data( - DataDef { + let src = ctx.program.def( + format!("char '{c}'"), + Some(UData { ty, origin: l.span, - label: format!("char '{c}'"), - }, - c.to_string().as_bytes().to_vec(), + content: c.to_string().as_bytes().to_vec(), + }), ); - ctx.push(IRUInstruction::LoadData { dest, src }); + ctx.push(UInstruction::LoadData { dest, src }); dest } super::PLiteral::Number(n) => { // TODO: temp let ty = Type::Bits(64); let dest = ctx.program.temp_var(l.span, Type::Bits(64)); - let src = ctx.program.def_data( - DataDef { + let src = ctx.program.def( + format!("num {n:?}"), + Some(UData { ty, origin: l.span, - label: format!("num {n:?}"), - }, - n.whole.parse::().unwrap().to_le_bytes().to_vec(), + content: n.whole.parse::().unwrap().to_le_bytes().to_vec(), + }), ); - ctx.push(IRUInstruction::LoadData { dest, src }); + ctx.push(UInstruction::LoadData { dest, src }); dest } - super::PLiteral::Unit => { - todo!(); - } + super::PLiteral::Unit => ctx.program.temp_var(l.span, Type::Unit), }, PExpr::Ident(i) => ctx.get_var(i)?, PExpr::BinaryOp(op, e1, e2) => { let res1 = e1.lower(ctx)?; if *op == PInfixOp::Access { - let sty = &ctx.program.get_var(res1.id).ty; + let sty = &ctx.program.expect(res1.id).ty; let Type::Struct { id: struct_id, args, @@ -72,7 +70,7 @@ impl FnLowerable for PExpr { )); return None; }; - let struc = ctx.program.get_struct(*struct_id); + let struc = ctx.program.expect(*struct_id); let Some(box PExpr::Ident(ident)) = &e2.inner else { ctx.err("Field accesses must be identifiers".to_string()); return None; @@ -102,7 +100,7 @@ impl FnLowerable for PExpr { PInfixOp::GreaterThan => todo!(), PInfixOp::Access => todo!(), PInfixOp::Assign => { - ctx.push(IRUInstruction::Mv { + ctx.push(UInstruction::Mv { dest: res1, src: res2, }); @@ -115,15 +113,15 @@ impl FnLowerable for PExpr { let res = e.lower(ctx)?; match op { UnaryOp::Ref => { - let temp = ctx.temp(ctx.program.get_var(res.id).ty.clone().rf()); - ctx.push(IRUInstruction::Ref { + let temp = ctx.temp(ctx.program.expect(res.id).ty.clone().rf()); + ctx.push(UInstruction::Ref { dest: temp, src: res, }); temp } UnaryOp::Deref => { - let t = &ctx.program.get_var(res.id).ty; + let t = &ctx.program.expect(res.id).ty; let Type::Ref(inner) = t else { ctx.err(format!( "Cannot dereference type {:?}", @@ -145,22 +143,13 @@ impl FnLowerable for PExpr { let arg = arg.lower(ctx)?; nargs.push(arg); } - let def = ctx.program.get_fn_var(fe.id); - let ty = match def { - Some(def) => def.ret.clone(), - None => { - ctx.err_at( - e.span, - format!( - "Expected function, found {}", - ctx.program.type_name(&ctx.program.get_var(fe.id).ty) - ), - ); - Type::Error - } - }; + let ty = ctx + .program + .get_fn_var(fe.id) + .map(|f| f.ret.clone()) + .unwrap_or(Type::Error); let temp = ctx.temp(ty); - ctx.push(IRUInstruction::Call { + ctx.push(UInstruction::Call { dest: temp, f: fe, args: nargs, @@ -176,7 +165,7 @@ impl FnLowerable for PExpr { body.lower(&mut body_ctx); let body = body_ctx.instructions; ctx.program.pop(); - ctx.push(IRUInstruction::If { cond, body }); + ctx.push(UInstruction::If { cond, body }); return None; } PExpr::Loop(body) => { @@ -185,15 +174,15 @@ impl FnLowerable for PExpr { body.lower(&mut body_ctx); let body = body_ctx.instructions; ctx.program.pop(); - ctx.push(IRUInstruction::Loop { body }); + ctx.push(UInstruction::Loop { body }); return None; } PExpr::Break => { - ctx.push(IRUInstruction::Break); + ctx.push(UInstruction::Break); return None; } PExpr::Continue => { - ctx.push(IRUInstruction::Continue); + ctx.push(UInstruction::Continue); return None; } }) diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs index 5a2f354..416f3d4 100644 --- a/src/parser/v3/lower/func.rs +++ b/src/parser/v3/lower/func.rs @@ -1,110 +1,102 @@ use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction}; use crate::{ - ir::{ - FnDef, FnID, IRUFunction, IRUInstrInst, IRUInstruction, IRUProgram, Idents, Type, VarDef, - VarInst, FieldRef, - }, + ir::{FieldRef, FnID, Idents, Type, UFunc, UInstrInst, UInstruction, UProgram, UVar, VarInst}, parser, }; impl Node { - pub fn lower_header(&self, map: &mut IRUProgram, output: &mut CompilerOutput) -> Option { - self.as_ref()?.lower_header(map, output) + pub fn lower_name(&self, p: &mut UProgram) -> Option { + Some(self.as_ref()?.lower_name(p)?) } - pub fn lower_body( - &self, - id: FnID, - map: &mut IRUProgram, - output: &mut CompilerOutput, - ) -> Option { - Some(self.as_ref()?.lower_body(id, map, output)) + pub fn lower(&self, id: FnID, p: &mut UProgram, output: &mut CompilerOutput) { + if let Some(s) = self.as_ref() { + s.lower(id, p, output) + } } } impl PFunction { - pub fn lower_header(&self, map: &mut IRUProgram, output: &mut CompilerOutput) -> Option { + pub fn lower_name(&self, p: &mut UProgram) -> Option { let header = self.header.as_ref()?; let name = header.name.as_ref()?; - let args = header - .args - .iter() - .map(|a| { - a.lower(map, output).unwrap_or(VarDef { - name: "{error}".to_string(), - origin: a.span, - parent: None, - ty: Type::Error, - }) - }) - .collect(); - let ret = match &header.ret { - Some(ty) => ty.lower(map, output), - None => Type::Unit, - }; - Some(map.def_fn(FnDef { - name: name.to_string(), - origin: self.header.span, - args, - ret, - })) + let id = p.def_searchable(name.to_string(), None); + let var = p.def_searchable( + name.to_string(), + Some(UVar { + parent: None, + ty: Type::Error, + origin: self.header.span, + }), + ); + p.fn_map.insert(var, id); + p.inv_fn_map.push(var); + Some(id) } - pub fn lower_body( - &self, - id: FnID, - map: &mut IRUProgram, - output: &mut CompilerOutput, - ) -> IRUFunction { - let def = map.get_fn(id).clone(); - let args = def.args.iter().map(|a| map.named_var(a.clone())).collect(); + pub fn lower(&self, id: FnID, p: &mut UProgram, output: &mut CompilerOutput) { + let (args, ret) = if let Some(header) = self.header.as_ref() { + ( + header + .args + .iter() + .flat_map(|a| Some(a.lower(p, output)?.id)) + .collect(), + match &header.ret { + Some(ty) => ty.lower(p, output), + None => Type::Unit, + }, + ) + } else { + (Vec::new(), Type::Error) + }; let mut ctx = FnLowerCtx { instructions: Vec::new(), - program: map, + program: p, output, span: self.body.span, }; if let Some(src) = self.body.lower(&mut ctx) { - ctx.instructions.push(IRUInstrInst { - i: IRUInstruction::Ret { src }, + ctx.instructions.push(UInstrInst { + i: UInstruction::Ret { src }, span: src.span, }); } - IRUFunction { - name: def.name.clone(), + let origin = self.header.span; + let f = UFunc { + origin, args, - ret: def.ret, + ret, instructions: ctx.instructions, - } + }; + p.expect_mut(p.inv_fn_map[id.0]).ty = f.ty(p); + p.write(id, f) } } pub struct FnLowerCtx<'a> { - pub program: &'a mut IRUProgram, - pub instructions: Vec, + pub program: &'a mut UProgram, + pub instructions: Vec, pub output: &'a mut CompilerOutput, pub span: FileSpan, } impl FnLowerCtx<'_> { - pub fn get(&mut self, node: &Node) -> Option { + pub fn get_idents(&mut self, node: &Node) -> Option { let name = node.inner.as_ref()?; - let res = self.program.get(name); + let res = self.program.get_idents(name); if res.is_none() { self.err_at(node.span, format!("Identifier '{}' not found", name)); } res } pub fn get_var(&mut self, node: &Node) -> Option { - let ids = self.get(node)?; - if ids.var.is_none() { + let ids = self.get_idents(node)?; + if ids.get::().is_none() { self.err_at( node.span, - format!( - "Variable '{}' not found; Type found but cannot be used here", - node.inner.as_ref()? - ), + format!("Variable '{}' not found", node.inner.as_ref()?), ); } - ids.var.map(|id| VarInst { + ids.get::().map(|id| VarInst { id, span: node.span, }) @@ -121,11 +113,11 @@ impl FnLowerCtx<'_> { pub fn temp_subvar(&mut self, ty: Type, parent: FieldRef) -> VarInst { self.program.temp_subvar(self.span, ty, parent) } - pub fn push(&mut self, i: IRUInstruction) { - self.instructions.push(IRUInstrInst { i, span: self.span }); + pub fn push(&mut self, i: UInstruction) { + self.instructions.push(UInstrInst { i, span: self.span }); } - pub fn push_at(&mut self, i: IRUInstruction, span: FileSpan) { - self.instructions.push(IRUInstrInst { i, span }); + pub fn push_at(&mut self, i: UInstruction, span: FileSpan) { + self.instructions.push(UInstrInst { i, span }); } pub fn branch<'a>(&'a mut self) -> FnLowerCtx<'a> { FnLowerCtx { diff --git a/src/parser/v3/lower/module.rs b/src/parser/v3/lower/module.rs index c9c5e4b..fc0c3f2 100644 --- a/src/parser/v3/lower/module.rs +++ b/src/parser/v3/lower/module.rs @@ -1,25 +1,25 @@ -use crate::ir::IRUProgram; +use crate::ir::UProgram; -use super::{PModule, CompilerOutput}; +use super::{CompilerOutput, PModule}; impl PModule { - pub fn lower(&self, p: &mut IRUProgram, output: &mut CompilerOutput) { + pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput) { + let mut structs = Vec::new(); for s in &self.structs { - s.lower(p, output); + structs.push(s.lower_name(p)); + } + for (s, id) in self.structs.iter().zip(structs) { + if let Some(id) = id { + s.lower(id, p, output); + } } let mut fns = Vec::new(); for f in &self.functions { - if let Some(id) = f.lower_header(p, output) { - fns.push(Some(id)); - } else { - fns.push(None) - } + fns.push(f.lower_name(p)); } for (f, id) in self.functions.iter().zip(fns) { if let Some(id) = id { - if let Some(res) = f.lower_body(id, p, output) { - p.write_fn(id, res); - } + f.lower(id, p, output) } } } diff --git a/src/parser/v3/lower/struc.rs b/src/parser/v3/lower/struc.rs index 82b2751..389e067 100644 --- a/src/parser/v3/lower/struc.rs +++ b/src/parser/v3/lower/struc.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use crate::{ common::{CompilerOutput, FileSpan}, - ir::{FieldID, IRUInstruction, IRUProgram, StructDef, StructField, Type, VarInst}, + ir::{FieldID, StructField, StructID, Type, UInstruction, UProgram, UStruct, VarInst}, parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields}, }; @@ -13,7 +13,7 @@ impl FnLowerable for PConstruct { fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let ty = self.name.lower(ctx.program, ctx.output); let field_map = match ty { - Type::Struct { id, .. } => ctx.program.get_struct(id), + Type::Struct { id, .. } => ctx.program.expect(id), _ => { ctx.err(format!( "Type {} cannot be constructed", @@ -62,7 +62,7 @@ impl FnLowerable for PConstruct { PConstructFields::None => Default::default(), }; let id = ctx.temp(ty); - ctx.push(IRUInstruction::Construct { dest: id, fields }); + ctx.push(UInstruction::Construct { dest: id, fields }); Some(id) } } @@ -70,7 +70,8 @@ impl FnLowerable for PConstruct { impl PStruct { pub fn lower( &self, - p: &mut IRUProgram, + id: StructID, + p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan, ) -> Option<()> { @@ -99,23 +100,30 @@ impl PStruct { .into_iter() .enumerate() .map(|(i, (name, ty))| { - let id = FieldID(i); + let id = FieldID::new(i); field_map.insert(name.clone(), id); StructField { name, ty } }) .collect(); - p.def_struct(StructDef { - name: self.name.as_ref()?.to_string(), - origin: span, - field_map, - fields, - }); + p.write( + id, + UStruct { + origin: span, + field_map, + fields, + }, + ); Some(()) } } impl Node { - pub fn lower(&self, p: &mut IRUProgram, output: &mut CompilerOutput) { - self.as_ref().map(|i| i.lower(p, output, self.span)); + pub fn lower_name(&self, p: &mut UProgram) -> Option { + let name = self.as_ref()?.name.as_ref()?.to_string(); + let id = p.def_searchable(name.to_string(), None); + Some(id) + } + pub fn lower(&self, id: StructID, p: &mut UProgram, output: &mut CompilerOutput) { + self.as_ref().map(|i| i.lower(id, p, output, self.span)); } }