actually compiles and does stuff now

This commit is contained in:
2024-12-06 19:44:33 -05:00
parent 31c197e991
commit 620c4557e9
67 changed files with 1931 additions and 1287 deletions

View File

@@ -1,18 +1,21 @@
trait Add { fn start() {
fn add(self, other: Self) -> Self print("Hello World!\n", 13);
exit(39);
} }
impl Add for b32 { fn print(msg, len) {
asm fn add(self, other) { asm (a1 = msg, a2 = len) {
add {out}, {self}, {other} ld a2, 0, a2
} li a0, 1
} li a7, 64
fn main() {
asm {
li a0, 3
li a7, 93
ecall ecall
} }
} }
fn exit(status) {
asm (a0 = status) {
ld a0, 0, a0
li a7, 93
ecall
};
}

3
src/compiler/arch/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
pub mod riscv64;
use super::*;

View File

@@ -1,33 +1,34 @@
use crate::compiler::program::{Addr, Instr, SymTable, Symbol}; use crate::{compiler::program::{Addr, Instr, SymTable}, ir::AddrID};
use super::*; use super::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum AsmInstruction { pub enum LinkerInstruction {
Add { dest: Reg, src1: Reg, src2: Reg }, Add { dest: Reg, src1: Reg, src2: Reg },
Addi { dest: Reg, src: Reg, imm: i32 }, Addi { dest: Reg, src: Reg, imm: i32 },
Andi { dest: Reg, src: Reg, imm: i32 }, Andi { dest: Reg, src: Reg, imm: i32 },
Slli { dest: Reg, src: Reg, imm: i32 }, Slli { dest: Reg, src: Reg, imm: i32 },
Srli { dest: Reg, src: Reg, imm: i32 }, Srli { dest: Reg, src: Reg, imm: i32 },
Sd { src: Reg, offset: i32, base: Reg }, Sd { src: Reg, offset: i32, base: Reg },
Ld { dest: Reg, offset: i32, base: Reg },
Mv { dest: Reg, src: Reg }, Mv { dest: Reg, src: Reg },
La { dest: Reg, sym: Symbol }, La { dest: Reg, src: AddrID },
Jal { dest: Reg, offset: i32 }, Jal { dest: Reg, offset: i32 },
Call(Symbol), Call(AddrID),
J(Symbol), J(AddrID),
Ret, Ret,
Ecall, Ecall,
Li { dest: Reg, imm: i64 }, Li { dest: Reg, imm: i64 },
} }
impl Instr for AsmInstruction { impl Instr for LinkerInstruction {
fn push( fn push(
&self, &self,
data: &mut Vec<u8>, data: &mut Vec<u8>,
sym_map: &SymTable, sym_map: &SymTable,
pos: Addr, pos: Addr,
missing: bool, missing: bool,
) -> Option<Symbol> { ) -> Option<AddrID> {
let last = match self { let last = match self {
Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2), Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2),
Self::Addi { dest, src, imm } => addi(*dest, *src, BitsI32::new(*imm)), 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::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)),
Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)), Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)),
Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base), Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base),
Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base),
Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)), Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)),
Self::La { dest, sym } => { Self::La { dest, src } => {
if let Some(addr) = sym_map.get(*sym) { if let Some(addr) = sym_map.get(*src) {
let offset = addr.val() as i32 - pos.val() as i32; let offset = addr.val() as i32 - pos.val() as i32;
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes()); data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
addi(*dest, *dest, BitsI32::new(offset)) addi(*dest, *dest, BitsI32::new(offset))
} else { } else {
data.extend_from_slice(&[0; 2 * 4]); data.extend_from_slice(&[0; 2 * 4]);
return Some(*sym); return Some(*src);
} }
} }
Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)), Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)),

View File

@@ -2,11 +2,11 @@ use crate::util::Bits32;
use super::Reg; 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<Item = u8> { pub fn to_le_bytes(&self) -> impl IntoIterator<Item = u8> {
self.0.to_le_bytes().into_iter() self.0.to_le_bytes().into_iter()
} }

View File

@@ -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<u8>, Option<Addr>) {
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)
}

View File

@@ -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<u8> {
// 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");
}

View File

@@ -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<Self> {
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",
}
)
}
}

View File

@@ -2,7 +2,7 @@ use crate::util::{Bits32, BitsI32};
use super::*; use super::*;
use Instruction as I; use RawInstruction as I;
pub const fn ecall() -> I { pub const fn ecall() -> I {
i_type(Bits32::new(0), zero, Bits32::new(0), zero, SYSTEM) i_type(Bits32::new(0), zero, Bits32::new(0), zero, SYSTEM)

View File

@@ -1,2 +0,0 @@
pub enum Instruction {
}

View File

@@ -5,14 +5,21 @@ use std::{
process::Command, process::Command,
}; };
pub mod arch;
mod elf; mod elf;
mod program; mod program;
pub mod riscv64;
mod target; mod target;
mod instruction;
pub use program::*; pub use program::*;
use crate::ir::Program;
pub fn compile(program: Program) -> Vec<u8> {
let (compiled, start) = arch::riscv64::compile(program);
let binary = elf::create(compiled, start.expect("no start method found"));
binary
}
pub fn main() { pub fn main() {
use std::io::prelude::*; use std::io::prelude::*;
let dir = Path::new("./build"); let dir = Path::new("./build");
@@ -27,7 +34,7 @@ pub fn main() {
.mode(0o750) .mode(0o750)
.open(path) .open(path)
.expect("Failed to create file"); .expect("Failed to create file");
file.write_all(&riscv64::gen()) file.write_all(&arch::riscv64::gen())
.expect("Failed to write to file"); .expect("Failed to write to file");
file.sync_all().expect("Failed to sync file"); file.sync_all().expect("Failed to sync file");
let mut p = Command::new("qemu-riscv64"); let mut p = Command::new("qemu-riscv64");
@@ -64,4 +71,3 @@ pub fn main() {
} }
} }
} }

View File

@@ -1,14 +1,21 @@
use std::{collections::HashMap, ops::Deref}; use std::{collections::HashMap, ops::Deref};
pub fn create_program<I: Instr>(map: SymMap<I>, start: Symbol) -> (Vec<u8>, Option<Addr>) { use crate::ir::AddrID;
pub fn create_program<I: Instr>(
fns: Vec<(Vec<I>, AddrID)>,
ro_data: Vec<(Vec<u8>, AddrID)>,
start: Option<AddrID>,
) -> (Vec<u8>, Option<Addr>) {
let mut data = Vec::new(); let mut data = Vec::new();
let mut sym_table = SymTable::new(map.len()); let mut sym_table = SymTable::new(fns.len() + ro_data.len());
let mut missing = HashMap::<Symbol, Vec<(Addr, I)>>::new(); let mut missing = HashMap::<AddrID, Vec<(Addr, I)>>::new();
for (val, id) in map.ro_data { for (val, id) in ro_data {
sym_table.insert(id, Addr(data.len() as u64)); sym_table.insert(id, Addr(data.len() as u64));
data.extend(val); 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)); sym_table.insert(id, Addr(data.len() as u64));
for i in fun { for i in fun {
let i_pos = Addr(data.len() as u64); let i_pos = Addr(data.len() as u64);
@@ -30,11 +37,15 @@ pub fn create_program<I: Instr>(map: SymMap<I>, start: Symbol) -> (Vec<u8>, Opti
} }
} }
assert!(missing.is_empty()); 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 { pub trait Instr {
fn push(&self, data: &mut Vec<u8>, syms: &SymTable, pos: Addr, missing: bool) -> Option<Symbol>; fn push(&self, data: &mut Vec<u8>, syms: &SymTable, pos: Addr, missing: bool)
-> Option<AddrID>;
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@@ -73,19 +84,23 @@ impl<I> SymMap<I> {
functions: Vec::new(), functions: Vec::new(),
} }
} }
pub fn push_ro_data(&mut self, data: impl Into<Vec<u8>>) -> (Symbol, usize) { pub fn push_ro_data(&mut self, data: Vec<u8>) -> Symbol {
let sym = self.reserve(); 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<u8>) -> (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<I>) -> Symbol { pub fn push_fn(&mut self, instructions: Vec<I>) -> Symbol {
let sym = self.reserve(); let sym = self.reserve();
self.write_fn(sym, instructions) self.write_fn(sym, instructions)
} }
pub fn write_ro_data(&mut self, sym: WritableSymbol, data: impl Into<Vec<u8>>) -> (Symbol, usize) { pub fn write_ro_data(&mut self, sym: WritableSymbol, data: Vec<u8>) -> Symbol {
let data = data.into(); let data = data.into();
let len = data.len();
self.ro_data.push((data, *sym)); self.ro_data.push((data, *sym));
(*sym, len) *sym
} }
pub fn write_fn(&mut self, sym: WritableSymbol, instructions: Vec<I>) -> Symbol { pub fn write_fn(&mut self, sym: WritableSymbol, instructions: Vec<I>) -> Symbol {
self.functions.push((instructions, *sym)); self.functions.push((instructions, *sym));
@@ -106,10 +121,10 @@ impl SymTable {
pub fn new(len: usize) -> Self { pub fn new(len: usize) -> Self {
Self(vec![Addr::NONE; len]) 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; self.0[sym.0] = addr;
} }
pub fn get(&self, sym: Symbol) -> Option<Addr> { pub fn get(&self, sym: AddrID) -> Option<Addr> {
match self.0[sym.0] { match self.0[sym.0] {
Addr::NONE => None, Addr::NONE => None,
addr => Some(addr), addr => Some(addr),

View File

@@ -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<u8> {
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!"))
}

View File

@@ -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<Self> {
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<Self> {
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<Self> {
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::<Self>();
match res {
Ok(int) => ParseResult::Ok(int),
Err(_) => ParseResult::Err(ParserMsg::from_span(
span,
format!("Expected an i32, found {}", word),
)),
}
}
}

View File

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

1
src/ir/arch/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod riscv64;

37
src/ir/arch/riscv64.rs Normal file
View File

@@ -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:?})"),
}
}
}

13
src/ir/asm.rs Normal file
View File

@@ -0,0 +1,13 @@
use super::VarID;
#[derive(Clone)]
pub struct IRAsmInstruction {
op: String,
args: Vec<RegRef>,
}
#[derive(Clone)]
pub enum RegRef {
Var(VarID),
Reg(String),
}

42
src/ir/id.rs Normal file
View File

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

6
src/ir/lower/data.rs Normal file
View File

@@ -0,0 +1,6 @@
use super::AddrID;
pub struct IRLData {
pub addr: AddrID,
pub data: Vec<u8>,
}

41
src/ir/lower/func.rs Normal file
View File

@@ -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<IRLInstruction>,
pub stack: HashMap<VarID, usize>,
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<RV64Instruction>,
args: Vec<(Reg, VarID)>,
},
Ret {
src: VarID,
},
}

9
src/ir/lower/mod.rs Normal file
View File

@@ -0,0 +1,9 @@
mod func;
mod data;
mod program;
pub use func::*;
pub use data::*;
pub use program::*;
use super::*;

85
src/ir/lower/program.rs Normal file
View File

@@ -0,0 +1,85 @@
use std::collections::HashMap;
use super::{AddrID, IRLData, IRLFunction, IRLInstruction, IRUInstruction, Namespace, VarID};
pub struct Program {
pub fns: Vec<IRLFunction>,
pub data: Vec<IRLData>,
}
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 }
}
}

