diff --git a/data/test.lang b/data/test.lang index ba5a860..9f7fa75 100644 --- a/data/test.lang +++ b/data/test.lang @@ -1,33 +1,33 @@ fn start() { - print("Helld!\n"); - print("Hello World!!!!!\n"); - thinger(); - print("what\n"); - exit(39); + print("Helld!\n"); + print("Hello World!!!!!\n"); + thinger(); + print("what\n"); + exit(39); } fn thinger() { - print("estamos jugando\n"); + print("estamos jugando\n"); } fn unused() { - print("el unused\n"); + print("el unused\n"); } fn print(msg: slice<8>) { - asm (a1 = msg) { - ld a2, 8, a1 - ld a1, 0, a1 - li a0, 1 - li a7, 64 - ecall - } + asm (a1 = msg) { + ld a2, 8, a1 + ld a1, 0, a1 + li a0, 1 + li a7, 64 + ecall + } } fn exit(status: 64) { - asm (a0 = status) { - ld a0, 0, a0 - li a7, 93 - ecall - }; + asm (a0 = status) { + ld a0, 0, a0 + li a7, 93 + ecall + }; } diff --git a/src/ir/file.rs b/src/common/file.rs similarity index 100% rename from src/ir/file.rs rename to src/common/file.rs diff --git a/src/common/mod.rs b/src/common/mod.rs new file mode 100644 index 0000000..7a3c486 --- /dev/null +++ b/src/common/mod.rs @@ -0,0 +1,5 @@ +mod output; +mod file; + +pub use output::*; +pub use file::*; diff --git a/src/common/output.rs b/src/common/output.rs new file mode 100644 index 0000000..87e42ea --- /dev/null +++ b/src/common/output.rs @@ -0,0 +1,64 @@ +use super::{FilePos, FileSpan}; + +#[derive(Debug, Clone)] +pub struct CompilerMsg { + pub msg: String, + pub spans: Vec, +} + +pub struct CompilerOutput { + pub errs: Vec, + pub hints: Vec, +} + +impl CompilerMsg { + pub fn from_msg(msg: String) -> Self { + Self { + msg, + spans: Vec::new(), + } + } + pub fn from_span(span: FileSpan, msg: String) -> Self { + Self { + msg, + spans: vec![span], + } + } + pub fn at(pos: FilePos, msg: String) -> Self { + Self { + msg, + spans: vec![FileSpan::at(pos)], + } + } + pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { + let after = if self.spans.is_empty() { "" } else { ":" }; + writeln!(writer, "{}: {}{}", ty, self.msg, after)?; + for span in &self.spans { + span.write_for(writer, file)?; + } + Ok(()) + } +} + +impl CompilerOutput { + pub fn new() -> Self { + Self { + errs: Vec::new(), + hints: Vec::new(), + } + } + pub fn err(&mut self, msg: CompilerMsg) { + self.errs.push(msg); + } + pub fn hint(&mut self, msg: CompilerMsg) { + self.hints.push(msg); + } + pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) { + for err in &self.errs { + err.write_for("error", out, file).unwrap(); + } + for hint in &self.hints { + hint.write_for("hint", out, file).unwrap(); + } + } +} diff --git a/src/compiler/arch/riscv64/asm.rs b/src/compiler/arch/riscv64/asm.rs index d7d8422..6b76923 100644 --- a/src/compiler/arch/riscv64/asm.rs +++ b/src/compiler/arch/riscv64/asm.rs @@ -10,7 +10,13 @@ pub enum LinkerInstruction { Slli { dest: Reg, src: Reg, imm: i32 }, Srli { dest: Reg, src: Reg, imm: i32 }, Sd { src: Reg, offset: i32, base: Reg }, + Sw { src: Reg, offset: i32, base: Reg }, + Sh { src: Reg, offset: i32, base: Reg }, + Sb { src: Reg, offset: i32, base: Reg }, Ld { dest: Reg, offset: i32, base: Reg }, + Lw { dest: Reg, offset: i32, base: Reg }, + Lh { dest: Reg, offset: i32, base: Reg }, + Lb { dest: Reg, offset: i32, base: Reg }, Mv { dest: Reg, src: Reg }, La { dest: Reg, src: Symbol }, Jal { dest: Reg, offset: i32 }, @@ -36,7 +42,13 @@ impl Instr for LinkerInstruction { Self::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)), Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)), Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base), + Self::Sw { src, offset, base } => sw(*src, BitsI32::new(*offset), *base), + Self::Sh { src, offset, base } => sh(*src, BitsI32::new(*offset), *base), + Self::Sb { src, offset, base } => sb(*src, BitsI32::new(*offset), *base), Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base), + Self::Lw { dest, offset, base } => lw(*dest, BitsI32::new(*offset), *base), + Self::Lh { dest, offset, base } => lh(*dest, BitsI32::new(*offset), *base), + Self::Lb { dest, offset, base } => lb(*dest, BitsI32::new(*offset), *base), Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)), Self::La { dest, src } => { if let Some(addr) = sym_map.get(*src) { diff --git a/src/compiler/arch/riscv64/compile.rs b/src/compiler/arch/riscv64/compile.rs index 93e1d80..9302055 100644 --- a/src/compiler/arch/riscv64/compile.rs +++ b/src/compiler/arch/riscv64/compile.rs @@ -4,7 +4,7 @@ use crate::{ compiler::{arch::riscv64::Reg, create_program, Addr}, ir::{ arch::riscv64::{RV64Instruction as AI, RegRef}, - IRLInstruction as IRI, IRLProgram, Len, Size, Symbol, VarID, + IRLInstruction as IRI, IRLProgram, Len, Size, }, }; @@ -40,6 +40,54 @@ fn mov_mem( len -= 8; off += 8; } + while len >= 4 { + v.extend([ + LI::Lw { + dest: temp, + offset: src_offset + off, + base: src, + }, + LI::Sw { + src: temp, + offset: dest_offset + off, + base: dest, + }, + ]); + len -= 4; + off += 4; + } + while len >= 2 { + v.extend([ + LI::Lh { + dest: temp, + offset: src_offset + off, + base: src, + }, + LI::Sh { + src: temp, + offset: dest_offset + off, + base: dest, + }, + ]); + len -= 2; + off += 2; + } + while len >= 1 { + v.extend([ + LI::Lb { + dest: temp, + offset: src_offset + off, + base: src, + }, + LI::Sb { + src: temp, + offset: dest_offset + off, + base: dest, + }, + ]); + len -= 1; + off += 1; + } } pub fn compile(program: IRLProgram) -> (Vec, Option) { diff --git a/src/compiler/arch/riscv64/single.rs b/src/compiler/arch/riscv64/single.rs index b6e98db..a63f5d7 100644 --- a/src/compiler/arch/riscv64/single.rs +++ b/src/compiler/arch/riscv64/single.rs @@ -13,24 +13,33 @@ pub const fn ebreak() -> I { pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> I { u_type(imm.to_u(), dest, AUIPC) } + pub const fn ld(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { i_type(offset.to_u(), base, width::D, dest, LOAD) } pub const fn lw(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { i_type(offset.to_u(), base, width::W, dest, LOAD) } +pub const fn lh(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { + i_type(offset.to_u(), base, width::H, dest, LOAD) +} pub const fn lb(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { i_type(offset.to_u(), base, width::B, dest, LOAD) } + +pub const fn sd(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { + s_type(src, base, width::D, offset.to_u(), STORE) +} pub const fn sb(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { s_type(src, base, width::B, offset.to_u(), STORE) } +pub const fn sh(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { + s_type(src, base, width::H, offset.to_u(), STORE) +} pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { s_type(src, base, width::W, offset.to_u(), STORE) } -pub const fn sd(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - s_type(src, base, width::D, offset.to_u(), STORE) -} + pub const fn add(dest: Reg, src1: Reg, src2: Reg) -> I { r_type(Bits32::new(0), src2, src1, ADD, dest, OP) } diff --git a/src/ir/arch/riscv64.rs b/src/ir/arch/riscv64.rs index 55ed3dd..b36cfef 100644 --- a/src/ir/arch/riscv64.rs +++ b/src/ir/arch/riscv64.rs @@ -1,17 +1,33 @@ -use crate::{compiler::arch::riscv64::*, ir::VarID}; +use crate::{ + compiler::arch::riscv64::*, + ir::{VarID, VarInst}, +}; #[derive(Copy, Clone)] pub enum RV64Instruction { Ecall, - Li { dest: RegRef, imm: i64 }, - Mv { dest: RegRef, src: RegRef }, - La { dest: RegRef, src: VarID }, - Ld { dest: RegRef, offset: i64, base: RegRef }, + Li { + dest: RegRef, + imm: i64, + }, + Mv { + dest: RegRef, + src: RegRef, + }, + La { + dest: RegRef, + src: VarInst, + }, + Ld { + dest: RegRef, + offset: i64, + base: RegRef, + }, } #[derive(Copy, Clone)] pub enum RegRef { - Var(VarID), + Var(VarInst), Reg(Reg), } diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs index 07f6ea1..06b6360 100644 --- a/src/ir/lower/program.rs +++ b/src/ir/lower/program.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use crate::ir::{FnID, SymbolSpace}; +use crate::ir::SymbolSpace; -use super::{IRLFunction, IRLInstruction, IRUInstruction, Len, Namespace, Symbol, VarID}; +use super::{IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, Type, VarID}; pub struct IRLProgram { sym_space: SymbolSpace, @@ -12,110 +12,116 @@ pub struct IRLProgram { // NOTE: there are THREE places here where I specify size (8) impl IRLProgram { - pub fn create(ns: &Namespace) -> Option { + pub fn create(p: &IRUProgram) -> Result { let mut start = None; - for (i, f) in ns.iter_fns() { - if f?.name == "start" { + for (i, f) in p.iter_fns() { + if f.name == "start" { start = Some(i); } } - let start = start?; + let start = start.ok_or("no start method found")?; let mut builder = SymbolSpace::with_entries(&[start]); let entry = builder.func(&start); while let Some((sym, i)) = builder.pop_fn() { - let f = ns.fns[i.0].as_ref().unwrap(); + let f = p.fns[i.0].as_ref().unwrap(); let mut instrs = Vec::new(); let mut stack = HashMap::new(); let mut makes_call = false; - let mut alloc_stack = |i: &VarID| -> bool { + let mut alloc_stack = |i: VarID| -> bool { let size = *stack - .entry(*i) - .or_insert(ns.size_of_var(i).expect("unsized type")); + .entry(i) + .or_insert(p.size_of_var(i).expect("unsized type")); size == 0 }; for i in &f.instructions { - match i { + match &i.i { IRUInstruction::Mv { dest, src } => { - if alloc_stack(dest) { + if alloc_stack(dest.id) { continue; } instrs.push(IRLInstruction::Mv { - dest: *dest, - src: *src, + dest: dest.id, + src: src.id, }); } IRUInstruction::Ref { dest, src } => { - if alloc_stack(dest) { + if alloc_stack(dest.id) { continue; } instrs.push(IRLInstruction::Ref { - dest: *dest, - src: *src, + dest: dest.id, + src: src.id, }); } IRUInstruction::LoadData { dest, src } => { - if alloc_stack(dest) { + if alloc_stack(dest.id) { continue; } - let data = &ns.data[src.0]; + let data = &p.data[src.0]; let sym = builder.ro_data(src, data); instrs.push(IRLInstruction::LoadData { - dest: *dest, + dest: dest.id, offset: 0, len: data.len() as Len, src: sym, }); } - IRUInstruction::LoadSlice { dest, src, len } => { - if alloc_stack(dest) { + IRUInstruction::LoadSlice { dest, src } => { + if alloc_stack(dest.id) { continue; } - let sym = builder.ro_data(src, &ns.data[src.0]); + let data = &p.data[src.0]; + let def = p.get_data(*src); + let Type::Array(ty, len) = &def.ty else { + return Err(format!("tried to load {} as slice", p.type_name(&def.ty))); + }; + let sym = builder.ro_data(src, data); instrs.push(IRLInstruction::LoadAddr { - dest: *dest, + dest: dest.id, offset: 0, src: sym, }); + let sym = builder.anon_ro_data(&(*len as u64).to_le_bytes()); instrs.push(IRLInstruction::LoadData { - dest: *dest, + dest: dest.id, offset: 8, len: 8, src: sym, }); } IRUInstruction::LoadFn { dest, src } => { - if alloc_stack(dest) { + if alloc_stack(dest.id) { continue; } let sym = builder.func(src); instrs.push(IRLInstruction::LoadAddr { - dest: *dest, + dest: dest.id, offset: 0, src: sym, }); } IRUInstruction::Call { dest, f, args } => { - alloc_stack(dest); + alloc_stack(dest.id); makes_call = true; - let fid = &ns.fn_map[f]; + let fid = &p.fn_map[&f.id]; let sym = builder.func(fid); instrs.push(IRLInstruction::Call { - dest: *dest, + dest: dest.id, f: sym, args: args .iter() - .map(|a| (*a, ns.size_of_var(a).expect("unsized type"))) + .map(|a| (a.id, p.size_of_var(a.id).expect("unsized type"))) .collect(), }); } IRUInstruction::AsmBlock { instructions, args } => { instrs.push(IRLInstruction::AsmBlock { instructions: instructions.clone(), - args: args.clone(), + args: args.iter().cloned().map(|(r, v)| (r, v.id)).collect(), }) } - IRUInstruction::Ret { src } => instrs.push(IRLInstruction::Ret { src: *src }), + IRUInstruction::Ret { src } => instrs.push(IRLInstruction::Ret { src: src.id }), }; } builder.write_fn( @@ -127,7 +133,7 @@ impl IRLProgram { args: f .args .iter() - .map(|a| (*a, ns.size_of_var(a).expect("unsized type"))) + .map(|a| (*a, p.size_of_var(*a).expect("unsized type"))) .collect(), stack, }, @@ -139,7 +145,7 @@ impl IRLProgram { // println!(" {:?}: {}", a, f.name); // } // println!("datas: {}", sym_space.ro_data().len()); - Some(Self { sym_space, entry }) + Ok(Self { sym_space, entry }) } pub fn entry(&self) -> Symbol { diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 68ff9eb..2883df1 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,5 +1,4 @@ mod upper; -mod file; mod lower; mod id; mod asm; @@ -7,5 +6,4 @@ pub mod arch; pub use upper::*; pub use lower::*; -pub use file::*; pub use id::*; diff --git a/src/ir/upper/def.rs b/src/ir/upper/def.rs index da5f9af..97c4314 100644 --- a/src/ir/upper/def.rs +++ b/src/ir/upper/def.rs @@ -1,4 +1,6 @@ -use super::{FileSpan, Type}; +use crate::common::FileSpan; + +use super::Type; use std::fmt::Debug; #[derive(Clone)] @@ -23,6 +25,12 @@ pub struct VarDef { pub origin: Origin, } +#[derive(Clone)] +pub struct DataDef { + pub ty: Type, + pub origin: Origin, +} + #[derive(Debug, Clone, Copy)] pub enum Origin { Builtin, diff --git a/src/ir/upper/error.rs b/src/ir/upper/error.rs new file mode 100644 index 0000000..f2ffe52 --- /dev/null +++ b/src/ir/upper/error.rs @@ -0,0 +1,19 @@ +use crate::common::{CompilerMsg, CompilerOutput, FileSpan}; + +use super::{IRUProgram, Type}; + +impl CompilerOutput { + pub fn check_assign(&mut self, p: &IRUProgram, src: &Type, dest: &Type, span: FileSpan) { + // TODO: spans + if src != dest { + self.err(CompilerMsg { + msg: format!( + "Cannot assign type '{}' to '{}'", + p.type_name(src), + p.type_name(dest) + ), + spans: vec![span], + }); + } + } +} diff --git a/src/ir/upper/func.rs b/src/ir/upper/func.rs index d9c190e..f5fdbe5 100644 --- a/src/ir/upper/func.rs +++ b/src/ir/upper/func.rs @@ -1,52 +1,51 @@ use std::fmt::Write; -use super::{arch::riscv64::RV64Instruction, DataID, FnID, Len, VarID}; -use crate::{compiler::arch::riscv64::Reg, util::Padder}; +use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, VarID}; +use crate::{common::FileSpan, compiler::arch::riscv64::Reg, util::Padder}; pub struct IRUFunction { pub name: String, pub args: Vec, - pub instructions: Vec, + pub instructions: Vec, } pub enum IRUInstruction { Mv { - dest: VarID, - src: VarID, + dest: VarInst, + src: VarInst, }, Ref { - dest: VarID, - src: VarID, + dest: VarInst, + src: VarInst, }, LoadData { - dest: VarID, + dest: VarInst, src: DataID, }, LoadSlice { - dest: VarID, + dest: VarInst, src: DataID, - len: Len, }, LoadFn { - dest: VarID, + dest: VarInst, src: FnID, }, Call { - dest: VarID, - f: VarID, - args: Vec, + dest: VarInst, + f: VarInst, + args: Vec, }, AsmBlock { instructions: Vec, - args: Vec<(Reg, VarID)>, + args: Vec<(Reg, VarInst)>, }, Ret { - src: VarID, + src: VarInst, }, } pub struct IRInstructions { - vec: Vec, + vec: Vec, } impl IRUFunction { @@ -63,8 +62,8 @@ impl IRInstructions { pub fn new() -> Self { Self { vec: Vec::new() } } - pub fn push(&mut self, i: IRUInstruction) { - self.vec.push(i); + pub fn push(&mut self, i: IRUInstruction, span: FileSpan) { + self.vec.push(IRUInstrInst { i, span }); } } @@ -75,7 +74,7 @@ impl std::fmt::Debug for IRUInstruction { Self::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}"), Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"), Self::LoadFn { dest, src } => write!(f, "{dest:?} <- {src:?}"), - Self::LoadSlice { dest, src, len } => write!(f, "{dest:?} <- &[{src:?}; {len}]"), + Self::LoadSlice { dest, src } => write!(f, "{dest:?} <- &[{src:?}]"), Self::Call { dest, f: func, diff --git a/src/ir/upper/inst.rs b/src/ir/upper/inst.rs new file mode 100644 index 0000000..6e93092 --- /dev/null +++ b/src/ir/upper/inst.rs @@ -0,0 +1,27 @@ +use crate::{common::FileSpan, ir::VarID}; +use std::fmt::Debug; + +use super::IRUInstruction; + +#[derive(Clone, Copy)] +pub struct VarInst { + pub id: VarID, + pub span: FileSpan, +} + +pub struct IRUInstrInst { + pub i: IRUInstruction, + pub span: FileSpan, +} + +impl Debug for VarInst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.id) + } +} + +impl Debug for IRUInstrInst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.i) + } +} diff --git a/src/ir/upper/mod.rs b/src/ir/upper/mod.rs index c027275..56992f9 100644 --- a/src/ir/upper/mod.rs +++ b/src/ir/upper/mod.rs @@ -1,10 +1,14 @@ mod def; mod func; mod ty; -mod namespace; +mod program; +mod validate; +mod error; +mod inst; use super::*; pub use def::*; pub use func::*; pub use ty::*; -pub use namespace::*; +pub use program::*; +pub use inst::*; diff --git a/src/ir/upper/namespace.rs b/src/ir/upper/program.rs similarity index 88% rename from src/ir/upper/namespace.rs rename to src/ir/upper/program.rs index f296390..ebf232d 100644 --- a/src/ir/upper/namespace.rs +++ b/src/ir/upper/program.rs @@ -4,12 +4,15 @@ use std::{ ops::{Deref, DerefMut}, }; -use super::*; +use crate::common::FileSpan; -pub struct Namespace { +use super::{inst::VarInst, *}; + +pub struct IRUProgram { pub fn_defs: Vec, pub var_defs: Vec, pub type_defs: Vec, + pub data_defs: Vec, pub fns: Vec>, pub data: Vec>, pub fn_map: HashMap, @@ -17,12 +20,13 @@ pub struct Namespace { pub stack: Vec>, } -impl Namespace { +impl IRUProgram { pub fn new() -> Self { Self { fn_defs: Vec::new(), var_defs: Vec::new(), type_defs: Vec::new(), + data_defs: Vec::new(), data: Vec::new(), fn_map: HashMap::new(), fns: Vec::new(), @@ -49,6 +53,9 @@ impl Namespace { pub fn get_fn(&self, id: FnID) -> &FnDef { &self.fn_defs[id.0] } + pub fn get_data(&self, id: DataID) -> &DataDef { + &self.data_defs[id.0] + } pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> { Some(&self.fn_defs[self.fn_map.get(&id)?.0]) } @@ -90,17 +97,20 @@ impl Namespace { Type::Unit => 0, }) } - pub fn size_of_var(&self, var: &VarID) -> Option { + pub fn size_of_var(&self, var: VarID) -> Option { self.size_of_type(&self.var_defs[var.0].ty) } - pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID { + pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarInst { let v = self.def_var(VarDef { name: format!("temp{}", self.temp), origin: super::Origin::File(origin), ty, }); self.temp += 1; - v + VarInst { + id: v, + span: origin, + } } pub fn def_fn(&mut self, def: FnDef) -> FnID { let i = self.fn_defs.len(); @@ -128,8 +138,9 @@ impl Namespace { self.type_defs.push(def); id } - pub fn def_data(&mut self, bytes: Vec) -> DataID { + 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) } @@ -187,18 +198,17 @@ impl Namespace { self.fns[id.0] = Some(f); } pub fn iter_vars(&self) -> impl Iterator { - (0..self.var_defs.len()) - .map(|i| VarID(i)) - .zip(self.var_defs.iter()) + self.var_defs.iter().enumerate().map(|(i, v)| (VarID(i), v)) } - pub fn iter_fns(&self) -> impl Iterator)> { - (0..self.fns.len()) - .map(|i| FnID(i)) - .zip(self.fns.iter().map(|f| f.as_ref())) + pub fn iter_fns(&self) -> impl Iterator { + self.fns + .iter() + .enumerate() + .flat_map(|(i, f)| Some((FnID(i), f.as_ref()?))) } } -pub struct NamespaceGuard<'a>(&'a mut Namespace); +pub struct NamespaceGuard<'a>(&'a mut IRUProgram); impl Drop for NamespaceGuard<'_> { fn drop(&mut self) { @@ -207,7 +217,7 @@ impl Drop for NamespaceGuard<'_> { } impl Deref for NamespaceGuard<'_> { - type Target = Namespace; + type Target = IRUProgram; fn deref(&self) -> &Self::Target { self.0 } diff --git a/src/ir/upper/ty.rs b/src/ir/upper/ty.rs index 89ac718..3f3cb6e 100644 --- a/src/ir/upper/ty.rs +++ b/src/ir/upper/ty.rs @@ -1,6 +1,6 @@ -use super::{Len, TypeID}; +use super::{IRUInstruction, IRUProgram, Len, TypeID}; -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Type { Concrete(TypeID), Bits(u32), @@ -25,3 +25,20 @@ impl Type { Self::Slice(Box::new(self)) } } + +pub fn resolve_types(ns: &IRUProgram) { + for (i, f) in ns.iter_fns() { + for inst in &f.instructions { + match &inst.i { + IRUInstruction::Mv { dest, src } => todo!(), + IRUInstruction::Ref { dest, src } => todo!(), + IRUInstruction::LoadData { dest, src } => todo!(), + IRUInstruction::LoadSlice { dest, src } => todo!(), + IRUInstruction::LoadFn { dest, src } => todo!(), + IRUInstruction::Call { dest, f, args } => todo!(), + IRUInstruction::AsmBlock { instructions, args } => todo!(), + IRUInstruction::Ret { src } => todo!(), + } + } + } +} diff --git a/src/ir/upper/validate.rs b/src/ir/upper/validate.rs new file mode 100644 index 0000000..407ee6a --- /dev/null +++ b/src/ir/upper/validate.rs @@ -0,0 +1,52 @@ +// TODO: move this into ir, not parser +use super::{IRUProgram, Type}; +use crate::common::CompilerOutput; + +impl IRUProgram { + pub fn validate(&self) -> CompilerOutput { + let mut output = CompilerOutput::new(); + for f in self.fns.iter().flatten() { + for i in &f.instructions { + match &i.i { + super::IRUInstruction::Mv { dest, src } => { + let dest = self.get_var(dest.id); + let src = self.get_var(src.id); + output.check_assign(self, &src.ty, &dest.ty, i.span); + } + super::IRUInstruction::Ref { dest, src } => todo!(), + super::IRUInstruction::LoadData { dest, src } => { + let dest = self.get_var(dest.id); + let src = self.get_data(*src); + output.check_assign(self, &src.ty, &dest.ty, i.span); + } + super::IRUInstruction::LoadSlice { dest, src } => { + let dest = self.get_var(dest.id); + let src = self.get_data(*src); + let Type::Array(srcty, ..) = &src.ty else { + todo!() + }; + output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span); + } + super::IRUInstruction::LoadFn { dest, src } => todo!(), + super::IRUInstruction::Call { dest, f, args } => { + let destty = &self.get_var(dest.id).ty; + let f = self.get_var(f.id); + let Type::Fn { args: argtys, ret } = &f.ty else { + todo!() + }; + output.check_assign(self, ret, destty, 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); + } + } + super::IRUInstruction::AsmBlock { instructions, args } => { + // TODO + } + super::IRUInstruction::Ret { src } => todo!(), + } + } + } + output + } +} diff --git a/src/main.rs b/src/main.rs index abdcebb..9cc250f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #![feature(box_patterns)] #![feature(try_trait_v2)] -use ir::{Namespace, IRLProgram}; +use ir::{IRLProgram, IRUProgram}; use parser::{NodeParsable, PModule, PStatement, ParserCtx}; use std::{ fs::{create_dir_all, OpenOptions}, @@ -11,10 +11,12 @@ use std::{ process::Command, }; +mod common; mod compiler; mod ir; mod parser; mod util; +use common::*; fn main() { let file = std::env::args_os().nth(1); @@ -34,7 +36,7 @@ fn run_file(file: &str, gdb: bool) { // println!("Parsed:"); // println!("{:#?}", res.node); if let Some(module) = res.node.as_ref() { - let mut namespace = Namespace::new(); + let mut namespace = IRUProgram::new(); module.lower(&mut namespace.push(), &mut ctx.output); if ctx.output.errs.is_empty() { // println!("vars:"); @@ -44,10 +46,14 @@ fn run_file(file: &str, gdb: bool) { // for (id, f) in namespace.iter_fns() { // println!("{id:?} = {:#?}", f.unwrap()); // } - let program = IRLProgram::create(&namespace); - let bin = compiler::compile(program.expect("morir")); - println!("compiled"); - save_run(&bin, gdb); + let output = namespace.validate(); + output.write_for(&mut stdout(), file); + if output.errs.is_empty() { + let program = IRLProgram::create(&namespace); + let bin = compiler::compile(program.expect("morir")); + println!("compiled"); + save_run(&bin, gdb); + } } } } diff --git a/src/parser/v3/ctx.rs b/src/parser/v3/ctx.rs index 93c8705..0b31515 100644 --- a/src/parser/v3/ctx.rs +++ b/src/parser/v3/ctx.rs @@ -1,10 +1,13 @@ use std::ops::{Deref, DerefMut}; -use super::{MaybeParsable, Node, NodeParseResult, Parsable, ParserMsg, ParserOutput, TokenCursor}; +use super::{ + MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith, CompilerMsg, CompilerOutput, + TokenCursor, +}; pub struct ParserCtx<'a> { pub cursor: TokenCursor<'a>, - pub output: ParserOutput, + pub output: CompilerOutput, } impl<'a> Deref for ParserCtx<'a> { @@ -22,15 +25,18 @@ impl DerefMut for ParserCtx<'_> { } impl<'a> ParserCtx<'a> { - pub fn err(&mut self, msg: ParserMsg) { + pub fn err(&mut self, msg: CompilerMsg) { self.output.err(msg); } - pub fn hint(&mut self, msg: ParserMsg) { + pub fn hint(&mut self, msg: CompilerMsg) { self.output.hint(msg); } pub fn parse(&mut self) -> NodeParseResult { Node::parse(self) } + pub fn parse_with(&mut self, data: T::Data) -> NodeParseResult { + Node::parse_with(self, data) + } pub fn maybe_parse(&mut self) -> Option> { Node::maybe_parse(self) } @@ -40,7 +46,7 @@ impl<'a> From> for ParserCtx<'a> { fn from(cursor: TokenCursor<'a>) -> Self { Self { cursor, - output: ParserOutput::new(), + output: CompilerOutput::new(), } } } @@ -49,7 +55,7 @@ impl<'a> From<&'a str> for ParserCtx<'a> { fn from(string: &'a str) -> Self { Self { cursor: TokenCursor::from(string), - output: ParserOutput::new(), + output: CompilerOutput::new(), } } } diff --git a/src/parser/v3/cursor.rs b/src/parser/v3/cursor.rs index ae430b0..3cabf9e 100644 --- a/src/parser/v3/cursor.rs +++ b/src/parser/v3/cursor.rs @@ -1,7 +1,7 @@ -use crate::ir::FilePos; - -use super::error::ParserMsg; -use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance}; +use super::{ + token::{CharCursor, Keyword, Symbol, Token, TokenInstance}, + CompilerMsg, FilePos, +}; pub struct TokenCursor<'a> { cursor: CharCursor<'a>, @@ -12,11 +12,7 @@ pub struct TokenCursor<'a> { impl<'a> TokenCursor<'a> { pub fn next(&mut self) -> Option { - self.prev_end = self - .next - .as_ref() - .map(|i| i.span.end) - .unwrap_or(FilePos::start()); + self.prev_end = self.cursor.prev_pos(); let next = TokenInstance::parse(&mut self.cursor); self.next_start = next .as_ref() @@ -24,19 +20,19 @@ impl<'a> TokenCursor<'a> { .unwrap_or(FilePos::start()); std::mem::replace(&mut self.next, next) } - pub fn expect_next(&mut self) -> Result { - self.peek().ok_or(ParserMsg::unexpected_end())?; + pub fn expect_next(&mut self) -> Result { + self.peek().ok_or(CompilerMsg::unexpected_end())?; Ok(self.next().unwrap()) } - pub fn expect_token(&mut self, t: Token) -> Result<(), ParserMsg> { + pub fn expect_token(&mut self, t: Token) -> Result<(), CompilerMsg> { let next = self.expect_next()?; if t == next.token { Ok(()) } else { - Err(ParserMsg::unexpected_token(&next, &format!("{t:?}"))) + Err(CompilerMsg::unexpected_token(&next, &format!("{t:?}"))) } } - pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> { + pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), CompilerMsg> { self.expect_token(Token::Symbol(symbol)) } pub fn next_on_new_line(&mut self) -> bool { @@ -64,14 +60,14 @@ impl<'a> TokenCursor<'a> { self.next(); } } - pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserMsg> { + pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), CompilerMsg> { self.expect_token(Token::Keyword(kw)) } pub fn peek(&self) -> Option<&TokenInstance> { self.next.as_ref() } - pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserMsg> { - self.peek().ok_or(ParserMsg::unexpected_end()) + pub fn expect_peek(&mut self) -> Result<&TokenInstance, CompilerMsg> { + self.peek().ok_or(CompilerMsg::unexpected_end()) } pub fn chars(&mut self) -> &mut CharCursor<'a> { &mut self.cursor diff --git a/src/parser/v3/error.rs b/src/parser/v3/error.rs index db1ebe7..b707240 100644 --- a/src/parser/v3/error.rs +++ b/src/parser/v3/error.rs @@ -1,36 +1,17 @@ -use crate::ir::{FilePos, FileSpan}; +use super::Node; +use super::PIdent; +use super::CompilerMsg; +use super::TokenInstance; -use super::{token::TokenInstance, PIdent, Node}; - -#[derive(Debug, Clone)] -pub struct ParserMsg { - pub msg: String, - pub spans: Vec, -} - -pub struct ParserOutput { - pub errs: Vec, - pub hints: Vec, -} - -impl ParserMsg { +impl CompilerMsg { pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self { - ParserMsg { + CompilerMsg { msg, spans: instances.iter().map(|i| i.span).collect(), } } - pub fn from_msg(msg: String) -> Self { - Self { - msg, - spans: Vec::new(), - } - } - pub fn from_span(span: FileSpan, msg: String) -> Self { - Self { - msg, - spans: vec![span], - } + pub fn unexpected_end() -> Self { + Self::from_msg("unexpected end of input".to_string()) } pub fn identifier_not_found(id: &Node) -> Self { Self { @@ -38,51 +19,11 @@ impl ParserMsg { spans: vec![id.span], } } - pub fn at(pos: FilePos, msg: String) -> Self { - Self { - msg, - spans: vec![FileSpan::at(pos)], - } - } - pub fn unexpected_end() -> Self { - Self::from_msg("unexpected end of input".to_string()) - } pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self { let t = &inst.token; - ParserMsg::from_instances( + CompilerMsg::from_instances( &[inst], format!("unexpected token {t:?}; expected {expected}"), ) } - pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { - let after = if self.spans.is_empty() { "" } else { ":" }; - writeln!(writer, "{}: {}{}", ty, self.msg, after)?; - for span in &self.spans { - span.write_for(writer, file)?; - } - Ok(()) - } -} - -impl ParserOutput { - pub fn new() -> Self { - Self { - errs: Vec::new(), - hints: Vec::new(), - } - } - pub fn err(&mut self, msg: ParserMsg) { - self.errs.push(msg); - } - pub fn hint(&mut self, msg: ParserMsg) { - self.hints.push(msg); - } - pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) { - for err in &self.errs { - err.write_for("error", out, file).unwrap(); - } - for hint in &self.hints { - hint.write_for("hint", out, file).unwrap(); - } - } } diff --git a/src/parser/v3/lower/arch/riscv64.rs b/src/parser/v3/lower/arch/riscv64.rs index 79cb72d..eb2cc92 100644 --- a/src/parser/v3/lower/arch/riscv64.rs +++ b/src/parser/v3/lower/arch/riscv64.rs @@ -3,7 +3,7 @@ use crate::{ compiler::arch::riscv64::*, ir::{ arch::riscv64::{RV64Instruction, RegRef}, - VarID, + VarInst, }, }; @@ -57,7 +57,7 @@ impl RV64Instruction { } } -pub fn arg_to_var(node: &Node, ctx: &mut FnLowerCtx) -> Option { +pub fn arg_to_var(node: &Node, ctx: &mut FnLowerCtx) -> Option { let PAsmArg::Ref(node) = node.inner.as_ref()? else { ctx.err_at( node.span, diff --git a/src/parser/v3/lower/asm.rs b/src/parser/v3/lower/asm.rs index b8dfd46..b65aeb8 100644 --- a/src/parser/v3/lower/asm.rs +++ b/src/parser/v3/lower/asm.rs @@ -1,9 +1,9 @@ use crate::{ compiler::arch::riscv64::Reg, - ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarID}, + ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarInst}, }; -use super::{PAsmBlock, PAsmBlockArg, FnLowerCtx, FnLowerable, PInstruction}; +use super::{FnLowerCtx, FnLowerable, PAsmBlock, PAsmBlockArg, PInstruction}; impl FnLowerable for PInstruction { type Output = RV64Instruction; @@ -43,7 +43,7 @@ impl FnLowerable for PAsmBlock { } impl FnLowerable for PAsmBlockArg { - type Output = (Reg, VarID); + type Output = (Reg, VarInst); fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let var = ctx.get_var(&self.var)?; diff --git a/src/parser/v3/lower/block.rs b/src/parser/v3/lower/block.rs index 39ed048..b735f91 100644 --- a/src/parser/v3/lower/block.rs +++ b/src/parser/v3/lower/block.rs @@ -1,10 +1,10 @@ -use crate::ir::{IRUInstruction, VarID}; +use crate::ir::{IRUInstruction, VarInst}; -use super::{PBlock, FnLowerCtx, FnLowerable, PStatement}; +use super::{FnLowerCtx, FnLowerable, PBlock, PStatement}; impl FnLowerable for PBlock { - type Output = VarID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = VarInst; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let ctx = &mut ctx.sub(); for statement in &self.statements { statement.lower(ctx); @@ -14,20 +14,20 @@ impl FnLowerable for PBlock { } impl FnLowerable for PStatement { - type Output = VarID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = VarInst; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { match self { super::PStatement::Let(def, e) => { let def = def.lower(ctx.map, ctx.output)?; let res = e.lower(ctx); if let Some(res) = res { - ctx.map.name_var(&def, res); + ctx.map.name_var(&def, res.id); } None } super::PStatement::Return(e) => { let src = e.lower(ctx)?; - ctx.push(IRUInstruction::Ret { src }); + ctx.push_at(IRUInstruction::Ret { src }, src.span); None } super::PStatement::Expr(e) => e.lower(ctx), diff --git a/src/parser/v3/lower/def.rs b/src/parser/v3/lower/def.rs index 0e4a3ef..2b8a9cc 100644 --- a/src/parser/v3/lower/def.rs +++ b/src/parser/v3/lower/def.rs @@ -1,12 +1,12 @@ -use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef}; +use crate::ir::{NamespaceGuard, Origin, Type, VarDef}; -use super::{Node, PType, PVarDef, ParserMsg, ParserOutput}; +use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef}; impl Node { pub fn lower( &self, namespace: &mut NamespaceGuard, - output: &mut ParserOutput, + output: &mut CompilerOutput, ) -> Option { let s = self.as_ref()?; let name = s.name.as_ref()?.to_string(); @@ -23,7 +23,7 @@ impl Node { } impl Node { - pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut ParserOutput) -> Type { + pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut CompilerOutput) -> Type { self.as_ref() .map(|t| t.lower(namespace, output, self.span)) .unwrap_or(Type::Error) @@ -34,7 +34,7 @@ impl PType { pub fn lower( &self, namespace: &mut NamespaceGuard, - output: &mut ParserOutput, + output: &mut CompilerOutput, span: FileSpan, ) -> Type { match namespace.get(&self.name).and_then(|ids| ids.ty) { @@ -60,7 +60,7 @@ impl PType { Type::Slice(Box::new(inner)) } _ => { - output.err(ParserMsg::from_span(span, "Type not found".to_string())); + output.err(CompilerMsg::from_span(span, "Type not found".to_string())); Type::Error } } diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs index 8f238dd..f2adb23 100644 --- a/src/parser/v3/lower/expr.rs +++ b/src/parser/v3/lower/expr.rs @@ -1,31 +1,48 @@ use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp}; -use crate::ir::{IRUInstruction, Size, Type, VarID}; +use crate::ir::{DataDef, IRUInstruction, Origin, Type, VarInst}; impl FnLowerable for PExpr { - type Output = VarID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + type Output = VarInst; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { Some(match self { PExpr::Lit(l) => match l.as_ref()? { super::PLiteral::String(s) => { let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice()); let data = s.as_bytes().to_vec(); - let len = data.len() as Size; - let src = ctx.map.def_data(data); - ctx.push(IRUInstruction::LoadSlice { dest, src, len }); + let src = ctx.map.def_data( + DataDef { + ty: Type::Bits(8).arr(data.len() as u32), + origin: Origin::File(l.span), + }, + data, + ); + ctx.push(IRUInstruction::LoadSlice { dest, src }); dest } super::PLiteral::Char(c) => { - let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice()); - let src = ctx.map.def_data(c.to_string().as_bytes().to_vec()); + let ty = Type::Bits(8); + let dest = ctx.map.temp_var(l.span, ty.clone()); + let src = ctx.map.def_data( + DataDef { + ty, + origin: Origin::File(l.span), + }, + c.to_string().as_bytes().to_vec(), + ); ctx.push(IRUInstruction::LoadData { dest, src }); dest } super::PLiteral::Number(n) => { // TODO: temp + let ty = Type::Bits(64); let dest = ctx.map.temp_var(l.span, Type::Bits(64)); - let src = ctx - .map - .def_data(n.whole.parse::().unwrap().to_le_bytes().to_vec()); + let src = ctx.map.def_data( + DataDef { + ty, + origin: Origin::File(l.span), + }, + n.whole.parse::().unwrap().to_le_bytes().to_vec(), + ); ctx.push(IRUInstruction::LoadData { dest, src }); dest } @@ -44,7 +61,7 @@ impl FnLowerable for PExpr { let res = e.lower(ctx)?; match op { UnaryOp::Ref => { - let temp = ctx.temp(ctx.map.get_var(res).ty.clone()); + let temp = ctx.temp(ctx.map.get_var(res.id).ty.clone()); ctx.push(IRUInstruction::Ref { dest: temp, src: res, @@ -52,7 +69,7 @@ impl FnLowerable for PExpr { temp } UnaryOp::Deref => { - let t = &ctx.map.get_var(res).ty; + let t = &ctx.map.get_var(res.id).ty; let Type::Ref(inner) = t else { ctx.err(format!( "Cannot dereference type {:?}", @@ -77,7 +94,7 @@ impl FnLowerable for PExpr { let arg = arg.lower(ctx)?; nargs.push(arg); } - let def = ctx.map.get_fn_var(fe); + let def = ctx.map.get_fn_var(fe.id); let ty = match def { Some(def) => def.ret.clone(), None => { @@ -85,7 +102,7 @@ impl FnLowerable for PExpr { e.span, format!( "Expected function, found {}", - ctx.map.type_name(&ctx.map.get_var(fe).ty) + ctx.map.type_name(&ctx.map.get_var(fe.id).ty) ), ); Type::Error @@ -100,6 +117,7 @@ impl FnLowerable for PExpr { temp } PExpr::Group(e) => e.lower(ctx)?, + PExpr::Construct(c) => todo!(), }) } } diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs index 9487fd0..e10b12b 100644 --- a/src/parser/v3/lower/func.rs +++ b/src/parser/v3/lower/func.rs @@ -1,8 +1,8 @@ -use super::{FnLowerable, Node, PFunction, ParserMsg, ParserOutput}; +use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction}; use crate::{ ir::{ - FileSpan, FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, - Origin, Type, VarDef, VarID, + FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, Origin, + Type, VarDef, VarID, VarInst, }, parser, }; @@ -11,7 +11,7 @@ impl Node { pub fn lower_header( &self, map: &mut NamespaceGuard, - output: &mut ParserOutput, + output: &mut CompilerOutput, ) -> Option { self.as_ref()?.lower_header(map, output) } @@ -19,7 +19,7 @@ impl Node { &self, id: FnID, map: &mut NamespaceGuard, - output: &mut ParserOutput, + output: &mut CompilerOutput, ) -> Option { Some(self.as_ref()?.lower_body(id, map, output)) } @@ -29,7 +29,7 @@ impl PFunction { pub fn lower_header( &self, map: &mut NamespaceGuard, - output: &mut ParserOutput, + output: &mut CompilerOutput, ) -> Option { let header = self.header.as_ref()?; let name = header.name.as_ref()?; @@ -59,7 +59,7 @@ impl PFunction { &self, id: FnID, map: &mut NamespaceGuard, - output: &mut ParserOutput, + output: &mut CompilerOutput, ) -> IRUFunction { let mut instructions = IRInstructions::new(); let def = map.get_fn(id).clone(); @@ -71,7 +71,7 @@ impl PFunction { span: self.body.span, }; if let Some(src) = self.body.lower(&mut ctx) { - instructions.push(IRUInstruction::Ret { src }); + instructions.push(IRUInstruction::Ret { src }, src.span); } IRUFunction::new(def.name.clone(), args, instructions) } @@ -80,7 +80,7 @@ impl PFunction { pub struct FnLowerCtx<'a, 'n> { pub map: &'a mut NamespaceGuard<'n>, pub instructions: &'a mut IRInstructions, - pub output: &'a mut ParserOutput, + pub output: &'a mut CompilerOutput, pub span: FileSpan, } @@ -101,7 +101,7 @@ impl<'n> FnLowerCtx<'_, 'n> { } res } - pub fn get_var(&mut self, node: &Node) -> Option { + pub fn get_var(&mut self, node: &Node) -> Option { let ids = self.get(node)?; if ids.var.is_none() { self.err_at( @@ -112,19 +112,25 @@ impl<'n> FnLowerCtx<'_, 'n> { ), ); } - ids.var + ids.var.map(|id| VarInst { + id, + span: node.span, + }) } pub fn err(&mut self, msg: String) { - self.output.err(ParserMsg::from_span(self.span, msg)) + self.output.err(CompilerMsg::from_span(self.span, msg)) } pub fn err_at(&mut self, span: FileSpan, msg: String) { - self.output.err(ParserMsg::from_span(span, msg)) + self.output.err(CompilerMsg::from_span(span, msg)) } - pub fn temp(&mut self, ty: Type) -> VarID { + pub fn temp(&mut self, ty: Type) -> VarInst { self.map.temp_var(self.span, ty) } pub fn push(&mut self, i: IRUInstruction) { - self.instructions.push(i); + self.instructions.push(i, self.span); + } + pub fn push_at(&mut self, i: IRUInstruction, span: FileSpan) { + self.instructions.push(i, span); } pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> { FnLowerCtx { diff --git a/src/parser/v3/lower/module.rs b/src/parser/v3/lower/module.rs index 22defa2..4d190c5 100644 --- a/src/parser/v3/lower/module.rs +++ b/src/parser/v3/lower/module.rs @@ -1,9 +1,9 @@ use crate::ir::NamespaceGuard; -use super::{PModule, ParserOutput}; +use super::{PModule, CompilerOutput}; impl PModule { - pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) { + pub fn lower(&self, map: &mut NamespaceGuard, output: &mut CompilerOutput) { let mut fns = Vec::new(); for f in &self.functions { if let Some(id) = f.lower_header(map, output) { diff --git a/src/parser/v3/mod.rs b/src/parser/v3/mod.rs index 8d3f489..682858f 100644 --- a/src/parser/v3/mod.rs +++ b/src/parser/v3/mod.rs @@ -1,3 +1,4 @@ +mod ctx; mod cursor; mod error; mod lower; @@ -5,13 +6,11 @@ mod node; mod nodes; mod parse; mod token; -mod ctx; +use crate::common::{CompilerMsg, CompilerOutput, FileSpan, FilePos}; +pub use ctx::*; pub use cursor::*; -pub use error::*; -pub use lower::*; pub use node::*; pub use nodes::*; pub use parse::*; pub use token::*; -pub use ctx::*; diff --git a/src/parser/v3/node.rs b/src/parser/v3/node.rs index e591566..28eb2d7 100644 --- a/src/parser/v3/node.rs +++ b/src/parser/v3/node.rs @@ -3,7 +3,7 @@ use std::{ ops::{Deref, DerefMut}, }; -use crate::ir::FileSpan; +use super::FileSpan; pub struct Node { pub inner: Option, @@ -46,4 +46,3 @@ impl Debug for Node { } } } - diff --git a/src/parser/v3/nodes/asm_instr.rs b/src/parser/v3/nodes/asm_instr.rs index e4305a0..4fdb04b 100644 --- a/src/parser/v3/nodes/asm_instr.rs +++ b/src/parser/v3/nodes/asm_instr.rs @@ -1,4 +1,4 @@ -use super::{PIdent, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol}; +use super::{Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg}; pub struct PInstruction { pub op: Node, @@ -38,7 +38,7 @@ impl Parsable for PAsmArg { let next = ctx.expect_peek()?; if !next.is_symbol(Symbol::OpenCurly) { - return ParseResult::Err(ParserMsg::unexpected_token( + return ParseResult::Err(CompilerMsg::unexpected_token( next, "An identifier or {identifier}", )); diff --git a/src/parser/v3/nodes/block.rs b/src/parser/v3/nodes/block.rs index 62d09aa..7d62e66 100644 --- a/src/parser/v3/nodes/block.rs +++ b/src/parser/v3/nodes/block.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Write}; use super::{ - token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement, + token::Symbol, Node, NodeParsable, PStatement, Parsable, ParseResult, ParserCtx, CompilerMsg, }; use crate::util::Padder; @@ -24,7 +24,7 @@ impl Parsable for PBlock { loop { let Some(next) = ctx.peek() else { recover = true; - ctx.err(ParserMsg::unexpected_end()); + ctx.err(CompilerMsg::unexpected_end()); break; }; if next.is_symbol(Symbol::CloseCurly) { @@ -36,7 +36,7 @@ impl Parsable for PBlock { expect_semi = false; continue; } else if expect_semi { - ctx.err(ParserMsg { + ctx.err(CompilerMsg { msg: "expected ';'".to_string(), spans: vec![ctx.next_start().char_span()], }); diff --git a/src/parser/v3/nodes/def.rs b/src/parser/v3/nodes/def.rs index c0f0698..128ebb4 100644 --- a/src/parser/v3/nodes/def.rs +++ b/src/parser/v3/nodes/def.rs @@ -1,7 +1,8 @@ use std::fmt::Debug; use super::{ - PIdent, MaybeParsable, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token, PType, + MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx, Symbol, + Token, CompilerMsg }; pub struct PVarDef { @@ -9,6 +10,11 @@ pub struct PVarDef { pub ty: Option>, } +pub struct PFieldDef { + pub name: Node, + pub val: Option>, +} + impl Parsable for PVarDef { fn parse(ctx: &mut ParserCtx) -> ParseResult { let name = ctx.parse()?; @@ -21,6 +27,21 @@ impl Parsable for PVarDef { } } +impl Parsable for PFieldDef { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let name = ctx.parse()?; + if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) { + ctx.next(); + ctx.parse().map(|ty| Self { + name, + val: Some(ty), + }) + } else { + ParseResult::Ok(Self { name, val: None }) + } + } +} + pub struct SelfVar { pub ty: SelfType, } @@ -32,7 +53,7 @@ pub enum SelfType { } impl MaybeParsable for SelfVar { - fn maybe_parse(ctx: &mut ParserCtx) -> Result, super::ParserMsg> { + fn maybe_parse(ctx: &mut ParserCtx) -> Result, CompilerMsg> { if let Some(mut next) = ctx.peek() { let mut ty = SelfType::Take; if next.is_symbol(Symbol::Ampersand) { @@ -47,7 +68,7 @@ impl MaybeParsable for SelfVar { } } if ty != SelfType::Take { - return Err(ParserMsg::unexpected_token(next, "self")); + return Err(CompilerMsg::unexpected_token(next, "self")); } } Ok(None) @@ -64,6 +85,16 @@ impl Debug for PVarDef { } } +impl Debug for PFieldDef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.name.fmt(f)?; + if let Some(val) = &self.val { + write!(f, ": {:?}", val)?; + } + Ok(()) + } +} + impl Debug for SelfVar { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( diff --git a/src/parser/v3/nodes/expr.rs b/src/parser/v3/nodes/expr.rs index 04ddcd4..f0c507f 100644 --- a/src/parser/v3/nodes/expr.rs +++ b/src/parser/v3/nodes/expr.rs @@ -1,10 +1,7 @@ use std::fmt::{Debug, Write}; use super::{ - op::{PInfixOp, UnaryOp}, - util::parse_list, - PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx, - ParserMsg, Symbol, + op::{PInfixOp, UnaryOp}, util::parse_list, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg }; type BoxNode = Node>; @@ -18,6 +15,7 @@ pub enum PExpr { Call(BoxNode, Vec>), Group(BoxNode), AsmBlock(Node), + Construct(Node), } impl Parsable for PExpr { @@ -63,7 +61,7 @@ impl Parsable for PExpr { Self::Ident(res.node) } else { let next = ctx.expect_peek()?; - return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression")); + return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression")); } }; let Some(mut next) = ctx.peek() else { @@ -140,6 +138,7 @@ impl Debug for PExpr { } PExpr::Group(inner) => inner.fmt(f)?, PExpr::AsmBlock(inner) => inner.fmt(f)?, + PExpr::Construct(inner) => inner.fmt(f)?, } Ok(()) } diff --git a/src/parser/v3/nodes/ident.rs b/src/parser/v3/nodes/ident.rs index d329d77..bb80ffd 100644 --- a/src/parser/v3/nodes/ident.rs +++ b/src/parser/v3/nodes/ident.rs @@ -1,4 +1,4 @@ -use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token}; +use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, Token, CompilerMsg}; use std::{ fmt::{Debug, Display}, ops::Deref, @@ -11,7 +11,7 @@ impl Parsable for PIdent { fn parse(ctx: &mut ParserCtx) -> ParseResult { let next = ctx.expect_peek()?; let Token::Word(name) = &next.token else { - return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier")); + return ParseResult::Err(CompilerMsg::unexpected_token(next, "an identifier")); }; let name = name.to_string(); ctx.next(); @@ -20,7 +20,7 @@ impl Parsable for PIdent { } impl MaybeParsable for PIdent { - fn maybe_parse(ctx: &mut ParserCtx) -> Result, ParserMsg> { + fn maybe_parse(ctx: &mut ParserCtx) -> Result, CompilerMsg> { let Some(next) = ctx.peek() else { return Ok(None) }; let Token::Word(name) = &next.token else { return Ok(None); diff --git a/src/parser/v3/nodes/lit.rs b/src/parser/v3/nodes/lit.rs index f2ac6e9..dba05c1 100644 --- a/src/parser/v3/nodes/lit.rs +++ b/src/parser/v3/nodes/lit.rs @@ -1,4 +1,4 @@ -use super::{CharCursor, MaybeParsable, ParserCtx, ParserMsg, Symbol, Token}; +use super::{CharCursor, MaybeParsable, ParserCtx, CompilerMsg, Symbol, Token}; use std::fmt::Debug; #[derive(Clone, PartialEq, Eq)] @@ -17,7 +17,7 @@ pub struct PNumber { } impl MaybeParsable for PLiteral { - fn maybe_parse(ctx: &mut ParserCtx) -> Result, ParserMsg> { + fn maybe_parse(ctx: &mut ParserCtx) -> Result, CompilerMsg> { let inst = ctx.expect_peek()?; Ok(Some(match &inst.token { Token::Symbol(Symbol::SingleQuote) => { @@ -37,7 +37,7 @@ impl MaybeParsable for PLiteral { if !first.is_ascii_digit() { return Ok(None); } - let (whole, ty) = parse_whole_num(text); + let (whole, ty) = parse_whole_num(&text); let mut num = PNumber { whole, decimal: None, @@ -81,7 +81,7 @@ pub fn parse_whole_num(text: &str) -> (String, Option) { (whole, if ty.is_empty() { None } else { Some(ty) }) } -pub fn string_from(cursor: &mut CharCursor) -> Result { +pub fn string_from(cursor: &mut CharCursor) -> Result { let mut str = String::new(); loop { let c = cursor.expect_next()?; diff --git a/src/parser/v3/nodes/module.rs b/src/parser/v3/nodes/module.rs index 2f74e05..2db6556 100644 --- a/src/parser/v3/nodes/module.rs +++ b/src/parser/v3/nodes/module.rs @@ -1,5 +1,5 @@ use super::{ - PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, + PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, CompilerMsg, PStruct, Symbol, Token, PTrait, }; use std::fmt::Debug; @@ -52,18 +52,18 @@ impl Parsable for PModule { } } _ => { - ctx.err(ParserMsg::unexpected_token(next, "a definition")); + ctx.err(CompilerMsg::unexpected_token(next, "a definition")); ctx.next(); } } } else if next.is_symbol(Symbol::Semicolon) { - ctx.hint(ParserMsg::from_instances( + ctx.hint(CompilerMsg::from_instances( &[next], "unneeded semicolon".to_string(), )); ctx.next(); } else { - ctx.err(ParserMsg::unexpected_token(next, "a definition")); + ctx.err(CompilerMsg::unexpected_token(next, "a definition")); ctx.next(); } } diff --git a/src/parser/v3/nodes/struc.rs b/src/parser/v3/nodes/struc.rs index a804c00..1f45755 100644 --- a/src/parser/v3/nodes/struc.rs +++ b/src/parser/v3/nodes/struc.rs @@ -1,8 +1,8 @@ use std::fmt::Debug; use super::{ - util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, - PType, PVarDef, + util::parse_list, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef, Parsable, + ParseResult, ParserCtx, CompilerMsg, Symbol, }; #[derive(Debug)] @@ -11,6 +11,12 @@ pub struct PStruct { pub fields: PStructFields, } +#[derive(Debug)] +pub struct PConstruct { + pub name: Node, + pub fields: PConstructFields, +} + #[derive(Debug)] pub enum PStructFields { Named(Vec>), @@ -18,6 +24,13 @@ pub enum PStructFields { None, } +#[derive(Debug)] +pub enum PConstructFields { + Named(Vec>), + Tuple(Vec>), + None, +} + impl Parsable for PStruct { fn parse(ctx: &mut ParserCtx) -> ParseResult { ctx.expect_kw(Keyword::Struct)?; @@ -33,7 +46,7 @@ impl Parsable for PStruct { ctx.next(); PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?) } else { - let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`"); + let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`"); ctx.err(msg); return ParseResult::Recover(PStruct { name, @@ -43,3 +56,29 @@ impl Parsable for PStruct { ParseResult::Ok(PStruct { name, fields }) } } + +impl Parsable for PConstruct { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + ctx.expect_kw(Keyword::Struct)?; + let name = ctx.parse()?; + let next = ctx.expect_peek()?; + let fields = if next.is_symbol(Symbol::Semicolon) { + ctx.next(); + PConstructFields::None + } else if next.is_symbol(Symbol::OpenCurly) { + ctx.next(); + PConstructFields::Named(parse_list(ctx, Symbol::CloseCurly)?) + } else if next.is_symbol(Symbol::OpenParen) { + ctx.next(); + PConstructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?) + } else { + let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`"); + ctx.err(msg); + return ParseResult::Recover(PConstruct { + name, + fields: PConstructFields::None, + }); + }; + ParseResult::Ok(PConstruct { name, fields }) + } +} diff --git a/src/parser/v3/nodes/ty.rs b/src/parser/v3/nodes/ty.rs index e1b4e37..1756432 100644 --- a/src/parser/v3/nodes/ty.rs +++ b/src/parser/v3/nodes/ty.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token}; +use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, CompilerMsg, Symbol, Token}; pub struct PType { pub name: String, @@ -19,7 +19,7 @@ impl Parsable for PType { } } else { let Token::Word(name) = &next.token else { - return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier")); + return ParseResult::Err(CompilerMsg::unexpected_token(next, "a type identifier")); }; let n = name.to_string(); ctx.next(); diff --git a/src/parser/v3/nodes/util.rs b/src/parser/v3/nodes/util.rs index e307c4f..e5e9c85 100644 --- a/src/parser/v3/nodes/util.rs +++ b/src/parser/v3/nodes/util.rs @@ -1,10 +1,10 @@ -use super::{Node, Parsable, ParserCtx, ParserMsg, Symbol}; +use super::{Node, Parsable, ParserCtx, CompilerMsg, Symbol}; pub fn parse_list_sep( ctx: &mut ParserCtx, sep: Symbol, end: Symbol, -) -> Result>, ParserMsg> { +) -> Result>, CompilerMsg> { let mut vals = Vec::new(); loop { let next = ctx.expect_peek()?; @@ -29,14 +29,14 @@ pub fn parse_list_sep( pub fn parse_list( ctx: &mut ParserCtx, end: Symbol, -) -> Result>, ParserMsg> { +) -> Result>, CompilerMsg> { parse_list_sep(ctx, Symbol::Comma, end) } pub fn parse_list_nosep( ctx: &mut ParserCtx, end: Symbol, -) -> Result>, ParserMsg> { +) -> Result>, CompilerMsg> { let mut vals = Vec::new(); loop { let next = ctx.expect_peek()?; diff --git a/src/parser/v3/parse.rs b/src/parser/v3/parse.rs index 1cc15cb..6292acb 100644 --- a/src/parser/v3/parse.rs +++ b/src/parser/v3/parse.rs @@ -3,14 +3,12 @@ use std::{ ops::{ControlFlow, FromResidual, Try}, }; -use crate::ir::FilePos; - -use super::{Node, ParserCtx, ParserMsg}; +use super::{CompilerMsg, FilePos, Node, ParserCtx}; pub enum ParseResult { Ok(T), Recover(T), - Err(ParserMsg), + Err(CompilerMsg), SubErr, } @@ -26,7 +24,7 @@ impl ParseResult { impl Try for ParseResult { type Output = T; - type Residual = Option; + type Residual = Option; fn from_output(output: Self::Output) -> Self { Self::Ok(output) } @@ -50,8 +48,8 @@ impl FromResidual for ParseResult { } } -impl FromResidual> for ParseResult { - fn from_residual(residual: Result) -> Self { +impl FromResidual> for ParseResult { + fn from_residual(residual: Result) -> Self { match residual { Err(e) => Self::Err(e), } @@ -115,14 +113,28 @@ pub trait Parsable: Sized { fn parse(ctx: &mut ParserCtx) -> ParseResult; } -pub trait MaybeParsable: Sized { - fn maybe_parse(ctx: &mut ParserCtx) -> Result, ParserMsg>; +pub trait ParsableWith: Sized { + type Data; + + fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult; } -impl Node { - pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult { +pub trait MaybeParsable: Sized { + fn maybe_parse(ctx: &mut ParserCtx) -> Result, CompilerMsg>; +} + +impl ParsableWith for T { + type Data = (); + + fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult { + T::parse(ctx) + } +} + +impl Node { + pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult { let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start()); - let (inner, recover) = match T::parse(ctx) { + let (inner, recover) = match T::parse(ctx, data) { ParseResult::Ok(v) => (Some(v), false), ParseResult::Recover(v) => (Some(v), true), ParseResult::Err(e) => { @@ -142,6 +154,12 @@ impl Node { } } +impl Node { + pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult { + Node::parse_with(ctx, ()) + } +} + impl Node { pub fn maybe_parse(ctx: &mut ParserCtx) -> Option { let start = ctx.next_start(); diff --git a/src/parser/v3/token/cursor.rs b/src/parser/v3/token/cursor.rs index 765b378..4aa0fb3 100644 --- a/src/parser/v3/token/cursor.rs +++ b/src/parser/v3/token/cursor.rs @@ -1,7 +1,6 @@ use std::{iter::Peekable, str::Chars}; -use super::super::ParserMsg; -use crate::ir::FilePos; +use super::super::{CompilerMsg, FilePos}; pub struct CharCursor<'a> { chars: Peekable>, @@ -15,12 +14,12 @@ impl CharCursor<'_> { self.advance(); Some(res) } - pub fn expect(&mut self, c: char) -> Result<(), ParserMsg> { + pub fn expect(&mut self, c: char) -> Result<(), CompilerMsg> { let next = self.expect_next()?; if next == c { Ok(()) } else { - Err(ParserMsg::at( + Err(CompilerMsg::at( self.prev_pos, format!("unexpected char '{next}'; expected '{c}'"), )) @@ -46,8 +45,8 @@ impl CharCursor<'_> { self.next_pos.col += 1; } } - pub fn expect_next(&mut self) -> Result { - self.next().ok_or(ParserMsg::unexpected_end()) + pub fn expect_next(&mut self) -> Result { + self.next().ok_or(CompilerMsg::unexpected_end()) } pub fn next_pos(&self) -> FilePos { self.next_pos diff --git a/src/parser/v3/token/mod.rs b/src/parser/v3/token/mod.rs index 2679231..0624702 100644 --- a/src/parser/v3/token/mod.rs +++ b/src/parser/v3/token/mod.rs @@ -7,8 +7,7 @@ use std::ops::Deref; pub use cursor::*; pub use keyword::*; pub use symbol::*; - -use crate::ir::FileSpan; +use super::FileSpan; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Token {