From 620c4557e9b850a54f0bbe74bc9077d7e3390d9f Mon Sep 17 00:00:00 2001 From: shadow cat Date: Fri, 6 Dec 2024 19:44:33 -0500 Subject: [PATCH] actually compiles and does stuff now --- data/test.lang | 27 +-- src/compiler/arch/mod.rs | 3 + src/compiler/{ => arch}/riscv64/asm.rs | 22 ++- src/compiler/{ => arch}/riscv64/base.rs | 6 +- src/compiler/arch/riscv64/compile.rs | 117 +++++++++++ src/compiler/{ => arch}/riscv64/funct.rs | 0 src/compiler/arch/riscv64/mod.rs | 63 ++++++ src/compiler/{ => arch}/riscv64/opcode.rs | 0 src/compiler/arch/riscv64/reg.rs | 179 +++++++++++++++++ src/compiler/{ => arch}/riscv64/single.rs | 2 +- src/compiler/instruction.rs | 2 - src/compiler/mod.rs | 14 +- src/compiler/program.rs | 43 ++-- src/compiler/riscv64/mod.rs | 63 ------ src/compiler/riscv64/parse.rs | 104 ---------- src/compiler/riscv64/reg.rs | 94 --------- src/ir/arch/mod.rs | 1 + src/ir/arch/riscv64.rs | 37 ++++ src/ir/asm.rs | 13 ++ src/ir/id.rs | 42 ++++ src/ir/lower/data.rs | 6 + src/ir/lower/func.rs | 41 ++++ src/ir/lower/mod.rs | 9 + src/ir/lower/program.rs | 85 ++++++++ src/ir/lvl1/func.rs | 56 ------ src/ir/lvl2/mod.rs | 0 src/ir/mod.rs | 14 +- src/ir/old.rs | 226 ---------------------- src/ir/{lvl1 => upper}/def.rs | 2 + src/ir/upper/func.rs | 82 ++++++++ src/ir/{lvl1 => upper}/mod.rs | 3 +- src/ir/{ => upper}/namespace.rs | 114 +++++------ src/ir/{lvl1 => upper}/ty.rs | 28 ++- src/main.rs | 112 ++++++++--- src/parser/v3/ctx.rs | 55 ++++++ src/parser/v3/cursor.rs | 35 ++-- src/parser/v3/error.rs | 14 +- src/parser/v3/lower/arch/mod.rs | 2 + src/parser/v3/lower/arch/riscv64.rs | 109 +++++++++++ src/parser/v3/lower/asm.rs | 53 +++++ src/parser/v3/lower/block.rs | 50 ++--- src/parser/v3/lower/def.rs | 4 +- src/parser/v3/lower/expr.rs | 160 ++++++--------- src/parser/v3/lower/func.rs | 155 ++++++++++++--- src/parser/v3/lower/mod.rs | 28 ++- src/parser/v3/lower/module.rs | 10 +- src/parser/v3/mod.rs | 2 + src/parser/v3/nodes/asm_block.rs | 68 +++++-- src/parser/v3/nodes/asm_fn.rs | 110 ++++++----- src/parser/v3/nodes/asm_instr.rs | 82 ++++++++ src/parser/v3/nodes/block.rs | 46 ++--- src/parser/v3/nodes/def.rs | 40 ++-- src/parser/v3/nodes/expr.rs | 100 +++++----- src/parser/v3/nodes/func.rs | 82 ++++---- src/parser/v3/nodes/ident.rs | 51 +++-- src/parser/v3/nodes/lit.rs | 41 ++-- src/parser/v3/nodes/mod.rs | 2 + src/parser/v3/nodes/module.rs | 56 ++---- src/parser/v3/nodes/op.rs | 6 +- src/parser/v3/nodes/statement.rs | 44 ++--- src/parser/v3/nodes/struc.rs | 48 ++--- src/parser/v3/nodes/trai.rs | 51 ++--- src/parser/v3/nodes/ty.rs | 31 ++- src/parser/v3/nodes/util.rs | 33 ++-- src/parser/v3/parse.rs | 36 ++-- src/parser/v3/token/cursor.rs | 2 +- src/parser/v3/token/keyword.rs | 2 + 67 files changed, 1931 insertions(+), 1287 deletions(-) create mode 100644 src/compiler/arch/mod.rs rename src/compiler/{ => arch}/riscv64/asm.rs (83%) rename src/compiler/{ => arch}/riscv64/base.rs (95%) create mode 100644 src/compiler/arch/riscv64/compile.rs rename src/compiler/{ => arch}/riscv64/funct.rs (100%) create mode 100644 src/compiler/arch/riscv64/mod.rs rename src/compiler/{ => arch}/riscv64/opcode.rs (100%) create mode 100644 src/compiler/arch/riscv64/reg.rs rename src/compiler/{ => arch}/riscv64/single.rs (98%) delete mode 100644 src/compiler/instruction.rs delete mode 100644 src/compiler/riscv64/mod.rs delete mode 100644 src/compiler/riscv64/parse.rs delete mode 100644 src/compiler/riscv64/reg.rs create mode 100644 src/ir/arch/mod.rs create mode 100644 src/ir/arch/riscv64.rs create mode 100644 src/ir/asm.rs create mode 100644 src/ir/id.rs create mode 100644 src/ir/lower/data.rs create mode 100644 src/ir/lower/func.rs create mode 100644 src/ir/lower/mod.rs create mode 100644 src/ir/lower/program.rs delete mode 100644 src/ir/lvl1/func.rs delete mode 100644 src/ir/lvl2/mod.rs delete mode 100644 src/ir/old.rs rename src/ir/{lvl1 => upper}/def.rs (94%) create mode 100644 src/ir/upper/func.rs rename src/ir/{lvl1 => upper}/mod.rs (70%) rename src/ir/{ => upper}/namespace.rs (71%) rename src/ir/{lvl1 => upper}/ty.rs (53%) create mode 100644 src/parser/v3/ctx.rs create mode 100644 src/parser/v3/lower/arch/mod.rs create mode 100644 src/parser/v3/lower/arch/riscv64.rs create mode 100644 src/parser/v3/lower/asm.rs create mode 100644 src/parser/v3/nodes/asm_instr.rs diff --git a/data/test.lang b/data/test.lang index 265bc34..26bb092 100644 --- a/data/test.lang +++ b/data/test.lang @@ -1,18 +1,21 @@ -trait Add { - fn add(self, other: Self) -> Self +fn start() { + print("Hello World!\n", 13); + exit(39); } -impl Add for b32 { - asm fn add(self, other) { - add {out}, {self}, {other} - } -} - -fn main() { - asm { - li a0, 3 - li a7, 93 +fn print(msg, len) { + asm (a1 = msg, a2 = len) { + ld a2, 0, a2 + li a0, 1 + li a7, 64 ecall } } +fn exit(status) { + asm (a0 = status) { + ld a0, 0, a0 + li a7, 93 + ecall + }; +} diff --git a/src/compiler/arch/mod.rs b/src/compiler/arch/mod.rs new file mode 100644 index 0000000..763b813 --- /dev/null +++ b/src/compiler/arch/mod.rs @@ -0,0 +1,3 @@ +pub mod riscv64; +use super::*; + diff --git a/src/compiler/riscv64/asm.rs b/src/compiler/arch/riscv64/asm.rs similarity index 83% rename from src/compiler/riscv64/asm.rs rename to src/compiler/arch/riscv64/asm.rs index f17e886..238e018 100644 --- a/src/compiler/riscv64/asm.rs +++ b/src/compiler/arch/riscv64/asm.rs @@ -1,33 +1,34 @@ -use crate::compiler::program::{Addr, Instr, SymTable, Symbol}; +use crate::{compiler::program::{Addr, Instr, SymTable}, ir::AddrID}; use super::*; #[derive(Debug, Clone)] -pub enum AsmInstruction { +pub enum LinkerInstruction { Add { dest: Reg, src1: Reg, src2: Reg }, Addi { dest: Reg, src: Reg, imm: i32 }, Andi { dest: Reg, src: Reg, imm: i32 }, Slli { dest: Reg, src: Reg, imm: i32 }, Srli { dest: Reg, src: Reg, imm: i32 }, Sd { src: Reg, offset: i32, base: Reg }, + Ld { dest: Reg, offset: i32, base: Reg }, Mv { dest: Reg, src: Reg }, - La { dest: Reg, sym: Symbol }, + La { dest: Reg, src: AddrID }, Jal { dest: Reg, offset: i32 }, - Call(Symbol), - J(Symbol), + Call(AddrID), + J(AddrID), Ret, Ecall, Li { dest: Reg, imm: i64 }, } -impl Instr for AsmInstruction { +impl Instr for LinkerInstruction { fn push( &self, data: &mut Vec, sym_map: &SymTable, pos: Addr, missing: bool, - ) -> Option { + ) -> Option { let last = match self { Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2), Self::Addi { dest, src, imm } => addi(*dest, *src, BitsI32::new(*imm)), @@ -35,15 +36,16 @@ impl Instr for AsmInstruction { 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::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base), Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)), - Self::La { dest, sym } => { - if let Some(addr) = sym_map.get(*sym) { + Self::La { dest, src } => { + if let Some(addr) = sym_map.get(*src) { let offset = addr.val() as i32 - pos.val() as i32; data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes()); addi(*dest, *dest, BitsI32::new(offset)) } else { data.extend_from_slice(&[0; 2 * 4]); - return Some(*sym); + return Some(*src); } } Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)), diff --git a/src/compiler/riscv64/base.rs b/src/compiler/arch/riscv64/base.rs similarity index 95% rename from src/compiler/riscv64/base.rs rename to src/compiler/arch/riscv64/base.rs index 6e81ff5..f40e66a 100644 --- a/src/compiler/riscv64/base.rs +++ b/src/compiler/arch/riscv64/base.rs @@ -2,11 +2,11 @@ use crate::util::Bits32; use super::Reg; -pub struct Instruction(u32); +pub struct RawInstruction(u32); -use Instruction as I; +use RawInstruction as I; -impl Instruction { +impl RawInstruction { pub fn to_le_bytes(&self) -> impl IntoIterator { self.0.to_le_bytes().into_iter() } diff --git a/src/compiler/arch/riscv64/compile.rs b/src/compiler/arch/riscv64/compile.rs new file mode 100644 index 0000000..6f88535 --- /dev/null +++ b/src/compiler/arch/riscv64/compile.rs @@ -0,0 +1,117 @@ +use std::collections::HashMap; + +use crate::{ + compiler::{arch::riscv64::Reg, create_program, Addr}, + ir::{ + arch::riscv64::{RV64Instruction as AI, RegRef}, + IRLInstruction as IRI, Program, + }, +}; + +use super::{LinkerInstruction as LI, *}; + +pub fn compile(program: Program) -> (Vec, Option) { + let mut fns = Vec::new(); + let mut data = Vec::new(); + for d in program.data { + data.push((d.data, d.addr)); + } + let mut start = None; + for f in program.fns { + let mut v = Vec::new(); + let mut stack = HashMap::new(); + let mut stack_len = 0; + if !f.stack.is_empty() || !f.args.is_empty() { + for (id, s) in &f.stack { + stack.insert(id, stack_len); + stack_len += *s as i32; + } + for (id, s) in f.args.iter().rev() { + stack.insert(id, stack_len); + stack_len += *s as i32; + } + v.push(LI::Addi { + dest: sp, + src: sp, + imm: -stack_len, + }); + } + for i in &f.instructions { + match i { + IRI::Mv { dest, src } => todo!(), + IRI::Ref { dest, src } => todo!(), + IRI::LoadAddr { dest, src } => { + v.extend([ + LI::La { + dest: t0, + src: *src, + }, + LI::Sd { + src: t0, + offset: stack[dest], + base: sp, + }, + ]); + } + IRI::Call { dest, f, args } => { + let mut offset = 0; + for (arg, s) in args { + offset -= *s as i32; + v.extend([ + LI::Ld { + dest: t0, + offset: stack[arg], + base: sp, + }, + LI::Sd { + src: t0, + offset, + base: sp, + }, + ]); + } + v.push(LI::Call(*f)); + } + IRI::AsmBlock { args, instructions } => { + for (reg, var) in args { + v.push(LI::Ld { + dest: *reg, + offset: stack[var], + base: sp, + }); + } + fn r(rr: RegRef) -> Reg { + match rr { + RegRef::Var(var_ident) => todo!(), + RegRef::Reg(reg) => reg, + } + } + for i in instructions { + match *i { + AI::Ecall => v.push(LI::Ecall), + AI::Li { dest, imm } => v.push(LI::Li { dest: r(dest), imm }), + AI::Mv { dest, src } => v.push(LI::Mv { + dest: r(dest), + src: r(src), + }), + AI::La { dest, src } => todo!(), + AI::Ld { dest, base, offset } => v.push(LI::Ld { + dest: r(dest), + offset: offset as i32, + base: r(base), + }), + } + } + } + IRI::Ret { src } => todo!(), + } + } + if f.name == "start" { + start = Some(f.addr); + } else { + v.push(LI::Ret); + } + fns.push((v, f.addr)); + } + create_program(fns, data, start) +} diff --git a/src/compiler/riscv64/funct.rs b/src/compiler/arch/riscv64/funct.rs similarity index 100% rename from src/compiler/riscv64/funct.rs rename to src/compiler/arch/riscv64/funct.rs diff --git a/src/compiler/arch/riscv64/mod.rs b/src/compiler/arch/riscv64/mod.rs new file mode 100644 index 0000000..76cb12d --- /dev/null +++ b/src/compiler/arch/riscv64/mod.rs @@ -0,0 +1,63 @@ +mod asm; +mod base; +mod funct; +mod opcode; +mod reg; +mod single; +mod compile; + +use crate::util::BitsI32; +pub use asm::*; +use base::*; +use funct::{op::*, width}; +use opcode::*; +pub use reg::*; +pub use compile::*; + +use single::*; + +pub fn gen() -> Vec { + // use asm::LinkerInstruction as I; + // let mut table = SymMap::new(); + // let (msg, len) = table.push_ro_data_size(b"Hello world!\n".to_vec()); + // let (msg2, len2) = table.push_ro_data_size(b"IT WORKS!!!!\n".to_vec()); + // let print_stuff = table.reserve(); + // let start = table.push_fn(vec![ + // I::Call(*print_stuff), + // I::Li { dest: a0, imm: 0 }, + // I::Li { dest: a7, imm: 93 }, + // I::Ecall, + // I::Jal { + // dest: zero, + // offset: 0, + // }, + // ]); + // table.write_fn( + // print_stuff, + // vec![ + // I::Li { dest: a0, imm: 1 }, + // I::La { dest: a1, src: msg }, + // I::Li { + // dest: a2, + // imm: len as i64, + // }, + // I::Li { dest: a7, imm: 64 }, + // I::Ecall, + // I::Li { dest: a0, imm: 1 }, + // I::La { + // dest: a1, + // src: msg2, + // }, + // I::Li { + // dest: a2, + // imm: len2 as i64, + // }, + // I::Li { dest: a7, imm: 64 }, + // I::Ecall, + // I::Ret, + // ], + // ); + // let (program, start) = create_program(table, Some(start)); + // elf::create(program, start.expect("no start!")) + todo!("remove this"); +} diff --git a/src/compiler/riscv64/opcode.rs b/src/compiler/arch/riscv64/opcode.rs similarity index 100% rename from src/compiler/riscv64/opcode.rs rename to src/compiler/arch/riscv64/opcode.rs diff --git a/src/compiler/arch/riscv64/reg.rs b/src/compiler/arch/riscv64/reg.rs new file mode 100644 index 0000000..92cea14 --- /dev/null +++ b/src/compiler/arch/riscv64/reg.rs @@ -0,0 +1,179 @@ +#![allow(non_upper_case_globals)] + +#[derive(Clone, Copy)] +pub struct Reg(u8); + +/// hard wired 0 +pub const zero: Reg = Reg(0); +/// return address +pub const ra: Reg = Reg(1); +/// stack pointer +pub const sp: Reg = Reg(2); +/// global pointer +pub const gp: Reg = Reg(3); +/// thread pointer +pub const tp: Reg = Reg(4); +/// temp / alternate link +pub const t0: Reg = Reg(5); +pub const t1: Reg = Reg(6); +pub const t2: Reg = Reg(7); + +pub const fp: Reg = Reg(8); +pub const s0: Reg = Reg(8); +pub const s1: Reg = Reg(9); + +pub const a0: Reg = Reg(10); +pub const a1: Reg = Reg(11); +pub const a2: Reg = Reg(12); +pub const a3: Reg = Reg(13); +pub const a4: Reg = Reg(14); +pub const a5: Reg = Reg(15); +pub const a6: Reg = Reg(16); +pub const a7: Reg = Reg(17); + +pub const s2: Reg = Reg(18); +pub const s3: Reg = Reg(19); +pub const s4: Reg = Reg(20); +pub const s5: Reg = Reg(21); +pub const s6: Reg = Reg(22); +pub const s7: Reg = Reg(23); +pub const s8: Reg = Reg(24); +pub const s9: Reg = Reg(25); +pub const s10: Reg = Reg(26); +pub const s11: Reg = Reg(27); + +pub const t3: Reg = Reg(28); +pub const t4: Reg = Reg(29); +pub const t5: Reg = Reg(30); +pub const t6: Reg = Reg(31); + +// pub const ft0: Reg = Reg(0); +// pub const ft1: Reg = Reg(1); +// pub const ft2: Reg = Reg(2); +// pub const ft3: Reg = Reg(3); +// pub const ft4: Reg = Reg(4); +// pub const ft5: Reg = Reg(5); +// pub const ft6: Reg = Reg(6); +// pub const ft7: Reg = Reg(7); +// +// pub const fs0: Reg = Reg(8); +// pub const fs1: Reg = Reg(9); +// +// pub const fa0: Reg = Reg(10); +// pub const fa1: Reg = Reg(11); +// pub const fa2: Reg = Reg(12); +// pub const fa3: Reg = Reg(13); +// pub const fa4: Reg = Reg(14); +// pub const fa5: Reg = Reg(15); +// pub const fa6: Reg = Reg(16); +// pub const fa7: Reg = Reg(17); +// +// pub const fs2: Reg = Reg(18); +// pub const fs3: Reg = Reg(19); +// pub const fs4: Reg = Reg(20); +// pub const fs5: Reg = Reg(21); +// pub const fs6: Reg = Reg(22); +// pub const fs7: Reg = Reg(23); +// pub const fs8: Reg = Reg(24); +// pub const fs9: Reg = Reg(25); +// pub const fs10: Reg = Reg(26); +// pub const fs11: Reg = Reg(27); +// +// pub const ft8: Reg = Reg(28); +// pub const ft9: Reg = Reg(29); +// pub const ft10: Reg = Reg(30); +// pub const ft11: Reg = Reg(31); + +impl Reg { + #[inline] + pub const fn val(&self) -> u32 { + self.0 as u32 + } +} + +impl Reg { + pub fn from_str(str: &str) -> Option { + Some(match str { + "zero" => zero, + "ra" => ra, + "sp" => sp, + "gp" => gp, + "tp" => tp, + "t0" => t0, + "t1" => t1, + "t2" => t2, + "fp" => fp, + "s0" => s0, + "s1" => s1, + "a0" => a0, + "a1" => a1, + "a2" => a2, + "a3" => a3, + "a4" => a4, + "a5" => a5, + "a6" => a6, + "a7" => a7, + "s2" => s2, + "s3" => s3, + "s4" => s4, + "s5" => s5, + "s6" => s6, + "s7" => s7, + "s8" => s8, + "s9" => s9, + "s10" => s10, + "s11" => s11, + "t3" => t3, + "t4" => t4, + "t5" => t5, + "t6" => t6, + _ => { + return None; + } + }) + } +} + +impl std::fmt::Debug for Reg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self.0 { + 0 => "zero", + 1 => "ra", + 2 => "sp", + 3 => "gp", + 4 => "tp", + 5 => "t0", + 6 => "t1", + 7 => "t2", + 8 => "fp", + 9 => "s1", + 10 => "a0", + 11 => "a1", + 12 => "a2", + 13 => "a3", + 14 => "a4", + 15 => "a5", + 16 => "a6", + 17 => "a7", + 18 => "s2", + 19 => "s3", + 20 => "s4", + 21 => "s5", + 22 => "s6", + 23 => "s7", + 24 => "s8", + 25 => "s9", + 26 => "s10", + 27 => "s11", + 28 => "t3", + 29 => "t4", + 30 => "t5", + 31 => "t6", + _ => "unknown", + } + ) + } +} diff --git a/src/compiler/riscv64/single.rs b/src/compiler/arch/riscv64/single.rs similarity index 98% rename from src/compiler/riscv64/single.rs rename to src/compiler/arch/riscv64/single.rs index 7bcdb57..b6e98db 100644 --- a/src/compiler/riscv64/single.rs +++ b/src/compiler/arch/riscv64/single.rs @@ -2,7 +2,7 @@ use crate::util::{Bits32, BitsI32}; use super::*; -use Instruction as I; +use RawInstruction as I; pub const fn ecall() -> I { i_type(Bits32::new(0), zero, Bits32::new(0), zero, SYSTEM) diff --git a/src/compiler/instruction.rs b/src/compiler/instruction.rs deleted file mode 100644 index 92ef7e7..0000000 --- a/src/compiler/instruction.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub enum Instruction { -} diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 7e6459d..2b95d2e 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -5,14 +5,21 @@ use std::{ process::Command, }; +pub mod arch; mod elf; mod program; -pub mod riscv64; mod target; -mod instruction; pub use program::*; +use crate::ir::Program; + +pub fn compile(program: Program) -> Vec { + let (compiled, start) = arch::riscv64::compile(program); + let binary = elf::create(compiled, start.expect("no start method found")); + binary +} + pub fn main() { use std::io::prelude::*; let dir = Path::new("./build"); @@ -27,7 +34,7 @@ pub fn main() { .mode(0o750) .open(path) .expect("Failed to create file"); - file.write_all(&riscv64::gen()) + file.write_all(&arch::riscv64::gen()) .expect("Failed to write to file"); file.sync_all().expect("Failed to sync file"); let mut p = Command::new("qemu-riscv64"); @@ -64,4 +71,3 @@ pub fn main() { } } } - diff --git a/src/compiler/program.rs b/src/compiler/program.rs index 1a8c8eb..68be362 100644 --- a/src/compiler/program.rs +++ b/src/compiler/program.rs @@ -1,14 +1,21 @@ use std::{collections::HashMap, ops::Deref}; -pub fn create_program(map: SymMap, start: Symbol) -> (Vec, Option) { +use crate::ir::AddrID; + +pub fn create_program( + fns: Vec<(Vec, AddrID)>, + ro_data: Vec<(Vec, AddrID)>, + start: Option, +) -> (Vec, Option) { let mut data = Vec::new(); - let mut sym_table = SymTable::new(map.len()); - let mut missing = HashMap::>::new(); - for (val, id) in map.ro_data { + let mut sym_table = SymTable::new(fns.len() + ro_data.len()); + let mut missing = HashMap::>::new(); + for (val, id) in ro_data { sym_table.insert(id, Addr(data.len() as u64)); data.extend(val); } - for (fun, id) in map.functions { + data.resize(data.len() + (4 - data.len() % 4), 0); + for (fun, id) in fns { sym_table.insert(id, Addr(data.len() as u64)); for i in fun { let i_pos = Addr(data.len() as u64); @@ -30,11 +37,15 @@ pub fn create_program(map: SymMap, start: Symbol) -> (Vec, Opti } } assert!(missing.is_empty()); - (data, sym_table.get(start)) + ( + data, + start.map(|s| sym_table.get(s).expect("start symbol doesn't exist")), + ) } pub trait Instr { - fn push(&self, data: &mut Vec, syms: &SymTable, pos: Addr, missing: bool) -> Option; + fn push(&self, data: &mut Vec, syms: &SymTable, pos: Addr, missing: bool) + -> Option; } #[derive(Debug, Clone, Copy, PartialEq)] @@ -73,19 +84,23 @@ impl SymMap { functions: Vec::new(), } } - pub fn push_ro_data(&mut self, data: impl Into>) -> (Symbol, usize) { + pub fn push_ro_data(&mut self, data: Vec) -> Symbol { let sym = self.reserve(); - self.write_ro_data(sym, data) + self.write_ro_data(sym, data.into()) + } + pub fn push_ro_data_size(&mut self, data: Vec) -> (Symbol, usize) { + let sym = self.reserve(); + let len = data.len(); + (self.write_ro_data(sym, data), len) } pub fn push_fn(&mut self, instructions: Vec) -> Symbol { let sym = self.reserve(); self.write_fn(sym, instructions) } - pub fn write_ro_data(&mut self, sym: WritableSymbol, data: impl Into>) -> (Symbol, usize) { + pub fn write_ro_data(&mut self, sym: WritableSymbol, data: Vec) -> Symbol { let data = data.into(); - let len = data.len(); self.ro_data.push((data, *sym)); - (*sym, len) + *sym } pub fn write_fn(&mut self, sym: WritableSymbol, instructions: Vec) -> Symbol { self.functions.push((instructions, *sym)); @@ -106,10 +121,10 @@ impl SymTable { pub fn new(len: usize) -> Self { Self(vec![Addr::NONE; len]) } - pub fn insert(&mut self, sym: Symbol, addr: Addr) { + pub fn insert(&mut self, sym: AddrID, addr: Addr) { self.0[sym.0] = addr; } - pub fn get(&self, sym: Symbol) -> Option { + pub fn get(&self, sym: AddrID) -> Option { match self.0[sym.0] { Addr::NONE => None, addr => Some(addr), diff --git a/src/compiler/riscv64/mod.rs b/src/compiler/riscv64/mod.rs deleted file mode 100644 index 7f888c7..0000000 --- a/src/compiler/riscv64/mod.rs +++ /dev/null @@ -1,63 +0,0 @@ -mod asm; -mod base; -mod funct; -mod opcode; -mod parse; -mod reg; -mod single; - -use super::{create_program, elf, SymMap}; -use crate::util::BitsI32; -pub use asm::*; -use base::*; -use funct::{op::*, width}; -use opcode::*; -pub use parse::*; -pub use reg::*; - -use single::*; - -pub fn gen() -> Vec { - use asm::AsmInstruction as I; - let mut table = SymMap::new(); - let (msg, len) = table.push_ro_data(b"Hello world!\n"); - let (msg2, len2) = table.push_ro_data(b"IT WORKS!!!!\n"); - let print_stuff = table.reserve(); - let start = table.push_fn(vec![ - I::Call(*print_stuff), - I::Li { dest: a0, imm: 0 }, - I::Li { dest: a7, imm: 93 }, - I::Ecall, - I::Jal { - dest: zero, - offset: 0, - }, - ]); - table.write_fn( - print_stuff, - vec![ - I::Li { dest: a0, imm: 1 }, - I::La { dest: a1, sym: msg }, - I::Li { - dest: a2, - imm: len as i64, - }, - I::Li { dest: a7, imm: 64 }, - I::Ecall, - I::Li { dest: a0, imm: 1 }, - I::La { - dest: a1, - sym: msg2, - }, - I::Li { - dest: a2, - imm: len2 as i64, - }, - I::Li { dest: a7, imm: 64 }, - I::Ecall, - I::Ret, - ], - ); - let (program, start) = create_program(table, start); - elf::create(program, start.expect("no start!")) -} diff --git a/src/compiler/riscv64/parse.rs b/src/compiler/riscv64/parse.rs deleted file mode 100644 index 7f39da8..0000000 --- a/src/compiler/riscv64/parse.rs +++ /dev/null @@ -1,104 +0,0 @@ -use super::{reg::*, AsmInstruction, Reg}; -use crate::parser::{Parsable, ParseResult, ParserMsg, ParserOutput, Symbol, Token}; - -impl Parsable for AsmInstruction { - fn parse( - cursor: &mut crate::parser::TokenCursor, - output: &mut ParserOutput, - ) -> ParseResult { - let t = cursor.expect_next()?; - let span = t.span; - match &t.token { - Token::Word(w) => ParseResult::Ok(match w.as_str() { - "ecall" => Self::Ecall, - "li" => { - let dest = Reg::parse(cursor, output)?; - cursor.expect_sym(Symbol::Comma)?; - let imm = i64::parse(cursor, output)?; - Self::Li { dest, imm } - } - _ => { - return ParseResult::Err(ParserMsg::from_span( - span, - format!("Unknown instruction {}", w), - )) - } - }), - _ => return ParseResult::Err(ParserMsg::unexpected_token(&t, "assembly or }")), - } - } -} - -impl Parsable for Reg { - fn parse( - cursor: &mut crate::parser::TokenCursor, - output: &mut ParserOutput, - ) -> ParseResult { - let next = cursor.expect_next()?; - let Token::Word(word) = next.token else { - return ParseResult::Err(ParserMsg::unexpected_token(&next, "a riscv register")); - }; - ParseResult::Ok(match word.as_str() { - "zero" => zero, - "ra" => ra, - "sp" => sp, - "gp" => gp, - "tp" => tp, - "t0" => t0, - "t1" => t1, - "t2" => t2, - "fp" => fp, - "s0" => s0, - "s1" => s1, - "a0" => a0, - "a1" => a1, - "a2" => a2, - "a3" => a3, - "a4" => a4, - "a5" => a5, - "a6" => a6, - "a7" => a7, - "s2" => s2, - "s3" => s3, - "s4" => s4, - "s5" => s5, - "s6" => s6, - "s7" => s7, - "s8" => s8, - "s9" => s9, - "s10" => s10, - "s11" => s11, - "t3" => t3, - "t4" => t4, - "t5" => t5, - "t6" => t6, - other => { - return ParseResult::Err(ParserMsg::from_span( - next.span, - format!("Unknown reg name {}", other), - )); - } - }) - } -} - -impl Parsable for i64 { - fn parse( - cursor: &mut crate::parser::TokenCursor, - _output: &mut ParserOutput, - ) -> ParseResult { - let next = cursor.expect_next()?; - let span = next.span; - let Token::Word(word) = next.token else { - return ParseResult::Err(ParserMsg::unexpected_token(&next, "an i32")); - }; - let res = word.parse::(); - match res { - Ok(int) => ParseResult::Ok(int), - Err(_) => ParseResult::Err(ParserMsg::from_span( - span, - format!("Expected an i32, found {}", word), - )), - } - } -} diff --git a/src/compiler/riscv64/reg.rs b/src/compiler/riscv64/reg.rs deleted file mode 100644 index ed71b46..0000000 --- a/src/compiler/riscv64/reg.rs +++ /dev/null @@ -1,94 +0,0 @@ -#![allow(non_upper_case_globals)] - -#[derive(Debug, Clone, Copy)] -pub struct Reg(u8); - -/// hard wired 0 -pub const zero: Reg = Reg(0); -/// return address -pub const ra: Reg = Reg(1); -/// stack pointer -pub const sp: Reg = Reg(2); -/// global pointer -pub const gp: Reg = Reg(3); -/// thread pointer -pub const tp: Reg = Reg(4); -/// temp / alternate link -pub const t0: Reg = Reg(5); -pub const t1: Reg = Reg(6); -pub const t2: Reg = Reg(7); - -pub const fp: Reg = Reg(8); -pub const s0: Reg = Reg(8); -pub const s1: Reg = Reg(9); - -pub const a0: Reg = Reg(10); -pub const a1: Reg = Reg(11); -pub const a2: Reg = Reg(12); -pub const a3: Reg = Reg(13); -pub const a4: Reg = Reg(14); -pub const a5: Reg = Reg(15); -pub const a6: Reg = Reg(16); -pub const a7: Reg = Reg(17); - -pub const s2: Reg = Reg(18); -pub const s3: Reg = Reg(19); -pub const s4: Reg = Reg(20); -pub const s5: Reg = Reg(21); -pub const s6: Reg = Reg(22); -pub const s7: Reg = Reg(23); -pub const s8: Reg = Reg(24); -pub const s9: Reg = Reg(25); -pub const s10: Reg = Reg(26); -pub const s11: Reg = Reg(27); - -pub const t3: Reg = Reg(28); -pub const t4: Reg = Reg(29); -pub const t5: Reg = Reg(30); -pub const t6: Reg = Reg(31); - - - -pub const ft0: Reg = Reg(0); -pub const ft1: Reg = Reg(1); -pub const ft2: Reg = Reg(2); -pub const ft3: Reg = Reg(3); -pub const ft4: Reg = Reg(4); -pub const ft5: Reg = Reg(5); -pub const ft6: Reg = Reg(6); -pub const ft7: Reg = Reg(7); - -pub const fs0: Reg = Reg(8); -pub const fs1: Reg = Reg(9); - -pub const fa0: Reg = Reg(10); -pub const fa1: Reg = Reg(11); -pub const fa2: Reg = Reg(12); -pub const fa3: Reg = Reg(13); -pub const fa4: Reg = Reg(14); -pub const fa5: Reg = Reg(15); -pub const fa6: Reg = Reg(16); -pub const fa7: Reg = Reg(17); - -pub const fs2: Reg = Reg(18); -pub const fs3: Reg = Reg(19); -pub const fs4: Reg = Reg(20); -pub const fs5: Reg = Reg(21); -pub const fs6: Reg = Reg(22); -pub const fs7: Reg = Reg(23); -pub const fs8: Reg = Reg(24); -pub const fs9: Reg = Reg(25); -pub const fs10: Reg = Reg(26); -pub const fs11: Reg = Reg(27); - -pub const ft8: Reg = Reg(28); -pub const ft9: Reg = Reg(29); -pub const ft10: Reg = Reg(30); -pub const ft11: Reg = Reg(31); - -impl Reg { - #[inline] - pub const fn val(&self) -> u32 { - self.0 as u32 - } -} diff --git a/src/ir/arch/mod.rs b/src/ir/arch/mod.rs new file mode 100644 index 0000000..ceb8572 --- /dev/null +++ b/src/ir/arch/mod.rs @@ -0,0 +1 @@ +pub mod riscv64; diff --git a/src/ir/arch/riscv64.rs b/src/ir/arch/riscv64.rs new file mode 100644 index 0000000..55ed3dd --- /dev/null +++ b/src/ir/arch/riscv64.rs @@ -0,0 +1,37 @@ +use crate::{compiler::arch::riscv64::*, ir::VarID}; + +#[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 }, +} + +#[derive(Copy, Clone)] +pub enum RegRef { + Var(VarID), + Reg(Reg), +} + +impl std::fmt::Debug for RegRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Var(v) => write!(f, "{{{:?}}}", v), + Self::Reg(r) => r.fmt(f), + } + } +} + +impl std::fmt::Debug for RV64Instruction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ecall => write!(f, "ecall"), + Self::Li { dest, imm } => write!(f, "li {dest:?}, {imm:?}"), + Self::Mv { dest, src } => write!(f, "mv {dest:?}, {src:?}"), + Self::La { dest, src } => write!(f, "la {dest:?}, {src:?}"), + Self::Ld { dest, offset, base } => write!(f, "ld {dest:?}, {offset}({base:?})"), + } + } +} diff --git a/src/ir/asm.rs b/src/ir/asm.rs new file mode 100644 index 0000000..08eb182 --- /dev/null +++ b/src/ir/asm.rs @@ -0,0 +1,13 @@ +use super::VarID; + +#[derive(Clone)] +pub struct IRAsmInstruction { + op: String, + args: Vec, +} + +#[derive(Clone)] +pub enum RegRef { + Var(VarID), + Reg(String), +} diff --git a/src/ir/id.rs b/src/ir/id.rs new file mode 100644 index 0000000..63ed37e --- /dev/null +++ b/src/ir/id.rs @@ -0,0 +1,42 @@ +use std::fmt::Debug; + +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +pub struct TypeID(pub usize); +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +pub struct VarID(pub usize); +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +pub struct FnID(pub usize); +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +pub struct DataID(pub usize); +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +pub struct AddrID(pub usize); + +impl Debug for VarID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "var{}", self.0) + } +} + +impl Debug for TypeID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ty{}", self.0) + } +} + +impl Debug for FnID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "fn{}", self.0) + } +} + +impl Debug for DataID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "data{}", self.0) + } +} + +impl Debug for AddrID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "@{}", self.0) + } +} diff --git a/src/ir/lower/data.rs b/src/ir/lower/data.rs new file mode 100644 index 0000000..84b92cd --- /dev/null +++ b/src/ir/lower/data.rs @@ -0,0 +1,6 @@ +use super::AddrID; + +pub struct IRLData { + pub addr: AddrID, + pub data: Vec, +} diff --git a/src/ir/lower/func.rs b/src/ir/lower/func.rs new file mode 100644 index 0000000..75ba270 --- /dev/null +++ b/src/ir/lower/func.rs @@ -0,0 +1,41 @@ +use super::*; +use crate::compiler::arch::riscv64::Reg; +use arch::riscv64::RV64Instruction; +use std::collections::HashMap; + +#[derive(Debug)] +pub struct IRLFunction { + pub name: String, + pub addr: AddrID, + pub instructions: Vec, + pub stack: HashMap, + pub args: Vec<(VarID, usize)>, +} + +#[derive(Debug)] +pub enum IRLInstruction { + Mv { + dest: VarID, + src: VarID, + }, + Ref { + dest: VarID, + src: VarID, + }, + LoadAddr { + dest: VarID, + src: AddrID, + }, + Call { + dest: VarID, + f: AddrID, + args: Vec<(VarID, usize)>, + }, + AsmBlock { + instructions: Vec, + args: Vec<(Reg, VarID)>, + }, + Ret { + src: VarID, + }, +} diff --git a/src/ir/lower/mod.rs b/src/ir/lower/mod.rs new file mode 100644 index 0000000..61b26da --- /dev/null +++ b/src/ir/lower/mod.rs @@ -0,0 +1,9 @@ +mod func; +mod data; +mod program; + +pub use func::*; +pub use data::*; +pub use program::*; + +use super::*; diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs new file mode 100644 index 0000000..6e10394 --- /dev/null +++ b/src/ir/lower/program.rs @@ -0,0 +1,85 @@ +use std::collections::HashMap; + +use super::{AddrID, IRLData, IRLFunction, IRLInstruction, IRUInstruction, Namespace, VarID}; + +pub struct Program { + pub fns: Vec, + pub data: Vec, +} + +impl Program { + pub fn create(ns: &Namespace) -> Self { + let mut fns = Vec::new(); + let mut data = Vec::new(); + let data_len = ns.data.len(); + for (i, d) in ns.data.iter().enumerate() { + data.push(IRLData { + addr: AddrID(i), + data: d.clone(), + }) + } + for (i, f) in ns.fns.iter().enumerate() { + let f = f.as_ref().unwrap(); + let mut instructions = Vec::new(); + let mut stack = HashMap::new(); + let mut alloc = |i: &VarID| { + if !stack.contains_key(i) { + stack.insert(*i, 8); + } + }; + for i in &f.instructions { + instructions.push(match i { + IRUInstruction::Mv { dest, src } => { + alloc(dest); + IRLInstruction::Mv { + dest: *dest, + src: *src, + } + } + IRUInstruction::Ref { dest, src } => { + alloc(dest); + IRLInstruction::Ref { + dest: *dest, + src: *src, + } + } + IRUInstruction::LoadData { dest, src } => { + alloc(dest); + IRLInstruction::LoadAddr { + dest: *dest, + src: AddrID(src.0), + } + } + IRUInstruction::LoadFn { dest, src } => { + alloc(dest); + IRLInstruction::LoadAddr { + dest: *dest, + src: AddrID(src.0 + data_len), + } + } + IRUInstruction::Call { dest, f, args } => { + alloc(dest); + IRLInstruction::Call { + dest: *dest, + f: AddrID(ns.fn_map[f].0 + data_len), + args: args.iter().map(|a| (*a, 8)).collect(), + } + } + IRUInstruction::AsmBlock { instructions, args } => IRLInstruction::AsmBlock { + instructions: instructions.clone(), + args: args.clone(), + }, + IRUInstruction::Ret { src } => IRLInstruction::Ret { src: *src }, + }); + } + fns.push(IRLFunction { + name: f.name.clone(), + addr: AddrID(i + data_len), + instructions, + args: f.args.iter().map(|a| (*a, 8)).collect(), + stack, + }) + } + Self { fns, data } + } +} diff --git a/src/ir/lvl1/func.rs b/src/ir/lvl1/func.rs deleted file mode 100644 index 1e8d7ea..0000000 --- a/src/ir/lvl1/func.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::compiler::riscv64::AsmInstruction; - -use super::{FnIdent, VarIdent}; - -#[derive(Debug)] -pub struct Function { - instructions: Vec, -} - -#[derive(Debug)] -pub enum Instruction { - Mv { - dest: VarIdent, - src: VarIdent, - }, - Ref { - dest: VarIdent, - src: VarIdent, - }, - Lf { - dest: VarIdent, - src: FnIdent, - }, - Call { - dest: VarIdent, - f: FnIdent, - args: Vec, - }, - AsmBlock { - instructions: Vec, - }, - Ret { - src: VarIdent, - }, -} - -pub struct Instructions { - vec: Vec, -} - -impl Function { - pub fn new(instructions: Instructions) -> Self { - Self { - instructions: instructions.vec, - } - } -} - -impl Instructions { - pub fn new() -> Self { - Self { vec: Vec::new() } - } - pub fn push(&mut self, i: Instruction) { - self.vec.push(i); - } -} diff --git a/src/ir/lvl2/mod.rs b/src/ir/lvl2/mod.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 0d9a88c..68ff9eb 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,9 +1,11 @@ -mod namespace; -mod lvl1; -mod lvl2; +mod upper; mod file; +mod lower; +mod id; +mod asm; +pub mod arch; -pub use namespace::*; -pub use lvl1::*; +pub use upper::*; +pub use lower::*; pub use file::*; - +pub use id::*; diff --git a/src/ir/old.rs b/src/ir/old.rs deleted file mode 100644 index 2ac5328..0000000 --- a/src/ir/old.rs +++ /dev/null @@ -1,226 +0,0 @@ -#[derive(Debug)] -pub enum IRInstruction { - Li(Var, Literal), - Mv(Var, Var), - Not(Var, Var), - Add(Var, Var, Var), - La(Var, IRIdent), - Call(Var, FnIdent, Vec), -} - -#[derive(Debug)] -pub struct IRFunction { - args: Vec, - instructions: Vec, -} - -impl Module { - pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) { - let mut fns = Vec::new(); - for f in &self.functions { - if let Some(f) = f.as_ref() { - if let Some(id) = f.reserve(map, errors) { - fns.push((id, f)); - } - } - } - for (id, f) in fns { - f.lower(id, map, errors); - } - } -} - -impl Function { - pub fn reserve(&self, map: &mut Namespace, errors: &mut ParserErrors) -> Option { - let name = self.name.as_ref()?; - if let Some(other) = map.get(name) { - errors.add(ParserError { - msg: format!("Already {:?} named '{:?}'", other.ty, self.name), - spans: vec![self.name.span, other.origin], - }); - None - } else { - Some(map.reserve_fn(name, self.name.span)) - } - } - pub fn lower( - &self, - ident: FnIdent, - map: &mut Namespace, - errors: &mut ParserErrors, - ) -> Option<()> { - let mut instructions = Vec::new(); - let mut map = map.push(); - let mut args = Vec::new(); - for arg in &self.args { - args.push(map.def_var(arg.as_ref()?, arg.span)?); - } - if let Some(b) = self.body.as_ref() { - b.lower(&mut map, &mut instructions, errors) - } - map.write_fn(ident, IRFunction { instructions, args }); - Some(()) - } -} - -impl Body { - pub fn lower( - &self, - map: &mut Namespace, - instructions: &mut Vec, - errors: &mut ParserErrors, - ) { - let mut map = map.push(); - for statement in &self.statements { - let Some(statement) = statement.as_ref() else { - continue; - }; - match statement { - Statement::Let(name_node, expr) => { - let Some(name) = name_node.as_ref() else { - continue; - }; - let res = expr.lower(&mut map, instructions, errors); - if let Some(res) = res { - match res { - ExprResult::Var(v) => map.name_var(name, v), - ExprResult::Fn(f) => todo!(), - }; - } - } - Statement::Return(e) => todo!(), - Statement::Expr(expr) => { - expr.lower(&mut map, instructions, errors); - } - } - } - } -} - -impl Node> { - pub fn lower( - &self, - map: &mut Namespace, - instructions: &mut Vec, - errors: &mut ParserErrors, - ) -> Option { - self.as_ref()?.lower(self.span, map, instructions, errors) - } -} - -impl Node { - pub fn lower( - &self, - map: &mut Namespace, - instructions: &mut Vec, - errors: &mut ParserErrors, - ) -> Option { - self.as_ref()?.lowerr(self.span, map, instructions, errors) - } -} - -impl Expr { - pub fn lowerr( - &self, - span: FileSpan, - map: &mut Namespace, - instructions: &mut Vec, - errors: &mut ParserErrors, - ) -> Option { - match self { - Expr::Lit(l) => { - let temp = map.temp_var(span); - instructions.push(IRInstruction::Li(temp, l.as_ref()?.clone())); - Some(ExprResult::Var(temp)) - }, - Expr::Ident(i) => { - let Some(id) = map.get(i.as_ref()?) else { - errors.add(ParserError::identifier_not_found(i)); - return None; - }; - match id.ty() { - IdentTypeMatch::Var(var) => Some(ExprResult::Var(var)), - IdentTypeMatch::Fn(f) => Some(ExprResult::Fn(f)), - } - } - Expr::BinaryOp(op, e1, e2) => { - let res1 = e1.lower(map, instructions, errors)?; - let res2 = e2.lower(map, instructions, errors)?; - let (ExprResult::Var(v1), ExprResult::Var(v2)) = (res1, res2) else { - errors.add(ParserError::from_span(span, "Cannot operate on functions".to_string())); - return None; - }; - let temp = map.temp_var(span); - match op { - crate::parser::BinaryOperator::Add => { - instructions.push(IRInstruction::Add(temp, v1, v2)) - } - crate::parser::BinaryOperator::Sub => todo!(), - crate::parser::BinaryOperator::Mul => todo!(), - crate::parser::BinaryOperator::Div => todo!(), - crate::parser::BinaryOperator::LessThan => todo!(), - crate::parser::BinaryOperator::GreaterThan => todo!(), - crate::parser::BinaryOperator::Access => todo!(), - crate::parser::BinaryOperator::Assign => todo!(), - } - Some(ExprResult::Var(temp)) - } - Expr::UnaryOp(op, e) => { - let res = e.lower(map, instructions, errors)?; - let res = match op { - crate::parser::UnaryOperator::Not => { - let temp = map.temp_var(span); - match res { - ExprResult::Var(i) => instructions.push(IRInstruction::Not(temp, i)), - ExprResult::Fn(_) => { - errors.add(ParserError::from_span( - span, - "Cannot call not on a function".to_string(), - )); - return None; - } - } - temp - } - crate::parser::UnaryOperator::Ref => todo!(), - }; - Some(ExprResult::Var(res)) - } - Expr::Block(_) => todo!(), - Expr::Call(e, args) => { - let fe = e.lower(map, instructions, errors); - let mut nargs = Vec::new(); - for arg in args.iter() { - let arg = arg.lower(map, instructions, errors)?; - nargs.push(arg); - } - if let Some(r) = fe { - match r { - ExprResult::Fn(f) => { - let temp = map.temp_var(span); - instructions.push(IRInstruction::Call(temp, f, nargs)); - Some(ExprResult::Var(temp)) - } - o => { - errors.add(ParserError::from_span( - span, - "Expected function".to_string(), - )); - None - } - } - } else { - None - } - } - Expr::Group(e) => e.lower(map, instructions, errors), - } - } -} - -#[derive(Debug)] -pub enum ExprResult { - Var(Var), - Fn(FnIdent), -} - diff --git a/src/ir/lvl1/def.rs b/src/ir/upper/def.rs similarity index 94% rename from src/ir/lvl1/def.rs rename to src/ir/upper/def.rs index 0ab1110..da5f9af 100644 --- a/src/ir/lvl1/def.rs +++ b/src/ir/upper/def.rs @@ -1,6 +1,7 @@ use super::{FileSpan, Type}; use std::fmt::Debug; +#[derive(Clone)] pub struct FnDef { pub name: String, pub args: Vec, @@ -8,6 +9,7 @@ pub struct FnDef { pub origin: Origin, } +#[derive(Clone)] pub struct TypeDef { pub name: String, pub args: usize, diff --git a/src/ir/upper/func.rs b/src/ir/upper/func.rs new file mode 100644 index 0000000..7fbe294 --- /dev/null +++ b/src/ir/upper/func.rs @@ -0,0 +1,82 @@ +use crate::compiler::arch::riscv64::Reg; + +use super::{arch::riscv64::RV64Instruction, DataID, FnID, VarID}; + +#[derive(Debug)] +pub struct IRUFunction { + pub name: String, + pub args: Vec, + pub instructions: Vec, +} + +pub enum IRUInstruction { + Mv { + dest: VarID, + src: VarID, + }, + Ref { + dest: VarID, + src: VarID, + }, + LoadData { + dest: VarID, + src: DataID, + }, + LoadFn { + dest: VarID, + src: FnID, + }, + Call { + dest: VarID, + f: VarID, + args: Vec, + }, + AsmBlock { + instructions: Vec, + args: Vec<(Reg, VarID)>, + }, + Ret { + src: VarID, + }, +} + +pub struct IRInstructions { + vec: Vec, +} + +impl IRUFunction { + pub fn new(name: String, args: Vec, instructions: IRInstructions) -> Self { + Self { + name, + args, + instructions: instructions.vec, + } + } +} + +impl IRInstructions { + pub fn new() -> Self { + Self { vec: Vec::new() } + } + pub fn push(&mut self, i: IRUInstruction) { + self.vec.push(i); + } +} + +impl std::fmt::Debug for IRUInstruction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}"), + 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::Call { + dest, + f: func, + args, + } => write!(f, "{dest:?} <- {func:?}({args:?})"), + Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}"), + Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish(), + } + } +} diff --git a/src/ir/lvl1/mod.rs b/src/ir/upper/mod.rs similarity index 70% rename from src/ir/lvl1/mod.rs rename to src/ir/upper/mod.rs index 93fd016..c027275 100644 --- a/src/ir/lvl1/mod.rs +++ b/src/ir/upper/mod.rs @@ -1,9 +1,10 @@ mod def; mod func; mod ty; +mod namespace; use super::*; pub use def::*; pub use func::*; pub use ty::*; - +pub use namespace::*; diff --git a/src/ir/namespace.rs b/src/ir/upper/namespace.rs similarity index 71% rename from src/ir/namespace.rs rename to src/ir/upper/namespace.rs index 24ffe2e..178b129 100644 --- a/src/ir/namespace.rs +++ b/src/ir/upper/namespace.rs @@ -4,13 +4,15 @@ use std::{ ops::{Deref, DerefMut}, }; -use super::{BuiltinType, FileSpan, FnDef, Function, Type, TypeDef, VarDef}; +use super::*; pub struct Namespace { pub fn_defs: Vec, pub var_defs: Vec, pub type_defs: Vec, - pub fns: Vec>, + pub fns: Vec>, + pub data: Vec>, + pub fn_map: HashMap, pub temp: usize, pub stack: Vec>, } @@ -21,6 +23,8 @@ impl Namespace { fn_defs: Vec::new(), var_defs: Vec::new(), type_defs: Vec::new(), + data: Vec::new(), + fn_map: HashMap::new(), fns: Vec::new(), temp: 0, stack: vec![HashMap::new()], @@ -43,27 +47,36 @@ impl Namespace { } None } - pub fn get_var(&self, id: VarIdent) -> &VarDef { + pub fn get_var(&self, id: VarID) -> &VarDef { &self.var_defs[id.0] } - pub fn get_fn(&self, id: FnIdent) -> &FnDef { + pub fn get_fn(&self, id: FnID) -> &FnDef { &self.fn_defs[id.0] } - pub fn get_type(&self, id: TypeIdent) -> &TypeDef { + pub fn get_fn_var(&self, id: VarID) -> &FnDef { + &self.fn_defs[self.fn_map[&id].0] + } + pub fn get_type(&self, id: TypeID) -> &TypeDef { &self.type_defs[id.0] } - pub fn alias_fn(&mut self, name: &str, id: FnIdent) { + pub fn alias_fn(&mut self, name: &str, id: FnID) { self.insert(name, Ident::Fn(id)); } - pub fn name_var(&mut self, def: &VarDef, var: VarIdent) { + pub fn named_var(&mut self, def: VarDef) -> VarID { + // TODO: this is stupid + let id = self.def_var(def.clone()); + self.name_var(&def, id); + id + } + pub fn name_var(&mut self, def: &VarDef, var: VarID) { self.insert(&def.name, Ident::Var(var)); } - pub fn def_var(&mut self, var: VarDef) -> VarIdent { + pub fn def_var(&mut self, var: VarDef) -> VarID { let i = self.var_defs.len(); self.var_defs.push(var); - VarIdent(i) + VarID(i) } - pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarIdent { + pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID { let v = self.def_var(VarDef { name: format!("temp{}", self.temp), origin: super::Origin::File(origin), @@ -72,21 +85,38 @@ impl Namespace { self.temp += 1; v } - pub fn def_fn(&mut self, def: FnDef) -> FnIdent { + pub fn def_fn(&mut self, def: FnDef) -> FnID { let i = self.fn_defs.len(); - let id = FnIdent(i); + let id = FnID(i); + let var_def = VarDef { + name: def.name.clone(), + origin: def.origin, + ty: def.ty(), + }; + + let vid = self.def_var(var_def); + self.insert(&def.name, Ident::Var(vid)); + self.fn_map.insert(vid, id); + self.insert(&def.name, Ident::Fn(id)); self.fn_defs.push(def); self.fns.push(None); + + id } - pub fn def_type(&mut self, def: TypeDef) -> TypeIdent { + pub fn def_type(&mut self, def: TypeDef) -> TypeID { let i = self.type_defs.len(); - let id = TypeIdent(i); + let id = TypeID(i); self.insert(&def.name, Ident::Type(id)); self.type_defs.push(def); id } + pub fn def_data(&mut self, bytes: Vec) -> DataID { + let i = self.data.len(); + self.data.push(bytes); + DataID(i) + } pub fn type_name(&self, ty: &Type) -> String { let mut str = String::new(); match ty { @@ -121,6 +151,8 @@ impl Namespace { } Type::Error => str += "{error}", Type::Infer => str += "{inferred}", + Type::Bits(size) => str += &format!("b{}", size), + Type::Array(t) => str += &format!("[{}]", self.type_name(t)), } str } @@ -133,7 +165,7 @@ impl Namespace { last.insert(name.to_string(), Idents::new(id)); } } - pub fn write_fn(&mut self, id: FnIdent, f: Function) { + pub fn write_fn(&mut self, id: FnID, f: IRUFunction) { self.fns[id.0] = Some(f); } } @@ -161,18 +193,17 @@ impl DerefMut for NamespaceGuard<'_> { #[derive(Debug, Clone, Copy)] pub enum Ident { - Var(VarIdent), - Fn(FnIdent), - Type(TypeIdent), + Var(VarID), + Fn(FnID), + Type(TypeID), } #[derive(Debug, Clone, Copy)] pub struct Idents { pub latest: Ident, - pub var: Option, - pub func: Option, - pub var_func: Option, - pub ty: Option, + pub var: Option, + pub func: Option, + pub ty: Option, } impl Idents { @@ -181,7 +212,6 @@ impl Idents { latest, var: None, func: None, - var_func: None, ty: None, }; s.insert(latest); @@ -192,50 +222,12 @@ impl Idents { match i { Ident::Var(v) => { self.var = Some(v); - self.var_func = Some(VarOrFnIdent::Var(v)); } Ident::Fn(f) => { self.func = Some(f); - self.var_func = Some(VarOrFnIdent::Fn(f)); } Ident::Type(t) => self.ty = Some(t), } } } -#[derive(Clone, Copy)] -pub struct TypeIdent(usize); -#[derive(Clone, Copy)] -pub struct VarIdent(usize); -#[derive(Clone, Copy)] -pub struct FnIdent(usize); - -#[derive(Debug, Clone, Copy)] -pub enum VarOrFnIdent { - Var(VarIdent), - Fn(FnIdent), -} - -impl TypeIdent { - pub fn builtin(ty: &BuiltinType) -> Self { - Self(*ty as usize) - } -} - -impl Debug for VarIdent { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "v{}", self.0) - } -} - -impl Debug for TypeIdent { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "t{}", self.0) - } -} - -impl Debug for FnIdent { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "f{}", self.0) - } -} diff --git a/src/ir/lvl1/ty.rs b/src/ir/upper/ty.rs similarity index 53% rename from src/ir/lvl1/ty.rs rename to src/ir/upper/ty.rs index e8d7ad5..f452e39 100644 --- a/src/ir/lvl1/ty.rs +++ b/src/ir/upper/ty.rs @@ -1,15 +1,26 @@ -use super::{Origin, TypeDef, TypeIdent}; +use super::{Origin, TypeDef, TypeID}; #[derive(Clone)] pub enum Type { - Concrete(TypeIdent), - Generic { base: TypeIdent, args: Vec }, + Concrete(TypeID), + Bits(u32), + Generic { base: TypeID, args: Vec }, Fn { args: Vec, ret: Box }, Ref(Box), + Array(Box), Infer, Error, } +impl Type { + pub fn rf(self) -> Self { + Self::Ref(Box::new(self)) + } + pub fn arr(self) -> Self { + Self::Array(Box::new(self)) + } +} + #[repr(usize)] #[derive(Debug, Clone, Copy)] pub enum BuiltinType { @@ -29,7 +40,14 @@ impl BuiltinType { }, } } - pub fn id(&self) -> TypeIdent { - TypeIdent::builtin(self) + pub fn id(&self) -> TypeID { + TypeID::builtin(self) } } + +impl TypeID { + pub fn builtin(ty: &BuiltinType) -> Self { + Self(*ty as usize) + } +} + diff --git a/src/main.rs b/src/main.rs index 7f505d7..8bbec6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,15 @@ #![feature(box_patterns)] #![feature(try_trait_v2)] -use std::io::{stdout, BufRead, BufReader}; - -use ir::Namespace; -use parser::{Module, NodeParsable, ParserOutput, Statement, TokenCursor}; +use ir::{Namespace, Program}; +use parser::{NodeParsable, PModule, PStatement, ParserCtx}; +use std::{ + fs::{create_dir_all, OpenOptions}, + io::{stdout, BufRead, BufReader}, + os::unix::fs::OpenOptionsExt, + path::Path, + process::Command, +}; mod compiler; mod ir; @@ -12,43 +17,102 @@ mod parser; mod util; fn main() { - let arg = std::env::args_os().nth(1); - if let Some(path) = arg { + let file = std::env::args_os().nth(1); + let gdb = std::env::args().nth(2).is_some_and(|a| a == "--debug"); + if let Some(path) = file { let file = std::fs::read_to_string(path).expect("failed to read file"); - run_file(&file); + run_file(&file, gdb); } else { run_stdin(); } // compiler::main(); } -fn run_file(file: &str) { - let mut output = ParserOutput::new(); - let res = Module::parse_node(&mut TokenCursor::from(file), &mut output); - println!("{:?}", res.node); - if let Some(module) = res.node.as_ref() { - let mut namespace = Namespace::new(); - module.lower(&mut namespace.push(), &mut output); - println!("{:?}", namespace.fns); +fn run_file(file: &str, gdb: bool) { + let mut ctx = ParserCtx::from(file); + let res = PModule::parse_node(&mut ctx); + if ctx.output.errs.is_empty() { + // println!("Parsed:"); + // println!("{:#?}", res.node); + if let Some(module) = res.node.as_ref() { + let mut namespace = Namespace::new(); + module.lower(&mut namespace.push(), &mut ctx.output); + if ctx.output.errs.is_empty() { + // println!("{:#?}", namespace.fns); + // println!("vars:"); + // for def in &namespace.var_defs { + // println!("{}: {}", def.name, namespace.type_name(&def.ty)); + // } + let program = Program::create(&namespace); + let bin = compiler::compile(program); + println!("compiled"); + save_run(&bin, gdb); + } + } + } + ctx.output.write_for(&mut stdout(), file); +} + +fn save_run(binary: &[u8], run_gdb: bool) { + use std::io::prelude::*; + let dir = Path::new("./build"); + create_dir_all(dir).expect("Failed to create or confirm build directory"); + let name = Path::new("test"); + let path = dir.join(name); + let path = path.as_os_str(); + let mut file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .mode(0o750) + .open(path) + .expect("Failed to create file"); + file.write_all(binary).expect("Failed to write to file"); + file.sync_all().expect("Failed to sync file"); + println!("running..."); + let mut p = Command::new("qemu-riscv64"); + let proc = if run_gdb { + p.arg("-g").arg("1234").arg(path).spawn() + } else { + p.arg(path).spawn() + }; + if let Ok(mut process) = proc { + if run_gdb { + match Command::new("gdb") + .arg("-q") + .arg("-ex") + .arg("target remote :1234") + .arg(path) + .spawn() + { + Ok(mut gdb) => { + gdb.wait().expect("xd"); + } + Err(e) => { + println!("gdb error: {e:?}"); + process.kill().expect("uh oh"); + } + } + } + if let Ok(status) = process.wait() { + if let Some(code) = status.code() { + std::process::exit(code); + } + } } - output.write_for(&mut stdout(), file); } pub fn run_stdin() { for line in BufReader::new(std::io::stdin()).lines() { - let mut output = ParserOutput::new(); let str = &line.expect("failed to read line"); - let mut cursor = TokenCursor::from(&str[..]); - if let Some(expr) = Statement::parse_node(&mut cursor, &mut output) - .node - .as_ref() - { - if cursor.next().is_none() { + let mut ctx = ParserCtx::from(&str[..]); + if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() { + if ctx.next().is_none() { println!("{:?}", expr); } else { println!("uhhhh ehehe"); } } - output.write_for(&mut stdout(), str); + ctx.output.write_for(&mut stdout(), str); } } diff --git a/src/parser/v3/ctx.rs b/src/parser/v3/ctx.rs new file mode 100644 index 0000000..93c8705 --- /dev/null +++ b/src/parser/v3/ctx.rs @@ -0,0 +1,55 @@ +use std::ops::{Deref, DerefMut}; + +use super::{MaybeParsable, Node, NodeParseResult, Parsable, ParserMsg, ParserOutput, TokenCursor}; + +pub struct ParserCtx<'a> { + pub cursor: TokenCursor<'a>, + pub output: ParserOutput, +} + +impl<'a> Deref for ParserCtx<'a> { + type Target = TokenCursor<'a>; + + fn deref(&self) -> &Self::Target { + &self.cursor + } +} + +impl DerefMut for ParserCtx<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cursor + } +} + +impl<'a> ParserCtx<'a> { + pub fn err(&mut self, msg: ParserMsg) { + self.output.err(msg); + } + pub fn hint(&mut self, msg: ParserMsg) { + self.output.hint(msg); + } + pub fn parse(&mut self) -> NodeParseResult { + Node::parse(self) + } + pub fn maybe_parse(&mut self) -> Option> { + Node::maybe_parse(self) + } +} + +impl<'a> From> for ParserCtx<'a> { + fn from(cursor: TokenCursor<'a>) -> Self { + Self { + cursor, + output: ParserOutput::new(), + } + } +} + +impl<'a> From<&'a str> for ParserCtx<'a> { + fn from(string: &'a str) -> Self { + Self { + cursor: TokenCursor::from(string), + output: ParserOutput::new(), + } + } +} diff --git a/src/parser/v3/cursor.rs b/src/parser/v3/cursor.rs index c4f0a99..ae430b0 100644 --- a/src/parser/v3/cursor.rs +++ b/src/parser/v3/cursor.rs @@ -6,15 +6,23 @@ use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance}; pub struct TokenCursor<'a> { cursor: CharCursor<'a>, next: Option, - next_pos: FilePos, + next_start: FilePos, prev_end: FilePos, } impl<'a> TokenCursor<'a> { pub fn next(&mut self) -> Option { - self.prev_end = self.cursor.prev_pos(); - self.next_pos = self.cursor.next_pos(); - std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor)) + self.prev_end = self + .next + .as_ref() + .map(|i| i.span.end) + .unwrap_or(FilePos::start()); + let next = TokenInstance::parse(&mut self.cursor); + self.next_start = next + .as_ref() + .map(|i| i.span.end) + .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())?; @@ -31,11 +39,11 @@ impl<'a> TokenCursor<'a> { pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> { self.expect_token(Token::Symbol(symbol)) } - pub fn seek_sym(&mut self, symbol: Symbol) { - while self - .next() - .is_some_and(|n| n.token != Token::Symbol(symbol)) - {} + pub fn next_on_new_line(&mut self) -> bool { + self.next_start.line != self.prev_end.line + } + pub fn seek_sym(&mut self, sym: Symbol) { + while self.next().is_some_and(|n| !n.is_symbol(sym)) {} } pub fn seek_syms(&mut self, syms: &[Symbol]) { while self @@ -45,6 +53,9 @@ impl<'a> TokenCursor<'a> { self.next(); } } + pub fn seek_sym_on_line(&mut self, sym: Symbol) { + while !self.next_on_new_line() && self.next().is_some_and(|n| !n.is_symbol(sym)) {} + } pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> { loop { if f(self.peek()?) { @@ -68,8 +79,8 @@ impl<'a> TokenCursor<'a> { pub fn prev_end(&self) -> FilePos { self.prev_end } - pub fn next_pos(&self) -> FilePos { - self.next_pos + pub fn next_start(&self) -> FilePos { + self.next_start } } @@ -85,7 +96,7 @@ impl<'a> From> for TokenCursor<'a> { Self { cursor, next: cur, - next_pos: FilePos::start(), + next_start: FilePos::start(), prev_end: FilePos::start(), } } diff --git a/src/parser/v3/error.rs b/src/parser/v3/error.rs index e0a07f8..db1ebe7 100644 --- a/src/parser/v3/error.rs +++ b/src/parser/v3/error.rs @@ -1,6 +1,6 @@ use crate::ir::{FilePos, FileSpan}; -use super::{token::TokenInstance, Ident, Node}; +use super::{token::TokenInstance, PIdent, Node}; #[derive(Debug, Clone)] pub struct ParserMsg { @@ -32,9 +32,9 @@ impl ParserMsg { spans: vec![span], } } - pub fn identifier_not_found(id: &Node) -> Self { + pub fn identifier_not_found(id: &Node) -> Self { Self { - msg: format!("Identifier '{}' not found", id.as_ref().unwrap().val()), + msg: format!("Identifier '{}' not found", id.as_ref().unwrap()), spans: vec![id.span], } } @@ -71,11 +71,11 @@ impl ParserOutput { hints: Vec::new(), } } - pub fn err(&mut self, err: ParserMsg) { - self.errs.push(err); + pub fn err(&mut self, msg: ParserMsg) { + self.errs.push(msg); } - pub fn hint(&mut self, err: ParserMsg) { - self.hints.push(err); + 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 { diff --git a/src/parser/v3/lower/arch/mod.rs b/src/parser/v3/lower/arch/mod.rs new file mode 100644 index 0000000..1bb80e6 --- /dev/null +++ b/src/parser/v3/lower/arch/mod.rs @@ -0,0 +1,2 @@ +pub mod riscv64; +pub use super::*; diff --git a/src/parser/v3/lower/arch/riscv64.rs b/src/parser/v3/lower/arch/riscv64.rs new file mode 100644 index 0000000..79cb72d --- /dev/null +++ b/src/parser/v3/lower/arch/riscv64.rs @@ -0,0 +1,109 @@ +use super::{PAsmArg, FnLowerCtx, PIdent, Node, PInstruction}; +use crate::{ + compiler::arch::riscv64::*, + ir::{ + arch::riscv64::{RV64Instruction, RegRef}, + VarID, + }, +}; + +impl RV64Instruction { + pub fn parse(inst: &PInstruction, ctx: &mut FnLowerCtx) -> Option { + let args = &inst.args[..]; + Some(match &**inst.op.inner.as_ref()? { + "ecall" => Self::Ecall, + "li" => { + let [dest, imm] = args else { + ctx.err("li requires 2 arguments".to_string()); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let imm = i64_from_arg(imm, ctx)?; + Self::Li { dest, imm } + } + "la" => { + let [dest, src] = args else { + ctx.err("la requires 2 arguments".to_string()); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let src = arg_to_var(src, ctx)?; + Self::La { dest, src } + } + "ld" => { + let [dest, offset, base] = args else { + ctx.err("ld requires 3 arguments".to_string()); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let offset = i64_from_arg(offset, ctx)?; + let base = RegRef::from_arg(base, ctx)?; + Self::Ld { dest, offset, base } + } + "mv" => { + let [dest, src] = args else { + ctx.err("la requires 2 arguments".to_string()); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let src = RegRef::from_arg(src, ctx)?; + Self::Mv { dest, src } + } + w => { + ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w)); + return None; + } + }) + } +} + +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, + "Expected variable / function reference".to_string(), + ); + return None; + }; + ctx.get_var(node) +} + +impl RegRef { + pub fn from_arg(node: &Node, ctx: &mut FnLowerCtx) -> Option { + Some(match node.inner.as_ref()? { + PAsmArg::Value(node) => { + let Some(reg) = Reg::from_ident(node, ctx) else { + return None; + }; + Self::Reg(reg) + } + PAsmArg::Ref(node) => Self::Var(ctx.get_var(node)?), + }) + } +} + +impl Reg { + pub fn from_ident(node: &Node, ctx: &mut FnLowerCtx) -> Option { + let s = &**node.inner.as_ref()?; + let res = Reg::from_str(s); + if res.is_none() { + ctx.err_at(node.span, format!("Unknown reg name '{}'", s)); + } + res + } +} + +fn i64_from_arg(node: &Node, ctx: &mut FnLowerCtx) -> Option { + let PAsmArg::Value(node) = node.inner.as_ref()? else { + ctx.err_at(node.span, format!("Expected an i64, found reference")); + return None; + }; + let word = node.inner.as_ref()?; + match word.parse::() { + Ok(x) => Some(x), + Err(_) => { + ctx.err_at(node.span, format!("Expected an i64, found {}", word)); + None + } + } +} diff --git a/src/parser/v3/lower/asm.rs b/src/parser/v3/lower/asm.rs new file mode 100644 index 0000000..b8dfd46 --- /dev/null +++ b/src/parser/v3/lower/asm.rs @@ -0,0 +1,53 @@ +use crate::{ + compiler::arch::riscv64::Reg, + ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarID}, +}; + +use super::{PAsmBlock, PAsmBlockArg, FnLowerCtx, FnLowerable, PInstruction}; + +impl FnLowerable for PInstruction { + type Output = RV64Instruction; + + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + RV64Instruction::parse(self, ctx) + } +} + +impl FnLowerable for PAsmBlock { + type Output = (); + + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + let block = IRUInstruction::AsmBlock { + instructions: { + let mut v = Vec::new(); + for i in &self.instructions { + if let Some(i) = i.lower(ctx) { + v.push(i); + } + } + v + }, + args: { + let mut v = Vec::new(); + for a in &self.args { + if let Some(a) = a.lower(ctx) { + v.push(a); + } + } + v + }, + }; + ctx.push(block); + Some(()) + } +} + +impl FnLowerable for PAsmBlockArg { + type Output = (Reg, VarID); + + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + let var = ctx.get_var(&self.var)?; + let reg = Reg::from_ident(&self.reg, ctx)?; + Some((reg, var)) + } +} diff --git a/src/parser/v3/lower/block.rs b/src/parser/v3/lower/block.rs index f2e7464..39ed048 100644 --- a/src/parser/v3/lower/block.rs +++ b/src/parser/v3/lower/block.rs @@ -1,15 +1,10 @@ -use crate::ir::Instruction; +use crate::ir::{IRUInstruction, VarID}; -use super::{Block, ExprResult, FnLowerCtx, Node, Statement}; +use super::{PBlock, FnLowerCtx, FnLowerable, PStatement}; -impl Node { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - self.as_ref()?.lower(ctx) - } -} - -impl Block { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { +impl FnLowerable for PBlock { + type Output = VarID; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { let ctx = &mut ctx.sub(); for statement in &self.statements { statement.lower(ctx); @@ -18,41 +13,24 @@ impl Block { } } -impl Node> { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - self.as_ref()?.lower(ctx) - } -} - -impl Node { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - self.as_ref()?.lower(ctx) - } -} - -impl Statement { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { +impl FnLowerable for PStatement { + type Output = VarID; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { match self { - super::Statement::Let(def, e) => { + super::PStatement::Let(def, e) => { let def = def.lower(ctx.map, ctx.output)?; let res = e.lower(ctx); if let Some(res) = res { - match res { - ExprResult::Var(v) => ctx.map.name_var(&def, v), - ExprResult::Fn(_) => todo!(), - } + ctx.map.name_var(&def, res); } None } - super::Statement::Return(e) => { - let res = e.lower(ctx)?; - match res { - ExprResult::Var(v) => ctx.push(Instruction::Ret { src: v }), - _ => todo!(), - } + super::PStatement::Return(e) => { + let src = e.lower(ctx)?; + ctx.push(IRUInstruction::Ret { src }); None } - super::Statement::Expr(e) => e.lower(ctx), + super::PStatement::Expr(e) => e.lower(ctx), } } } diff --git a/src/parser/v3/lower/def.rs b/src/parser/v3/lower/def.rs index 4b0aa0e..6e0cbb7 100644 --- a/src/parser/v3/lower/def.rs +++ b/src/parser/v3/lower/def.rs @@ -1,6 +1,6 @@ use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef}; -use super::{Node, ParserMsg, ParserOutput, Type as PType, VarDef as PVarDef}; +use super::{Node, ParserMsg, ParserOutput, PType, PVarDef}; impl Node { pub fn lower( @@ -9,7 +9,7 @@ impl Node { output: &mut ParserOutput, ) -> Option { let s = self.as_ref()?; - let name = s.name.as_ref()?.val().clone(); + let name = s.name.as_ref()?.to_string(); let ty = match &s.ty { Some(ty) => ty.lower(namespace, output), None => Type::Infer, diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs index 9b90269..e90d98d 100644 --- a/src/parser/v3/lower/expr.rs +++ b/src/parser/v3/lower/expr.rs @@ -1,32 +1,37 @@ -use super::{func::FnLowerCtx, Expr as PExpr, Node, UnaryOp}; -use crate::ir::{FnIdent, Instruction, Type, VarIdent, VarOrFnIdent}; +use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp}; +use crate::ir::{IRUInstruction, Type, VarID}; -impl PExpr { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { +impl FnLowerable for PExpr { + type Output = VarID; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { Some(match self { PExpr::Lit(l) => match l.as_ref()? { - super::Literal::String(s) => todo!(), - super::Literal::Char(c) => todo!(), - super::Literal::Number(n) => todo!(), - super::Literal::Unit => { + super::PLiteral::String(s) => { + let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf()); + let src = ctx.map.def_data(s.as_bytes().to_vec()); + ctx.push(IRUInstruction::LoadData { dest, src }); + dest + } + super::PLiteral::Char(c) => { + let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf()); + let src = ctx.map.def_data(c.to_string().as_bytes().to_vec()); + ctx.push(IRUInstruction::LoadData { dest, src }); + dest + } + super::PLiteral::Number(n) => { + // TODO: temp + let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf()); + let src = ctx + .map + .def_data(n.whole.parse::().unwrap().to_le_bytes().to_vec()); + ctx.push(IRUInstruction::LoadData { dest, src }); + dest + } + super::PLiteral::Unit => { todo!(); } }, - PExpr::Ident(i) => { - let name = i.as_ref()?.val(); - let Some(id) = ctx.get(name) else { - ctx.err(format!("Identifier '{}' not found.", name)); - return None; - }; - let Some(vf) = id.var_func else { - ctx.err(format!("Variable or function '{}' not found; Found type, but types cannot be used here.", name)); - return None; - }; - match vf { - VarOrFnIdent::Var(var) => ExprResult::Var(var), - VarOrFnIdent::Fn(f) => ExprResult::Fn(f), - } - } + PExpr::Ident(i) => ctx.get_var(i)?, PExpr::BinaryOp(op, e1, e2) => { let res1 = e1.lower(ctx)?; let res2 = e2.lower(ctx)?; @@ -36,101 +41,50 @@ impl PExpr { PExpr::UnaryOp(op, e) => { let res = e.lower(ctx)?; match op { - UnaryOp::Ref => ExprResult::Var(match res { - ExprResult::Var(v) => { - let temp = ctx.temp(ctx.map.get_var(v).ty.clone()); - ctx.push(Instruction::Ref { dest: temp, src: v }); - temp - } - ExprResult::Fn(f) => { - let temp = ctx.temp(Type::Ref(Box::new(ctx.map.get_fn(f).ty()))); - ctx.push(Instruction::Lf { dest: temp, src: f }); - temp - } - }), - UnaryOp::Deref => match res { - ExprResult::Var(v) => match &ctx.map.get_var(v).ty { - Type::Ref(inner) => { - todo!() - } - t => { - ctx.err(format!( - "Cannot dereference type {:?}", - ctx.map.type_name(t) - )); - return None; - } - }, - ExprResult::Fn(f) => { - ctx.err("Cannot dereference functions".to_string()); + UnaryOp::Ref => { + let temp = ctx.temp(ctx.map.get_var(res).ty.clone()); + ctx.push(IRUInstruction::Ref { + dest: temp, + src: res, + }); + temp + } + UnaryOp::Deref => { + let t = &ctx.map.get_var(res).ty; + let Type::Ref(inner) = t else { + ctx.err(format!( + "Cannot dereference type {:?}", + ctx.map.type_name(t) + )); return None; - } - }, + }; + todo!(); + } UnaryOp::Not => todo!(), } } PExpr::Block(b) => b.lower(ctx)?, PExpr::AsmBlock(b) => { - ctx.push(Instruction::AsmBlock { - instructions: b.as_ref()?.instructions.clone(), - }); + b.lower(ctx); return None; } PExpr::Call(e, args) => { - let fe = e.lower(ctx)?; + let f = e.lower(ctx)?; let mut nargs = Vec::new(); for arg in args.iter() { let arg = arg.lower(ctx)?; - nargs.push(match arg { - ExprResult::Var(v) => v, - ExprResult::Fn(_) => todo!(), - }); - } - match fe { - ExprResult::Fn(f) => { - let temp = ctx.temp(ctx.map.get_fn(f).ret.clone()); - ctx.push(Instruction::Call { - dest: temp, - f, - args: nargs, - }); - ExprResult::Var(temp) - } - o => { - ctx.err(format!("Expected function, found {:?}", o)); - return None; - } + nargs.push(arg); } + let temp = ctx.temp(ctx.map.get_fn_var(f).ret.clone()); + ctx.push(IRUInstruction::Call { + dest: temp, + f, + args: nargs, + }); + // ctx.err(format!("Expected function, found {:?}", f)); + return None; } PExpr::Group(e) => e.lower(ctx)?, }) } } - -impl Node { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - self.inner.as_ref()?.lower(&mut FnLowerCtx { - map: ctx.map, - instructions: ctx.instructions, - output: ctx.output, - span: self.span, - }) - } -} - -impl Node> { - pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - self.inner.as_ref()?.lower(&mut FnLowerCtx { - map: ctx.map, - instructions: ctx.instructions, - output: ctx.output, - span: self.span, - }) - } -} - -#[derive(Debug)] -pub enum ExprResult { - Var(VarIdent), - Fn(FnIdent), -} diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs index 28b41ce..05058e6 100644 --- a/src/parser/v3/lower/func.rs +++ b/src/parser/v3/lower/func.rs @@ -1,7 +1,10 @@ -use super::{Function as PFunction, Node, ParserMsg, ParserOutput}; -use crate::ir::{ - BuiltinType, FileSpan, FnDef, FnIdent, Function, Idents, Instruction, Instructions, - NamespaceGuard, Origin, Type, VarDef, VarIdent, +use super::{FnLowerable, PFunction, Node, ParserMsg, ParserOutput}; +use crate::{ + ir::{ + BuiltinType, FileSpan, FnDef, FnID, IRUFunction, Idents, IRUInstruction, IRInstructions, + NamespaceGuard, Origin, Type, VarDef, VarID, + }, + parser, }; impl Node { @@ -9,15 +12,16 @@ impl Node { &self, map: &mut NamespaceGuard, output: &mut ParserOutput, - ) -> Option { + ) -> Option { self.as_ref()?.lower_header(map, output) } - pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Option { - if let Some(f) = self.as_ref() { - Some(f.lower_body(map, output)) - } else { - None - } + pub fn lower_body( + &self, + id: FnID, + map: &mut NamespaceGuard, + output: &mut ParserOutput, + ) -> Option { + Some(self.as_ref()?.lower_body(id, map, output)) } } @@ -26,7 +30,7 @@ impl PFunction { &self, map: &mut NamespaceGuard, output: &mut ParserOutput, - ) -> Option { + ) -> Option { let header = self.header.as_ref()?; let name = header.name.as_ref()?; let args = header @@ -44,50 +48,145 @@ impl PFunction { Some(ty) => ty.lower(map, output), None => Type::Concrete(BuiltinType::Unit.id()), }; - // ignoring self var for now Some(map.def_fn(FnDef { - name: name.val().clone(), + name: name.to_string(), origin: Origin::File(self.header.span), args, ret, })) } - pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Function { - let mut instructions = Instructions::new(); + pub fn lower_body( + &self, + id: FnID, + map: &mut NamespaceGuard, + output: &mut ParserOutput, + ) -> IRUFunction { + let mut instructions = IRInstructions::new(); + let def = map.get_fn(id).clone(); + let args = def.args.iter().map(|a| { + map.named_var(a.clone()) + }).collect(); let mut ctx = FnLowerCtx { instructions: &mut instructions, map, output, span: self.body.span, }; - if let Some(res) = self.body.lower(&mut ctx) { - match res { - super::ExprResult::Var(v) => instructions.push(Instruction::Ret { src: v }), - super::ExprResult::Fn(_) => todo!(), - } + if let Some(src) = self.body.lower(&mut ctx) { + instructions.push(IRUInstruction::Ret { src }); } - Function::new(instructions) + IRUFunction::new(def.name.clone(), args, instructions) } } +// impl Node { +// pub fn lower_header( +// &self, +// map: &mut NamespaceGuard, +// output: &mut ParserOutput, +// ) -> Option { +// self.as_ref()?.lower_header(map, output) +// } +// pub fn lower_body( +// &self, +// map: &mut NamespaceGuard, +// output: &mut ParserOutput, +// ) -> Option { +// Some(self.as_ref()?.lower_body(map, output)) +// } +// } +// +// impl AsmFunction { +// pub fn lower_header( +// &self, +// map: &mut NamespaceGuard, +// output: &mut ParserOutput, +// ) -> Option { +// let header = self.header.as_ref()?; +// let name = header.name.as_ref()?; +// let args = header +// .args +// .iter() +// .map(|a| { +// // a.lower(map, output).unwrap_or(VarDef { +// // name: "{error}".to_string(), +// // origin: Origin::File(a.span), +// // ty: Type::Error, +// // }) +// }) +// .collect(); +// // let ret = match &header.ret { +// // Some(ty) => ty.lower(map, output), +// // None => Type::Concrete(BuiltinType::Unit.id()), +// // }; +// let ret = Type::Concrete(BuiltinType::Unit.id()); +// Some(map.def_fn(FnDef { +// name: name.to_string(), +// origin: Origin::File(self.header.span), +// args, +// ret, +// })) +// } +// pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Function { +// let mut instructions = Instructions::new(); +// let mut ctx = FnLowerCtx { +// instructions: &mut instructions, +// map, +// output, +// span: self.body.span, +// }; +// self.body.lower(&mut ctx); +// Function::new(instructions) +// } +// } + pub struct FnLowerCtx<'a, 'n> { pub map: &'a mut NamespaceGuard<'n>, - pub instructions: &'a mut Instructions, + pub instructions: &'a mut IRInstructions, pub output: &'a mut ParserOutput, pub span: FileSpan, } -impl<'a, 'n> FnLowerCtx<'a, 'n> { - pub fn get(&self, name: &str) -> Option { - self.map.get(name) +impl<'n> FnLowerCtx<'_, 'n> { + pub fn span<'b>(&'b mut self, span: FileSpan) -> FnLowerCtx<'b, 'n> { + FnLowerCtx { + map: self.map, + instructions: self.instructions, + output: self.output, + span, + } + } + pub fn get(&mut self, node: &Node) -> Option { + let name = node.inner.as_ref()?; + let res = self.map.get(name); + if res.is_none() { + self.err_at(node.span, format!("Identifier '{}' not found", name)); + } + res + } + pub fn get_var(&mut self, node: &Node) -> Option { + let ids = self.get(node)?; + if ids.var.is_none() { + self.err_at( + node.span, + format!( + "Variable '{}' not found; Type found but cannot be used here", + node.inner.as_ref()? + ), + ); + } + ids.var } pub fn err(&mut self, msg: String) { self.output.err(ParserMsg::from_span(self.span, msg)) } - pub fn temp(&mut self, ty: Type) -> VarIdent { + pub fn err_at(&mut self, span: FileSpan, msg: String) { + self.output.err(ParserMsg::from_span(span, msg)) + } + pub fn temp(&mut self, ty: Type) -> VarID { self.map.temp_var(self.span, ty) } - pub fn push(&mut self, i: Instruction) { + pub fn push(&mut self, i: IRUInstruction) { self.instructions.push(i); } pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> { diff --git a/src/parser/v3/lower/mod.rs b/src/parser/v3/lower/mod.rs index f6849fa..adeea0b 100644 --- a/src/parser/v3/lower/mod.rs +++ b/src/parser/v3/lower/mod.rs @@ -1,12 +1,30 @@ +mod asm; mod block; mod def; mod expr; mod func; mod module; +mod arch; use super::*; -use block::*; -use def::*; -use expr::*; -use func::*; -use module::*; + +pub use func::FnLowerCtx; + +pub trait FnLowerable { + type Output; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option; +} + +impl FnLowerable for Node { + type Output = T::Output; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + self.as_ref()?.lower(&mut ctx.span(self.span)) + } +} + +impl FnLowerable for Box { + type Output = T::Output; + fn lower(&self, ctx: &mut FnLowerCtx) -> Option { + self.as_ref().lower(ctx) + } +} diff --git a/src/parser/v3/lower/module.rs b/src/parser/v3/lower/module.rs index d694dbb..22defa2 100644 --- a/src/parser/v3/lower/module.rs +++ b/src/parser/v3/lower/module.rs @@ -1,8 +1,8 @@ use crate::ir::NamespaceGuard; -use super::{Module, ParserOutput}; +use super::{PModule, ParserOutput}; -impl Module { +impl PModule { pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) { let mut fns = Vec::new(); for f in &self.functions { @@ -13,8 +13,10 @@ impl Module { } } for (f, id) in self.functions.iter().zip(fns) { - if let (Some(res), Some(id)) = (f.lower_body(map, output), id) { - map.write_fn(id, res); + if let Some(id) = id { + if let Some(res) = f.lower_body(id, map, output) { + map.write_fn(id, res); + } } } } diff --git a/src/parser/v3/mod.rs b/src/parser/v3/mod.rs index d63d5b9..8d3f489 100644 --- a/src/parser/v3/mod.rs +++ b/src/parser/v3/mod.rs @@ -5,6 +5,7 @@ mod node; mod nodes; mod parse; mod token; +mod ctx; pub use cursor::*; pub use error::*; @@ -13,3 +14,4 @@ pub use node::*; pub use nodes::*; pub use parse::*; pub use token::*; +pub use ctx::*; diff --git a/src/parser/v3/nodes/asm_block.rs b/src/parser/v3/nodes/asm_block.rs index 6275180..f438508 100644 --- a/src/parser/v3/nodes/asm_block.rs +++ b/src/parser/v3/nodes/asm_block.rs @@ -1,23 +1,59 @@ -use crate::compiler::riscv64::AsmInstruction; +use super::{ + util::parse_list, PIdent, Node, Parsable, ParseResult, PInstruction, ParserCtx, Symbol, +}; -use super::{Parsable, ParseResult, Symbol}; - -#[derive(Debug)] -pub struct AsmBlock { - pub instructions: Vec, +pub struct PAsmBlock { + pub instructions: Vec>, + pub args: Vec>, } -impl Parsable for AsmBlock { - fn parse( - cursor: &mut super::TokenCursor, - output: &mut super::ParserOutput, - ) -> ParseResult { - cursor.expect_sym(Symbol::OpenCurly)?; +pub struct PAsmBlockArg { + pub reg: Node, + pub var: Node, +} + +impl Parsable for PAsmBlock { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let args = if ctx.expect_peek()?.is_symbol(Symbol::OpenParen) { + ctx.next(); + parse_list(ctx, Symbol::CloseParen)? + } else { + Vec::new() + }; + ctx.expect_sym(Symbol::OpenCurly)?; let mut instructions = Vec::new(); - while !cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { - instructions.push(AsmInstruction::parse(cursor, output)?); + while !ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) { + let res = ctx.parse(); + instructions.push(res.node); + if res.recover { + ctx.seek_sym_on_line(Symbol::CloseCurly); + } } - cursor.expect_sym(Symbol::CloseCurly)?; - ParseResult::Ok(Self { instructions }) + ctx.expect_sym(Symbol::CloseCurly)?; + ParseResult::Ok(Self { instructions, args }) + } +} + +impl Parsable for PAsmBlockArg { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let reg = ctx.parse()?; + ctx.expect_sym(Symbol::Equals)?; + let var = ctx.parse()?; + ParseResult::Ok(Self { reg, var }) + } +} + +impl std::fmt::Debug for PAsmBlock { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("asm {")?; + for i in &self.instructions { + f.write_str("\n ")?; + i.fmt(f)?; + } + if !self.instructions.is_empty() { + f.write_str("\n")?; + } + f.write_str("}")?; + Ok(()) } } diff --git a/src/parser/v3/nodes/asm_fn.rs b/src/parser/v3/nodes/asm_fn.rs index 7e4c412..319a068 100644 --- a/src/parser/v3/nodes/asm_fn.rs +++ b/src/parser/v3/nodes/asm_fn.rs @@ -1,53 +1,63 @@ -use crate::compiler::riscv64::{AsmInstruction, Reg}; - use super::{ - util::parse_list, AsmBlock, Ident, Keyword, Node, Parsable, ParseResult, SelfVar, Symbol, + util::parse_list, PAsmBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, PType, PVarDef, }; -#[derive(Debug)] -pub struct AsmFunctionHeader { - pub name: Node, - pub sel: Option>, - pub args: Vec>, -} - -#[derive(Debug)] -pub struct AsmFunction { - pub header: Node, - pub body: Node, -} - -impl Parsable for AsmFunctionHeader { - fn parse( - cursor: &mut super::TokenCursor, - output: &mut super::ParserOutput, - ) -> ParseResult { - cursor.expect_kw(Keyword::Asm)?; - cursor.expect_kw(Keyword::Fn)?; - let name = Node::parse(cursor, output)?; - cursor.expect_sym(Symbol::OpenParen)?; - let sel = Node::maybe_parse(cursor, output); - if sel.is_some() { - if let Err(err) = cursor.expect_sym(Symbol::Comma) { - output.err(err); - cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]); - if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) { - cursor.next(); - } - } - } - let args = parse_list(cursor, output, Symbol::CloseParen)?; - ParseResult::Ok(Self { name, sel, args }) - } -} - -impl Parsable for AsmFunction { - fn parse( - cursor: &mut super::TokenCursor, - output: &mut super::ParserOutput, - ) -> ParseResult { - let header = Node::parse(cursor, output)?; - let body = Node::parse(cursor, output)?; - ParseResult::Ok(Self { header, body }) - } -} +// #[derive(Debug)] +// pub struct AsmFunctionHeader { +// pub name: Node, +// pub args: Vec>, +// } +// +// #[derive(Debug)] +// pub struct AsmFunction { +// pub header: Node, +// pub body: Node, +// } +// +// impl Parsable for AsmFunctionHeader { +// fn parse(ctx: &mut ParserCtx) -> ParseResult { +// ctx.expect_kw(Keyword::Asm)?; +// ctx.expect_kw(Keyword::Fn)?; +// let name = ctx.parse()?; +// ctx.expect_sym(Symbol::OpenParen)?; +// let args = parse_list(ctx, Symbol::CloseParen)?; +// ParseResult::Ok(Self { name, args }) +// } +// } +// +// impl Parsable for AsmFunction { +// fn parse(ctx: &mut ParserCtx) -> ParseResult { +// let header = ctx.parse()?; +// let body = ctx.parse()?; +// ParseResult::Ok(Self { header, body }) +// } +// } +// +// pub struct AsmVarDef { +// pub reg: Node, +// pub name: Node, +// pub ty: Option>, +// } +// +// impl Parsable for AsmVarDef { +// fn parse(ctx: &mut ParserCtx) -> ParseResult { +// let reg = ctx.parse()?; +// let name = ctx.parse()?; +// if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) { +// ctx.next(); +// ctx.parse().map(|ty| Self { reg, name, ty: Some(ty) }) +// } else { +// ParseResult::Ok(Self { reg, name, ty: None }) +// } +// } +// } +// +// impl std::fmt::Debug for AsmVarDef { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// self.name.fmt(f)?; +// if let Some(ty) = &self.ty { +// write!(f, ": {:?}", ty)?; +// } +// Ok(()) +// } +// } diff --git a/src/parser/v3/nodes/asm_instr.rs b/src/parser/v3/nodes/asm_instr.rs new file mode 100644 index 0000000..e4305a0 --- /dev/null +++ b/src/parser/v3/nodes/asm_instr.rs @@ -0,0 +1,82 @@ +use super::{PIdent, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol}; + +pub struct PInstruction { + pub op: Node, + pub args: Vec>, +} + +pub enum PAsmArg { + Value(Node), + Ref(Node), +} + +impl Parsable for PInstruction { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let op = ctx.parse()?; + let mut args = Vec::new(); + if !ctx.next_on_new_line() { + let arg = ctx.parse()?; + args.push(arg); + loop { + if ctx.next_on_new_line() { + break; + } + ctx.expect_sym(Symbol::Comma)?; + let arg = ctx.parse()?; + args.push(arg); + } + } + ParseResult::Ok(Self { op, args }) + } +} + +impl Parsable for PAsmArg { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + if let Some(ident) = ctx.maybe_parse() { + return ParseResult::Ok(Self::Value(ident)); + } + + let next = ctx.expect_peek()?; + if !next.is_symbol(Symbol::OpenCurly) { + return ParseResult::Err(ParserMsg::unexpected_token( + next, + "An identifier or {identifier}", + )); + } + ctx.next(); + + let res = ctx.parse(); + if res.recover { + ctx.seek_sym(Symbol::CloseCurly); + return ParseResult::SubErr; + } + + ctx.expect_sym(Symbol::CloseCurly)?; + ParseResult::Ok(Self::Ref(res.node)) + } +} + +impl std::fmt::Debug for PAsmArg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Value(v) => v.fmt(f), + Self::Ref(r) => write!(f, "{{{:?}}}", r), + } + } +} + +impl std::fmt::Debug for PInstruction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.op.fmt(f)?; + let mut iter = self.args.iter(); + if let Some(arg) = iter.next() { + f.write_str(" ")?; + arg.fmt(f)?; + } + for arg in iter { + f.write_str(", ")?; + arg.fmt(f)?; + } + Ok(()) + } +} diff --git a/src/parser/v3/nodes/block.rs b/src/parser/v3/nodes/block.rs index f222691..62d09aa 100644 --- a/src/parser/v3/nodes/block.rs +++ b/src/parser/v3/nodes/block.rs @@ -1,53 +1,52 @@ use std::fmt::{Debug, Write}; use super::{ - token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserMsg, ParserOutput, Statement, - TokenCursor, + token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement, }; use crate::util::Padder; -pub struct Block { - pub statements: Vec>, - pub result: Option>>, +pub struct PBlock { + pub statements: Vec>, + pub result: Option>>, } -impl Parsable for Block { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { +impl Parsable for PBlock { + fn parse(ctx: &mut ParserCtx) -> ParseResult { let mut statements = Vec::new(); let mut result = None; - cursor.expect_sym(Symbol::OpenCurly)?; - if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { - cursor.next(); + ctx.expect_sym(Symbol::OpenCurly)?; + if ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) { + ctx.next(); return ParseResult::Ok(Self { statements, result }); } let mut expect_semi = false; let mut recover = false; loop { - let Some(next) = cursor.peek() else { + let Some(next) = ctx.peek() else { recover = true; - errors.err(ParserMsg::unexpected_end()); + ctx.err(ParserMsg::unexpected_end()); break; }; if next.is_symbol(Symbol::CloseCurly) { - cursor.next(); + ctx.next(); break; } if next.is_symbol(Symbol::Semicolon) { - cursor.next(); + ctx.next(); expect_semi = false; continue; } else if expect_semi { - errors.err(ParserMsg { + ctx.err(ParserMsg { msg: "expected ';'".to_string(), - spans: vec![cursor.next_pos().char_span()], + spans: vec![ctx.next_start().char_span()], }); } - let res = Statement::parse_node(cursor, errors); + let res = PStatement::parse_node(ctx); statements.push(res.node); expect_semi = true; if res.recover { - cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); - if cursor.peek().is_none() { + ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); + if ctx.peek().is_none() { recover = true; break; } @@ -62,14 +61,17 @@ impl Parsable for Block { } } -impl Debug for Block { +impl Debug for PBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.statements.first().is_some() { + if !self.statements.is_empty() || self.result.is_some() { f.write_str("{\n ")?; let mut padder = Padder::new(f); for s in &self.statements { // they don't expose wrap_buf :grief: - padder.write_str(&format!("{s:?}\n"))?; + padder.write_str(&format!("{s:?};\n"))?; + } + if let Some(res) = &self.result { + padder.write_str(&format!("{res:?}\n"))?; } f.write_char('}')?; } else { diff --git a/src/parser/v3/nodes/def.rs b/src/parser/v3/nodes/def.rs index af930b4..c0f0698 100644 --- a/src/parser/v3/nodes/def.rs +++ b/src/parser/v3/nodes/def.rs @@ -1,21 +1,20 @@ use std::fmt::Debug; -use super::{Ident, MaybeParsable, Node, Parsable, ParseResult, ParserMsg, Symbol, Token, Type}; +use super::{ + PIdent, MaybeParsable, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token, PType, +}; -pub struct VarDef { - pub name: Node, - pub ty: Option>, +pub struct PVarDef { + pub name: Node, + pub ty: Option>, } -impl Parsable for VarDef { - fn parse( - cursor: &mut super::TokenCursor, - errors: &mut super::ParserOutput, - ) -> ParseResult { - let name = Node::parse(cursor, errors)?; - if cursor.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) { - cursor.next(); - Node::parse(cursor, errors).map(|ty| Self { name, ty: Some(ty) }) +impl Parsable for PVarDef { + 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, ty: Some(ty) }) } else { ParseResult::Ok(Self { name, ty: None }) } @@ -33,20 +32,17 @@ pub enum SelfType { } impl MaybeParsable for SelfVar { - fn maybe_parse( - cursor: &mut super::TokenCursor, - errors: &mut super::ParserOutput, - ) -> Result, super::ParserMsg> { - if let Some(mut next) = cursor.peek() { + fn maybe_parse(ctx: &mut ParserCtx) -> Result, super::ParserMsg> { + if let Some(mut next) = ctx.peek() { let mut ty = SelfType::Take; if next.is_symbol(Symbol::Ampersand) { - cursor.next(); + ctx.next(); ty = SelfType::Ref; - next = cursor.expect_peek()?; + next = ctx.expect_peek()?; } if let Token::Word(name) = &next.token { if name == "self" { - cursor.next(); + ctx.next(); return Ok(Some(Self { ty })); } } @@ -58,7 +54,7 @@ impl MaybeParsable for SelfVar { } } -impl Debug for VarDef { +impl Debug for PVarDef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.name.fmt(f)?; if let Some(ty) = &self.ty { diff --git a/src/parser/v3/nodes/expr.rs b/src/parser/v3/nodes/expr.rs index c5e73bc..04ddcd4 100644 --- a/src/parser/v3/nodes/expr.rs +++ b/src/parser/v3/nodes/expr.rs @@ -1,52 +1,52 @@ use std::fmt::{Debug, Write}; use super::{ - op::{BinaryOp, UnaryOp}, + op::{PInfixOp, UnaryOp}, util::parse_list, - AsmBlock, Block, Ident, Keyword, Literal, Node, NodeParsable, Parsable, ParseResult, ParserMsg, - ParserOutput, Symbol, TokenCursor, + PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx, + ParserMsg, Symbol, }; -type BoxNode = Node>; +type BoxNode = Node>; -pub enum Expr { - Lit(Node), - Ident(Node), - BinaryOp(BinaryOp, BoxNode, BoxNode), +pub enum PExpr { + Lit(Node), + Ident(Node), + BinaryOp(PInfixOp, BoxNode, BoxNode), UnaryOp(UnaryOp, BoxNode), - Block(Node), - Call(BoxNode, Vec>), + Block(Node), + Call(BoxNode, Vec>), Group(BoxNode), - AsmBlock(Node), + AsmBlock(Node), } -impl Parsable for Expr { - fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult { - let start = cursor.next_pos(); - let next = cursor.expect_peek()?; +impl Parsable for PExpr { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let start = ctx.next_start(); + let next = ctx.expect_peek()?; let mut e1 = if next.is_symbol(Symbol::OpenParen) { - cursor.next(); - if cursor.expect_peek()?.is_symbol(Symbol::CloseParen) { - cursor.next(); - return ParseResult::Ok(Expr::Lit(Node::new( - Literal::Unit, - cursor.next_pos().char_span(), + ctx.next(); + if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) { + ctx.next(); + return ParseResult::Ok(PExpr::Lit(Node::new( + PLiteral::Unit, + ctx.next_start().char_span(), ))); } - let res = Node::parse(cursor, output); + let res = ctx.parse(); if res.recover { - cursor.seek_sym(Symbol::CloseParen); + ctx.seek_sym(Symbol::CloseParen); } - cursor.expect_sym(Symbol::CloseParen)?; + ctx.expect_sym(Symbol::CloseParen)?; Self::Group(res.node.bx()) } else if next.is_symbol(Symbol::OpenCurly) { - Self::Block(Block::parse_node(cursor, output)?) + Self::Block(PBlock::parse_node(ctx)?) } else if next.is_keyword(Keyword::Asm) { - cursor.next(); - Self::AsmBlock(Node::parse(cursor, output)?) + ctx.next(); + Self::AsmBlock(ctx.parse()?) } else if let Some(op) = UnaryOp::from_token(next) { - cursor.next(); - return Node::parse(cursor, output).map(|n| { + ctx.next(); + return ctx.parse().map(|n| { let n = n.bx(); if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner { let span = start.to(n1.span.end); @@ -55,36 +55,36 @@ impl Parsable for Expr { Self::UnaryOp(op, n) } }); - } else if let Some(val) = Node::maybe_parse(cursor, output) { + } else if let Some(val) = Node::maybe_parse(ctx) { Self::Lit(val) } else { - let res = Node::parse(cursor, &mut ParserOutput::new()); + let res = ctx.parse(); if res.node.is_some() { Self::Ident(res.node) } else { - let next = cursor.expect_peek()?; + let next = ctx.expect_peek()?; return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression")); } }; - let Some(mut next) = cursor.peek() else { + let Some(mut next) = ctx.peek() else { return ParseResult::Ok(e1); }; while next.is_symbol(Symbol::OpenParen) { - cursor.next(); - let args = parse_list(cursor, output, Symbol::CloseParen)?; - let end = cursor.prev_end(); + ctx.next(); + let args = parse_list(ctx, Symbol::CloseParen)?; + let end = ctx.prev_end(); e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args); - let Some(next2) = cursor.peek() else { + let Some(next2) = ctx.peek() else { return ParseResult::Ok(e1); }; next = next2 } - let end = cursor.prev_end(); + let end = ctx.prev_end(); let mut recover = false; - let res = if let Some(mut op) = BinaryOp::from_token(&next.token) { - cursor.next(); + let res = if let Some(mut op) = PInfixOp::from_token(&next.token) { + ctx.next(); let mut n1 = Node::new(e1, start.to(end)).bx(); - let res = Node::parse(cursor, output); + let res = ctx.parse(); let mut n2 = res.node.bx(); recover = res.recover; if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() { @@ -106,13 +106,13 @@ impl Parsable for Expr { } } -impl Debug for Expr { +impl Debug for PExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Expr::Lit(c) => c.fmt(f)?, - Expr::Ident(n) => n.fmt(f)?, - Expr::Block(b) => b.fmt(f)?, - Expr::BinaryOp(op, e1, e2) => { + PExpr::Lit(c) => c.fmt(f)?, + PExpr::Ident(n) => n.fmt(f)?, + PExpr::Block(b) => b.fmt(f)?, + PExpr::BinaryOp(op, e1, e2) => { write!(f, "({:?}", *e1)?; if op.pad() { write!(f, " {} ", op.str())?; @@ -121,7 +121,7 @@ impl Debug for Expr { } write!(f, "{:?})", *e2)?; } - Expr::Call(n, args) => { + PExpr::Call(n, args) => { n.fmt(f)?; f.write_char('(')?; if let Some(a) = args.first() { @@ -133,13 +133,13 @@ impl Debug for Expr { } f.write_char(')')?; } - Expr::UnaryOp(op, e) => { + PExpr::UnaryOp(op, e) => { write!(f, "(")?; write!(f, "{}", op.str())?; write!(f, "{:?})", *e)?; } - Expr::Group(inner) => inner.fmt(f)?, - Expr::AsmBlock(inner) => inner.fmt(f)?, + PExpr::Group(inner) => inner.fmt(f)?, + PExpr::AsmBlock(inner) => inner.fmt(f)?, } Ok(()) } diff --git a/src/parser/v3/nodes/func.rs b/src/parser/v3/nodes/func.rs index 08ee048..55f4c80 100644 --- a/src/parser/v3/nodes/func.rs +++ b/src/parser/v3/nodes/func.rs @@ -1,71 +1,69 @@ use super::{ - util::parse_list, Block, Ident, Keyword, Node, Parsable, ParseResult, ParserOutput, SelfVar, - Symbol, TokenCursor, Type, VarDef, + util::parse_list, PBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, + Symbol, PType, PVarDef, }; use std::fmt::Debug; -pub struct FunctionHeader { - pub name: Node, - pub sel: Option>, - pub args: Vec>, - pub ret: Option>, +pub struct PFunctionHeader { + pub name: Node, + pub args: Vec>, + pub ret: Option>, } -pub struct Function { - pub header: Node, - pub body: Node, +pub struct PFunction { + pub header: Node, + pub body: Node, } -impl Parsable for FunctionHeader { - fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult { - cursor.expect_kw(Keyword::Fn)?; - let name = Node::parse(cursor, output)?; - cursor.expect_sym(Symbol::OpenParen)?; - let sel = Node::maybe_parse(cursor, output); - if sel.is_some() { - if let Err(err) = cursor.expect_sym(Symbol::Comma) { - output.err(err); - cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]); - if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) { - cursor.next(); - } - } - } - let args = parse_list(cursor, output, Symbol::CloseParen)?; - let ret = if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) { - cursor.next(); - Some(Node::parse(cursor, output)?) +impl Parsable for PFunctionHeader { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + ctx.expect_kw(Keyword::Fn)?; + let name = ctx.parse()?; + ctx.expect_sym(Symbol::OpenParen)?; + // let sel = ctx.maybe_parse(); + // if sel.is_some() { + // if let Err(err) = ctx.expect_sym(Symbol::Comma) { + // ctx.err(err); + // ctx.seek_syms(&[Symbol::Comma, Symbol::CloseParen]); + // if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) { + // ctx.next(); + // } + // } + // } + let args = parse_list(ctx, Symbol::CloseParen)?; + let ret = if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) { + ctx.next(); + Some(ctx.parse()?) } else { None }; ParseResult::Ok(Self { name, args, - sel, ret, }) } } -impl Parsable for Function { - fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult { - let header = Node::parse(cursor, output)?; - let body = Node::parse(cursor, output)?; +impl Parsable for PFunction { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let header = ctx.parse()?; + let body = ctx.parse()?; ParseResult::Ok(Self { header, body }) } } -impl Debug for FunctionHeader { +impl Debug for PFunctionHeader { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("fn ")?; self.name.fmt(f)?; f.write_str("(")?; - if let Some(s) = &self.sel { - s.fmt(f)?; - if self.args.first().is_some() { - f.write_str(", ")?; - } - } + // if let Some(s) = &self.sel { + // s.fmt(f)?; + // if self.args.first().is_some() { + // f.write_str(", ")?; + // } + // } if let Some(a) = self.args.first() { a.fmt(f)?; } @@ -80,7 +78,7 @@ impl Debug for FunctionHeader { Ok(()) } } -impl Debug for Function { +impl Debug for PFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.header.fmt(f)?; f.write_str(" ")?; diff --git a/src/parser/v3/nodes/ident.rs b/src/parser/v3/nodes/ident.rs index 8e7cdf6..d329d77 100644 --- a/src/parser/v3/nodes/ident.rs +++ b/src/parser/v3/nodes/ident.rs @@ -1,29 +1,52 @@ -use std::fmt::Debug; -use super::{Parsable, ParseResult, ParserMsg, Token}; +use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token}; +use std::{ + fmt::{Debug, Display}, + ops::Deref, +}; -pub struct Ident(String); +#[derive(Clone)] +pub struct PIdent(String); -impl Ident { - pub fn val(&self) -> &String { - &self.0 - } -} - -impl Parsable for Ident { - fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> ParseResult { - let next = cursor.expect_peek()?; +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")); }; let name = name.to_string(); - cursor.next(); + ctx.next(); ParseResult::Ok(Self(name)) } } -impl Debug for Ident { +impl MaybeParsable for PIdent { + fn maybe_parse(ctx: &mut ParserCtx) -> Result, ParserMsg> { + let Some(next) = ctx.peek() else { return Ok(None) }; + let Token::Word(name) = &next.token else { + return Ok(None); + }; + let name = name.to_string(); + ctx.next(); + Ok(Some(Self(name))) + } +} + +impl Debug for PIdent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } +impl Deref for PIdent { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for PIdent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/src/parser/v3/nodes/lit.rs b/src/parser/v3/nodes/lit.rs index 7efe138..f2ac6e9 100644 --- a/src/parser/v3/nodes/lit.rs +++ b/src/parser/v3/nodes/lit.rs @@ -1,38 +1,35 @@ -use super::{CharCursor, MaybeParsable, ParserMsg, ParserOutput, Symbol, Token, TokenCursor}; +use super::{CharCursor, MaybeParsable, ParserCtx, ParserMsg, Symbol, Token}; use std::fmt::Debug; #[derive(Clone, PartialEq, Eq)] -pub enum Literal { +pub enum PLiteral { String(String), Char(char), - Number(Number), + Number(PNumber), Unit, } #[derive(Clone, PartialEq, Eq)] -pub struct Number { +pub struct PNumber { pub whole: String, pub decimal: Option, pub ty: Option, } -impl MaybeParsable for Literal { - fn maybe_parse( - cursor: &mut TokenCursor, - _: &mut ParserOutput, - ) -> Result, ParserMsg> { - let inst = cursor.expect_peek()?; +impl MaybeParsable for PLiteral { + fn maybe_parse(ctx: &mut ParserCtx) -> Result, ParserMsg> { + let inst = ctx.expect_peek()?; Ok(Some(match &inst.token { Token::Symbol(Symbol::SingleQuote) => { - let chars = cursor.chars(); + let chars = ctx.chars(); let c = chars.expect_next()?; chars.expect('\'')?; - cursor.next(); + ctx.next(); Self::Char(c) } Token::Symbol(Symbol::DoubleQuote) => { - let res = Self::String(string_from(cursor.chars())?); - cursor.next(); + let res = Self::String(string_from(ctx.chars())?); + ctx.next(); res } Token::Word(text) => { @@ -41,21 +38,21 @@ impl MaybeParsable for Literal { return Ok(None); } let (whole, ty) = parse_whole_num(text); - let mut num = Number { + let mut num = PNumber { whole, decimal: None, ty, }; - cursor.next(); - if num.ty.is_none() && cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) { - cursor.next(); - if let Some(next) = cursor.peek() { + ctx.next(); + if num.ty.is_none() && ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) { + ctx.next(); + if let Some(next) = ctx.peek() { if let Token::Word(i) = &next.token { if i.chars().next().unwrap().is_ascii_digit() { let (decimal, ty) = parse_whole_num(i); num.decimal = Some(decimal); num.ty = ty; - cursor.next(); + ctx.next(); } } } @@ -110,7 +107,7 @@ pub fn string_from(cursor: &mut CharCursor) -> Result { } } -impl Debug for Literal { +impl Debug for PLiteral { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::String(str) => str.fmt(f), @@ -121,7 +118,7 @@ impl Debug for Literal { } } -impl Debug for Number { +impl Debug for PNumber { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.whole)?; if let Some(d) = &self.decimal { diff --git a/src/parser/v3/nodes/mod.rs b/src/parser/v3/nodes/mod.rs index 08e1c60..fb76572 100644 --- a/src/parser/v3/nodes/mod.rs +++ b/src/parser/v3/nodes/mod.rs @@ -13,6 +13,7 @@ mod util; mod trai; mod asm_fn; mod asm_block; +mod asm_instr; pub use block::*; pub use expr::*; @@ -28,6 +29,7 @@ pub use trai::*; pub use op::*; pub use asm_fn::*; pub use asm_block::*; +pub use asm_instr::*; use super::*; diff --git a/src/parser/v3/nodes/module.rs b/src/parser/v3/nodes/module.rs index 58aa602..2f74e05 100644 --- a/src/parser/v3/nodes/module.rs +++ b/src/parser/v3/nodes/module.rs @@ -1,79 +1,70 @@ use super::{ - AsmFunction, Function, Impl, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput, - Struct, Symbol, Token, TokenCursor, Trait, + PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, + PStruct, Symbol, Token, PTrait, }; use std::fmt::Debug; -pub struct Module { - pub traits: Vec>, - pub structs: Vec>, - pub functions: Vec>, - pub asm_fns: Vec>, - pub impls: Vec>, +pub struct PModule { + pub traits: Vec>, + pub structs: Vec>, + pub functions: Vec>, + pub impls: Vec>, } -impl Parsable for Module { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { +impl Parsable for PModule { + fn parse(ctx: &mut ParserCtx) -> ParseResult { let mut functions = Vec::new(); let mut structs = Vec::new(); let mut traits = Vec::new(); let mut impls = Vec::new(); - let mut asm_fns = Vec::new(); loop { - let Some(next) = cursor.peek() else { + let Some(next) = ctx.peek() else { break; }; if let Token::Keyword(kw) = next.token { match kw { Keyword::Fn => { - let res = Node::parse(cursor, errors); + let res = ctx.parse(); functions.push(res.node); if res.recover { break; } } Keyword::Struct => { - let res = Node::parse(cursor, errors); + let res = ctx.parse(); structs.push(res.node); if res.recover { break; } } Keyword::Trait => { - let res = Node::parse(cursor, errors); + let res = ctx.parse(); traits.push(res.node); if res.recover { break; } } Keyword::Impl => { - let res = Node::parse(cursor, errors); + let res = ctx.parse(); impls.push(res.node); if res.recover { break; } } - Keyword::Asm => { - let res = Node::parse(cursor, errors); - asm_fns.push(res.node); - if res.recover { - break; - } - } _ => { - errors.err(ParserMsg::unexpected_token(next, "a definition")); - cursor.next(); + ctx.err(ParserMsg::unexpected_token(next, "a definition")); + ctx.next(); } } } else if next.is_symbol(Symbol::Semicolon) { - errors.hint(ParserMsg::from_instances( + ctx.hint(ParserMsg::from_instances( &[next], "unneeded semicolon".to_string(), )); - cursor.next(); + ctx.next(); } else { - errors.err(ParserMsg::unexpected_token(next, "a definition")); - cursor.next(); + ctx.err(ParserMsg::unexpected_token(next, "a definition")); + ctx.next(); } } ParseResult::Ok(Self { @@ -81,12 +72,11 @@ impl Parsable for Module { structs, traits, impls, - asm_fns, }) } } -impl Debug for Module { +impl Debug for PModule { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for st in &self.structs { st.fmt(f)?; @@ -104,10 +94,6 @@ impl Debug for Module { func.fmt(f)?; writeln!(f)?; } - for func in &self.asm_fns { - func.fmt(f)?; - writeln!(f)?; - } Ok(()) } } diff --git a/src/parser/v3/nodes/op.rs b/src/parser/v3/nodes/op.rs index 70044d6..db219ee 100644 --- a/src/parser/v3/nodes/op.rs +++ b/src/parser/v3/nodes/op.rs @@ -1,7 +1,7 @@ use super::{Symbol, Token}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum BinaryOp { +pub enum PInfixOp { Add, Sub, Mul, @@ -12,7 +12,7 @@ pub enum BinaryOp { Assign, } -impl BinaryOp { +impl PInfixOp { pub fn presedence(&self) -> u32 { match self { Self::Assign => 0, @@ -69,7 +69,7 @@ pub enum UnaryOp { Deref, } -impl BinaryOp { +impl PInfixOp { pub fn from_token(token: &Token) -> Option { let Token::Symbol(symbol) = token else { return None; diff --git a/src/parser/v3/nodes/statement.rs b/src/parser/v3/nodes/statement.rs index 41af52f..7d52269 100644 --- a/src/parser/v3/nodes/statement.rs +++ b/src/parser/v3/nodes/statement.rs @@ -1,51 +1,45 @@ -use super::{ - Expr, Keyword, Node, Parsable, ParseResult, ParserOutput, Symbol, Token, TokenCursor, VarDef, -}; -use std::fmt::{Debug, Write}; +use super::{PExpr, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, Token, PVarDef}; -pub enum Statement { - Let(Node, Node), - Return(Node), - Expr(Node), +pub enum PStatement { + Let(Node, Node), + Return(Node), + Expr(Node), } -impl Parsable for Statement { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { - let next = cursor.expect_peek()?; +impl Parsable for PStatement { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let next = ctx.expect_peek()?; match next.token { Token::Keyword(Keyword::Let) => { - cursor.next(); - let def = Node::parse(cursor, errors)?; - cursor.expect_sym(Symbol::Equals)?; - Node::parse(cursor, errors).map(|expr| Self::Let(def, expr)) + ctx.next(); + let def = ctx.parse()?; + ctx.expect_sym(Symbol::Equals)?; + ctx.parse().map(|expr| Self::Let(def, expr)) } Token::Keyword(Keyword::Return) => { - cursor.next(); - Node::parse(cursor, errors).map(Self::Return) + ctx.next(); + ctx.parse().map(Self::Return) } - _ => Node::parse(cursor, errors).map(Self::Expr), + _ => ctx.parse().map(Self::Expr), } } } -impl Debug for Statement { +impl std::fmt::Debug for PStatement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Statement::Let(n, e) => { + PStatement::Let(n, e) => { f.write_str("let ")?; n.fmt(f)?; f.write_str(" = ")?; e.fmt(f)?; - f.write_char(';')?; } - Statement::Return(e) => { + PStatement::Return(e) => { f.write_str("return ")?; e.fmt(f)?; - f.write_char(';')?; } - Statement::Expr(e) => { + PStatement::Expr(e) => { e.fmt(f)?; - f.write_char(';')?; } } Ok(()) diff --git a/src/parser/v3/nodes/struc.rs b/src/parser/v3/nodes/struc.rs index 779cb2f..a804c00 100644 --- a/src/parser/v3/nodes/struc.rs +++ b/src/parser/v3/nodes/struc.rs @@ -1,45 +1,45 @@ use std::fmt::Debug; use super::{ - util::parse_list, Ident, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput, - Symbol, TokenCursor, Type, VarDef, + util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, + PType, PVarDef, }; #[derive(Debug)] -pub struct Struct { - pub name: Node, - pub fields: StructFields, +pub struct PStruct { + pub name: Node, + pub fields: PStructFields, } #[derive(Debug)] -pub enum StructFields { - Named(Vec>), - Tuple(Vec>), +pub enum PStructFields { + Named(Vec>), + Tuple(Vec>), None, } -impl Parsable for Struct { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult { - cursor.expect_kw(Keyword::Struct)?; - let name = Node::parse(cursor, errors)?; - let next = cursor.expect_peek()?; +impl Parsable for PStruct { + 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) { - cursor.next(); - StructFields::None + ctx.next(); + PStructFields::None } else if next.is_symbol(Symbol::OpenCurly) { - cursor.next(); - StructFields::Named(parse_list(cursor, errors, Symbol::CloseCurly)?) + ctx.next(); + PStructFields::Named(parse_list(ctx, Symbol::CloseCurly)?) } else if next.is_symbol(Symbol::OpenParen) { - cursor.next(); - StructFields::Tuple(parse_list(cursor, errors, Symbol::CloseParen)?) + ctx.next(); + PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?) } else { - errors.err(ParserMsg::unexpected_token(next, "`;`, `(`, or `{`")); - return ParseResult::Recover(Struct { + let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`"); + ctx.err(msg); + return ParseResult::Recover(PStruct { name, - fields: StructFields::None, + fields: PStructFields::None, }); }; - ParseResult::Ok(Struct { name, fields }) + ParseResult::Ok(PStruct { name, fields }) } } - diff --git a/src/parser/v3/nodes/trai.rs b/src/parser/v3/nodes/trai.rs index 43ff099..5e9a763 100644 --- a/src/parser/v3/nodes/trai.rs +++ b/src/parser/v3/nodes/trai.rs @@ -1,36 +1,39 @@ -use super::{util::{parse_list, parse_list_nosep}, Function, FunctionHeader, Ident, Keyword, Node, Parsable, Symbol, Type}; +use super::{ + util::{parse_list, parse_list_nosep}, + PFunction, PFunctionHeader, PIdent, Keyword, Node, Parsable, ParserCtx, Symbol, PType, +}; #[derive(Debug)] -pub struct Trait { - pub name: Node, - pub fns: Vec> +pub struct PTrait { + pub name: Node, + pub fns: Vec>, } #[derive(Debug)] -pub struct Impl { - pub trait_: Node, - pub for_: Node, - pub fns: Vec> +pub struct PImpl { + pub trait_: Node, + pub for_: Node, + pub fns: Vec>, } -impl Parsable for Trait { - fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult { - cursor.expect_kw(Keyword::Trait)?; - let name = Node::parse(cursor, errors)?; - cursor.expect_sym(Symbol::OpenCurly)?; - let fns = parse_list(cursor, errors, Symbol::CloseCurly)?; - super::ParseResult::Ok(Self {name, fns}) +impl Parsable for PTrait { + fn parse(ctx: &mut ParserCtx) -> super::ParseResult { + ctx.expect_kw(Keyword::Trait)?; + let name = ctx.parse()?; + ctx.expect_sym(Symbol::OpenCurly)?; + let fns = parse_list(ctx, Symbol::CloseCurly)?; + super::ParseResult::Ok(Self { name, fns }) } } -impl Parsable for Impl { - fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult { - cursor.expect_kw(Keyword::Impl)?; - let trait_ = Node::parse(cursor, errors)?; - cursor.expect_kw(Keyword::For)?; - let for_ = Node::parse(cursor, errors)?; - cursor.expect_sym(Symbol::OpenCurly)?; - let fns = parse_list_nosep(cursor, errors, Symbol::CloseCurly)?; - super::ParseResult::Ok(Self {trait_, for_, fns}) +impl Parsable for PImpl { + fn parse(ctx: &mut ParserCtx) -> super::ParseResult { + ctx.expect_kw(Keyword::Impl)?; + let trait_ = ctx.parse()?; + ctx.expect_kw(Keyword::For)?; + let for_ = ctx.parse()?; + ctx.expect_sym(Symbol::OpenCurly)?; + let fns = parse_list_nosep(ctx, Symbol::CloseCurly)?; + super::ParseResult::Ok(Self { trait_, for_, fns }) } } diff --git a/src/parser/v3/nodes/ty.rs b/src/parser/v3/nodes/ty.rs index c5387a6..3809e32 100644 --- a/src/parser/v3/nodes/ty.rs +++ b/src/parser/v3/nodes/ty.rs @@ -1,13 +1,13 @@ use std::fmt::Debug; -use super::{util::parse_list, Node, Parsable, ParseResult, ParserMsg, Symbol, Token}; +use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token}; -pub struct Type { +pub struct PType { pub name: String, - pub args: Vec>, + pub args: Vec>, } -impl Type { +impl PType { pub fn unit() -> Self { Self { name: "()".to_string(), @@ -16,15 +16,12 @@ impl Type { } } -impl Parsable for Type { - fn parse( - cursor: &mut super::TokenCursor, - errors: &mut super::ParserOutput, - ) -> ParseResult { - let next = cursor.expect_peek()?; +impl Parsable for PType { + fn parse(ctx: &mut ParserCtx) -> ParseResult { + let next = ctx.expect_peek()?; let res = if next.is_symbol(Symbol::Ampersand) { - cursor.next(); - let arg = Node::parse(cursor, errors)?; + ctx.next(); + let arg = ctx.parse()?; Self { name: "&".to_string(), args: vec![arg], @@ -34,12 +31,12 @@ impl Parsable for Type { return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier")); }; let n = name.to_string(); - cursor.next(); + ctx.next(); let mut args = Vec::new(); - if let Some(next) = cursor.peek() { + if let Some(next) = ctx.peek() { if next.is_symbol(Symbol::OpenAngle) { - cursor.next(); - args = parse_list(cursor, errors, Symbol::CloseAngle)?; + ctx.next(); + args = parse_list(ctx, Symbol::CloseAngle)?; } } Self { name: n, args } @@ -48,7 +45,7 @@ impl Parsable for Type { } } -impl Debug for Type { +impl Debug for PType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name)?; if self.name == "&" { diff --git a/src/parser/v3/nodes/util.rs b/src/parser/v3/nodes/util.rs index 125d0d5..e307c4f 100644 --- a/src/parser/v3/nodes/util.rs +++ b/src/parser/v3/nodes/util.rs @@ -1,57 +1,54 @@ -use super::{Node, Parsable, ParserMsg, ParserOutput, Symbol, TokenCursor}; +use super::{Node, Parsable, ParserCtx, ParserMsg, Symbol}; pub fn parse_list_sep( - cursor: &mut TokenCursor, - errors: &mut ParserOutput, + ctx: &mut ParserCtx, sep: Symbol, end: Symbol, ) -> Result>, ParserMsg> { let mut vals = Vec::new(); loop { - let next = cursor.expect_peek()?; + let next = ctx.expect_peek()?; if next.is_symbol(end) { break; } - let res = Node::parse(cursor, errors); + let res = ctx.parse(); vals.push(res.node); if res.recover { - cursor.seek_syms(&[end, sep]); + ctx.seek_syms(&[end, sep]); } - let next = cursor.expect_peek()?; + let next = ctx.expect_peek()?; if !next.is_symbol(sep) { break; } - cursor.next(); + ctx.next(); } - cursor.expect_sym(end)?; + ctx.expect_sym(end)?; Ok(vals) } pub fn parse_list( - cursor: &mut TokenCursor, - errors: &mut ParserOutput, + ctx: &mut ParserCtx, end: Symbol, ) -> Result>, ParserMsg> { - parse_list_sep(cursor, errors, Symbol::Comma, end) + parse_list_sep(ctx, Symbol::Comma, end) } pub fn parse_list_nosep( - cursor: &mut TokenCursor, - errors: &mut ParserOutput, + ctx: &mut ParserCtx, end: Symbol, ) -> Result>, ParserMsg> { let mut vals = Vec::new(); loop { - let next = cursor.expect_peek()?; + let next = ctx.expect_peek()?; if next.is_symbol(end) { break; } - let res = Node::parse(cursor, errors); + let res = ctx.parse(); vals.push(res.node); if res.recover { - cursor.seek_sym(end); + ctx.seek_sym(end); } } - cursor.expect_sym(end)?; + ctx.expect_sym(end)?; Ok(vals) } diff --git a/src/parser/v3/parse.rs b/src/parser/v3/parse.rs index c7c5522..1cc15cb 100644 --- a/src/parser/v3/parse.rs +++ b/src/parser/v3/parse.rs @@ -5,7 +5,7 @@ use std::{ use crate::ir::FilePos; -use super::{Node, ParserMsg, ParserOutput, TokenCursor}; +use super::{Node, ParserCtx, ParserMsg}; pub enum ParseResult { Ok(T), @@ -33,6 +33,7 @@ impl Try for ParseResult { fn branch(self) -> ControlFlow { match self { ParseResult::Ok(v) => ControlFlow::Continue(v), + // TODO: this is messed up; need to break w a Result> or smth :woozy: ParseResult::Recover(v) => ControlFlow::Break(None), ParseResult::Err(e) => ControlFlow::Break(Some(e)), ParseResult::SubErr => ControlFlow::Break(None), @@ -111,29 +112,26 @@ impl FromResidual for NodeParseResult { } pub trait Parsable: Sized { - fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult; + fn parse(ctx: &mut ParserCtx) -> ParseResult; } pub trait MaybeParsable: Sized { - fn maybe_parse( - cursor: &mut TokenCursor, - errors: &mut ParserOutput, - ) -> Result, ParserMsg>; + fn maybe_parse(ctx: &mut ParserCtx) -> Result, ParserMsg>; } impl Node { - pub fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> NodeParseResult { - let start = cursor.peek().map(|t| t.span.start).unwrap_or(FilePos::start()); - let (inner, recover) = match T::parse(cursor, output) { + pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult { + let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start()); + let (inner, recover) = match T::parse(ctx) { ParseResult::Ok(v) => (Some(v), false), ParseResult::Recover(v) => (Some(v), true), ParseResult::Err(e) => { - output.err(e); + ctx.err(e); (None, true) } ParseResult::SubErr => (None, true), }; - let end = cursor.prev_end(); + let end = ctx.prev_end(); NodeParseResult { node: Self { inner, @@ -145,16 +143,16 @@ impl Node { } impl Node { - pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> Option { - let start = cursor.next_pos(); - let inner = match T::maybe_parse(cursor, errors) { + pub fn maybe_parse(ctx: &mut ParserCtx) -> Option { + let start = ctx.next_start(); + let inner = match T::maybe_parse(ctx) { Ok(v) => Some(v?), Err(e) => { - errors.err(e); + ctx.err(e); None } }; - let end = cursor.prev_end(); + let end = ctx.prev_end(); Some(Self { inner, span: start.to(end), @@ -163,15 +161,15 @@ impl Node { } pub trait NodeParsable { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult + fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult where Self: Sized; } impl NodeParsable for T { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult + fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult where Self: Sized, { - Node::::parse(cursor, errors) + Node::::parse(ctx) } } diff --git a/src/parser/v3/token/cursor.rs b/src/parser/v3/token/cursor.rs index 365c759..765b378 100644 --- a/src/parser/v3/token/cursor.rs +++ b/src/parser/v3/token/cursor.rs @@ -1,7 +1,7 @@ use std::{iter::Peekable, str::Chars}; -use crate::ir::FilePos; use super::super::ParserMsg; +use crate::ir::FilePos; pub struct CharCursor<'a> { chars: Peekable>, diff --git a/src/parser/v3/token/keyword.rs b/src/parser/v3/token/keyword.rs index 85d656a..a0c696d 100644 --- a/src/parser/v3/token/keyword.rs +++ b/src/parser/v3/token/keyword.rs @@ -9,6 +9,7 @@ pub enum Keyword { Impl, For, Asm, + Funne, } impl Keyword { @@ -23,6 +24,7 @@ impl Keyword { "trait" => Self::Trait, "impl" => Self::Impl, "asm" => Self::Asm, + "funne" => Self::Funne, _ => return None, }) }