type checking !?!?

This commit is contained in:
2025-03-22 14:40:32 -04:00
parent 606cb30c6b
commit 7f809d797c
44 changed files with 664 additions and 314 deletions

View File

@@ -1,33 +1,33 @@
fn start() { fn start() {
print("Helld!\n"); print("Helld!\n");
print("Hello World!!!!!\n"); print("Hello World!!!!!\n");
thinger(); thinger();
print("what\n"); print("what\n");
exit(39); exit(39);
} }
fn thinger() { fn thinger() {
print("estamos jugando\n"); print("estamos jugando\n");
} }
fn unused() { fn unused() {
print("el unused\n"); print("el unused\n");
} }
fn print(msg: slice<8>) { fn print(msg: slice<8>) {
asm (a1 = msg) { asm (a1 = msg) {
ld a2, 8, a1 ld a2, 8, a1
ld a1, 0, a1 ld a1, 0, a1
li a0, 1 li a0, 1
li a7, 64 li a7, 64
ecall ecall
} }
} }
fn exit(status: 64) { fn exit(status: 64) {
asm (a0 = status) { asm (a0 = status) {
ld a0, 0, a0 ld a0, 0, a0
li a7, 93 li a7, 93
ecall ecall
}; };
} }

5
src/common/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
mod output;
mod file;
pub use output::*;
pub use file::*;

64
src/common/output.rs Normal file
View File

@@ -0,0 +1,64 @@
use super::{FilePos, FileSpan};
#[derive(Debug, Clone)]
pub struct CompilerMsg {
pub msg: String,
pub spans: Vec<FileSpan>,
}
pub struct CompilerOutput {
pub errs: Vec<CompilerMsg>,
pub hints: Vec<CompilerMsg>,
}
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();
}
}
}

View File