View File

@@ -1,56 +0,0 @@
use crate::compiler::riscv64::AsmInstruction;
use super::{FnIdent, VarIdent};
#[derive(Debug)]
pub struct Function {
instructions: Vec<Instruction>,
}
#[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<VarIdent>,
},
AsmBlock {
instructions: Vec<AsmInstruction>,
},
Ret {
src: VarIdent,
},
}
pub struct Instructions {
vec: Vec<Instruction>,
}
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);
}
}

View File

View File

@@ -1,9 +1,11 @@
mod namespace; mod upper;
mod lvl1;
mod lvl2;
mod file; mod file;
mod lower;
mod id;
mod asm;
pub mod arch;
pub use namespace::*; pub use upper::*;
pub use lvl1::*; pub use lower::*;
pub use file::*; pub use file::*;
pub use id::*;

View File

@@ -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<ExprResult>),
}
#[derive(Debug)]
pub struct IRFunction {
args: Vec<Var>,
instructions: Vec<IRInstruction>,
}
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<FnIdent> {
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<IRInstruction>,
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<Box<Expr>> {
pub fn lower(
&self,
map: &mut Namespace,
instructions: &mut Vec<IRInstruction>,
errors: &mut ParserErrors,
) -> Option<ExprResult> {
self.as_ref()?.lower(self.span, map, instructions, errors)
}
}
impl Node<Expr> {
pub fn lower(
&self,
map: &mut Namespace,
instructions: &mut Vec<IRInstruction>,
errors: &mut ParserErrors,
) -> Option<ExprResult> {
self.as_ref()?.lowerr(self.span, map, instructions, errors)
}
}
impl Expr {
pub fn lowerr(
&self,
span: FileSpan,
map: &mut Namespace,
instructions: &mut Vec<IRInstruction>,
errors: &mut ParserErrors,
) -> Option<ExprResult> {
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),
}

View File

@@ -1,6 +1,7 @@
use super::{FileSpan, Type}; use super::{FileSpan, Type};
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Clone)]
pub struct FnDef { pub struct FnDef {
pub name: String, pub name: String,
pub args: Vec<VarDef>, pub args: Vec<VarDef>,
@@ -8,6 +9,7 @@ pub struct FnDef {
pub origin: Origin, pub origin: Origin,
} }
#[derive(Clone)]
pub struct TypeDef { pub struct TypeDef {
pub name: String, pub name: String,
pub args: usize, pub args: usize,

82
src/ir/upper/func.rs Normal file
View File

@@ -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<VarID>,
pub instructions: Vec<IRUInstruction>,
}
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<VarID>,
},
AsmBlock {
instructions: Vec<RV64Instruction>,
args: Vec<(Reg, VarID)>,
},
Ret {
src: VarID,
},
}
pub struct IRInstructions {
vec: Vec<IRUInstruction>,
}
impl IRUFunction {
pub fn new(name: String, args: Vec<VarID>, 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(),
}
}
}

View File

@@ -1,9 +1,10 @@
mod def; mod def;
mod func; mod func;
mod ty; mod ty;
mod namespace;
use super::*; use super::*;
pub use def::*; pub use def::*;
pub use func::*; pub use func::*;
pub use ty::*; pub use ty::*;
pub use namespace::*;

View File

@@ -4,13 +4,15 @@ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
use super::{BuiltinType, FileSpan, FnDef, Function, Type, TypeDef, VarDef}; use super::*;
pub struct Namespace { pub struct Namespace {
pub fn_defs: Vec<FnDef>, pub fn_defs: Vec<FnDef>,
pub var_defs: Vec<VarDef>, pub var_defs: Vec<VarDef>,
pub type_defs: Vec<TypeDef>, pub type_defs: Vec<TypeDef>,
pub fns: Vec<Option<Function>>, pub fns: Vec<Option<IRUFunction>>,
pub data: Vec<Vec<u8>>,
pub fn_map: HashMap<VarID, FnID>,
pub temp: usize, pub temp: usize,
pub stack: Vec<HashMap<String, Idents>>, pub stack: Vec<HashMap<String, Idents>>,
} }
@@ -21,6 +23,8 @@ impl Namespace {
fn_defs: Vec::new(), fn_defs: Vec::new(),
var_defs: Vec::new(), var_defs: Vec::new(),
type_defs: Vec::new(), type_defs: Vec::new(),
data: Vec::new(),
fn_map: HashMap::new(),
fns: Vec::new(), fns: Vec::new(),
temp: 0, temp: 0,
stack: vec![HashMap::new()], stack: vec![HashMap::new()],
@@ -43,27 +47,36 @@ impl Namespace {
} }
None None
} }
pub fn get_var(&self, id: VarIdent) -> &VarDef { pub fn get_var(&self, id: VarID) -> &VarDef {
&self.var_defs[id.0] &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] &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] &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)); 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)); 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(); let i = self.var_defs.len();
self.var_defs.push(var); 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 { let v = self.def_var(VarDef {
name: format!("temp{}", self.temp), name: format!("temp{}", self.temp),
origin: super::Origin::File(origin), origin: super::Origin::File(origin),
@@ -72,21 +85,38 @@ impl Namespace {
self.temp += 1; self.temp += 1;
v 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 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.insert(&def.name, Ident::Fn(id));
self.fn_defs.push(def); self.fn_defs.push(def);
self.fns.push(None); self.fns.push(None);
id 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 i = self.type_defs.len();
let id = TypeIdent(i); let id = TypeID(i);
self.insert(&def.name, Ident::Type(id)); self.insert(&def.name, Ident::Type(id));
self.type_defs.push(def); self.type_defs.push(def);
id id
} }
pub fn def_data(&mut self, bytes: Vec<u8>) -> DataID {
let i = self.data.len();
self.data.push(bytes);
DataID(i)
}
pub fn type_name(&self, ty: &Type) -> String { pub fn type_name(&self, ty: &Type) -> String {
let mut str = String::new(); let mut str = String::new();
match ty { match ty {
@@ -121,6 +151,8 @@ impl Namespace {
} }
Type::Error => str += "{error}", Type::Error => str += "{error}",
Type::Infer => str += "{inferred}", Type::Infer => str += "{inferred}",
Type::Bits(size) => str += &format!("b{}", size),
Type::Array(t) => str += &format!("[{}]", self.type_name(t)),
} }
str str
} }
@@ -133,7 +165,7 @@ impl Namespace {
last.insert(name.to_string(), Idents::new(id)); 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); self.fns[id.0] = Some(f);
} }
} }
@@ -161,18 +193,17 @@ impl DerefMut for NamespaceGuard<'_> {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Ident { pub enum Ident {
Var(VarIdent), Var(VarID),
Fn(FnIdent), Fn(FnID),
Type(TypeIdent), Type(TypeID),
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Idents { pub struct Idents {
pub latest: Ident, pub latest: Ident,
pub var: Option<VarIdent>, pub var: Option<VarID>,
pub func: Option<FnIdent>, pub func: Option<FnID>,
pub var_func: Option<VarOrFnIdent>, pub ty: Option<TypeID>,
pub ty: Option<TypeIdent>,
} }
impl Idents { impl Idents {
@@ -181,7 +212,6 @@ impl Idents {
latest, latest,
var: None, var: None,
func: None, func: None,
var_func: None,
ty: None, ty: None,
}; };
s.insert(latest); s.insert(latest);
@@ -192,50 +222,12 @@ impl Idents {
match i { match i {
Ident::Var(v) => { Ident::Var(v) => {
self.var = Some(v); self.var = Some(v);
self.var_func = Some(VarOrFnIdent::Var(v));
} }
Ident::Fn(f) => { Ident::Fn(f) => {
self.func = Some(f); self.func = Some(f);
self.var_func = Some(VarOrFnIdent::Fn(f));
} }
Ident::Type(t) => self.ty = Some(t), 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)
}
}

View File

@@ -1,15 +1,26 @@
use super::{Origin, TypeDef, TypeIdent}; use super::{Origin, TypeDef, TypeID};
#[derive(Clone)] #[derive(Clone)]
pub enum Type { pub enum Type {
Concrete(TypeIdent), Concrete(TypeID),
Generic { base: TypeIdent, args: Vec<Type> }, Bits(u32),
Generic { base: TypeID, args: Vec<Type> },
Fn { args: Vec<Type>, ret: Box<Type> }, Fn { args: Vec<Type>, ret: Box<Type> },
Ref(Box<Type>), Ref(Box<Type>),
Array(Box<Type>),
Infer, Infer,
Error, 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)] #[repr(usize)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum BuiltinType { pub enum BuiltinType {
@@ -29,7 +40,14 @@ impl BuiltinType {
}, },
} }
} }
pub fn id(&self) -> TypeIdent { pub fn id(&self) -> TypeID {
TypeIdent::builtin(self) TypeID::builtin(self)
} }
} }
impl TypeID {
pub fn builtin(ty: &BuiltinType) -> Self {
Self(*ty as usize)
}
}

View File