@@ -10,7 +10,13 @@ pub enum LinkerInstruction {
Slli { dest: Reg, src: Reg, imm: i32 }, Slli { dest: Reg, src: Reg, imm: i32 },
Srli { dest: Reg, src: Reg, imm: i32 }, Srli { dest: Reg, src: Reg, imm: i32 },
Sd { src: Reg, offset: i32, base: Reg }, 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 }, 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 }, Mv { dest: Reg, src: Reg },
La { dest: Reg, src: Symbol }, La { dest: Reg, src: Symbol },
Jal { dest: Reg, offset: i32 }, 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::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)),
Self::Srli { dest, src, imm } => srli(*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::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::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::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)),
Self::La { dest, src } => { Self::La { dest, src } => {
if let Some(addr) = sym_map.get(*src) { if let Some(addr) = sym_map.get(*src) {

View File

@@ -4,7 +4,7 @@ use crate::{
compiler::{arch::riscv64::Reg, create_program, Addr}, compiler::{arch::riscv64::Reg, create_program, Addr},
ir::{ ir::{
arch::riscv64::{RV64Instruction as AI, RegRef}, 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; len -= 8;
off += 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<u8>, Option<Addr>) { pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {

View File

@@ -13,24 +13,33 @@ pub const fn ebreak() -> I {
pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> I { pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> I {
u_type(imm.to_u(), dest, AUIPC) u_type(imm.to_u(), dest, AUIPC)
} }
pub const fn ld(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { pub const fn ld(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
i_type(offset.to_u(), base, width::D, dest, LOAD) i_type(offset.to_u(), base, width::D, dest, LOAD)
} }
pub const fn lw(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { pub const fn lw(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
i_type(offset.to_u(), base, width::W, dest, LOAD) 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 { pub const fn lb(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
i_type(offset.to_u(), base, width::B, dest, LOAD) 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 { pub const fn sb(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
s_type(src, base, width::B, offset.to_u(), STORE) 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 { pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
s_type(src, base, width::W, offset.to_u(), STORE) 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 { pub const fn add(dest: Reg, src1: Reg, src2: Reg) -> I {
r_type(Bits32::new(0), src2, src1, ADD, dest, OP) r_type(Bits32::new(0), src2, src1, ADD, dest, OP)
} }

View File

@@ -1,17 +1,33 @@
use crate::{compiler::arch::riscv64::*, ir::VarID}; use crate::{
compiler::arch::riscv64::*,
ir::{VarID, VarInst},
};
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum RV64Instruction { pub enum RV64Instruction {
Ecall, Ecall,
Li { dest: RegRef, imm: i64 }, Li {
Mv { dest: RegRef, src: RegRef }, dest: RegRef,
La { dest: RegRef, src: VarID }, imm: i64,
Ld { dest: RegRef, offset: i64, base: RegRef }, },
Mv {
dest: RegRef,
src: RegRef,
},
La {
dest: RegRef,
src: VarInst,
},
Ld {
dest: RegRef,
offset: i64,
base: RegRef,
},
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum RegRef { pub enum RegRef {
Var(VarID), Var(VarInst),
Reg(Reg), Reg(Reg),
} }

View File

@@ -1,8 +1,8 @@
use std::collections::HashMap; 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 { pub struct IRLProgram {
sym_space: SymbolSpace, sym_space: SymbolSpace,
@@ -12,110 +12,116 @@ pub struct IRLProgram {
// NOTE: there are THREE places here where I specify size (8) // NOTE: there are THREE places here where I specify size (8)
impl IRLProgram { impl IRLProgram {
pub fn create(ns: &Namespace) -> Option<Self> { pub fn create(p: &IRUProgram) -> Result<Self, String> {
let mut start = None; let mut start = None;
for (i, f) in ns.iter_fns() { for (i, f) in p.iter_fns() {
if f?.name == "start" { if f.name == "start" {
start = Some(i); start = Some(i);
} }
} }
let start = start?; let start = start.ok_or("no start method found")?;
let mut builder = SymbolSpace::with_entries(&[start]); let mut builder = SymbolSpace::with_entries(&[start]);
let entry = builder.func(&start); let entry = builder.func(&start);
while let Some((sym, i)) = builder.pop_fn() { 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 instrs = Vec::new();
let mut stack = HashMap::new(); let mut stack = HashMap::new();
let mut makes_call = false; let mut makes_call = false;
let mut alloc_stack = |i: &VarID| -> bool { let mut alloc_stack = |i: VarID| -> bool {
let size = *stack let size = *stack
.entry(*i) .entry(i)
.or_insert(ns.size_of_var(i).expect("unsized type")); .or_insert(p.size_of_var(i).expect("unsized type"));
size == 0 size == 0
}; };
for i in &f.instructions { for i in &f.instructions {
match i { match &i.i {
IRUInstruction::Mv { dest, src } => { IRUInstruction::Mv { dest, src } => {
if alloc_stack(dest) { if alloc_stack(dest.id) {
continue; continue;
} }
instrs.push(IRLInstruction::Mv { instrs.push(IRLInstruction::Mv {
dest: *dest, dest: dest.id,
src: *src, src: src.id,
}); });
} }
IRUInstruction::Ref { dest, src } => { IRUInstruction::Ref { dest, src } => {
if alloc_stack(dest) { if alloc_stack(dest.id) {
continue; continue;
} }
instrs.push(IRLInstruction::Ref { instrs.push(IRLInstruction::Ref {
dest: *dest, dest: dest.id,
src: *src, src: src.id,
}); });
} }
IRUInstruction::LoadData { dest, src } => { IRUInstruction::LoadData { dest, src } => {
if alloc_stack(dest) { if alloc_stack(dest.id) {
continue; continue;
} }
let data = &ns.data[src.0]; let data = &p.data[src.0];
let sym = builder.ro_data(src, data); let sym = builder.ro_data(src, data);
instrs.push(IRLInstruction::LoadData { instrs.push(IRLInstruction::LoadData {
dest: *dest, dest: dest.id,
offset: 0, offset: 0,
len: data.len() as Len, len: data.len() as Len,
src: sym, src: sym,
}); });
} }
IRUInstruction::LoadSlice { dest, src, len } => { IRUInstruction::LoadSlice { dest, src } => {
if alloc_stack(dest) { if alloc_stack(dest.id) {
continue; 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 { instrs.push(IRLInstruction::LoadAddr {
dest: *dest, dest: dest.id,
offset: 0, offset: 0,
src: sym, src: sym,
}); });
let sym = builder.anon_ro_data(&(*len as u64).to_le_bytes()); let sym = builder.anon_ro_data(&(*len as u64).to_le_bytes());
instrs.push(IRLInstruction::LoadData { instrs.push(IRLInstruction::LoadData {
dest: *dest, dest: dest.id,
offset: 8, offset: 8,
len: 8, len: 8,
src: sym, src: sym,
}); });
} }
IRUInstruction::LoadFn { dest, src } => { IRUInstruction::LoadFn { dest, src } => {
if alloc_stack(dest) { if alloc_stack(dest.id) {
continue; continue;
} }
let sym = builder.func(src); let sym = builder.func(src);
instrs.push(IRLInstruction::LoadAddr { instrs.push(IRLInstruction::LoadAddr {
dest: *dest, dest: dest.id,
offset: 0, offset: 0,
src: sym, src: sym,
}); });
} }
IRUInstruction::Call { dest, f, args } => { IRUInstruction::Call { dest, f, args } => {
alloc_stack(dest); alloc_stack(dest.id);
makes_call = true; makes_call = true;
let fid = &ns.fn_map[f]; let fid = &p.fn_map[&f.id];
let sym = builder.func(fid); let sym = builder.func(fid);
instrs.push(IRLInstruction::Call { instrs.push(IRLInstruction::Call {
dest: *dest, dest: dest.id,
f: sym, f: sym,
args: args args: args
.iter() .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(), .collect(),
}); });
} }
IRUInstruction::AsmBlock { instructions, args } => { IRUInstruction::AsmBlock { instructions, args } => {
instrs.push(IRLInstruction::AsmBlock { instrs.push(IRLInstruction::AsmBlock {
instructions: instructions.clone(), 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( builder.write_fn(
@@ -127,7 +133,7 @@ impl IRLProgram {
args: f args: f
.args .args
.iter() .iter()
.map(|a| (*a, ns.size_of_var(a).expect("unsized type"))) .map(|a| (*a, p.size_of_var(*a).expect("unsized type")))
.collect(), .collect(),
stack, stack,
}, },
@@ -139,7 +145,7 @@ impl IRLProgram {
// println!(" {:?}: {}", a, f.name); // println!(" {:?}: {}", a, f.name);
// } // }
// println!("datas: {}", sym_space.ro_data().len()); // println!("datas: {}", sym_space.ro_data().len());
Some(Self { sym_space, entry }) Ok(Self { sym_space, entry })
} }
pub fn entry(&self) -> Symbol { pub fn entry(&self) -> Symbol {

View File

@@ -1,5 +1,4 @@
mod upper; mod upper;
mod file;
mod lower; mod lower;
mod id; mod id;
mod asm; mod asm;
@@ -7,5 +6,4 @@ pub mod arch;
pub use upper::*; pub use upper::*;
pub use lower::*; pub use lower::*;
pub use file::*;
pub use id::*; pub use id::*;

View File

@@ -1,4 +1,6 @@
use super::{FileSpan, Type}; use crate::common::FileSpan;
use super::Type;
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Clone)] #[derive(Clone)]
@@ -23,6 +25,12 @@ pub struct VarDef {
pub origin: Origin, pub origin: Origin,
} }
#[derive(Clone)]
pub struct DataDef {
pub ty: Type,
pub origin: Origin,
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Origin { pub enum Origin {
Builtin, Builtin,

19
src/ir/upper/error.rs Normal file
View File

@@ -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],
});
}
}
}

View File

@@ -1,52 +1,51 @@
use std::fmt::Write; use std::fmt::Write;
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Len, VarID}; use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, VarID};
use crate::{compiler::arch::riscv64::Reg, util::Padder}; use crate::{common::FileSpan, compiler::arch::riscv64::Reg, util::Padder};
pub struct IRUFunction { pub struct IRUFunction {
pub name: String, pub name: String,
pub args: Vec<VarID>, pub args: Vec<VarID>,
pub instructions: Vec<IRUInstruction>, pub instructions: Vec<IRUInstrInst>,
} }
pub enum IRUInstruction { pub enum IRUInstruction {
Mv { Mv {
dest: VarID, dest: VarInst,
src: VarID, src: VarInst,
}, },
Ref { Ref {
dest: VarID, dest: VarInst,
src: VarID, src: VarInst,
}, },
LoadData { LoadData {
dest: VarID, dest: VarInst,
src: DataID, src: DataID,
}, },
LoadSlice { LoadSlice {
dest: VarID, dest: VarInst,
src: DataID, src: DataID,
len: Len,
}, },
LoadFn { LoadFn {
dest: VarID, dest: VarInst,
src: FnID, src: FnID,
}, },
Call { Call {
dest: VarID, dest: VarInst,
f: VarID, f: VarInst,
args: Vec<VarID>, args: Vec<VarInst>,
}, },
AsmBlock { AsmBlock {
instructions: Vec<RV64Instruction>, instructions: Vec<RV64Instruction>,
args: Vec<(Reg, VarID)>, args: Vec<(Reg, VarInst)>,
}, },
Ret { Ret {
src: VarID, src: VarInst,
}, },
} }
pub struct IRInstructions { pub struct IRInstructions {
vec: Vec<IRUInstruction>, vec: Vec<IRUInstrInst>,
} }
impl IRUFunction { impl IRUFunction {
@@ -63,8 +62,8 @@ impl IRInstructions {
pub fn new() -> Self { pub fn new() -> Self {
Self { vec: Vec::new() } Self { vec: Vec::new() }
} }
pub fn push(&mut self, i: IRUInstruction) { pub fn push(&mut self, i: IRUInstruction, span: FileSpan) {
self.vec.push(i); 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::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}"),
Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"), Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::LoadFn { 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 { Self::Call {
dest, dest,
f: func, f: func,

27
src/ir/upper/inst.rs Normal file
View File

@@ -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)
}
}

View File

@@ -1,10 +1,14 @@
mod def; mod def;
mod func; mod func;
mod ty; mod ty;
mod namespace; mod program;
mod validate;
mod error;
mod inst;
use super::*; use super::*;
pub use def::*; pub use def::*;
pub use func::*; pub use func::*;
pub use ty::*; pub use ty::*;
pub use namespace::*; pub use program::*;
pub use inst::*;

View File

@@ -4,12 +4,15 @@ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
use super::*; use crate::common::FileSpan;
pub struct Namespace { use super::{inst::VarInst, *};
pub struct IRUProgram {
pub fn_defs: Vec<FnDef>, pub fn_defs: Vec<FnDef>,
pub var_defs: Vec<VarDef>, pub var_defs: Vec<VarDef>,
pub type_defs: Vec<TypeDef>, pub type_defs: Vec<TypeDef>,
pub data_defs: Vec<DataDef>,
pub fns: Vec<Option<IRUFunction>>, pub fns: Vec<Option<IRUFunction>>,
pub data: Vec<Vec<u8>>, pub data: Vec<Vec<u8>>,
pub fn_map: HashMap<VarID, FnID>, pub fn_map: HashMap<VarID, FnID>,
@@ -17,12 +20,13 @@ pub struct Namespace {
pub stack: Vec<HashMap<String, Idents>>, pub stack: Vec<HashMap<String, Idents>>,
} }
impl Namespace { impl IRUProgram {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
fn_defs: Vec::new(), fn_defs: Vec::new(),
var_defs: Vec::new(), var_defs: Vec::new(),
type_defs: Vec::new(), type_defs: Vec::new(),
data_defs: Vec::new(),
data: Vec::new(), data: Vec::new(),
fn_map: HashMap::new(), fn_map: HashMap::new(),
fns: Vec::new(), fns: Vec::new(),
@@ -49,6 +53,9 @@ impl Namespace {
pub fn get_fn(&self, id: FnID) -> &FnDef { pub fn get_fn(&self, id: FnID) -> &FnDef {
&self.fn_defs[id.0] &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> { pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
Some(&self.fn_defs[self.fn_map.get(&id)?.0]) Some(&self.fn_defs[self.fn_map.get(&id)?.0])
} }
@@ -90,17 +97,20 @@ impl Namespace {
Type::Unit => 0, Type::Unit => 0,
}) })
} }
pub fn size_of_var(&self, var: &VarID) -> Option<Size> { pub fn size_of_var(&self, var: VarID) -> Option<Size> {
self.size_of_type(&self.var_defs[var.0].ty) 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 { let v = self.def_var(VarDef {
name: format!("temp{}", self.temp), name: format!("temp{}", self.temp),
origin: super::Origin::File(origin), origin: super::Origin::File(origin),
ty, ty,
}); });
self.temp += 1; self.temp += 1;
v VarInst {
id: v,
span: origin,
}
} }
pub fn def_fn(&mut self, def: FnDef) -> FnID { pub fn def_fn(&mut self, def: FnDef) -> FnID {
let i = self.fn_defs.len(); let i = self.fn_defs.len();
@@ -128,8 +138,9 @@ impl Namespace {
self.type_defs.push(def); self.type_defs.push(def);
id id
} }
pub fn def_data(&mut self, bytes: Vec<u8>) -> DataID { pub fn def_data(&mut self, def: DataDef, bytes: Vec<u8>) -> DataID {
let i = self.data.len(); let i = self.data.len();
self.data_defs.push(def);
self.data.push(bytes); self.data.push(bytes);
DataID(i) DataID(i)
} }
@@ -187,18 +198,17 @@ impl Namespace {
self.fns[id.0] = Some(f); self.fns[id.0] = Some(f);
} }
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &VarDef)> { pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &VarDef)> {
(0..self.var_defs.len()) self.var_defs.iter().enumerate().map(|(i, v)| (VarID(i), v))
.map(|i| VarID(i))
.zip(self.var_defs.iter())
} }
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, Option<&IRUFunction>)> { pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, &IRUFunction)> {
(0..self.fns.len()) self.fns
.map(|i| FnID(i)) .iter()
.zip(self.fns.iter().map(|f| f.as_ref())) .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<'_> { impl Drop for NamespaceGuard<'_> {
fn drop(&mut self) { fn drop(&mut self) {
@@ -207,7 +217,7 @@ impl Drop for NamespaceGuard<'_> {
} }
impl Deref for NamespaceGuard<'_> { impl Deref for NamespaceGuard<'_> {
type Target = Namespace; type Target = IRUProgram;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.0 self.0
} }

View File

@@ -1,6 +1,6 @@
use super::{Len, TypeID}; use super::{IRUInstruction, IRUProgram, Len, TypeID};
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub enum Type { pub enum Type {
Concrete(TypeID), Concrete(TypeID),
Bits(u32), Bits(u32),
@@ -25,3 +25,20 @@ impl Type {
Self::Slice(Box::new(self)) 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!(),
}
}
}
}

52
src/ir/upper/validate.rs Normal file
View File

@@ -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
}
}

View File

@@ -1,7 +1,7 @@
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(try_trait_v2)] #![feature(try_trait_v2)]
use ir::{Namespace, IRLProgram}; use ir::{IRLProgram, IRUProgram};
use parser::{NodeParsable, PModule, PStatement, ParserCtx}; use parser::{NodeParsable, PModule, PStatement, ParserCtx};
use std::{ use std::{
fs::{create_dir_all, OpenOptions}, fs::{create_dir_all, OpenOptions},
@@ -11,10 +11,12 @@ use std::{
process::Command, process::Command,
}; };
mod common;
mod compiler; mod compiler;
mod ir; mod ir;
mod parser; mod parser;
mod util; mod util;
use common::*;
fn main() { fn main() {
let file = std::env::args_os().nth(1); let file = std::env::args_os().nth(1);
@@ -34,7 +36,7 @@ fn run_file(file: &str, gdb: bool) {
// println!("Parsed:"); // println!("Parsed:");
// println!("{:#?}", res.node); // println!("{:#?}", res.node);
if let Some(module) = res.node.as_ref() { 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); module.lower(&mut namespace.push(), &mut ctx.output);
if ctx.output.errs.is_empty() { if ctx.output.errs.is_empty() {
// println!("vars:"); // println!("vars:");
@@ -44,10 +46,14 @@ fn run_file(file: &str, gdb: bool) {
// for (id, f) in namespace.iter_fns() { // for (id, f) in namespace.iter_fns() {
// println!("{id:?} = {:#?}", f.unwrap()); // println!("{id:?} = {:#?}", f.unwrap());
// } // }
let program = IRLProgram::create(&namespace); let output = namespace.validate();
let bin = compiler::compile(program.expect("morir")); output.write_for(&mut stdout(), file);
println!("compiled"); if output.errs.is_empty() {
save_run(&bin, gdb); let program = IRLProgram::create(&namespace);
let bin = compiler::compile(program.expect("morir"));
println!("compiled");
save_run(&bin, gdb);
}
} }
} }
} }

View File

@@ -1,10 +1,13 @@
use std::ops::{Deref, DerefMut}; 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 struct ParserCtx<'a> {
pub cursor: TokenCursor<'a>, pub cursor: TokenCursor<'a>,
pub output: ParserOutput, pub output: CompilerOutput,
} }
impl<'a> Deref for ParserCtx<'a> { impl<'a> Deref for ParserCtx<'a> {
@@ -22,15 +25,18 @@ impl DerefMut for ParserCtx<'_> {
} }
impl<'a> ParserCtx<'a> { impl<'a> ParserCtx<'a> {
pub fn err(&mut self, msg: ParserMsg) { pub fn err(&mut self, msg: CompilerMsg) {
self.output.err(msg); self.output.err(msg);
} }
pub fn hint(&mut self, msg: ParserMsg) { pub fn hint(&mut self, msg: CompilerMsg) {
self.output.hint(msg); self.output.hint(msg);
} }
pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> { pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> {
Node::parse(self) Node::parse(self)
} }
pub fn parse_with<T: ParsableWith>(&mut self, data: T::Data) -> NodeParseResult<T> {
Node::parse_with(self, data)
}
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> { pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
Node::maybe_parse(self) Node::maybe_parse(self)
} }
@@ -40,7 +46,7 @@ impl<'a> From<TokenCursor<'a>> for ParserCtx<'a> {
fn from(cursor: TokenCursor<'a>) -> Self { fn from(cursor: TokenCursor<'a>) -> Self {
Self { Self {
cursor, 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 { fn from(string: &'a str) -> Self {
Self { Self {
cursor: TokenCursor::from(string), cursor: TokenCursor::from(string),
output: ParserOutput::new(), output: CompilerOutput::new(),
} }
} }
} }

View File

@@ -1,7 +1,7 @@
use crate::ir::FilePos; use super::{
token::{CharCursor, Keyword, Symbol, Token, TokenInstance},
use super::error::ParserMsg; CompilerMsg, FilePos,
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance}; };
pub struct TokenCursor<'a> { pub struct TokenCursor<'a> {
cursor: CharCursor<'a>, cursor: CharCursor<'a>,
@@ -12,11 +12,7 @@ pub struct TokenCursor<'a> {
impl<'a> TokenCursor<'a> { impl<'a> TokenCursor<'a> {
pub fn next(&mut self) -> Option<TokenInstance> { pub fn next(&mut self) -> Option<TokenInstance> {
self.prev_end = self self.prev_end = self.cursor.prev_pos();
.next
.as_ref()
.map(|i| i.span.end)
.unwrap_or(FilePos::start());
let next = TokenInstance::parse(&mut self.cursor); let next = TokenInstance::parse(&mut self.cursor);
self.next_start = next self.next_start = next
.as_ref() .as_ref()
@@ -24,19 +20,19 @@ impl<'a> TokenCursor<'a> {
.unwrap_or(FilePos::start()); .unwrap_or(FilePos::start());
std::mem::replace(&mut self.next, next) std::mem::replace(&mut self.next, next)
} }
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserMsg> { pub fn expect_next(&mut self) -> Result<TokenInstance, CompilerMsg> {
self.peek().ok_or(ParserMsg::unexpected_end())?; self.peek().ok_or(CompilerMsg::unexpected_end())?;
Ok(self.next().unwrap()) 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()?; let next = self.expect_next()?;
if t == next.token { if t == next.token {
Ok(()) Ok(())
} else { } 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)) self.expect_token(Token::Symbol(symbol))
} }
pub fn next_on_new_line(&mut self) -> bool { pub fn next_on_new_line(&mut self) -> bool {
@@ -64,14 +60,14 @@ impl<'a> TokenCursor<'a> {
self.next(); 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)) self.expect_token(Token::Keyword(kw))
} }
pub fn peek(&self) -> Option<&TokenInstance> { pub fn peek(&self) -> Option<&TokenInstance> {
self.next.as_ref() self.next.as_ref()
} }
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserMsg> { pub fn expect_peek(&mut self) -> Result<&TokenInstance, CompilerMsg> {
self.peek().ok_or(ParserMsg::unexpected_end()) self.peek().ok_or(CompilerMsg::unexpected_end())
} }
pub fn chars(&mut self) -> &mut CharCursor<'a> { pub fn chars(&mut self) -> &mut CharCursor<'a> {
&mut self.cursor &mut self.cursor

View File

@@ -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}; impl CompilerMsg {
#[derive(Debug, Clone)]
pub struct ParserMsg {
pub msg: String,
pub spans: Vec<FileSpan>,
}
pub struct ParserOutput {
pub errs: Vec<ParserMsg>,
pub hints: Vec<ParserMsg>,
}
impl ParserMsg {
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self { pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
ParserMsg { CompilerMsg {
msg, msg,
spans: instances.iter().map(|i| i.span).collect(), spans: instances.iter().map(|i| i.span).collect(),
} }
} }
pub fn from_msg(msg: String) -> Self { pub fn unexpected_end() -> Self {
Self { Self::from_msg("unexpected end of input".to_string())
msg,
spans: Vec::new(),
}
}
pub fn from_span(span: FileSpan, msg: String) -> Self {
Self {
msg,
spans: vec![span],
}
} }
pub fn identifier_not_found(id: &Node<PIdent>) -> Self { pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
Self { Self {
@@ -38,51 +19,11 @@ impl ParserMsg {
spans: vec![id.span], 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 { pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
let t = &inst.token; let t = &inst.token;
ParserMsg::from_instances( CompilerMsg::from_instances(
&[inst], &[inst],
format!("unexpected token {t:?}; expected {expected}"), 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();
}
}
} }

View File

@@ -3,7 +3,7 @@ use crate::{
compiler::arch::riscv64::*, compiler::arch::riscv64::*,
ir::{ ir::{
arch::riscv64::{RV64Instruction, RegRef}, arch::riscv64::{RV64Instruction, RegRef},
VarID, VarInst,
}, },
}; };
@@ -57,7 +57,7 @@ impl RV64Instruction {
} }
} }
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarID> { pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let PAsmArg::Ref(node) = node.inner.as_ref()? else { let PAsmArg::Ref(node) = node.inner.as_ref()? else {
ctx.err_at( ctx.err_at(
node.span, node.span,

View File

@@ -1,9 +1,9 @@
use crate::{ use crate::{
compiler::arch::riscv64::Reg, 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 { impl FnLowerable for PInstruction {
type Output = RV64Instruction; type Output = RV64Instruction;
@@ -43,7 +43,7 @@ impl FnLowerable for PAsmBlock {
} }
impl FnLowerable for PAsmBlockArg { impl FnLowerable for PAsmBlockArg {
type Output = (Reg, VarID); type Output = (Reg, VarInst);
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
let var = ctx.get_var(&self.var)?; let var = ctx.get_var(&self.var)?;

View File

@@ -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 { impl FnLowerable for PBlock {
type Output = VarID; type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let ctx = &mut ctx.sub(); let ctx = &mut ctx.sub();
for statement in &self.statements { for statement in &self.statements {
statement.lower(ctx); statement.lower(ctx);
@@ -14,20 +14,20 @@ impl FnLowerable for PBlock {
} }
impl FnLowerable for PStatement { impl FnLowerable for PStatement {
type Output = VarID; type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
match self { match self {
super::PStatement::Let(def, e) => { super::PStatement::Let(def, e) => {
let def = def.lower(ctx.map, ctx.output)?; let def = def.lower(ctx.map, ctx.output)?;
let res = e.lower(ctx); let res = e.lower(ctx);
if let Some(res) = res { if let Some(res) = res {
ctx.map.name_var(&def, res); ctx.map.name_var(&def, res.id);
} }
None None
} }
super::PStatement::Return(e) => { super::PStatement::Return(e) => {
let src = e.lower(ctx)?; let src = e.lower(ctx)?;
ctx.push(IRUInstruction::Ret { src }); ctx.push_at(IRUInstruction::Ret { src }, src.span);
None None
} }
super::PStatement::Expr(e) => e.lower(ctx), super::PStatement::Expr(e) => e.lower(ctx),

View File

@@ -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<PVarDef> { impl Node<PVarDef> {
pub fn lower( pub fn lower(
&self, &self,
namespace: &mut NamespaceGuard, namespace: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut CompilerOutput,
) -> Option<VarDef> { ) -> Option<VarDef> {
let s = self.as_ref()?; let s = self.as_ref()?;
let name = s.name.as_ref()?.to_string(); let name = s.name.as_ref()?.to_string();
@@ -23,7 +23,7 @@ impl Node<PVarDef> {
} }
impl Node<PType> { impl Node<PType> {
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() self.as_ref()
.map(|t| t.lower(namespace, output, self.span)) .map(|t| t.lower(namespace, output, self.span))
.unwrap_or(Type::Error) .unwrap_or(Type::Error)
@@ -34,7 +34,7 @@ impl PType {
pub fn lower( pub fn lower(
&self, &self,
namespace: &mut NamespaceGuard, namespace: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut CompilerOutput,
span: FileSpan, span: FileSpan,
) -> Type { ) -> Type {
match namespace.get(&self.name).and_then(|ids| ids.ty) { match namespace.get(&self.name).and_then(|ids| ids.ty) {
@@ -60,7 +60,7 @@ impl PType {
Type::Slice(Box::new(inner)) 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 Type::Error
} }
} }

View File

@@ -1,31 +1,48 @@
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp}; 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 { impl FnLowerable for PExpr {
type Output = VarID; type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
Some(match self { Some(match self {
PExpr::Lit(l) => match l.as_ref()? { PExpr::Lit(l) => match l.as_ref()? {
super::PLiteral::String(s) => { super::PLiteral::String(s) => {
let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice()); let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice());
let data = s.as_bytes().to_vec(); let data = s.as_bytes().to_vec();
let len = data.len() as Size; let src = ctx.map.def_data(
let src = ctx.map.def_data(data); DataDef {
ctx.push(IRUInstruction::LoadSlice { dest, src, len }); ty: Type::Bits(8).arr(data.len() as u32),
origin: Origin::File(l.span),
},
data,
);
ctx.push(IRUInstruction::LoadSlice { dest, src });
dest dest
} }
super::PLiteral::Char(c) => { super::PLiteral::Char(c) => {
let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice()); let ty = Type::Bits(8);
let src = ctx.map.def_data(c.to_string().as_bytes().to_vec()); 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 }); ctx.push(IRUInstruction::LoadData { dest, src });
dest dest
} }
super::PLiteral::Number(n) => { super::PLiteral::Number(n) => {
// TODO: temp // TODO: temp
let ty = Type::Bits(64);
let dest = ctx.map.temp_var(l.span, Type::Bits(64)); let dest = ctx.map.temp_var(l.span, Type::Bits(64));
let src = ctx let src = ctx.map.def_data(
.map DataDef {
.def_data(n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec()); ty,
origin: Origin::File(l.span),
},
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
);
ctx.push(IRUInstruction::LoadData { dest, src }); ctx.push(IRUInstruction::LoadData { dest, src });
dest dest
} }
@@ -44,7 +61,7 @@ impl FnLowerable for PExpr {
let res = e.lower(ctx)?; let res = e.lower(ctx)?;
match op { match op {
UnaryOp::Ref => { 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 { ctx.push(IRUInstruction::Ref {
dest: temp, dest: temp,
src: res, src: res,
@@ -52,7 +69,7 @@ impl FnLowerable for PExpr {
temp temp
} }
UnaryOp::Deref => { 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 { let Type::Ref(inner) = t else {
ctx.err(format!( ctx.err(format!(
"Cannot dereference type {:?}", "Cannot dereference type {:?}",
@@ -77,7 +94,7 @@ impl FnLowerable for PExpr {
let arg = arg.lower(ctx)?; let arg = arg.lower(ctx)?;
nargs.push(arg); nargs.push(arg);
} }
let def = ctx.map.get_fn_var(fe); let def = ctx.map.get_fn_var(fe.id);
let ty = match def { let ty = match def {
Some(def) => def.ret.clone(), Some(def) => def.ret.clone(),
None => { None => {
@@ -85,7 +102,7 @@ impl FnLowerable for PExpr {
e.span, e.span,
format!( format!(
"Expected function, found {}", "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 Type::Error
@@ -100,6 +117,7 @@ impl FnLowerable for PExpr {
temp temp
} }
PExpr::Group(e) => e.lower(ctx)?, PExpr::Group(e) => e.lower(ctx)?,
PExpr::Construct(c) => todo!(),
}) })
} }
} }

View File

@@ -1,8 +1,8 @@
use super::{FnLowerable, Node, PFunction, ParserMsg, ParserOutput}; use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
use crate::{ use crate::{
ir::{ ir::{
FileSpan, FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, Origin,
Origin, Type, VarDef, VarID, Type, VarDef, VarID, VarInst,
}, },
parser, parser,
}; };
@@ -11,7 +11,7 @@ impl Node<PFunction> {
pub fn lower_header( pub fn lower_header(
&self, &self,
map: &mut NamespaceGuard, map: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut CompilerOutput,
) -> Option<FnID> { ) -> Option<FnID> {
self.as_ref()?.lower_header(map, output) self.as_ref()?.lower_header(map, output)
} }
@@ -19,7 +19,7 @@ impl Node<PFunction> {
&self, &self,
id: FnID, id: FnID,
map: &mut NamespaceGuard, map: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut CompilerOutput,
) -> Option<IRUFunction> { ) -> Option<IRUFunction> {
Some(self.as_ref()?.lower_body(id, map, output)) Some(self.as_ref()?.lower_body(id, map, output))
} }
@@ -29,7 +29,7 @@ impl PFunction {
pub fn lower_header( pub fn lower_header(
&self, &self,
map: &mut NamespaceGuard, map: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut CompilerOutput,
) -> Option<FnID> { ) -> Option<FnID> {
let header = self.header.as_ref()?; let header = self.header.as_ref()?;
let name = header.name.as_ref()?; let name = header.name.as_ref()?;
@@ -59,7 +59,7 @@ impl PFunction {
&self, &self,
id: FnID, id: FnID,
map: &mut NamespaceGuard, map: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut CompilerOutput,
) -> IRUFunction { ) -> IRUFunction {
let mut instructions = IRInstructions::new(); let mut instructions = IRInstructions::new();
let def = map.get_fn(id).clone(); let def = map.get_fn(id).clone();
@@ -71,7 +71,7 @@ impl PFunction {
span: self.body.span, span: self.body.span,
}; };
if let Some(src) = self.body.lower(&mut ctx) { 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) IRUFunction::new(def.name.clone(), args, instructions)
} }
@@ -80,7 +80,7 @@ impl PFunction {
pub struct FnLowerCtx<'a, 'n> { pub struct FnLowerCtx<'a, 'n> {
pub map: &'a mut NamespaceGuard<'n>, pub map: &'a mut NamespaceGuard<'n>,
pub instructions: &'a mut IRInstructions, pub instructions: &'a mut IRInstructions,
pub output: &'a mut ParserOutput, pub output: &'a mut CompilerOutput,
pub span: FileSpan, pub span: FileSpan,
} }
@@ -101,7 +101,7 @@ impl<'n> FnLowerCtx<'_, 'n> {
} }
res res
} }
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarID> { pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarInst> {
let ids = self.get(node)?; let ids = self.get(node)?;
if ids.var.is_none() { if ids.var.is_none() {
self.err_at( 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) { 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) { 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) self.map.temp_var(self.span, ty)
} }
pub fn push(&mut self, i: IRUInstruction) { 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> { pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
FnLowerCtx { FnLowerCtx {

View File

@@ -1,9 +1,9 @@
use crate::ir::NamespaceGuard; use crate::ir::NamespaceGuard;
use super::{PModule, ParserOutput}; use super::{PModule, CompilerOutput};
impl PModule { 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(); let mut fns = Vec::new();
for f in &self.functions { for f in &self.functions {
if let Some(id) = f.lower_header(map, output) { if let Some(id) = f.lower_header(map, output) {

View File

@@ -1,3 +1,4 @@
mod ctx;
mod cursor; mod cursor;
mod error; mod error;
mod lower; mod lower;
@@ -5,13 +6,11 @@ mod node;
mod nodes; mod nodes;
mod parse; mod parse;
mod token; mod token;
mod ctx;
use crate::common::{CompilerMsg, CompilerOutput, FileSpan, FilePos};
pub use ctx::*;
pub use cursor::*; pub use cursor::*;
pub use error::*;
pub use lower::*;
pub use node::*; pub use node::*;
pub use nodes::*; pub use nodes::*;
pub use parse::*; pub use parse::*;
pub use token::*; pub use token::*;
pub use ctx::*;

View File

@@ -3,7 +3,7 @@ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
use crate::ir::FileSpan; use super::FileSpan;
pub struct Node<T> { pub struct Node<T> {
pub inner: Option<T>, pub inner: Option<T>,
@@ -46,4 +46,3 @@ impl<T: Debug> Debug for Node<T> {
} }
} }
} }

View File

@@ -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 struct PInstruction {
pub op: Node<PIdent>, pub op: Node<PIdent>,
@@ -38,7 +38,7 @@ impl Parsable for PAsmArg {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;
if !next.is_symbol(Symbol::OpenCurly) { if !next.is_symbol(Symbol::OpenCurly) {
return ParseResult::Err(ParserMsg::unexpected_token( return ParseResult::Err(CompilerMsg::unexpected_token(
next, next,
"An identifier or {identifier}", "An identifier or {identifier}",
)); ));

View File

@@ -1,7 +1,7 @@
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
use super::{ use super::{
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement, token::Symbol, Node, NodeParsable, PStatement, Parsable, ParseResult, ParserCtx, CompilerMsg,
}; };
use crate::util::Padder; use crate::util::Padder;
@@ -24,7 +24,7 @@ impl Parsable for PBlock {
loop { loop {
let Some(next) = ctx.peek() else { let Some(next) = ctx.peek() else {
recover = true; recover = true;
ctx.err(ParserMsg::unexpected_end()); ctx.err(CompilerMsg::unexpected_end());
break; break;
}; };
if next.is_symbol(Symbol::CloseCurly) { if next.is_symbol(Symbol::CloseCurly) {
@@ -36,7 +36,7 @@ impl Parsable for PBlock {
expect_semi = false; expect_semi = false;
continue; continue;
} else if expect_semi { } else if expect_semi {
ctx.err(ParserMsg { ctx.err(CompilerMsg {
msg: "expected ';'".to_string(), msg: "expected ';'".to_string(),
spans: vec![ctx.next_start().char_span()], spans: vec![ctx.next_start().char_span()],
}); });

View File

@@ -1,7 +1,8 @@
use std::fmt::Debug; use std::fmt::Debug;
use super::{ 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 { pub struct PVarDef {
@@ -9,6 +10,11 @@ pub struct PVarDef {
pub ty: Option<Node<PType>>, pub ty: Option<Node<PType>>,
} }
pub struct PFieldDef {
pub name: Node<PIdent>,
pub val: Option<Node<PExpr>>,
}
impl Parsable for PVarDef { impl Parsable for PVarDef {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let name = ctx.parse()?; let name = ctx.parse()?;
@@ -21,6 +27,21 @@ impl Parsable for PVarDef {
} }
} }
impl Parsable for PFieldDef {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
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 struct SelfVar {
pub ty: SelfType, pub ty: SelfType,
} }
@@ -32,7 +53,7 @@ pub enum SelfType {
} }
impl MaybeParsable for SelfVar { impl MaybeParsable for SelfVar {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, super::ParserMsg> { fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
if let Some(mut next) = ctx.peek() { if let Some(mut next) = ctx.peek() {
let mut ty = SelfType::Take; let mut ty = SelfType::Take;
if next.is_symbol(Symbol::Ampersand) { if next.is_symbol(Symbol::Ampersand) {
@@ -47,7 +68,7 @@ impl MaybeParsable for SelfVar {
} }
} }
if ty != SelfType::Take { if ty != SelfType::Take {
return Err(ParserMsg::unexpected_token(next, "self")); return Err(CompilerMsg::unexpected_token(next, "self"));
} }
} }
Ok(None) 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 { impl Debug for SelfVar {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(

View File

@@ -1,10 +1,7 @@
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
use super::{ use super::{
op::{PInfixOp, UnaryOp}, op::{PInfixOp, UnaryOp}, util::parse_list, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg
util::parse_list,
PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx,
ParserMsg, Symbol,
}; };
type BoxNode = Node<Box<PExpr>>; type BoxNode = Node<Box<PExpr>>;
@@ -18,6 +15,7 @@ pub enum PExpr {
Call(BoxNode, Vec<Node<PExpr>>), Call(BoxNode, Vec<Node<PExpr>>),
Group(BoxNode), Group(BoxNode),
AsmBlock(Node<PAsmBlock>), AsmBlock(Node<PAsmBlock>),
Construct(Node<PConstruct>),
} }
impl Parsable for PExpr { impl Parsable for PExpr {
@@ -63,7 +61,7 @@ impl Parsable for PExpr {
Self::Ident(res.node) Self::Ident(res.node)
} else { } else {
let next = ctx.expect_peek()?; 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 { let Some(mut next) = ctx.peek() else {
@@ -140,6 +138,7 @@ impl Debug for PExpr {
} }
PExpr::Group(inner) => inner.fmt(f)?, PExpr::Group(inner) => inner.fmt(f)?,
PExpr::AsmBlock(inner) => inner.fmt(f)?, PExpr::AsmBlock(inner) => inner.fmt(f)?,
PExpr::Construct(inner) => inner.fmt(f)?,
} }
Ok(()) Ok(())
} }

View File

@@ -1,4 +1,4 @@
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token}; use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, Token, CompilerMsg};
use std::{ use std::{
fmt::{Debug, Display}, fmt::{Debug, Display},
ops::Deref, ops::Deref,
@@ -11,7 +11,7 @@ impl Parsable for PIdent {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;
let Token::Word(name) = &next.token else { 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(); let name = name.to_string();
ctx.next(); ctx.next();
@@ -20,7 +20,7 @@ impl Parsable for PIdent {
} }
impl MaybeParsable for PIdent { impl MaybeParsable for PIdent {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> { fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
let Some(next) = ctx.peek() else { return Ok(None) }; let Some(next) = ctx.peek() else { return Ok(None) };
let Token::Word(name) = &next.token else { let Token::Word(name) = &next.token else {
return Ok(None); return Ok(None);

View File

@@ -1,4 +1,4 @@
use super::{CharCursor, MaybeParsable, ParserCtx, ParserMsg, Symbol, Token}; use super::{CharCursor, MaybeParsable, ParserCtx, CompilerMsg, Symbol, Token};
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
@@ -17,7 +17,7 @@ pub struct PNumber {
} }
impl MaybeParsable for PLiteral { impl MaybeParsable for PLiteral {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> { fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
let inst = ctx.expect_peek()?; let inst = ctx.expect_peek()?;
Ok(Some(match &inst.token { Ok(Some(match &inst.token {
Token::Symbol(Symbol::SingleQuote) => { Token::Symbol(Symbol::SingleQuote) => {
@@ -37,7 +37,7 @@ impl MaybeParsable for PLiteral {
if !first.is_ascii_digit() { if !first.is_ascii_digit() {
return Ok(None); return Ok(None);
} }
let (whole, ty) = parse_whole_num(text); let (whole, ty) = parse_whole_num(&text);
let mut num = PNumber { let mut num = PNumber {
whole, whole,
decimal: None, decimal: None,
@@ -81,7 +81,7 @@ pub fn parse_whole_num(text: &str) -> (String, Option<String>) {
(whole, if ty.is_empty() { None } else { Some(ty) }) (whole, if ty.is_empty() { None } else { Some(ty) })
} }
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> { pub fn string_from(cursor: &mut CharCursor) -> Result<String, CompilerMsg> {
let mut str = String::new(); let mut str = String::new();
loop { loop {
let c = cursor.expect_next()?; let c = cursor.expect_next()?;

View File

@@ -1,5 +1,5 @@
use super::{ use super::{
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, CompilerMsg,
PStruct, Symbol, Token, PTrait, PStruct, Symbol, Token, PTrait,
}; };
use std::fmt::Debug; 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(); ctx.next();
} }
} }
} else if next.is_symbol(Symbol::Semicolon) { } else if next.is_symbol(Symbol::Semicolon) {
ctx.hint(ParserMsg::from_instances( ctx.hint(CompilerMsg::from_instances(
&[next], &[next],
"unneeded semicolon".to_string(), "unneeded semicolon".to_string(),
)); ));
ctx.next(); ctx.next();
} else { } else {
ctx.err(ParserMsg::unexpected_token(next, "a definition")); ctx.err(CompilerMsg::unexpected_token(next, "a definition"));
ctx.next(); ctx.next();
} }
} }

View File

@@ -1,8 +1,8 @@
use std::fmt::Debug; use std::fmt::Debug;
use super::{ use super::{
util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, util::parse_list, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef, Parsable,
PType, PVarDef, ParseResult, ParserCtx, CompilerMsg, Symbol,
}; };
#[derive(Debug)] #[derive(Debug)]
@@ -11,6 +11,12 @@ pub struct PStruct {
pub fields: PStructFields, pub fields: PStructFields,
} }
#[derive(Debug)]
pub struct PConstruct {
pub name: Node<PIdent>,
pub fields: PConstructFields,
}
#[derive(Debug)] #[derive(Debug)]
pub enum PStructFields { pub enum PStructFields {
Named(Vec<Node<PVarDef>>), Named(Vec<Node<PVarDef>>),
@@ -18,6 +24,13 @@ pub enum PStructFields {
None, None,
} }
#[derive(Debug)]
pub enum PConstructFields {
Named(Vec<Node<PFieldDef>>),
Tuple(Vec<Node<PExpr>>),
None,
}
impl Parsable for PStruct { impl Parsable for PStruct {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
ctx.expect_kw(Keyword::Struct)?; ctx.expect_kw(Keyword::Struct)?;
@@ -33,7 +46,7 @@ impl Parsable for PStruct {
ctx.next(); ctx.next();
PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?) PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
} else { } else {
let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`"); let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`");
ctx.err(msg); ctx.err(msg);
return ParseResult::Recover(PStruct { return ParseResult::Recover(PStruct {
name, name,
@@ -43,3 +56,29 @@ impl Parsable for PStruct {
ParseResult::Ok(PStruct { name, fields }) ParseResult::Ok(PStruct { name, fields })
} }
} }
impl Parsable for PConstruct {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
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 })
}
}

View File

@@ -1,6 +1,6 @@
use std::fmt::Debug; 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 struct PType {
pub name: String, pub name: String,
@@ -19,7 +19,7 @@ impl Parsable for PType {
} }
} else { } else {
let Token::Word(name) = &next.token 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(); let n = name.to_string();
ctx.next(); ctx.next();

View File

@@ -1,10 +1,10 @@
use super::{Node, Parsable, ParserCtx, ParserMsg, Symbol}; use super::{Node, Parsable, ParserCtx, CompilerMsg, Symbol};
pub fn parse_list_sep<T: Parsable>( pub fn parse_list_sep<T: Parsable>(
ctx: &mut ParserCtx, ctx: &mut ParserCtx,
sep: Symbol, sep: Symbol,
end: Symbol, end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> { ) -> Result<Vec<Node<T>>, CompilerMsg> {
let mut vals = Vec::new(); let mut vals = Vec::new();
loop { loop {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;
@@ -29,14 +29,14 @@ pub fn parse_list_sep<T: Parsable>(
pub fn parse_list<T: Parsable>( pub fn parse_list<T: Parsable>(
ctx: &mut ParserCtx, ctx: &mut ParserCtx,
end: Symbol, end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> { ) -> Result<Vec<Node<T>>, CompilerMsg> {
parse_list_sep(ctx, Symbol::Comma, end) parse_list_sep(ctx, Symbol::Comma, end)
} }
pub fn parse_list_nosep<T: Parsable>( pub fn parse_list_nosep<T: Parsable>(
ctx: &mut ParserCtx, ctx: &mut ParserCtx,
end: Symbol, end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> { ) -> Result<Vec<Node<T>>, CompilerMsg> {
let mut vals = Vec::new(); let mut vals = Vec::new();
loop { loop {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;

View File

@@ -3,14 +3,12 @@ use std::{
ops::{ControlFlow, FromResidual, Try}, ops::{ControlFlow, FromResidual, Try},
}; };
use crate::ir::FilePos; use super::{CompilerMsg, FilePos, Node, ParserCtx};
use super::{Node, ParserCtx, ParserMsg};
pub enum ParseResult<T> { pub enum ParseResult<T> {
Ok(T), Ok(T),
Recover(T), Recover(T),
Err(ParserMsg), Err(CompilerMsg),
SubErr, SubErr,
} }
@@ -26,7 +24,7 @@ impl<T> ParseResult<T> {
impl<T> Try for ParseResult<T> { impl<T> Try for ParseResult<T> {
type Output = T; type Output = T;
type Residual = Option<ParserMsg>; type Residual = Option<CompilerMsg>;
fn from_output(output: Self::Output) -> Self { fn from_output(output: Self::Output) -> Self {
Self::Ok(output) Self::Ok(output)
} }
@@ -50,8 +48,8 @@ impl<T> FromResidual for ParseResult<T> {
} }
} }
impl<T> FromResidual<Result<Infallible, ParserMsg>> for ParseResult<T> { impl<T> FromResidual<Result<Infallible, CompilerMsg>> for ParseResult<T> {
fn from_residual(residual: Result<Infallible, ParserMsg>) -> Self { fn from_residual(residual: Result<Infallible, CompilerMsg>) -> Self {
match residual { match residual {
Err(e) => Self::Err(e), Err(e) => Self::Err(e),
} }
@@ -115,14 +113,28 @@ pub trait Parsable: Sized {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self>; fn parse(ctx: &mut ParserCtx) -> ParseResult<Self>;
} }
pub trait MaybeParsable: Sized { pub trait ParsableWith: Sized {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg>; type Data;
fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult<Self>;
} }
impl<T: Parsable> Node<T> { pub trait MaybeParsable: Sized {
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> { fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg>;
}
impl<T: Parsable> ParsableWith for T {
type Data = ();
fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult<Self> {
T::parse(ctx)
}
}
impl<T: ParsableWith> Node<T> {
pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult<T> {
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start()); 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::Ok(v) => (Some(v), false),
ParseResult::Recover(v) => (Some(v), true), ParseResult::Recover(v) => (Some(v), true),
ParseResult::Err(e) => { ParseResult::Err(e) => {
@@ -142,6 +154,12 @@ impl<T: Parsable> Node<T> {
} }
} }
impl<T: Parsable> Node<T> {
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
Node::parse_with(ctx, ())
}
}
impl<T: MaybeParsable> Node<T> { impl<T: MaybeParsable> Node<T> {
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> { pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
let start = ctx.next_start(); let start = ctx.next_start();

View File

@@ -1,7 +1,6 @@
use std::{iter::Peekable, str::Chars}; use std::{iter::Peekable, str::Chars};
use super::super::ParserMsg; use super::super::{CompilerMsg, FilePos};
use crate::ir::FilePos;
pub struct CharCursor<'a> { pub struct CharCursor<'a> {
chars: Peekable<Chars<'a>>, chars: Peekable<Chars<'a>>,
@@ -15,12 +14,12 @@ impl CharCursor<'_> {
self.advance(); self.advance();
Some(res) 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()?; let next = self.expect_next()?;
if next == c { if next == c {
Ok(()) Ok(())
} else { } else {
Err(ParserMsg::at( Err(CompilerMsg::at(
self.prev_pos, self.prev_pos,
format!("unexpected char '{next}'; expected '{c}'"), format!("unexpected char '{next}'; expected '{c}'"),
)) ))
@@ -46,8 +45,8 @@ impl CharCursor<'_> {
self.next_pos.col += 1; self.next_pos.col += 1;
} }
} }
pub fn expect_next(&mut self) -> Result<char, ParserMsg> { pub fn expect_next(&mut self) -> Result<char, CompilerMsg> {
self.next().ok_or(ParserMsg::unexpected_end()) self.next().ok_or(CompilerMsg::unexpected_end())
} }
pub fn next_pos(&self) -> FilePos { pub fn next_pos(&self) -> FilePos {
self.next_pos self.next_pos

View File

@@ -7,8 +7,7 @@ use std::ops::Deref;
pub use cursor::*; pub use cursor::*;
pub use keyword::*; pub use keyword::*;
pub use symbol::*; pub use symbol::*;
use super::FileSpan;
use crate::ir::FileSpan;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum Token { pub enum Token {