@@ -1,10 +1,15 @@
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(try_trait_v2)] #![feature(try_trait_v2)]
use std::io::{stdout, BufRead, BufReader}; use ir::{Namespace, Program};
use parser::{NodeParsable, PModule, PStatement, ParserCtx};
use ir::Namespace; use std::{
use parser::{Module, NodeParsable, ParserOutput, Statement, TokenCursor}; fs::{create_dir_all, OpenOptions},
io::{stdout, BufRead, BufReader},
os::unix::fs::OpenOptionsExt,
path::Path,
process::Command,
};
mod compiler; mod compiler;
mod ir; mod ir;
@@ -12,43 +17,102 @@ mod parser;
mod util; mod util;
fn main() { fn main() {
let arg = std::env::args_os().nth(1); let file = std::env::args_os().nth(1);
if let Some(path) = arg { 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"); let file = std::fs::read_to_string(path).expect("failed to read file");
run_file(&file); run_file(&file, gdb);
} else { } else {
run_stdin(); run_stdin();
} }
// compiler::main(); // compiler::main();
} }
fn run_file(file: &str) { fn run_file(file: &str, gdb: bool) {
let mut output = ParserOutput::new(); let mut ctx = ParserCtx::from(file);
let res = Module::parse_node(&mut TokenCursor::from(file), &mut output); let res = PModule::parse_node(&mut ctx);
println!("{:?}", res.node); if ctx.output.errs.is_empty() {
// println!("Parsed:");
// println!("{:#?}", res.node);
if let Some(module) = res.node.as_ref() { if let Some(module) = res.node.as_ref() {
let mut namespace = Namespace::new(); let mut namespace = Namespace::new();
module.lower(&mut namespace.push(), &mut output); module.lower(&mut namespace.push(), &mut ctx.output);
println!("{:?}", namespace.fns); 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() { pub fn run_stdin() {
for line in BufReader::new(std::io::stdin()).lines() { for line in BufReader::new(std::io::stdin()).lines() {
let mut output = ParserOutput::new();
let str = &line.expect("failed to read line"); let str = &line.expect("failed to read line");
let mut cursor = TokenCursor::from(&str[..]); let mut ctx = ParserCtx::from(&str[..]);
if let Some(expr) = Statement::parse_node(&mut cursor, &mut output) if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() {
.node if ctx.next().is_none() {
.as_ref()
{
if cursor.next().is_none() {
println!("{:?}", expr); println!("{:?}", expr);
} else { } else {
println!("uhhhh ehehe"); println!("uhhhh ehehe");
} }
} }
output.write_for(&mut stdout(), str); ctx.output.write_for(&mut stdout(), str);
} }
} }

55
src/parser/v3/ctx.rs Normal file
View File

@@ -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<T: Parsable>(&mut self) -> NodeParseResult<T> {
Node::parse(self)
}
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
Node::maybe_parse(self)
}
}
impl<'a> From<TokenCursor<'a>> 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(),
}
}
}

View File

@@ -6,15 +6,23 @@ use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
pub struct TokenCursor<'a> { pub struct TokenCursor<'a> {
cursor: CharCursor<'a>, cursor: CharCursor<'a>,
next: Option<TokenInstance>, next: Option<TokenInstance>,
next_pos: FilePos, next_start: FilePos,
prev_end: FilePos, prev_end: FilePos,
} }
impl<'a> TokenCursor<'a> { impl<'a> TokenCursor<'a> {
pub fn next(&mut self) -> Option<TokenInstance> { pub fn next(&mut self) -> Option<TokenInstance> {
self.prev_end = self.cursor.prev_pos(); self.prev_end = self
self.next_pos = self.cursor.next_pos(); .next
std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor)) .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<TokenInstance, ParserMsg> { pub fn expect_next(&mut self) -> Result<TokenInstance, ParserMsg> {
self.peek().ok_or(ParserMsg::unexpected_end())?; 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> { pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> {
self.expect_token(Token::Symbol(symbol)) self.expect_token(Token::Symbol(symbol))
} }
pub fn seek_sym(&mut self, symbol: Symbol) { pub fn next_on_new_line(&mut self) -> bool {
while self self.next_start.line != self.prev_end.line
.next() }
.is_some_and(|n| n.token != Token::Symbol(symbol)) 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]) { pub fn seek_syms(&mut self, syms: &[Symbol]) {
while self while self
@@ -45,6 +53,9 @@ impl<'a> TokenCursor<'a> {
self.next(); 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> { pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> {
loop { loop {
if f(self.peek()?) { if f(self.peek()?) {
@@ -68,8 +79,8 @@ impl<'a> TokenCursor<'a> {
pub fn prev_end(&self) -> FilePos { pub fn prev_end(&self) -> FilePos {
self.prev_end self.prev_end
} }
pub fn next_pos(&self) -> FilePos { pub fn next_start(&self) -> FilePos {
self.next_pos self.next_start
} }
} }
@@ -85,7 +96,7 @@ impl<'a> From<CharCursor<'a>> for TokenCursor<'a> {
Self { Self {
cursor, cursor,
next: cur, next: cur,
next_pos: FilePos::start(), next_start: FilePos::start(),
prev_end: FilePos::start(), prev_end: FilePos::start(),
} }
} }

View File

@@ -1,6 +1,6 @@
use crate::ir::{FilePos, FileSpan}; use crate::ir::{FilePos, FileSpan};
use super::{token::TokenInstance, Ident, Node}; use super::{token::TokenInstance, PIdent, Node};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ParserMsg { pub struct ParserMsg {
@@ -32,9 +32,9 @@ impl ParserMsg {
spans: vec![span], spans: vec![span],
} }
} }
pub fn identifier_not_found(id: &Node<Ident>) -> Self { pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
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], spans: vec![id.span],
} }
} }
@@ -71,11 +71,11 @@ impl ParserOutput {
hints: Vec::new(), hints: Vec::new(),
} }
} }
pub fn err(&mut self, err: ParserMsg) { pub fn err(&mut self, msg: ParserMsg) {
self.errs.push(err); self.errs.push(msg);
} }
pub fn hint(&mut self, err: ParserMsg) { pub fn hint(&mut self, msg: ParserMsg) {
self.hints.push(err); self.hints.push(msg);
} }
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) { pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
for err in &self.errs { for err in &self.errs {

View File

@@ -0,0 +1,2 @@
pub mod riscv64;
pub use super::*;

View File

@@ -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<Self> {
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<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarID> {
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<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<Self> {
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<PIdent>, ctx: &mut FnLowerCtx) -> Option<Self> {
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<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<i64> {
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::<i64>() {
Ok(x) => Some(x),
Err(_) => {
ctx.err_at(node.span, format!("Expected an i64, found {}", word));
None
}
}
}

View File

@@ -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> {
RV64Instruction::parse(self, ctx)
}
}
impl FnLowerable for PAsmBlock {
type Output = ();
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
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<Self::Output> {
let var = ctx.get_var(&self.var)?;
let reg = Reg::from_ident(&self.reg, ctx)?;
Some((reg, var))
}
}

View File

@@ -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<Block> { impl FnLowerable for PBlock {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> { type Output = VarID;
self.as_ref()?.lower(ctx) fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
}
}
impl Block {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
let ctx = &mut ctx.sub(); let ctx = &mut ctx.sub();
for statement in &self.statements { for statement in &self.statements {
statement.lower(ctx); statement.lower(ctx);
@@ -18,41 +13,24 @@ impl Block {
} }
} }
impl Node<Box<Statement>> { impl FnLowerable for PStatement {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> { type Output = VarID;
self.as_ref()?.lower(ctx) fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
}
}
impl Node<Statement> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
self.as_ref()?.lower(ctx)
}
}
impl Statement {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
match self { match self {
super::Statement::Let(def, e) => { super::PStatement::Let(def, e) => {
let def = def.lower(ctx.map, ctx.output)?; let def = def.lower(ctx.map, ctx.output)?;
let res = e.lower(ctx); let res = e.lower(ctx);
if let Some(res) = res { if let Some(res) = res {
match res { ctx.map.name_var(&def, res);
ExprResult::Var(v) => ctx.map.name_var(&def, v),
ExprResult::Fn(_) => todo!(),
}
} }
None None
} }
super::Statement::Return(e) => { super::PStatement::Return(e) => {
let res = e.lower(ctx)?; let src = e.lower(ctx)?;
match res { ctx.push(IRUInstruction::Ret { src });
ExprResult::Var(v) => ctx.push(Instruction::Ret { src: v }),
_ => todo!(),
}
None None
} }
super::Statement::Expr(e) => e.lower(ctx), super::PStatement::Expr(e) => e.lower(ctx),
} }
} }
} }

View File

@@ -1,6 +1,6 @@
use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef}; 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<PVarDef> { impl Node<PVarDef> {
pub fn lower( pub fn lower(
@@ -9,7 +9,7 @@ impl Node<PVarDef> {
output: &mut ParserOutput, output: &mut ParserOutput,
) -> Option<VarDef> { ) -> Option<VarDef> {
let s = self.as_ref()?; 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 { let ty = match &s.ty {
Some(ty) => ty.lower(namespace, output), Some(ty) => ty.lower(namespace, output),
None => Type::Infer, None => Type::Infer,

View File

@@ -1,32 +1,37 @@
use super::{func::FnLowerCtx, Expr as PExpr, Node, UnaryOp}; use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
use crate::ir::{FnIdent, Instruction, Type, VarIdent, VarOrFnIdent}; use crate::ir::{IRUInstruction, Type, VarID};
impl PExpr { impl FnLowerable for PExpr {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> { type Output = VarID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
Some(match self { Some(match self {
PExpr::Lit(l) => match l.as_ref()? { PExpr::Lit(l) => match l.as_ref()? {
super::Literal::String(s) => todo!(), super::PLiteral::String(s) => {
super::Literal::Char(c) => todo!(), let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf());
super::Literal::Number(n) => todo!(), let src = ctx.map.def_data(s.as_bytes().to_vec());
super::Literal::Unit => { 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::<i64>().unwrap().to_le_bytes().to_vec());
ctx.push(IRUInstruction::LoadData { dest, src });
dest
}
super::PLiteral::Unit => {
todo!(); todo!();
} }
}, },
PExpr::Ident(i) => { PExpr::Ident(i) => ctx.get_var(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::BinaryOp(op, e1, e2) => { PExpr::BinaryOp(op, e1, e2) => {
let res1 = e1.lower(ctx)?; let res1 = e1.lower(ctx)?;
let res2 = e2.lower(ctx)?; let res2 = e2.lower(ctx)?;
@@ -36,101 +41,50 @@ impl PExpr {
PExpr::UnaryOp(op, e) => { PExpr::UnaryOp(op, e) => {
let res = e.lower(ctx)?; let res = e.lower(ctx)?;
match op { match op {
UnaryOp::Ref => ExprResult::Var(match res { UnaryOp::Ref => {
ExprResult::Var(v) => { let temp = ctx.temp(ctx.map.get_var(res).ty.clone());
let temp = ctx.temp(ctx.map.get_var(v).ty.clone()); ctx.push(IRUInstruction::Ref {
ctx.push(Instruction::Ref { dest: temp, src: v }); dest: temp,
src: res,
});
temp temp
} }
ExprResult::Fn(f) => { UnaryOp::Deref => {
let temp = ctx.temp(Type::Ref(Box::new(ctx.map.get_fn(f).ty()))); let t = &ctx.map.get_var(res).ty;
ctx.push(Instruction::Lf { dest: temp, src: f }); let Type::Ref(inner) = t else {
temp
}
}),
UnaryOp::Deref => match res {
ExprResult::Var(v) => match &ctx.map.get_var(v).ty {
Type::Ref(inner) => {
todo!()
}
t => {
ctx.err(format!( ctx.err(format!(
"Cannot dereference type {:?}", "Cannot dereference type {:?}",
ctx.map.type_name(t) ctx.map.type_name(t)
)); ));
return None; return None;
};
todo!();
} }
},
ExprResult::Fn(f) => {
ctx.err("Cannot dereference functions".to_string());
return None;
}
},
UnaryOp::Not => todo!(), UnaryOp::Not => todo!(),
} }
} }
PExpr::Block(b) => b.lower(ctx)?, PExpr::Block(b) => b.lower(ctx)?,
PExpr::AsmBlock(b) => { PExpr::AsmBlock(b) => {
ctx.push(Instruction::AsmBlock { b.lower(ctx);
instructions: b.as_ref()?.instructions.clone(),
});
return None; return None;
} }
PExpr::Call(e, args) => { PExpr::Call(e, args) => {
let fe = e.lower(ctx)?; let f = e.lower(ctx)?;
let mut nargs = Vec::new(); let mut nargs = Vec::new();
for arg in args.iter() { for arg in args.iter() {
let arg = arg.lower(ctx)?; let arg = arg.lower(ctx)?;
nargs.push(match arg { nargs.push(arg);
ExprResult::Var(v) => v,
ExprResult::Fn(_) => todo!(),
});
} }
match fe { let temp = ctx.temp(ctx.map.get_fn_var(f).ret.clone());
ExprResult::Fn(f) => { ctx.push(IRUInstruction::Call {
let temp = ctx.temp(ctx.map.get_fn(f).ret.clone());
ctx.push(Instruction::Call {
dest: temp, dest: temp,
f, f,
args: nargs, args: nargs,
}); });
ExprResult::Var(temp) // ctx.err(format!("Expected function, found {:?}", f));
}
o => {
ctx.err(format!("Expected function, found {:?}", o));
return None; return None;
} }
}
}
PExpr::Group(e) => e.lower(ctx)?, PExpr::Group(e) => e.lower(ctx)?,
}) })
} }
} }
impl Node<PExpr> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
self.inner.as_ref()?.lower(&mut FnLowerCtx {
map: ctx.map,
instructions: ctx.instructions,
output: ctx.output,
span: self.span,
})
}
}
impl Node<Box<PExpr>> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
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),
}

View File

@@ -1,7 +1,10 @@
use super::{Function as PFunction, Node, ParserMsg, ParserOutput}; use super::{FnLowerable, PFunction, Node, ParserMsg, ParserOutput};
use crate::ir::{ use crate::{
BuiltinType, FileSpan, FnDef, FnIdent, Function, Idents, Instruction, Instructions, ir::{
NamespaceGuard, Origin, Type, VarDef, VarIdent, BuiltinType, FileSpan, FnDef, FnID, IRUFunction, Idents, IRUInstruction, IRInstructions,
NamespaceGuard, Origin, Type, VarDef, VarID,
},
parser,
}; };
impl Node<PFunction> { impl Node<PFunction> {
@@ -9,15 +12,16 @@ impl Node<PFunction> {
&self, &self,
map: &mut NamespaceGuard, map: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut ParserOutput,
) -> Option<FnIdent> { ) -> Option<FnID> {
self.as_ref()?.lower_header(map, output) self.as_ref()?.lower_header(map, output)
} }
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Option<Function> { pub fn lower_body(
if let Some(f) = self.as_ref() { &self,
Some(f.lower_body(map, output)) id: FnID,
} else { map: &mut NamespaceGuard,
None output: &mut ParserOutput,
} ) -> Option<IRUFunction> {
Some(self.as_ref()?.lower_body(id, map, output))
} }
} }
@@ -26,7 +30,7 @@ impl PFunction {
&self, &self,
map: &mut NamespaceGuard, map: &mut NamespaceGuard,
output: &mut ParserOutput, output: &mut ParserOutput,
) -> Option<FnIdent> { ) -> Option<FnID> {
let header = self.header.as_ref()?; let header = self.header.as_ref()?;
let name = header.name.as_ref()?; let name = header.name.as_ref()?;
let args = header let args = header
@@ -44,50 +48,145 @@ impl PFunction {
Some(ty) => ty.lower(map, output), Some(ty) => ty.lower(map, output),
None => Type::Concrete(BuiltinType::Unit.id()), None => Type::Concrete(BuiltinType::Unit.id()),
}; };
// ignoring self var for now
Some(map.def_fn(FnDef { Some(map.def_fn(FnDef {
name: name.val().clone(), name: name.to_string(),
origin: Origin::File(self.header.span), origin: Origin::File(self.header.span),
args, args,
ret, ret,
})) }))
} }
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Function { pub fn lower_body(
let mut instructions = Instructions::new(); &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 { let mut ctx = FnLowerCtx {
instructions: &mut instructions, instructions: &mut instructions,
map, map,
output, output,
span: self.body.span, span: self.body.span,
}; };
if let Some(res) = self.body.lower(&mut ctx) { if let Some(src) = self.body.lower(&mut ctx) {
match res { instructions.push(IRUInstruction::Ret { src });
super::ExprResult::Var(v) => instructions.push(Instruction::Ret { src: v }),
super::ExprResult::Fn(_) => todo!(),
} }
} IRUFunction::new(def.name.clone(), args, instructions)
Function::new(instructions)
} }
} }
// impl Node<AsmFunction> {
// pub fn lower_header(
// &self,
// map: &mut NamespaceGuard,
// output: &mut ParserOutput,
// ) -> Option<FnIdent> {
// self.as_ref()?.lower_header(map, output)
// }
// pub fn lower_body(
// &self,
// map: &mut NamespaceGuard,
// output: &mut ParserOutput,
// ) -> Option<Function> {
// Some(self.as_ref()?.lower_body(map, output))
// }
// }
//
// impl AsmFunction {
// pub fn lower_header(
// &self,
// map: &mut NamespaceGuard,
// output: &mut ParserOutput,
// ) -> Option<FnIdent> {
// 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 struct FnLowerCtx<'a, 'n> {
pub map: &'a mut NamespaceGuard<'n>, pub map: &'a mut NamespaceGuard<'n>,
pub instructions: &'a mut Instructions, pub instructions: &'a mut IRInstructions,
pub output: &'a mut ParserOutput, pub output: &'a mut ParserOutput,
pub span: FileSpan, pub span: FileSpan,
} }
impl<'a, 'n> FnLowerCtx<'a, 'n> { impl<'n> FnLowerCtx<'_, 'n> {
pub fn get(&self, name: &str) -> Option<Idents> { pub fn span<'b>(&'b mut self, span: FileSpan) -> FnLowerCtx<'b, 'n> {
self.map.get(name) FnLowerCtx {
map: self.map,
instructions: self.instructions,
output: self.output,
span,
}
}
pub fn get(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> {
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<parser::PIdent>) -> Option<VarID> {
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) { pub fn err(&mut self, msg: String) {
self.output.err(ParserMsg::from_span(self.span, msg)) 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) 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); self.instructions.push(i);
} }
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> { pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {

View File

@@ -1,12 +1,30 @@
mod asm;
mod block; mod block;
mod def; mod def;
mod expr; mod expr;
mod func; mod func;
mod module; mod module;
mod arch;
use super::*; use super::*;
use block::*;
use def::*; pub use func::FnLowerCtx;
use expr::*;
use func::*; pub trait FnLowerable {
use module::*; type Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output>;
}
impl<T: FnLowerable> FnLowerable for Node<T> {
type Output = T::Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
self.as_ref()?.lower(&mut ctx.span(self.span))
}
}
impl<T: FnLowerable> FnLowerable for Box<T> {
type Output = T::Output;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
self.as_ref().lower(ctx)
}
}

View File

@@ -1,8 +1,8 @@
use crate::ir::NamespaceGuard; 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) { pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) {
let mut fns = Vec::new(); let mut fns = Vec::new();
for f in &self.functions { for f in &self.functions {
@@ -13,9 +13,11 @@ impl Module {
} }
} }
for (f, id) in self.functions.iter().zip(fns) { for (f, id) in self.functions.iter().zip(fns) {
if let (Some(res), Some(id)) = (f.lower_body(map, output), id) { if let Some(id) = id {
if let Some(res) = f.lower_body(id, map, output) {
map.write_fn(id, res); map.write_fn(id, res);
} }
} }
} }
}
} }

View File

@@ -5,6 +5,7 @@ mod node;
mod nodes; mod nodes;
mod parse; mod parse;
mod token; mod token;
mod ctx;
pub use cursor::*; pub use cursor::*;
pub use error::*; pub use error::*;
@@ -13,3 +14,4 @@ pub use node::*;
pub use nodes::*; pub use nodes::*;
pub use parse::*; pub use parse::*;
pub use token::*; pub use token::*;
pub use ctx::*;

View File

@@ -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}; pub struct PAsmBlock {
pub instructions: Vec<Node<PInstruction>>,
#[derive(Debug)] pub args: Vec<Node<PAsmBlockArg>>,
pub struct AsmBlock {
pub instructions: Vec<AsmInstruction>,
} }
impl Parsable for AsmBlock { pub struct PAsmBlockArg {
fn parse( pub reg: Node<PIdent>,
cursor: &mut super::TokenCursor, pub var: Node<PIdent>,
output: &mut super::ParserOutput, }
) -> ParseResult<Self> {
cursor.expect_sym(Symbol::OpenCurly)?; impl Parsable for PAsmBlock {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
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(); let mut instructions = Vec::new();
while !cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { while !ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
instructions.push(AsmInstruction::parse(cursor, output)?); 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<Self> {
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(())
} }
} }

View File

@@ -1,53 +1,63 @@
use crate::compiler::riscv64::{AsmInstruction, Reg};
use super::{ 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)] // #[derive(Debug)]
pub struct AsmFunctionHeader { // pub struct AsmFunctionHeader {
pub name: Node<Ident>, // pub name: Node<Ident>,
pub sel: Option<Node<SelfVar>>, // pub args: Vec<Node<AsmVarDef>>,
pub args: Vec<Node<Reg>>, // }
} //
// #[derive(Debug)]
#[derive(Debug)] // pub struct AsmFunction {
pub struct AsmFunction { // pub header: Node<AsmFunctionHeader>,
pub header: Node<AsmFunctionHeader>, // pub body: Node<AsmBlock>,
pub body: Node<AsmBlock>, // }
} //
// impl Parsable for AsmFunctionHeader {
impl Parsable for AsmFunctionHeader { // fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
fn parse( // ctx.expect_kw(Keyword::Asm)?;
cursor: &mut super::TokenCursor, // ctx.expect_kw(Keyword::Fn)?;
output: &mut super::ParserOutput, // let name = ctx.parse()?;
) -> ParseResult<Self> { // ctx.expect_sym(Symbol::OpenParen)?;
cursor.expect_kw(Keyword::Asm)?; // let args = parse_list(ctx, Symbol::CloseParen)?;
cursor.expect_kw(Keyword::Fn)?; // ParseResult::Ok(Self { name, args })
let name = Node::parse(cursor, output)?; // }
cursor.expect_sym(Symbol::OpenParen)?; // }
let sel = Node::maybe_parse(cursor, output); //
if sel.is_some() { // impl Parsable for AsmFunction {
if let Err(err) = cursor.expect_sym(Symbol::Comma) { // fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
output.err(err); // let header = ctx.parse()?;
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]); // let body = ctx.parse()?;
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) { // ParseResult::Ok(Self { header, body })
cursor.next(); // }
} // }
} //
} // pub struct AsmVarDef {
let args = parse_list(cursor, output, Symbol::CloseParen)?; // pub reg: Node<Ident>,
ParseResult::Ok(Self { name, sel, args }) // pub name: Node<Ident>,
} // pub ty: Option<Node<Type>>,
} // }
//
impl Parsable for AsmFunction { // impl Parsable for AsmVarDef {
fn parse( // fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
cursor: &mut super::TokenCursor, // let reg = ctx.parse()?;
output: &mut super::ParserOutput, // let name = ctx.parse()?;
) -> ParseResult<Self> { // if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
let header = Node::parse(cursor, output)?; // ctx.next();
let body = Node::parse(cursor, output)?; // ctx.parse().map(|ty| Self { reg, name, ty: Some(ty) })
ParseResult::Ok(Self { header, body }) // } 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(())
// }
// }

View File

@@ -0,0 +1,82 @@
use super::{PIdent, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol};
pub struct PInstruction {
pub op: Node<PIdent>,
pub args: Vec<Node<PAsmArg>>,
}
pub enum PAsmArg {
Value(Node<PIdent>),
Ref(Node<PIdent>),
}
impl Parsable for PInstruction {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
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<Self> {
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(())
}
}

View File

@@ -1,53 +1,52 @@
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
use super::{ use super::{
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserMsg, ParserOutput, Statement, token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement,
TokenCursor,
}; };
use crate::util::Padder; use crate::util::Padder;
pub struct Block { pub struct PBlock {
pub statements: Vec<Node<Statement>>, pub statements: Vec<Node<PStatement>>,
pub result: Option<Node<Box<Statement>>>, pub result: Option<Node<Box<PStatement>>>,
} }
impl Parsable for Block { impl Parsable for PBlock {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let mut statements = Vec::new(); let mut statements = Vec::new();
let mut result = None; let mut result = None;
cursor.expect_sym(Symbol::OpenCurly)?; ctx.expect_sym(Symbol::OpenCurly)?;
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { if ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
cursor.next(); ctx.next();
return ParseResult::Ok(Self { statements, result }); return ParseResult::Ok(Self { statements, result });
} }
let mut expect_semi = false; let mut expect_semi = false;
let mut recover = false; let mut recover = false;
loop { loop {
let Some(next) = cursor.peek() else { let Some(next) = ctx.peek() else {
recover = true; recover = true;
errors.err(ParserMsg::unexpected_end()); ctx.err(ParserMsg::unexpected_end());
break; break;
}; };
if next.is_symbol(Symbol::CloseCurly) { if next.is_symbol(Symbol::CloseCurly) {
cursor.next(); ctx.next();
break; break;
} }
if next.is_symbol(Symbol::Semicolon) { if next.is_symbol(Symbol::Semicolon) {
cursor.next(); ctx.next();
expect_semi = false; expect_semi = false;
continue; continue;
} else if expect_semi { } else if expect_semi {
errors.err(ParserMsg { ctx.err(ParserMsg {
msg: "expected ';'".to_string(), 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); statements.push(res.node);
expect_semi = true; expect_semi = true;
if res.recover { if res.recover {
cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
if cursor.peek().is_none() { if ctx.peek().is_none() {
recover = true; recover = true;
break; 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 { 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 ")?; f.write_str("{\n ")?;
let mut padder = Padder::new(f); let mut padder = Padder::new(f);
for s in &self.statements { for s in &self.statements {
// they don't expose wrap_buf :grief: // 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('}')?; f.write_char('}')?;
} else { } else {

View File

@@ -1,21 +1,20 @@
use std::fmt::Debug; 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 struct PVarDef {
pub name: Node<Ident>, pub name: Node<PIdent>,
pub ty: Option<Node<Type>>, pub ty: Option<Node<PType>>,
} }
impl Parsable for VarDef { impl Parsable for PVarDef {
fn parse( fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
cursor: &mut super::TokenCursor, let name = ctx.parse()?;
errors: &mut super::ParserOutput, if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
) -> ParseResult<Self> { ctx.next();
let name = Node::parse(cursor, errors)?; ctx.parse().map(|ty| Self { name, ty: Some(ty) })
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) })
} else { } else {
ParseResult::Ok(Self { name, ty: None }) ParseResult::Ok(Self { name, ty: None })
} }
@@ -33,20 +32,17 @@ pub enum SelfType {
} }
impl MaybeParsable for SelfVar { impl MaybeParsable for SelfVar {
fn maybe_parse( fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, super::ParserMsg> {
cursor: &mut super::TokenCursor, if let Some(mut next) = ctx.peek() {
errors: &mut super::ParserOutput,
) -> Result<Option<Self>, super::ParserMsg> {
if let Some(mut next) = cursor.peek() {
let mut ty = SelfType::Take; let mut ty = SelfType::Take;
if next.is_symbol(Symbol::Ampersand) { if next.is_symbol(Symbol::Ampersand) {
cursor.next(); ctx.next();
ty = SelfType::Ref; ty = SelfType::Ref;
next = cursor.expect_peek()?; next = ctx.expect_peek()?;
} }
if let Token::Word(name) = &next.token { if let Token::Word(name) = &next.token {
if name == "self" { if name == "self" {
cursor.next(); ctx.next();
return Ok(Some(Self { ty })); 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.name.fmt(f)?; self.name.fmt(f)?;
if let Some(ty) = &self.ty { if let Some(ty) = &self.ty {

View File

@@ -1,52 +1,52 @@
use std::fmt::{Debug, Write}; use std::fmt::{Debug, Write};
use super::{ use super::{
op::{BinaryOp, UnaryOp}, op::{PInfixOp, UnaryOp},
util::parse_list, util::parse_list,
AsmBlock, Block, Ident, Keyword, Literal, Node, NodeParsable, Parsable, ParseResult, ParserMsg, PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx,
ParserOutput, Symbol, TokenCursor, ParserMsg, Symbol,
}; };
type BoxNode = Node<Box<Expr>>; type BoxNode = Node<Box<PExpr>>;
pub enum Expr { pub enum PExpr {
Lit(Node<Literal>), Lit(Node<PLiteral>),
Ident(Node<Ident>), Ident(Node<PIdent>),
BinaryOp(BinaryOp, BoxNode, BoxNode), BinaryOp(PInfixOp, BoxNode, BoxNode),
UnaryOp(UnaryOp, BoxNode), UnaryOp(UnaryOp, BoxNode),
Block(Node<Block>), Block(Node<PBlock>),
Call(BoxNode, Vec<Node<Expr>>), Call(BoxNode, Vec<Node<PExpr>>),
Group(BoxNode), Group(BoxNode),
AsmBlock(Node<AsmBlock>), AsmBlock(Node<PAsmBlock>),
} }
impl Parsable for Expr { impl Parsable for PExpr {
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let start = cursor.next_pos(); let start = ctx.next_start();
let next = cursor.expect_peek()?; let next = ctx.expect_peek()?;
let mut e1 = if next.is_symbol(Symbol::OpenParen) { let mut e1 = if next.is_symbol(Symbol::OpenParen) {
cursor.next(); ctx.next();
if cursor.expect_peek()?.is_symbol(Symbol::CloseParen) { if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
cursor.next(); ctx.next();
return ParseResult::Ok(Expr::Lit(Node::new( return ParseResult::Ok(PExpr::Lit(Node::new(
Literal::Unit, PLiteral::Unit,
cursor.next_pos().char_span(), ctx.next_start().char_span(),
))); )));
} }
let res = Node::parse(cursor, output); let res = ctx.parse();
if res.recover { 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()) Self::Group(res.node.bx())
} else if next.is_symbol(Symbol::OpenCurly) { } 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) { } else if next.is_keyword(Keyword::Asm) {
cursor.next(); ctx.next();
Self::AsmBlock(Node::parse(cursor, output)?) Self::AsmBlock(ctx.parse()?)
} else if let Some(op) = UnaryOp::from_token(next) { } else if let Some(op) = UnaryOp::from_token(next) {
cursor.next(); ctx.next();
return Node::parse(cursor, output).map(|n| { return ctx.parse().map(|n| {
let n = n.bx(); let n = n.bx();
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner { if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
let span = start.to(n1.span.end); let span = start.to(n1.span.end);
@@ -55,36 +55,36 @@ impl Parsable for Expr {
Self::UnaryOp(op, n) 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) Self::Lit(val)
} else { } else {
let res = Node::parse(cursor, &mut ParserOutput::new()); let res = ctx.parse();
if res.node.is_some() { if res.node.is_some() {
Self::Ident(res.node) Self::Ident(res.node)
} else { } else {
let next = cursor.expect_peek()?; let next = ctx.expect_peek()?;
return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression")); 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); return ParseResult::Ok(e1);
}; };
while next.is_symbol(Symbol::OpenParen) { while next.is_symbol(Symbol::OpenParen) {
cursor.next(); ctx.next();
let args = parse_list(cursor, output, Symbol::CloseParen)?; let args = parse_list(ctx, Symbol::CloseParen)?;
let end = cursor.prev_end(); let end = ctx.prev_end();
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args); 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); return ParseResult::Ok(e1);
}; };
next = next2 next = next2
} }
let end = cursor.prev_end(); let end = ctx.prev_end();
let mut recover = false; let mut recover = false;
let res = if let Some(mut op) = BinaryOp::from_token(&next.token) { let res = if let Some(mut op) = PInfixOp::from_token(&next.token) {
cursor.next(); ctx.next();
let mut n1 = Node::new(e1, start.to(end)).bx(); 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(); let mut n2 = res.node.bx();
recover = res.recover; recover = res.recover;
if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() { 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Expr::Lit(c) => c.fmt(f)?, PExpr::Lit(c) => c.fmt(f)?,
Expr::Ident(n) => n.fmt(f)?, PExpr::Ident(n) => n.fmt(f)?,
Expr::Block(b) => b.fmt(f)?, PExpr::Block(b) => b.fmt(f)?,
Expr::BinaryOp(op, e1, e2) => { PExpr::BinaryOp(op, e1, e2) => {
write!(f, "({:?}", *e1)?; write!(f, "({:?}", *e1)?;
if op.pad() { if op.pad() {
write!(f, " {} ", op.str())?; write!(f, " {} ", op.str())?;
@@ -121,7 +121,7 @@ impl Debug for Expr {
} }
write!(f, "{:?})", *e2)?; write!(f, "{:?})", *e2)?;
} }
Expr::Call(n, args) => { PExpr::Call(n, args) => {
n.fmt(f)?; n.fmt(f)?;
f.write_char('(')?; f.write_char('(')?;
if let Some(a) = args.first() { if let Some(a) = args.first() {
@@ -133,13 +133,13 @@ impl Debug for Expr {
} }
f.write_char(')')?; f.write_char(')')?;
} }
Expr::UnaryOp(op, e) => { PExpr::UnaryOp(op, e) => {
write!(f, "(")?; write!(f, "(")?;
write!(f, "{}", op.str())?; write!(f, "{}", op.str())?;
write!(f, "{:?})", *e)?; write!(f, "{:?})", *e)?;
} }
Expr::Group(inner) => inner.fmt(f)?, PExpr::Group(inner) => inner.fmt(f)?,
Expr::AsmBlock(inner) => inner.fmt(f)?, PExpr::AsmBlock(inner) => inner.fmt(f)?,
} }
Ok(()) Ok(())
} }

View File

@@ -1,71 +1,69 @@
use super::{ use super::{
util::parse_list, Block, Ident, Keyword, Node, Parsable, ParseResult, ParserOutput, SelfVar, util::parse_list, PBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx,
Symbol, TokenCursor, Type, VarDef, Symbol, PType, PVarDef,
}; };
use std::fmt::Debug; use std::fmt::Debug;
pub struct FunctionHeader { pub struct PFunctionHeader {
pub name: Node<Ident>, pub name: Node<PIdent>,
pub sel: Option<Node<SelfVar>>, pub args: Vec<Node<PVarDef>>,
pub args: Vec<Node<VarDef>>, pub ret: Option<Node<PType>>,
pub ret: Option<Node<Type>>,
} }
pub struct Function { pub struct PFunction {
pub header: Node<FunctionHeader>, pub header: Node<PFunctionHeader>,
pub body: Node<Block>, pub body: Node<PBlock>,
} }
impl Parsable for FunctionHeader { impl Parsable for PFunctionHeader {
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
cursor.expect_kw(Keyword::Fn)?; ctx.expect_kw(Keyword::Fn)?;
let name = Node::parse(cursor, output)?; let name = ctx.parse()?;
cursor.expect_sym(Symbol::OpenParen)?; ctx.expect_sym(Symbol::OpenParen)?;
let sel = Node::maybe_parse(cursor, output); // let sel = ctx.maybe_parse();
if sel.is_some() { // if sel.is_some() {
if let Err(err) = cursor.expect_sym(Symbol::Comma) { // if let Err(err) = ctx.expect_sym(Symbol::Comma) {
output.err(err); // ctx.err(err);
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]); // ctx.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) { // if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
cursor.next(); // ctx.next();
} // }
} // }
} // }
let args = parse_list(cursor, output, Symbol::CloseParen)?; let args = parse_list(ctx, Symbol::CloseParen)?;
let ret = if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) { let ret = if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) {
cursor.next(); ctx.next();
Some(Node::parse(cursor, output)?) Some(ctx.parse()?)
} else { } else {
None None
}; };
ParseResult::Ok(Self { ParseResult::Ok(Self {
name, name,
args, args,
sel,
ret, ret,
}) })
} }
} }
impl Parsable for Function { impl Parsable for PFunction {
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let header = Node::parse(cursor, output)?; let header = ctx.parse()?;
let body = Node::parse(cursor, output)?; let body = ctx.parse()?;
ParseResult::Ok(Self { header, body }) ParseResult::Ok(Self { header, body })
} }
} }
impl Debug for FunctionHeader { impl Debug for PFunctionHeader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("fn ")?; f.write_str("fn ")?;
self.name.fmt(f)?; self.name.fmt(f)?;
f.write_str("(")?; f.write_str("(")?;
if let Some(s) = &self.sel { // if let Some(s) = &self.sel {
s.fmt(f)?; // s.fmt(f)?;
if self.args.first().is_some() { // if self.args.first().is_some() {
f.write_str(", ")?; // f.write_str(", ")?;
} // }
} // }
if let Some(a) = self.args.first() { if let Some(a) = self.args.first() {
a.fmt(f)?; a.fmt(f)?;
} }
@@ -80,7 +78,7 @@ impl Debug for FunctionHeader {
Ok(()) Ok(())
} }
} }
impl Debug for Function { impl Debug for PFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.header.fmt(f)?; self.header.fmt(f)?;
f.write_str(" ")?; f.write_str(" ")?;

View File

@@ -1,29 +1,52 @@
use std::fmt::Debug; use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token};
use super::{Parsable, ParseResult, ParserMsg, Token}; use std::{
fmt::{Debug, Display},
ops::Deref,
};
pub struct Ident(String); #[derive(Clone)]
pub struct PIdent(String);
impl Ident { impl Parsable for PIdent {
pub fn val(&self) -> &String { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
&self.0 let next = ctx.expect_peek()?;
}
}
impl Parsable for Ident {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
let Token::Word(name) = &next.token else { let Token::Word(name) = &next.token else {
return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier")); return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier"));
}; };
let name = name.to_string(); let name = name.to_string();
cursor.next(); ctx.next();
ParseResult::Ok(Self(name)) ParseResult::Ok(Self(name))
} }
} }
impl Debug for Ident { impl MaybeParsable for PIdent {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0) 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)
}
}

View File

@@ -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; use std::fmt::Debug;
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub enum Literal { pub enum PLiteral {
String(String), String(String),
Char(char), Char(char),
Number(Number), Number(PNumber),
Unit, Unit,
} }
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub struct Number { pub struct PNumber {
pub whole: String, pub whole: String,
pub decimal: Option<String>, pub decimal: Option<String>,
pub ty: Option<String>, pub ty: Option<String>,
} }
impl MaybeParsable for Literal { impl MaybeParsable for PLiteral {
fn maybe_parse( fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
cursor: &mut TokenCursor, let inst = ctx.expect_peek()?;
_: &mut ParserOutput,
) -> Result<Option<Self>, ParserMsg> {
let inst = cursor.expect_peek()?;
Ok(Some(match &inst.token { Ok(Some(match &inst.token {
Token::Symbol(Symbol::SingleQuote) => { Token::Symbol(Symbol::SingleQuote) => {
let chars = cursor.chars(); let chars = ctx.chars();
let c = chars.expect_next()?; let c = chars.expect_next()?;
chars.expect('\'')?; chars.expect('\'')?;
cursor.next(); ctx.next();
Self::Char(c) Self::Char(c)
} }
Token::Symbol(Symbol::DoubleQuote) => { Token::Symbol(Symbol::DoubleQuote) => {
let res = Self::String(string_from(cursor.chars())?); let res = Self::String(string_from(ctx.chars())?);
cursor.next(); ctx.next();
res res
} }
Token::Word(text) => { Token::Word(text) => {
@@ -41,21 +38,21 @@ impl MaybeParsable for Literal {
return Ok(None); return Ok(None);
} }
let (whole, ty) = parse_whole_num(text); let (whole, ty) = parse_whole_num(text);
let mut num = Number { let mut num = PNumber {
whole, whole,
decimal: None, decimal: None,
ty, ty,
}; };
cursor.next(); ctx.next();
if num.ty.is_none() && cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) { if num.ty.is_none() && ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) {
cursor.next(); ctx.next();
if let Some(next) = cursor.peek() { if let Some(next) = ctx.peek() {
if let Token::Word(i) = &next.token { if let Token::Word(i) = &next.token {
if i.chars().next().unwrap().is_ascii_digit() { if i.chars().next().unwrap().is_ascii_digit() {
let (decimal, ty) = parse_whole_num(i); let (decimal, ty) = parse_whole_num(i);
num.decimal = Some(decimal); num.decimal = Some(decimal);
num.ty = ty; num.ty = ty;
cursor.next(); ctx.next();
} }
} }
} }
@@ -110,7 +107,7 @@ pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> {
} }
} }
impl Debug for Literal { impl Debug for PLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::String(str) => str.fmt(f), 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.whole)?; write!(f, "{}", self.whole)?;
if let Some(d) = &self.decimal { if let Some(d) = &self.decimal {

View File

@@ -13,6 +13,7 @@ mod util;
mod trai; mod trai;
mod asm_fn; mod asm_fn;
mod asm_block; mod asm_block;
mod asm_instr;
pub use block::*; pub use block::*;
pub use expr::*; pub use expr::*;
@@ -28,6 +29,7 @@ pub use trai::*;
pub use op::*; pub use op::*;
pub use asm_fn::*; pub use asm_fn::*;
pub use asm_block::*; pub use asm_block::*;
pub use asm_instr::*;
use super::*; use super::*;

View File

@@ -1,79 +1,70 @@
use super::{ use super::{
AsmFunction, Function, Impl, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput, PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg,
Struct, Symbol, Token, TokenCursor, Trait, PStruct, Symbol, Token, PTrait,
}; };
use std::fmt::Debug; use std::fmt::Debug;
pub struct Module { pub struct PModule {
pub traits: Vec<Node<Trait>>, pub traits: Vec<Node<PTrait>>,
pub structs: Vec<Node<Struct>>, pub structs: Vec<Node<PStruct>>,
pub functions: Vec<Node<Function>>, pub functions: Vec<Node<PFunction>>,
pub asm_fns: Vec<Node<AsmFunction>>, pub impls: Vec<Node<PImpl>>,
pub impls: Vec<Node<Impl>>,
} }
impl Parsable for Module { impl Parsable for PModule {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let mut functions = Vec::new(); let mut functions = Vec::new();
let mut structs = Vec::new(); let mut structs = Vec::new();
let mut traits = Vec::new(); let mut traits = Vec::new();
let mut impls = Vec::new(); let mut impls = Vec::new();
let mut asm_fns = Vec::new();
loop { loop {
let Some(next) = cursor.peek() else { let Some(next) = ctx.peek() else {
break; break;
}; };
if let Token::Keyword(kw) = next.token { if let Token::Keyword(kw) = next.token {
match kw { match kw {
Keyword::Fn => { Keyword::Fn => {
let res = Node::parse(cursor, errors); let res = ctx.parse();
functions.push(res.node); functions.push(res.node);
if res.recover { if res.recover {
break; break;
} }
} }
Keyword::Struct => { Keyword::Struct => {
let res = Node::parse(cursor, errors); let res = ctx.parse();
structs.push(res.node); structs.push(res.node);
if res.recover { if res.recover {
break; break;
} }
} }
Keyword::Trait => { Keyword::Trait => {
let res = Node::parse(cursor, errors); let res = ctx.parse();
traits.push(res.node); traits.push(res.node);
if res.recover { if res.recover {
break; break;
} }
} }
Keyword::Impl => { Keyword::Impl => {
let res = Node::parse(cursor, errors); let res = ctx.parse();
impls.push(res.node); impls.push(res.node);
if res.recover { if res.recover {
break; 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")); ctx.err(ParserMsg::unexpected_token(next, "a definition"));
cursor.next(); ctx.next();
} }
} }
} else if next.is_symbol(Symbol::Semicolon) { } else if next.is_symbol(Symbol::Semicolon) {
errors.hint(ParserMsg::from_instances( ctx.hint(ParserMsg::from_instances(
&[next], &[next],
"unneeded semicolon".to_string(), "unneeded semicolon".to_string(),
)); ));
cursor.next(); ctx.next();
} else { } else {
errors.err(ParserMsg::unexpected_token(next, "a definition")); ctx.err(ParserMsg::unexpected_token(next, "a definition"));
cursor.next(); ctx.next();
} }
} }
ParseResult::Ok(Self { ParseResult::Ok(Self {
@@ -81,12 +72,11 @@ impl Parsable for Module {
structs, structs,
traits, traits,
impls, impls,
asm_fns,
}) })
} }
} }
impl Debug for Module { impl Debug for PModule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for st in &self.structs { for st in &self.structs {
st.fmt(f)?; st.fmt(f)?;
@@ -104,10 +94,6 @@ impl Debug for Module {
func.fmt(f)?; func.fmt(f)?;
writeln!(f)?; writeln!(f)?;
} }
for func in &self.asm_fns {
func.fmt(f)?;
writeln!(f)?;
}
Ok(()) Ok(())
} }
} }

View File

@@ -1,7 +1,7 @@
use super::{Symbol, Token}; use super::{Symbol, Token};
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BinaryOp { pub enum PInfixOp {
Add, Add,
Sub, Sub,
Mul, Mul,
@@ -12,7 +12,7 @@ pub enum BinaryOp {
Assign, Assign,
} }
impl BinaryOp { impl PInfixOp {
pub fn presedence(&self) -> u32 { pub fn presedence(&self) -> u32 {
match self { match self {
Self::Assign => 0, Self::Assign => 0,
@@ -69,7 +69,7 @@ pub enum UnaryOp {
Deref, Deref,
} }
impl BinaryOp { impl PInfixOp {
pub fn from_token(token: &Token) -> Option<Self> { pub fn from_token(token: &Token) -> Option<Self> {
let Token::Symbol(symbol) = token else { let Token::Symbol(symbol) = token else {
return None; return None;

View File

@@ -1,51 +1,45 @@
use super::{ use super::{PExpr, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, Token, PVarDef};
Expr, Keyword, Node, Parsable, ParseResult, ParserOutput, Symbol, Token, TokenCursor, VarDef,
};
use std::fmt::{Debug, Write};
pub enum Statement { pub enum PStatement {
Let(Node<VarDef>, Node<Expr>), Let(Node<PVarDef>, Node<PExpr>),
Return(Node<Expr>), Return(Node<PExpr>),
Expr(Node<Expr>), Expr(Node<PExpr>),
} }
impl Parsable for Statement { impl Parsable for PStatement {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let next = cursor.expect_peek()?; let next = ctx.expect_peek()?;
match next.token { match next.token {
Token::Keyword(Keyword::Let) => { Token::Keyword(Keyword::Let) => {
cursor.next(); ctx.next();
let def = Node::parse(cursor, errors)?; let def = ctx.parse()?;
cursor.expect_sym(Symbol::Equals)?; ctx.expect_sym(Symbol::Equals)?;
Node::parse(cursor, errors).map(|expr| Self::Let(def, expr)) ctx.parse().map(|expr| Self::Let(def, expr))
} }
Token::Keyword(Keyword::Return) => { Token::Keyword(Keyword::Return) => {
cursor.next(); ctx.next();
Node::parse(cursor, errors).map(Self::Return) 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Statement::Let(n, e) => { PStatement::Let(n, e) => {
f.write_str("let ")?; f.write_str("let ")?;
n.fmt(f)?; n.fmt(f)?;
f.write_str(" = ")?; f.write_str(" = ")?;
e.fmt(f)?; e.fmt(f)?;
f.write_char(';')?;
} }
Statement::Return(e) => { PStatement::Return(e) => {
f.write_str("return ")?; f.write_str("return ")?;
e.fmt(f)?; e.fmt(f)?;
f.write_char(';')?;
} }
Statement::Expr(e) => { PStatement::Expr(e) => {
e.fmt(f)?; e.fmt(f)?;
f.write_char(';')?;
} }
} }
Ok(()) Ok(())

View File

@@ -1,45 +1,45 @@
use std::fmt::Debug; use std::fmt::Debug;
use super::{ use super::{
util::parse_list, Ident, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput, util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol,
Symbol, TokenCursor, Type, VarDef, PType, PVarDef,
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct Struct { pub struct PStruct {
pub name: Node<Ident>, pub name: Node<PIdent>,
pub fields: StructFields, pub fields: PStructFields,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum StructFields { pub enum PStructFields {
Named(Vec<Node<VarDef>>), Named(Vec<Node<PVarDef>>),
Tuple(Vec<Node<Type>>), Tuple(Vec<Node<PType>>),
None, None,
} }
impl Parsable for Struct { impl Parsable for PStruct {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
cursor.expect_kw(Keyword::Struct)?; ctx.expect_kw(Keyword::Struct)?;
let name = Node::parse(cursor, errors)?; let name = ctx.parse()?;
let next = cursor.expect_peek()?; let next = ctx.expect_peek()?;
let fields = if next.is_symbol(Symbol::Semicolon) { let fields = if next.is_symbol(Symbol::Semicolon) {
cursor.next(); ctx.next();
StructFields::None PStructFields::None
} else if next.is_symbol(Symbol::OpenCurly) { } else if next.is_symbol(Symbol::OpenCurly) {
cursor.next(); ctx.next();
StructFields::Named(parse_list(cursor, errors, Symbol::CloseCurly)?) PStructFields::Named(parse_list(ctx, Symbol::CloseCurly)?)
} else if next.is_symbol(Symbol::OpenParen) { } else if next.is_symbol(Symbol::OpenParen) {
cursor.next(); ctx.next();
StructFields::Tuple(parse_list(cursor, errors, Symbol::CloseParen)?) PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
} else { } else {
errors.err(ParserMsg::unexpected_token(next, "`;`, `(`, or `{`")); let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`");
return ParseResult::Recover(Struct { ctx.err(msg);
return ParseResult::Recover(PStruct {
name, name,
fields: StructFields::None, fields: PStructFields::None,
}); });
}; };
ParseResult::Ok(Struct { name, fields }) ParseResult::Ok(PStruct { name, fields })
} }
} }

View File

@@ -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)] #[derive(Debug)]
pub struct Trait { pub struct PTrait {
pub name: Node<Ident>, pub name: Node<PIdent>,
pub fns: Vec<Node<FunctionHeader>> pub fns: Vec<Node<PFunctionHeader>>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Impl { pub struct PImpl {
pub trait_: Node<Type>, pub trait_: Node<PType>,
pub for_: Node<Type>, pub for_: Node<PType>,
pub fns: Vec<Node<Function>> pub fns: Vec<Node<PFunction>>,
} }
impl Parsable for Trait { impl Parsable for PTrait {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> super::ParseResult<Self> {
cursor.expect_kw(Keyword::Trait)?; ctx.expect_kw(Keyword::Trait)?;
let name = Node::parse(cursor, errors)?; let name = ctx.parse()?;
cursor.expect_sym(Symbol::OpenCurly)?; ctx.expect_sym(Symbol::OpenCurly)?;
let fns = parse_list(cursor, errors, Symbol::CloseCurly)?; let fns = parse_list(ctx, Symbol::CloseCurly)?;
super::ParseResult::Ok(Self {name, fns}) super::ParseResult::Ok(Self { name, fns })
} }
} }
impl Parsable for Impl { impl Parsable for PImpl {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> super::ParseResult<Self> {
cursor.expect_kw(Keyword::Impl)?; ctx.expect_kw(Keyword::Impl)?;
let trait_ = Node::parse(cursor, errors)?; let trait_ = ctx.parse()?;
cursor.expect_kw(Keyword::For)?; ctx.expect_kw(Keyword::For)?;
let for_ = Node::parse(cursor, errors)?; let for_ = ctx.parse()?;
cursor.expect_sym(Symbol::OpenCurly)?; ctx.expect_sym(Symbol::OpenCurly)?;
let fns = parse_list_nosep(cursor, errors, Symbol::CloseCurly)?; let fns = parse_list_nosep(ctx, Symbol::CloseCurly)?;
super::ParseResult::Ok(Self {trait_, for_, fns}) super::ParseResult::Ok(Self { trait_, for_, fns })
} }
} }

View File

@@ -1,13 +1,13 @@
use std::fmt::Debug; 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 name: String,
pub args: Vec<Node<Type>>, pub args: Vec<Node<PType>>,
} }
impl Type { impl PType {
pub fn unit() -> Self { pub fn unit() -> Self {
Self { Self {
name: "()".to_string(), name: "()".to_string(),
@@ -16,15 +16,12 @@ impl Type {
} }
} }
impl Parsable for Type { impl Parsable for PType {
fn parse( fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
cursor: &mut super::TokenCursor, let next = ctx.expect_peek()?;
errors: &mut super::ParserOutput,
) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
let res = if next.is_symbol(Symbol::Ampersand) { let res = if next.is_symbol(Symbol::Ampersand) {
cursor.next(); ctx.next();
let arg = Node::parse(cursor, errors)?; let arg = ctx.parse()?;
Self { Self {
name: "&".to_string(), name: "&".to_string(),
args: vec![arg], args: vec![arg],
@@ -34,12 +31,12 @@ impl Parsable for Type {
return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier")); return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier"));
}; };
let n = name.to_string(); let n = name.to_string();
cursor.next(); ctx.next();
let mut args = Vec::new(); let mut args = Vec::new();
if let Some(next) = cursor.peek() { if let Some(next) = ctx.peek() {
if next.is_symbol(Symbol::OpenAngle) { if next.is_symbol(Symbol::OpenAngle) {
cursor.next(); ctx.next();
args = parse_list(cursor, errors, Symbol::CloseAngle)?; args = parse_list(ctx, Symbol::CloseAngle)?;
} }
} }
Self { name: n, args } 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)?; write!(f, "{}", self.name)?;
if self.name == "&" { if self.name == "&" {

View File

@@ -1,57 +1,54 @@
use super::{Node, Parsable, ParserMsg, ParserOutput, Symbol, TokenCursor}; use super::{Node, Parsable, ParserCtx, ParserMsg, Symbol};
pub fn parse_list_sep<T: Parsable>( pub fn parse_list_sep<T: Parsable>(
cursor: &mut TokenCursor, ctx: &mut ParserCtx,
errors: &mut ParserOutput,
sep: Symbol, sep: Symbol,
end: Symbol, end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> { ) -> Result<Vec<Node<T>>, ParserMsg> {
let mut vals = Vec::new(); let mut vals = Vec::new();
loop { loop {
let next = cursor.expect_peek()?; let next = ctx.expect_peek()?;
if next.is_symbol(end) { if next.is_symbol(end) {
break; break;
} }
let res = Node::parse(cursor, errors); let res = ctx.parse();
vals.push(res.node); vals.push(res.node);
if res.recover { 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) { if !next.is_symbol(sep) {
break; break;
} }
cursor.next(); ctx.next();
} }
cursor.expect_sym(end)?; ctx.expect_sym(end)?;
Ok(vals) Ok(vals)
} }
pub fn parse_list<T: Parsable>( pub fn parse_list<T: Parsable>(
cursor: &mut TokenCursor, ctx: &mut ParserCtx,
errors: &mut ParserOutput,
end: Symbol, end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> { ) -> Result<Vec<Node<T>>, ParserMsg> {
parse_list_sep(cursor, errors, Symbol::Comma, end) parse_list_sep(ctx, Symbol::Comma, end)
} }
pub fn parse_list_nosep<T: Parsable>( pub fn parse_list_nosep<T: Parsable>(
cursor: &mut TokenCursor, ctx: &mut ParserCtx,
errors: &mut ParserOutput,
end: Symbol, end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> { ) -> Result<Vec<Node<T>>, ParserMsg> {
let mut vals = Vec::new(); let mut vals = Vec::new();
loop { loop {
let next = cursor.expect_peek()?; let next = ctx.expect_peek()?;
if next.is_symbol(end) { if next.is_symbol(end) {
break; break;
} }
let res = Node::parse(cursor, errors); let res = ctx.parse();
vals.push(res.node); vals.push(res.node);
if res.recover { if res.recover {
cursor.seek_sym(end); ctx.seek_sym(end);
} }
} }
cursor.expect_sym(end)?; ctx.expect_sym(end)?;
Ok(vals) Ok(vals)
} }

View File

@@ -5,7 +5,7 @@ use std::{
use crate::ir::FilePos; use crate::ir::FilePos;
use super::{Node, ParserMsg, ParserOutput, TokenCursor}; use super::{Node, ParserCtx, ParserMsg};
pub enum ParseResult<T> { pub enum ParseResult<T> {
Ok(T), Ok(T),
@@ -33,6 +33,7 @@ impl<T> Try for ParseResult<T> {
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self { match self {
ParseResult::Ok(v) => ControlFlow::Continue(v), ParseResult::Ok(v) => ControlFlow::Continue(v),
// TODO: this is messed up; need to break w a Result<Option<T>> or smth :woozy:
ParseResult::Recover(v) => ControlFlow::Break(None), ParseResult::Recover(v) => ControlFlow::Break(None),
ParseResult::Err(e) => ControlFlow::Break(Some(e)), ParseResult::Err(e) => ControlFlow::Break(Some(e)),
ParseResult::SubErr => ControlFlow::Break(None), ParseResult::SubErr => ControlFlow::Break(None),
@@ -111,29 +112,26 @@ impl<T> FromResidual for NodeParseResult<T> {
} }
pub trait Parsable: Sized { pub trait Parsable: Sized {
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self>; fn parse(ctx: &mut ParserCtx) -> ParseResult<Self>;
} }
pub trait MaybeParsable: Sized { pub trait MaybeParsable: Sized {
fn maybe_parse( fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg>;
cursor: &mut TokenCursor,
errors: &mut ParserOutput,
) -> Result<Option<Self>, ParserMsg>;
} }
impl<T: Parsable> Node<T> { impl<T: Parsable> Node<T> {
pub fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> NodeParseResult<T> { pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
let start = cursor.peek().map(|t| t.span.start).unwrap_or(FilePos::start()); let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
let (inner, recover) = match T::parse(cursor, output) { let (inner, recover) = match T::parse(ctx) {
ParseResult::Ok(v) => (Some(v), false), ParseResult::Ok(v) => (Some(v), false),
ParseResult::Recover(v) => (Some(v), true), ParseResult::Recover(v) => (Some(v), true),
ParseResult::Err(e) => { ParseResult::Err(e) => {
output.err(e); ctx.err(e);
(None, true) (None, true)
} }
ParseResult::SubErr => (None, true), ParseResult::SubErr => (None, true),
}; };
let end = cursor.prev_end(); let end = ctx.prev_end();
NodeParseResult { NodeParseResult {
node: Self { node: Self {
inner, inner,
@@ -145,16 +143,16 @@ impl<T: Parsable> Node<T> {
} }
impl<T: MaybeParsable> Node<T> { impl<T: MaybeParsable> Node<T> {
pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> Option<Self> { pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
let start = cursor.next_pos(); let start = ctx.next_start();
let inner = match T::maybe_parse(cursor, errors) { let inner = match T::maybe_parse(ctx) {
Ok(v) => Some(v?), Ok(v) => Some(v?),
Err(e) => { Err(e) => {
errors.err(e); ctx.err(e);
None None
} }
}; };
let end = cursor.prev_end(); let end = ctx.prev_end();
Some(Self { Some(Self {
inner, inner,
span: start.to(end), span: start.to(end),
@@ -163,15 +161,15 @@ impl<T: MaybeParsable> Node<T> {
} }
pub trait NodeParsable { pub trait NodeParsable {
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self> fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult<Self>
where where
Self: Sized; Self: Sized;
} }
impl<T: Parsable> NodeParsable for T { impl<T: Parsable> NodeParsable for T {
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self> fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult<Self>
where where
Self: Sized, Self: Sized,
{ {
Node::<Self>::parse(cursor, errors) Node::<Self>::parse(ctx)
} }
} }

View File

@@ -1,7 +1,7 @@
use std::{iter::Peekable, str::Chars}; use std::{iter::Peekable, str::Chars};
use crate::ir::FilePos;
use super::super::ParserMsg; use super::super::ParserMsg;
use crate::ir::FilePos;
pub struct CharCursor<'a> { pub struct CharCursor<'a> {
chars: Peekable<Chars<'a>>, chars: Peekable<Chars<'a>>,

View File

@@ -9,6 +9,7 @@ pub enum Keyword {
Impl, Impl,
For, For,
Asm, Asm,
Funne,
} }
impl Keyword { impl Keyword {
@@ -23,6 +24,7 @@ impl Keyword {
"trait" => Self::Trait, "trait" => Self::Trait,
"impl" => Self::Impl, "impl" => Self::Impl,
"asm" => Self::Asm, "asm" => Self::Asm,
"funne" => Self::Funne,
_ => return None, _ => return None,
}) })
} }