actually compiles and does stuff now
This commit is contained in:
@@ -1,18 +1,21 @@
|
||||
trait Add {
|
||||
fn add(self, other: Self) -> Self
|
||||
fn start() {
|
||||
print("Hello World!\n", 13);
|
||||
exit(39);
|
||||
}
|
||||
|
||||
impl Add for b32 {
|
||||
asm fn add(self, other) {
|
||||
add {out}, {self}, {other}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
asm {
|
||||
li a0, 3
|
||||
li a7, 93
|
||||
fn print(msg, len) {
|
||||
asm (a1 = msg, a2 = len) {
|
||||
ld a2, 0, a2
|
||||
li a0, 1
|
||||
li a7, 64
|
||||
ecall
|
||||
}
|
||||
}
|
||||
|
||||
fn exit(status) {
|
||||
asm (a0 = status) {
|
||||
ld a0, 0, a0
|
||||
li a7, 93
|
||||
ecall
|
||||
};
|
||||
}
|
||||
|
||||
3
src/compiler/arch/mod.rs
Normal file
3
src/compiler/arch/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod riscv64;
|
||||
use super::*;
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
use crate::compiler::program::{Addr, Instr, SymTable, Symbol};
|
||||
use crate::{compiler::program::{Addr, Instr, SymTable}, ir::AddrID};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AsmInstruction {
|
||||
pub enum LinkerInstruction {
|
||||
Add { dest: Reg, src1: Reg, src2: Reg },
|
||||
Addi { dest: Reg, src: Reg, imm: i32 },
|
||||
Andi { dest: Reg, src: Reg, imm: i32 },
|
||||
Slli { dest: Reg, src: Reg, imm: i32 },
|
||||
Srli { dest: Reg, src: Reg, imm: i32 },
|
||||
Sd { src: Reg, offset: i32, base: Reg },
|
||||
Ld { dest: Reg, offset: i32, base: Reg },
|
||||
Mv { dest: Reg, src: Reg },
|
||||
La { dest: Reg, sym: Symbol },
|
||||
La { dest: Reg, src: AddrID },
|
||||
Jal { dest: Reg, offset: i32 },
|
||||
Call(Symbol),
|
||||
J(Symbol),
|
||||
Call(AddrID),
|
||||
J(AddrID),
|
||||
Ret,
|
||||
Ecall,
|
||||
Li { dest: Reg, imm: i64 },
|
||||
}
|
||||
|
||||
impl Instr for AsmInstruction {
|
||||
impl Instr for LinkerInstruction {
|
||||
fn push(
|
||||
&self,
|
||||
data: &mut Vec<u8>,
|
||||
sym_map: &SymTable,
|
||||
pos: Addr,
|
||||
missing: bool,
|
||||
) -> Option<Symbol> {
|
||||
) -> Option<AddrID> {
|
||||
let last = match self {
|
||||
Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2),
|
||||
Self::Addi { dest, src, imm } => addi(*dest, *src, BitsI32::new(*imm)),
|
||||
@@ -35,15 +36,16 @@ impl Instr for AsmInstruction {
|
||||
Self::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)),
|
||||
Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)),
|
||||
Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base),
|
||||
Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base),
|
||||
Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)),
|
||||
Self::La { dest, sym } => {
|
||||
if let Some(addr) = sym_map.get(*sym) {
|
||||
Self::La { dest, src } => {
|
||||
if let Some(addr) = sym_map.get(*src) {
|
||||
let offset = addr.val() as i32 - pos.val() as i32;
|
||||
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
|
||||
addi(*dest, *dest, BitsI32::new(offset))
|
||||
} else {
|
||||
data.extend_from_slice(&[0; 2 * 4]);
|
||||
return Some(*sym);
|
||||
return Some(*src);
|
||||
}
|
||||
}
|
||||
Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)),
|
||||
@@ -2,11 +2,11 @@ use crate::util::Bits32;
|
||||
|
||||
use super::Reg;
|
||||
|
||||
pub struct Instruction(u32);
|
||||
pub struct RawInstruction(u32);
|
||||
|
||||
use Instruction as I;
|
||||
use RawInstruction as I;
|
||||
|
||||
impl Instruction {
|
||||
impl RawInstruction {
|
||||
pub fn to_le_bytes(&self) -> impl IntoIterator<Item = u8> {
|
||||
self.0.to_le_bytes().into_iter()
|
||||
}
|
||||
117
src/compiler/arch/riscv64/compile.rs
Normal file
117
src/compiler/arch/riscv64/compile.rs
Normal 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)
|
||||
}
|
||||
63
src/compiler/arch/riscv64/mod.rs
Normal file
63
src/compiler/arch/riscv64/mod.rs
Normal 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");
|
||||
}
|
||||
179
src/compiler/arch/riscv64/reg.rs
Normal file
179
src/compiler/arch/riscv64/reg.rs
Normal 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",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ use crate::util::{Bits32, BitsI32};
|
||||
|
||||
use super::*;
|
||||
|
||||
use Instruction as I;
|
||||
use RawInstruction as I;
|
||||
|
||||
pub const fn ecall() -> I {
|
||||
i_type(Bits32::new(0), zero, Bits32::new(0), zero, SYSTEM)
|
||||
@@ -1,2 +0,0 @@
|
||||
pub enum Instruction {
|
||||
}
|
||||
@@ -5,14 +5,21 @@ use std::{
|
||||
process::Command,
|
||||
};
|
||||
|
||||
pub mod arch;
|
||||
mod elf;
|
||||
mod program;
|
||||
pub mod riscv64;
|
||||
mod target;
|
||||
mod instruction;
|
||||
|
||||
pub use program::*;
|
||||
|
||||
use crate::ir::Program;
|
||||
|
||||
pub fn compile(program: Program) -> Vec<u8> {
|
||||
let (compiled, start) = arch::riscv64::compile(program);
|
||||
let binary = elf::create(compiled, start.expect("no start method found"));
|
||||
binary
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
use std::io::prelude::*;
|
||||
let dir = Path::new("./build");
|
||||
@@ -27,7 +34,7 @@ pub fn main() {
|
||||
.mode(0o750)
|
||||
.open(path)
|
||||
.expect("Failed to create file");
|
||||
file.write_all(&riscv64::gen())
|
||||
file.write_all(&arch::riscv64::gen())
|
||||
.expect("Failed to write to file");
|
||||
file.sync_all().expect("Failed to sync file");
|
||||
let mut p = Command::new("qemu-riscv64");
|
||||
@@ -64,4 +71,3 @@ pub fn main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
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 sym_table = SymTable::new(map.len());
|
||||
let mut missing = HashMap::<Symbol, Vec<(Addr, I)>>::new();
|
||||
for (val, id) in map.ro_data {
|
||||
let mut sym_table = SymTable::new(fns.len() + ro_data.len());
|
||||
let mut missing = HashMap::<AddrID, Vec<(Addr, I)>>::new();
|
||||
for (val, id) in ro_data {
|
||||
sym_table.insert(id, Addr(data.len() as u64));
|
||||
data.extend(val);
|
||||
}
|
||||
for (fun, id) in map.functions {
|
||||
data.resize(data.len() + (4 - data.len() % 4), 0);
|
||||
for (fun, id) in fns {
|
||||
sym_table.insert(id, Addr(data.len() as u64));
|
||||
for i in fun {
|
||||
let i_pos = Addr(data.len() as u64);
|
||||
@@ -30,11 +37,15 @@ pub fn create_program<I: Instr>(map: SymMap<I>, start: Symbol) -> (Vec<u8>, Opti
|
||||
}
|
||||
}
|
||||
assert!(missing.is_empty());
|
||||
(data, sym_table.get(start))
|
||||
(
|
||||
data,
|
||||
start.map(|s| sym_table.get(s).expect("start symbol doesn't exist")),
|
||||
)
|
||||
}
|
||||
|
||||
pub trait Instr {
|
||||
fn push(&self, data: &mut Vec<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)]
|
||||
@@ -73,19 +84,23 @@ impl<I> SymMap<I> {
|
||||
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();
|
||||
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 {
|
||||
let sym = self.reserve();
|
||||
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 len = data.len();
|
||||
self.ro_data.push((data, *sym));
|
||||
(*sym, len)
|
||||
*sym
|
||||
}
|
||||
pub fn write_fn(&mut self, sym: WritableSymbol, instructions: Vec<I>) -> Symbol {
|
||||
self.functions.push((instructions, *sym));
|
||||
@@ -106,10 +121,10 @@ impl SymTable {
|
||||
pub fn new(len: usize) -> Self {
|
||||
Self(vec![Addr::NONE; len])
|
||||
}
|
||||
pub fn insert(&mut self, sym: Symbol, addr: Addr) {
|
||||
pub fn insert(&mut self, sym: AddrID, addr: Addr) {
|
||||
self.0[sym.0] = addr;
|
||||
}
|
||||
pub fn get(&self, sym: Symbol) -> Option<Addr> {
|
||||
pub fn get(&self, sym: AddrID) -> Option<Addr> {
|
||||
match self.0[sym.0] {
|
||||
Addr::NONE => None,
|
||||
addr => Some(addr),
|
||||
|
||||
@@ -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!"))
|
||||
}
|
||||
@@ -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),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
1
src/ir/arch/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod riscv64;
|
||||
37
src/ir/arch/riscv64.rs
Normal file
37
src/ir/arch/riscv64.rs
Normal 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
13
src/ir/asm.rs
Normal 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
42
src/ir/id.rs
Normal 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
6
src/ir/lower/data.rs
Normal 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
41
src/ir/lower/func.rs
Normal 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
9
src/ir/lower/mod.rs
Normal 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
85
src/ir/lower/program.rs
Normal 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 }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
mod namespace;
|
||||
mod lvl1;
|
||||
mod lvl2;
|
||||
mod upper;
|
||||
mod file;
|
||||
mod lower;
|
||||
mod id;
|
||||
mod asm;
|
||||
pub mod arch;
|
||||
|
||||
pub use namespace::*;
|
||||
pub use lvl1::*;
|
||||
pub use upper::*;
|
||||
pub use lower::*;
|
||||
pub use file::*;
|
||||
|
||||
pub use id::*;
|
||||
|
||||
226
src/ir/old.rs
226
src/ir/old.rs
@@ -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),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::{FileSpan, Type};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FnDef {
|
||||
pub name: String,
|
||||
pub args: Vec<VarDef>,
|
||||
@@ -8,6 +9,7 @@ pub struct FnDef {
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TypeDef {
|
||||
pub name: String,
|
||||
pub args: usize,
|
||||
82
src/ir/upper/func.rs
Normal file
82
src/ir/upper/func.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
mod def;
|
||||
mod func;
|
||||
mod ty;
|
||||
mod namespace;
|
||||
|
||||
use super::*;
|
||||
pub use def::*;
|
||||
pub use func::*;
|
||||
pub use ty::*;
|
||||
|
||||
pub use namespace::*;
|
||||
@@ -4,13 +4,15 @@ use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use super::{BuiltinType, FileSpan, FnDef, Function, Type, TypeDef, VarDef};
|
||||
use super::*;
|
||||
|
||||
pub struct Namespace {
|
||||
pub fn_defs: Vec<FnDef>,
|
||||
pub var_defs: Vec<VarDef>,
|
||||
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 stack: Vec<HashMap<String, Idents>>,
|
||||
}
|
||||
@@ -21,6 +23,8 @@ impl Namespace {
|
||||
fn_defs: Vec::new(),
|
||||
var_defs: Vec::new(),
|
||||
type_defs: Vec::new(),
|
||||
data: Vec::new(),
|
||||
fn_map: HashMap::new(),
|
||||
fns: Vec::new(),
|
||||
temp: 0,
|
||||
stack: vec![HashMap::new()],
|
||||
@@ -43,27 +47,36 @@ impl Namespace {
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn get_var(&self, id: VarIdent) -> &VarDef {
|
||||
pub fn get_var(&self, id: VarID) -> &VarDef {
|
||||
&self.var_defs[id.0]
|
||||
}
|
||||
pub fn get_fn(&self, id: FnIdent) -> &FnDef {
|
||||
pub fn get_fn(&self, id: FnID) -> &FnDef {
|
||||
&self.fn_defs[id.0]
|
||||
}
|
||||
pub fn get_type(&self, id: TypeIdent) -> &TypeDef {
|
||||
pub fn get_fn_var(&self, id: VarID) -> &FnDef {
|
||||
&self.fn_defs[self.fn_map[&id].0]
|
||||
}
|
||||
pub fn get_type(&self, id: TypeID) -> &TypeDef {
|
||||
&self.type_defs[id.0]
|
||||
}
|
||||
pub fn alias_fn(&mut self, name: &str, id: FnIdent) {
|
||||
pub fn alias_fn(&mut self, name: &str, id: FnID) {
|
||||
self.insert(name, Ident::Fn(id));
|
||||
}
|
||||
pub fn name_var(&mut self, def: &VarDef, var: VarIdent) {
|
||||
pub fn named_var(&mut self, def: VarDef) -> VarID {
|
||||
// TODO: this is stupid
|
||||
let id = self.def_var(def.clone());
|
||||
self.name_var(&def, id);
|
||||
id
|
||||
}
|
||||
pub fn name_var(&mut self, def: &VarDef, var: VarID) {
|
||||
self.insert(&def.name, Ident::Var(var));
|
||||
}
|
||||
pub fn def_var(&mut self, var: VarDef) -> VarIdent {
|
||||
pub fn def_var(&mut self, var: VarDef) -> VarID {
|
||||
let i = self.var_defs.len();
|
||||
self.var_defs.push(var);
|
||||
VarIdent(i)
|
||||
VarID(i)
|
||||
}
|
||||
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarIdent {
|
||||
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID {
|
||||
let v = self.def_var(VarDef {
|
||||
name: format!("temp{}", self.temp),
|
||||
origin: super::Origin::File(origin),
|
||||
@@ -72,21 +85,38 @@ impl Namespace {
|
||||
self.temp += 1;
|
||||
v
|
||||
}
|
||||
pub fn def_fn(&mut self, def: FnDef) -> FnIdent {
|
||||
pub fn def_fn(&mut self, def: FnDef) -> FnID {
|
||||
let i = self.fn_defs.len();
|
||||
let id = FnIdent(i);
|
||||
let id = FnID(i);
|
||||
let var_def = VarDef {
|
||||
name: def.name.clone(),
|
||||
origin: def.origin,
|
||||
ty: def.ty(),
|
||||
};
|
||||
|
||||
let vid = self.def_var(var_def);
|
||||
self.insert(&def.name, Ident::Var(vid));
|
||||
self.fn_map.insert(vid, id);
|
||||
|
||||
self.insert(&def.name, Ident::Fn(id));
|
||||
self.fn_defs.push(def);
|
||||
self.fns.push(None);
|
||||
|
||||
|
||||
id
|
||||
}
|
||||
pub fn def_type(&mut self, def: TypeDef) -> TypeIdent {
|
||||
pub fn def_type(&mut self, def: TypeDef) -> TypeID {
|
||||
let i = self.type_defs.len();
|
||||
let id = TypeIdent(i);
|
||||
let id = TypeID(i);
|
||||
self.insert(&def.name, Ident::Type(id));
|
||||
self.type_defs.push(def);
|
||||
id
|
||||
}
|
||||
pub fn def_data(&mut self, bytes: Vec<u8>) -> DataID {
|
||||
let i = self.data.len();
|
||||
self.data.push(bytes);
|
||||
DataID(i)
|
||||
}
|
||||
pub fn type_name(&self, ty: &Type) -> String {
|
||||
let mut str = String::new();
|
||||
match ty {
|
||||
@@ -121,6 +151,8 @@ impl Namespace {
|
||||
}
|
||||
Type::Error => str += "{error}",
|
||||
Type::Infer => str += "{inferred}",
|
||||
Type::Bits(size) => str += &format!("b{}", size),
|
||||
Type::Array(t) => str += &format!("[{}]", self.type_name(t)),
|
||||
}
|
||||
str
|
||||
}
|
||||
@@ -133,7 +165,7 @@ impl Namespace {
|
||||
last.insert(name.to_string(), Idents::new(id));
|
||||
}
|
||||
}
|
||||
pub fn write_fn(&mut self, id: FnIdent, f: Function) {
|
||||
pub fn write_fn(&mut self, id: FnID, f: IRUFunction) {
|
||||
self.fns[id.0] = Some(f);
|
||||
}
|
||||
}
|
||||
@@ -161,18 +193,17 @@ impl DerefMut for NamespaceGuard<'_> {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Ident {
|
||||
Var(VarIdent),
|
||||
Fn(FnIdent),
|
||||
Type(TypeIdent),
|
||||
Var(VarID),
|
||||
Fn(FnID),
|
||||
Type(TypeID),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Idents {
|
||||
pub latest: Ident,
|
||||
pub var: Option<VarIdent>,
|
||||
pub func: Option<FnIdent>,
|
||||
pub var_func: Option<VarOrFnIdent>,
|
||||
pub ty: Option<TypeIdent>,
|
||||
pub var: Option<VarID>,
|
||||
pub func: Option<FnID>,
|
||||
pub ty: Option<TypeID>,
|
||||
}
|
||||
|
||||
impl Idents {
|
||||
@@ -181,7 +212,6 @@ impl Idents {
|
||||
latest,
|
||||
var: None,
|
||||
func: None,
|
||||
var_func: None,
|
||||
ty: None,
|
||||
};
|
||||
s.insert(latest);
|
||||
@@ -192,50 +222,12 @@ impl Idents {
|
||||
match i {
|
||||
Ident::Var(v) => {
|
||||
self.var = Some(v);
|
||||
self.var_func = Some(VarOrFnIdent::Var(v));
|
||||
}
|
||||
Ident::Fn(f) => {
|
||||
self.func = Some(f);
|
||||
self.var_func = Some(VarOrFnIdent::Fn(f));
|
||||
}
|
||||
Ident::Type(t) => self.ty = Some(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TypeIdent(usize);
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VarIdent(usize);
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FnIdent(usize);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum VarOrFnIdent {
|
||||
Var(VarIdent),
|
||||
Fn(FnIdent),
|
||||
}
|
||||
|
||||
impl TypeIdent {
|
||||
pub fn builtin(ty: &BuiltinType) -> Self {
|
||||
Self(*ty as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VarIdent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "v{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for TypeIdent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "t{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FnIdent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "f{}", self.0)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,26 @@
|
||||
use super::{Origin, TypeDef, TypeIdent};
|
||||
use super::{Origin, TypeDef, TypeID};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Type {
|
||||
Concrete(TypeIdent),
|
||||
Generic { base: TypeIdent, args: Vec<Type> },
|
||||
Concrete(TypeID),
|
||||
Bits(u32),
|
||||
Generic { base: TypeID, args: Vec<Type> },
|
||||
Fn { args: Vec<Type>, ret: Box<Type> },
|
||||
Ref(Box<Type>),
|
||||
Array(Box<Type>),
|
||||
Infer,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn rf(self) -> Self {
|
||||
Self::Ref(Box::new(self))
|
||||
}
|
||||
pub fn arr(self) -> Self {
|
||||
Self::Array(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(usize)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum BuiltinType {
|
||||
@@ -29,7 +40,14 @@ impl BuiltinType {
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn id(&self) -> TypeIdent {
|
||||
TypeIdent::builtin(self)
|
||||
pub fn id(&self) -> TypeID {
|
||||
TypeID::builtin(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeID {
|
||||
pub fn builtin(ty: &BuiltinType) -> Self {
|
||||
Self(*ty as usize)
|
||||
}
|
||||
}
|
||||
|
||||
108
src/main.rs
108
src/main.rs
@@ -1,10 +1,15 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(try_trait_v2)]
|
||||
|
||||
use std::io::{stdout, BufRead, BufReader};
|
||||
|
||||
use ir::Namespace;
|
||||
use parser::{Module, NodeParsable, ParserOutput, Statement, TokenCursor};
|
||||
use ir::{Namespace, Program};
|
||||
use parser::{NodeParsable, PModule, PStatement, ParserCtx};
|
||||
use std::{
|
||||
fs::{create_dir_all, OpenOptions},
|
||||
io::{stdout, BufRead, BufReader},
|
||||
os::unix::fs::OpenOptionsExt,
|
||||
path::Path,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
mod compiler;
|
||||
mod ir;
|
||||
@@ -12,43 +17,102 @@ mod parser;
|
||||
mod util;
|
||||
|
||||
fn main() {
|
||||
let arg = std::env::args_os().nth(1);
|
||||
if let Some(path) = arg {
|
||||
let file = std::env::args_os().nth(1);
|
||||
let gdb = std::env::args().nth(2).is_some_and(|a| a == "--debug");
|
||||
if let Some(path) = file {
|
||||
let file = std::fs::read_to_string(path).expect("failed to read file");
|
||||
run_file(&file);
|
||||
run_file(&file, gdb);
|
||||
} else {
|
||||
run_stdin();
|
||||
}
|
||||
// compiler::main();
|
||||
}
|
||||
|
||||
fn run_file(file: &str) {
|
||||
let mut output = ParserOutput::new();
|
||||
let res = Module::parse_node(&mut TokenCursor::from(file), &mut output);
|
||||
println!("{:?}", res.node);
|
||||
fn run_file(file: &str, gdb: bool) {
|
||||
let mut ctx = ParserCtx::from(file);
|
||||
let res = PModule::parse_node(&mut ctx);
|
||||
if ctx.output.errs.is_empty() {
|
||||
// println!("Parsed:");
|
||||
// println!("{:#?}", res.node);
|
||||
if let Some(module) = res.node.as_ref() {
|
||||
let mut namespace = Namespace::new();
|
||||
module.lower(&mut namespace.push(), &mut output);
|
||||
println!("{:?}", namespace.fns);
|
||||
module.lower(&mut namespace.push(), &mut ctx.output);
|
||||
if ctx.output.errs.is_empty() {
|
||||
// println!("{:#?}", namespace.fns);
|
||||
// println!("vars:");
|
||||
// for def in &namespace.var_defs {
|
||||
// println!("{}: {}", def.name, namespace.type_name(&def.ty));
|
||||
// }
|
||||
let program = Program::create(&namespace);
|
||||
let bin = compiler::compile(program);
|
||||
println!("compiled");
|
||||
save_run(&bin, gdb);
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.output.write_for(&mut stdout(), file);
|
||||
}
|
||||
|
||||
fn save_run(binary: &[u8], run_gdb: bool) {
|
||||
use std::io::prelude::*;
|
||||
let dir = Path::new("./build");
|
||||
create_dir_all(dir).expect("Failed to create or confirm build directory");
|
||||
let name = Path::new("test");
|
||||
let path = dir.join(name);
|
||||
let path = path.as_os_str();
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.mode(0o750)
|
||||
.open(path)
|
||||
.expect("Failed to create file");
|
||||
file.write_all(binary).expect("Failed to write to file");
|
||||
file.sync_all().expect("Failed to sync file");
|
||||
println!("running...");
|
||||
let mut p = Command::new("qemu-riscv64");
|
||||
let proc = if run_gdb {
|
||||
p.arg("-g").arg("1234").arg(path).spawn()
|
||||
} else {
|
||||
p.arg(path).spawn()
|
||||
};
|
||||
if let Ok(mut process) = proc {
|
||||
if run_gdb {
|
||||
match Command::new("gdb")
|
||||
.arg("-q")
|
||||
.arg("-ex")
|
||||
.arg("target remote :1234")
|
||||
.arg(path)
|
||||
.spawn()
|
||||
{
|
||||
Ok(mut gdb) => {
|
||||
gdb.wait().expect("xd");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("gdb error: {e:?}");
|
||||
process.kill().expect("uh oh");
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Ok(status) = process.wait() {
|
||||
if let Some(code) = status.code() {
|
||||
std::process::exit(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
output.write_for(&mut stdout(), file);
|
||||
}
|
||||
|
||||
pub fn run_stdin() {
|
||||
for line in BufReader::new(std::io::stdin()).lines() {
|
||||
let mut output = ParserOutput::new();
|
||||
let str = &line.expect("failed to read line");
|
||||
let mut cursor = TokenCursor::from(&str[..]);
|
||||
if let Some(expr) = Statement::parse_node(&mut cursor, &mut output)
|
||||
.node
|
||||
.as_ref()
|
||||
{
|
||||
if cursor.next().is_none() {
|
||||
let mut ctx = ParserCtx::from(&str[..]);
|
||||
if let Some(expr) = PStatement::parse_node(&mut ctx).node.as_ref() {
|
||||
if ctx.next().is_none() {
|
||||
println!("{:?}", expr);
|
||||
} else {
|
||||
println!("uhhhh ehehe");
|
||||
}
|
||||
}
|
||||
output.write_for(&mut stdout(), str);
|
||||
ctx.output.write_for(&mut stdout(), str);
|
||||
}
|
||||
}
|
||||
|
||||
55
src/parser/v3/ctx.rs
Normal file
55
src/parser/v3/ctx.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,23 @@ use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
||||
pub struct TokenCursor<'a> {
|
||||
cursor: CharCursor<'a>,
|
||||
next: Option<TokenInstance>,
|
||||
next_pos: FilePos,
|
||||
next_start: FilePos,
|
||||
prev_end: FilePos,
|
||||
}
|
||||
|
||||
impl<'a> TokenCursor<'a> {
|
||||
pub fn next(&mut self) -> Option<TokenInstance> {
|
||||
self.prev_end = self.cursor.prev_pos();
|
||||
self.next_pos = self.cursor.next_pos();
|
||||
std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor))
|
||||
self.prev_end = self
|
||||
.next
|
||||
.as_ref()
|
||||
.map(|i| i.span.end)
|
||||
.unwrap_or(FilePos::start());
|
||||
let next = TokenInstance::parse(&mut self.cursor);
|
||||
self.next_start = next
|
||||
.as_ref()
|
||||
.map(|i| i.span.end)
|
||||
.unwrap_or(FilePos::start());
|
||||
std::mem::replace(&mut self.next, next)
|
||||
}
|
||||
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserMsg> {
|
||||
self.peek().ok_or(ParserMsg::unexpected_end())?;
|
||||
@@ -31,11 +39,11 @@ impl<'a> TokenCursor<'a> {
|
||||
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> {
|
||||
self.expect_token(Token::Symbol(symbol))
|
||||
}
|
||||
pub fn seek_sym(&mut self, symbol: Symbol) {
|
||||
while self
|
||||
.next()
|
||||
.is_some_and(|n| n.token != Token::Symbol(symbol))
|
||||
{}
|
||||
pub fn next_on_new_line(&mut self) -> bool {
|
||||
self.next_start.line != self.prev_end.line
|
||||
}
|
||||
pub fn seek_sym(&mut self, sym: Symbol) {
|
||||
while self.next().is_some_and(|n| !n.is_symbol(sym)) {}
|
||||
}
|
||||
pub fn seek_syms(&mut self, syms: &[Symbol]) {
|
||||
while self
|
||||
@@ -45,6 +53,9 @@ impl<'a> TokenCursor<'a> {
|
||||
self.next();
|
||||
}
|
||||
}
|
||||
pub fn seek_sym_on_line(&mut self, sym: Symbol) {
|
||||
while !self.next_on_new_line() && self.next().is_some_and(|n| !n.is_symbol(sym)) {}
|
||||
}
|
||||
pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> {
|
||||
loop {
|
||||
if f(self.peek()?) {
|
||||
@@ -68,8 +79,8 @@ impl<'a> TokenCursor<'a> {
|
||||
pub fn prev_end(&self) -> FilePos {
|
||||
self.prev_end
|
||||
}
|
||||
pub fn next_pos(&self) -> FilePos {
|
||||
self.next_pos
|
||||
pub fn next_start(&self) -> FilePos {
|
||||
self.next_start
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +96,7 @@ impl<'a> From<CharCursor<'a>> for TokenCursor<'a> {
|
||||
Self {
|
||||
cursor,
|
||||
next: cur,
|
||||
next_pos: FilePos::start(),
|
||||
next_start: FilePos::start(),
|
||||
prev_end: FilePos::start(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::ir::{FilePos, FileSpan};
|
||||
|
||||
use super::{token::TokenInstance, Ident, Node};
|
||||
use super::{token::TokenInstance, PIdent, Node};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParserMsg {
|
||||
@@ -32,9 +32,9 @@ impl ParserMsg {
|
||||
spans: vec![span],
|
||||
}
|
||||
}
|
||||
pub fn identifier_not_found(id: &Node<Ident>) -> Self {
|
||||
pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
|
||||
Self {
|
||||
msg: format!("Identifier '{}' not found", id.as_ref().unwrap().val()),
|
||||
msg: format!("Identifier '{}' not found", id.as_ref().unwrap()),
|
||||
spans: vec![id.span],
|
||||
}
|
||||
}
|
||||
@@ -71,11 +71,11 @@ impl ParserOutput {
|
||||
hints: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn err(&mut self, err: ParserMsg) {
|
||||
self.errs.push(err);
|
||||
pub fn err(&mut self, msg: ParserMsg) {
|
||||
self.errs.push(msg);
|
||||
}
|
||||
pub fn hint(&mut self, err: ParserMsg) {
|
||||
self.hints.push(err);
|
||||
pub fn hint(&mut self, msg: ParserMsg) {
|
||||
self.hints.push(msg);
|
||||
}
|
||||
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
|
||||
for err in &self.errs {
|
||||
|
||||
2
src/parser/v3/lower/arch/mod.rs
Normal file
2
src/parser/v3/lower/arch/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod riscv64;
|
||||
pub use super::*;
|
||||
109
src/parser/v3/lower/arch/riscv64.rs
Normal file
109
src/parser/v3/lower/arch/riscv64.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/parser/v3/lower/asm.rs
Normal file
53
src/parser/v3/lower/asm.rs
Normal 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))
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||
self.as_ref()?.lower(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||
impl FnLowerable for PBlock {
|
||||
type Output = VarID;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
||||
let ctx = &mut ctx.sub();
|
||||
for statement in &self.statements {
|
||||
statement.lower(ctx);
|
||||
@@ -18,41 +13,24 @@ impl Block {
|
||||
}
|
||||
}
|
||||
|
||||
impl Node<Box<Statement>> {
|
||||
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||
self.as_ref()?.lower(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
impl FnLowerable for PStatement {
|
||||
type Output = VarID;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
||||
match self {
|
||||
super::Statement::Let(def, e) => {
|
||||
super::PStatement::Let(def, e) => {
|
||||
let def = def.lower(ctx.map, ctx.output)?;
|
||||
let res = e.lower(ctx);
|
||||
if let Some(res) = res {
|
||||
match res {
|
||||
ExprResult::Var(v) => ctx.map.name_var(&def, v),
|
||||
ExprResult::Fn(_) => todo!(),
|
||||
}
|
||||
ctx.map.name_var(&def, res);
|
||||
}
|
||||
None
|
||||
}
|
||||
super::Statement::Return(e) => {
|
||||
let res = e.lower(ctx)?;
|
||||
match res {
|
||||
ExprResult::Var(v) => ctx.push(Instruction::Ret { src: v }),
|
||||
_ => todo!(),
|
||||
}
|
||||
super::PStatement::Return(e) => {
|
||||
let src = e.lower(ctx)?;
|
||||
ctx.push(IRUInstruction::Ret { src });
|
||||
None
|
||||
}
|
||||
super::Statement::Expr(e) => e.lower(ctx),
|
||||
super::PStatement::Expr(e) => e.lower(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef};
|
||||
|
||||
use super::{Node, ParserMsg, ParserOutput, Type as PType, VarDef as PVarDef};
|
||||
use super::{Node, ParserMsg, ParserOutput, PType, PVarDef};
|
||||
|
||||
impl Node<PVarDef> {
|
||||
pub fn lower(
|
||||
@@ -9,7 +9,7 @@ impl Node<PVarDef> {
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<VarDef> {
|
||||
let s = self.as_ref()?;
|
||||
let name = s.name.as_ref()?.val().clone();
|
||||
let name = s.name.as_ref()?.to_string();
|
||||
let ty = match &s.ty {
|
||||
Some(ty) => ty.lower(namespace, output),
|
||||
None => Type::Infer,
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
use super::{func::FnLowerCtx, Expr as PExpr, Node, UnaryOp};
|
||||
use crate::ir::{FnIdent, Instruction, Type, VarIdent, VarOrFnIdent};
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||
use crate::ir::{IRUInstruction, Type, VarID};
|
||||
|
||||
impl PExpr {
|
||||
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||
impl FnLowerable for PExpr {
|
||||
type Output = VarID;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
||||
Some(match self {
|
||||
PExpr::Lit(l) => match l.as_ref()? {
|
||||
super::Literal::String(s) => todo!(),
|
||||
super::Literal::Char(c) => todo!(),
|
||||
super::Literal::Number(n) => todo!(),
|
||||
super::Literal::Unit => {
|
||||
super::PLiteral::String(s) => {
|
||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf());
|
||||
let src = ctx.map.def_data(s.as_bytes().to_vec());
|
||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Char(c) => {
|
||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf());
|
||||
let src = ctx.map.def_data(c.to_string().as_bytes().to_vec());
|
||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Number(n) => {
|
||||
// TODO: temp
|
||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf());
|
||||
let src = ctx
|
||||
.map
|
||||
.def_data(n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec());
|
||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Unit => {
|
||||
todo!();
|
||||
}
|
||||
},
|
||||
PExpr::Ident(i) => {
|
||||
let name = i.as_ref()?.val();
|
||||
let Some(id) = ctx.get(name) else {
|
||||
ctx.err(format!("Identifier '{}' not found.", name));
|
||||
return None;
|
||||
};
|
||||
let Some(vf) = id.var_func else {
|
||||
ctx.err(format!("Variable or function '{}' not found; Found type, but types cannot be used here.", name));
|
||||
return None;
|
||||
};
|
||||
match vf {
|
||||
VarOrFnIdent::Var(var) => ExprResult::Var(var),
|
||||
VarOrFnIdent::Fn(f) => ExprResult::Fn(f),
|
||||
}
|
||||
}
|
||||
PExpr::Ident(i) => ctx.get_var(i)?,
|
||||
PExpr::BinaryOp(op, e1, e2) => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
let res2 = e2.lower(ctx)?;
|
||||
@@ -36,101 +41,50 @@ impl PExpr {
|
||||
PExpr::UnaryOp(op, e) => {
|
||||
let res = e.lower(ctx)?;
|
||||
match op {
|
||||
UnaryOp::Ref => ExprResult::Var(match res {
|
||||
ExprResult::Var(v) => {
|
||||
let temp = ctx.temp(ctx.map.get_var(v).ty.clone());
|
||||
ctx.push(Instruction::Ref { dest: temp, src: v });
|
||||
UnaryOp::Ref => {
|
||||
let temp = ctx.temp(ctx.map.get_var(res).ty.clone());
|
||||
ctx.push(IRUInstruction::Ref {
|
||||
dest: temp,
|
||||
src: res,
|
||||
});
|
||||
temp
|
||||
}
|
||||
ExprResult::Fn(f) => {
|
||||
let temp = ctx.temp(Type::Ref(Box::new(ctx.map.get_fn(f).ty())));
|
||||
ctx.push(Instruction::Lf { dest: temp, src: f });
|
||||
temp
|
||||
}
|
||||
}),
|
||||
UnaryOp::Deref => match res {
|
||||
ExprResult::Var(v) => match &ctx.map.get_var(v).ty {
|
||||
Type::Ref(inner) => {
|
||||
todo!()
|
||||
}
|
||||
t => {
|
||||
UnaryOp::Deref => {
|
||||
let t = &ctx.map.get_var(res).ty;
|
||||
let Type::Ref(inner) = t else {
|
||||
ctx.err(format!(
|
||||
"Cannot dereference type {:?}",
|
||||
ctx.map.type_name(t)
|
||||
));
|
||||
return None;
|
||||
};
|
||||
todo!();
|
||||
}
|
||||
},
|
||||
ExprResult::Fn(f) => {
|
||||
ctx.err("Cannot dereference functions".to_string());
|
||||
return None;
|
||||
}
|
||||
},
|
||||
UnaryOp::Not => todo!(),
|
||||
}
|
||||
}
|
||||
PExpr::Block(b) => b.lower(ctx)?,
|
||||
PExpr::AsmBlock(b) => {
|
||||
ctx.push(Instruction::AsmBlock {
|
||||
instructions: b.as_ref()?.instructions.clone(),
|
||||
});
|
||||
b.lower(ctx);
|
||||
return None;
|
||||
}
|
||||
PExpr::Call(e, args) => {
|
||||
let fe = e.lower(ctx)?;
|
||||
let f = e.lower(ctx)?;
|
||||
let mut nargs = Vec::new();
|
||||
for arg in args.iter() {
|
||||
let arg = arg.lower(ctx)?;
|
||||
nargs.push(match arg {
|
||||
ExprResult::Var(v) => v,
|
||||
ExprResult::Fn(_) => todo!(),
|
||||
});
|
||||
nargs.push(arg);
|
||||
}
|
||||
match fe {
|
||||
ExprResult::Fn(f) => {
|
||||
let temp = ctx.temp(ctx.map.get_fn(f).ret.clone());
|
||||
ctx.push(Instruction::Call {
|
||||
let temp = ctx.temp(ctx.map.get_fn_var(f).ret.clone());
|
||||
ctx.push(IRUInstruction::Call {
|
||||
dest: temp,
|
||||
f,
|
||||
args: nargs,
|
||||
});
|
||||
ExprResult::Var(temp)
|
||||
}
|
||||
o => {
|
||||
ctx.err(format!("Expected function, found {:?}", o));
|
||||
// ctx.err(format!("Expected function, found {:?}", f));
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
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),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use super::{Function as PFunction, Node, ParserMsg, ParserOutput};
|
||||
use crate::ir::{
|
||||
BuiltinType, FileSpan, FnDef, FnIdent, Function, Idents, Instruction, Instructions,
|
||||
NamespaceGuard, Origin, Type, VarDef, VarIdent,
|
||||
use super::{FnLowerable, PFunction, Node, ParserMsg, ParserOutput};
|
||||
use crate::{
|
||||
ir::{
|
||||
BuiltinType, FileSpan, FnDef, FnID, IRUFunction, Idents, IRUInstruction, IRInstructions,
|
||||
NamespaceGuard, Origin, Type, VarDef, VarID,
|
||||
},
|
||||
parser,
|
||||
};
|
||||
|
||||
impl Node<PFunction> {
|
||||
@@ -9,15 +12,16 @@ impl Node<PFunction> {
|
||||
&self,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<FnIdent> {
|
||||
) -> Option<FnID> {
|
||||
self.as_ref()?.lower_header(map, output)
|
||||
}
|
||||
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Option<Function> {
|
||||
if let Some(f) = self.as_ref() {
|
||||
Some(f.lower_body(map, output))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn lower_body(
|
||||
&self,
|
||||
id: FnID,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<IRUFunction> {
|
||||
Some(self.as_ref()?.lower_body(id, map, output))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +30,7 @@ impl PFunction {
|
||||
&self,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<FnIdent> {
|
||||
) -> Option<FnID> {
|
||||
let header = self.header.as_ref()?;
|
||||
let name = header.name.as_ref()?;
|
||||
let args = header
|
||||
@@ -44,50 +48,145 @@ impl PFunction {
|
||||
Some(ty) => ty.lower(map, output),
|
||||
None => Type::Concrete(BuiltinType::Unit.id()),
|
||||
};
|
||||
// ignoring self var for now
|
||||
Some(map.def_fn(FnDef {
|
||||
name: name.val().clone(),
|
||||
name: name.to_string(),
|
||||
origin: Origin::File(self.header.span),
|
||||
args,
|
||||
ret,
|
||||
}))
|
||||
}
|
||||
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Function {
|
||||
let mut instructions = Instructions::new();
|
||||
pub fn lower_body(
|
||||
&self,
|
||||
id: FnID,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> IRUFunction {
|
||||
let mut instructions = IRInstructions::new();
|
||||
let def = map.get_fn(id).clone();
|
||||
let args = def.args.iter().map(|a| {
|
||||
map.named_var(a.clone())
|
||||
}).collect();
|
||||
let mut ctx = FnLowerCtx {
|
||||
instructions: &mut instructions,
|
||||
map,
|
||||
output,
|
||||
span: self.body.span,
|
||||
};
|
||||
if let Some(res) = self.body.lower(&mut ctx) {
|
||||
match res {
|
||||
super::ExprResult::Var(v) => instructions.push(Instruction::Ret { src: v }),
|
||||
super::ExprResult::Fn(_) => todo!(),
|
||||
if let Some(src) = self.body.lower(&mut ctx) {
|
||||
instructions.push(IRUInstruction::Ret { src });
|
||||
}
|
||||
}
|
||||
Function::new(instructions)
|
||||
IRUFunction::new(def.name.clone(), args, instructions)
|
||||
}
|
||||
}
|
||||
|
||||
// impl Node<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 map: &'a mut NamespaceGuard<'n>,
|
||||
pub instructions: &'a mut Instructions,
|
||||
pub instructions: &'a mut IRInstructions,
|
||||
pub output: &'a mut ParserOutput,
|
||||
pub span: FileSpan,
|
||||
}
|
||||
|
||||
impl<'a, 'n> FnLowerCtx<'a, 'n> {
|
||||
pub fn get(&self, name: &str) -> Option<Idents> {
|
||||
self.map.get(name)
|
||||
impl<'n> FnLowerCtx<'_, 'n> {
|
||||
pub fn span<'b>(&'b mut self, span: FileSpan) -> FnLowerCtx<'b, 'n> {
|
||||
FnLowerCtx {
|
||||
map: self.map,
|
||||
instructions: self.instructions,
|
||||
output: self.output,
|
||||
span,
|
||||
}
|
||||
}
|
||||
pub fn get(&mut self, node: &Node<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) {
|
||||
self.output.err(ParserMsg::from_span(self.span, msg))
|
||||
}
|
||||
pub fn temp(&mut self, ty: Type) -> VarIdent {
|
||||
pub fn err_at(&mut self, span: FileSpan, msg: String) {
|
||||
self.output.err(ParserMsg::from_span(span, msg))
|
||||
}
|
||||
pub fn temp(&mut self, ty: Type) -> VarID {
|
||||
self.map.temp_var(self.span, ty)
|
||||
}
|
||||
pub fn push(&mut self, i: Instruction) {
|
||||
pub fn push(&mut self, i: IRUInstruction) {
|
||||
self.instructions.push(i);
|
||||
}
|
||||
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
|
||||
|
||||
@@ -1,12 +1,30 @@
|
||||
mod asm;
|
||||
mod block;
|
||||
mod def;
|
||||
mod expr;
|
||||
mod func;
|
||||
mod module;
|
||||
mod arch;
|
||||
|
||||
use super::*;
|
||||
use block::*;
|
||||
use def::*;
|
||||
use expr::*;
|
||||
use func::*;
|
||||
use module::*;
|
||||
|
||||
pub use func::FnLowerCtx;
|
||||
|
||||
pub trait FnLowerable {
|
||||
type Output;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::ir::NamespaceGuard;
|
||||
|
||||
use super::{Module, ParserOutput};
|
||||
use super::{PModule, ParserOutput};
|
||||
|
||||
impl Module {
|
||||
impl PModule {
|
||||
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) {
|
||||
let mut fns = Vec::new();
|
||||
for f in &self.functions {
|
||||
@@ -13,9 +13,11 @@ impl Module {
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ mod node;
|
||||
mod nodes;
|
||||
mod parse;
|
||||
mod token;
|
||||
mod ctx;
|
||||
|
||||
pub use cursor::*;
|
||||
pub use error::*;
|
||||
@@ -13,3 +14,4 @@ pub use node::*;
|
||||
pub use nodes::*;
|
||||
pub use parse::*;
|
||||
pub use token::*;
|
||||
pub use ctx::*;
|
||||
|
||||
@@ -1,23 +1,59 @@
|
||||
use crate::compiler::riscv64::AsmInstruction;
|
||||
use super::{
|
||||
util::parse_list, PIdent, Node, Parsable, ParseResult, PInstruction, ParserCtx, Symbol,
|
||||
};
|
||||
|
||||
use super::{Parsable, ParseResult, Symbol};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsmBlock {
|
||||
pub instructions: Vec<AsmInstruction>,
|
||||
pub struct PAsmBlock {
|
||||
pub instructions: Vec<Node<PInstruction>>,
|
||||
pub args: Vec<Node<PAsmBlockArg>>,
|
||||
}
|
||||
|
||||
impl Parsable for AsmBlock {
|
||||
fn parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
output: &mut super::ParserOutput,
|
||||
) -> ParseResult<Self> {
|
||||
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||
pub struct PAsmBlockArg {
|
||||
pub reg: Node<PIdent>,
|
||||
pub var: Node<PIdent>,
|
||||
}
|
||||
|
||||
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();
|
||||
while !cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
instructions.push(AsmInstruction::parse(cursor, output)?);
|
||||
while !ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
let res = ctx.parse();
|
||||
instructions.push(res.node);
|
||||
if res.recover {
|
||||
ctx.seek_sym_on_line(Symbol::CloseCurly);
|
||||
}
|
||||
cursor.expect_sym(Symbol::CloseCurly)?;
|
||||
ParseResult::Ok(Self { instructions })
|
||||
}
|
||||
ctx.expect_sym(Symbol::CloseCurly)?;
|
||||
ParseResult::Ok(Self { instructions, args })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for PAsmBlockArg {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,63 @@
|
||||
use crate::compiler::riscv64::{AsmInstruction, Reg};
|
||||
|
||||
use super::{
|
||||
util::parse_list, AsmBlock, Ident, Keyword, Node, Parsable, ParseResult, SelfVar, Symbol,
|
||||
util::parse_list, PAsmBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, PType, PVarDef,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsmFunctionHeader {
|
||||
pub name: Node<Ident>,
|
||||
pub sel: Option<Node<SelfVar>>,
|
||||
pub args: Vec<Node<Reg>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsmFunction {
|
||||
pub header: Node<AsmFunctionHeader>,
|
||||
pub body: Node<AsmBlock>,
|
||||
}
|
||||
|
||||
impl Parsable for AsmFunctionHeader {
|
||||
fn parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
output: &mut super::ParserOutput,
|
||||
) -> ParseResult<Self> {
|
||||
cursor.expect_kw(Keyword::Asm)?;
|
||||
cursor.expect_kw(Keyword::Fn)?;
|
||||
let name = Node::parse(cursor, output)?;
|
||||
cursor.expect_sym(Symbol::OpenParen)?;
|
||||
let sel = Node::maybe_parse(cursor, output);
|
||||
if sel.is_some() {
|
||||
if let Err(err) = cursor.expect_sym(Symbol::Comma) {
|
||||
output.err(err);
|
||||
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
|
||||
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
|
||||
cursor.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
let args = parse_list(cursor, output, Symbol::CloseParen)?;
|
||||
ParseResult::Ok(Self { name, sel, args })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for AsmFunction {
|
||||
fn parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
output: &mut super::ParserOutput,
|
||||
) -> ParseResult<Self> {
|
||||
let header = Node::parse(cursor, output)?;
|
||||
let body = Node::parse(cursor, output)?;
|
||||
ParseResult::Ok(Self { header, body })
|
||||
}
|
||||
}
|
||||
// #[derive(Debug)]
|
||||
// pub struct AsmFunctionHeader {
|
||||
// pub name: Node<Ident>,
|
||||
// pub args: Vec<Node<AsmVarDef>>,
|
||||
// }
|
||||
//
|
||||
// #[derive(Debug)]
|
||||
// pub struct AsmFunction {
|
||||
// pub header: Node<AsmFunctionHeader>,
|
||||
// pub body: Node<AsmBlock>,
|
||||
// }
|
||||
//
|
||||
// impl Parsable for AsmFunctionHeader {
|
||||
// fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
// ctx.expect_kw(Keyword::Asm)?;
|
||||
// ctx.expect_kw(Keyword::Fn)?;
|
||||
// let name = ctx.parse()?;
|
||||
// ctx.expect_sym(Symbol::OpenParen)?;
|
||||
// let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
// ParseResult::Ok(Self { name, args })
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Parsable for AsmFunction {
|
||||
// fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
// let header = ctx.parse()?;
|
||||
// let body = ctx.parse()?;
|
||||
// ParseResult::Ok(Self { header, body })
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub struct AsmVarDef {
|
||||
// pub reg: Node<Ident>,
|
||||
// pub name: Node<Ident>,
|
||||
// pub ty: Option<Node<Type>>,
|
||||
// }
|
||||
//
|
||||
// impl Parsable for AsmVarDef {
|
||||
// fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
// let reg = ctx.parse()?;
|
||||
// let name = ctx.parse()?;
|
||||
// if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
// ctx.next();
|
||||
// ctx.parse().map(|ty| Self { reg, name, ty: Some(ty) })
|
||||
// } else {
|
||||
// ParseResult::Ok(Self { reg, name, ty: None })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl std::fmt::Debug for AsmVarDef {
|
||||
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// self.name.fmt(f)?;
|
||||
// if let Some(ty) = &self.ty {
|
||||
// write!(f, ": {:?}", ty)?;
|
||||
// }
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
||||
82
src/parser/v3/nodes/asm_instr.rs
Normal file
82
src/parser/v3/nodes/asm_instr.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,52 @@
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use super::{
|
||||
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserMsg, ParserOutput, Statement,
|
||||
TokenCursor,
|
||||
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement,
|
||||
};
|
||||
use crate::util::Padder;
|
||||
|
||||
pub struct Block {
|
||||
pub statements: Vec<Node<Statement>>,
|
||||
pub result: Option<Node<Box<Statement>>>,
|
||||
pub struct PBlock {
|
||||
pub statements: Vec<Node<PStatement>>,
|
||||
pub result: Option<Node<Box<PStatement>>>,
|
||||
}
|
||||
|
||||
impl Parsable for Block {
|
||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||
impl Parsable for PBlock {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let mut statements = Vec::new();
|
||||
let mut result = None;
|
||||
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
cursor.next();
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
if ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
ctx.next();
|
||||
return ParseResult::Ok(Self { statements, result });
|
||||
}
|
||||
let mut expect_semi = false;
|
||||
let mut recover = false;
|
||||
loop {
|
||||
let Some(next) = cursor.peek() else {
|
||||
let Some(next) = ctx.peek() else {
|
||||
recover = true;
|
||||
errors.err(ParserMsg::unexpected_end());
|
||||
ctx.err(ParserMsg::unexpected_end());
|
||||
break;
|
||||
};
|
||||
if next.is_symbol(Symbol::CloseCurly) {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
break;
|
||||
}
|
||||
if next.is_symbol(Symbol::Semicolon) {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
expect_semi = false;
|
||||
continue;
|
||||
} else if expect_semi {
|
||||
errors.err(ParserMsg {
|
||||
ctx.err(ParserMsg {
|
||||
msg: "expected ';'".to_string(),
|
||||
spans: vec![cursor.next_pos().char_span()],
|
||||
spans: vec![ctx.next_start().char_span()],
|
||||
});
|
||||
}
|
||||
let res = Statement::parse_node(cursor, errors);
|
||||
let res = PStatement::parse_node(ctx);
|
||||
statements.push(res.node);
|
||||
expect_semi = true;
|
||||
if res.recover {
|
||||
cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
|
||||
if cursor.peek().is_none() {
|
||||
ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
|
||||
if ctx.peek().is_none() {
|
||||
recover = true;
|
||||
break;
|
||||
}
|
||||
@@ -62,14 +61,17 @@ impl Parsable for Block {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Block {
|
||||
impl Debug for PBlock {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.statements.first().is_some() {
|
||||
if !self.statements.is_empty() || self.result.is_some() {
|
||||
f.write_str("{\n ")?;
|
||||
let mut padder = Padder::new(f);
|
||||
for s in &self.statements {
|
||||
// they don't expose wrap_buf :grief:
|
||||
padder.write_str(&format!("{s:?}\n"))?;
|
||||
padder.write_str(&format!("{s:?};\n"))?;
|
||||
}
|
||||
if let Some(res) = &self.result {
|
||||
padder.write_str(&format!("{res:?}\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{Ident, MaybeParsable, Node, Parsable, ParseResult, ParserMsg, Symbol, Token, Type};
|
||||
use super::{
|
||||
PIdent, MaybeParsable, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token, PType,
|
||||
};
|
||||
|
||||
pub struct VarDef {
|
||||
pub name: Node<Ident>,
|
||||
pub ty: Option<Node<Type>>,
|
||||
pub struct PVarDef {
|
||||
pub name: Node<PIdent>,
|
||||
pub ty: Option<Node<PType>>,
|
||||
}
|
||||
|
||||
impl Parsable for VarDef {
|
||||
fn parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
errors: &mut super::ParserOutput,
|
||||
) -> ParseResult<Self> {
|
||||
let name = Node::parse(cursor, errors)?;
|
||||
if cursor.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
cursor.next();
|
||||
Node::parse(cursor, errors).map(|ty| Self { name, ty: Some(ty) })
|
||||
impl Parsable for PVarDef {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let name = ctx.parse()?;
|
||||
if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
ctx.next();
|
||||
ctx.parse().map(|ty| Self { name, ty: Some(ty) })
|
||||
} else {
|
||||
ParseResult::Ok(Self { name, ty: None })
|
||||
}
|
||||
@@ -33,20 +32,17 @@ pub enum SelfType {
|
||||
}
|
||||
|
||||
impl MaybeParsable for SelfVar {
|
||||
fn maybe_parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
errors: &mut super::ParserOutput,
|
||||
) -> Result<Option<Self>, super::ParserMsg> {
|
||||
if let Some(mut next) = cursor.peek() {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, super::ParserMsg> {
|
||||
if let Some(mut next) = ctx.peek() {
|
||||
let mut ty = SelfType::Take;
|
||||
if next.is_symbol(Symbol::Ampersand) {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
ty = SelfType::Ref;
|
||||
next = cursor.expect_peek()?;
|
||||
next = ctx.expect_peek()?;
|
||||
}
|
||||
if let Token::Word(name) = &next.token {
|
||||
if name == "self" {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
return Ok(Some(Self { ty }));
|
||||
}
|
||||
}
|
||||
@@ -58,7 +54,7 @@ impl MaybeParsable for SelfVar {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VarDef {
|
||||
impl Debug for PVarDef {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.name.fmt(f)?;
|
||||
if let Some(ty) = &self.ty {
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use super::{
|
||||
op::{BinaryOp, UnaryOp},
|
||||
op::{PInfixOp, UnaryOp},
|
||||
util::parse_list,
|
||||
AsmBlock, Block, Ident, Keyword, Literal, Node, NodeParsable, Parsable, ParseResult, ParserMsg,
|
||||
ParserOutput, Symbol, TokenCursor,
|
||||
PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx,
|
||||
ParserMsg, Symbol,
|
||||
};
|
||||
|
||||
type BoxNode = Node<Box<Expr>>;
|
||||
type BoxNode = Node<Box<PExpr>>;
|
||||
|
||||
pub enum Expr {
|
||||
Lit(Node<Literal>),
|
||||
Ident(Node<Ident>),
|
||||
BinaryOp(BinaryOp, BoxNode, BoxNode),
|
||||
pub enum PExpr {
|
||||
Lit(Node<PLiteral>),
|
||||
Ident(Node<PIdent>),
|
||||
BinaryOp(PInfixOp, BoxNode, BoxNode),
|
||||
UnaryOp(UnaryOp, BoxNode),
|
||||
Block(Node<Block>),
|
||||
Call(BoxNode, Vec<Node<Expr>>),
|
||||
Block(Node<PBlock>),
|
||||
Call(BoxNode, Vec<Node<PExpr>>),
|
||||
Group(BoxNode),
|
||||
AsmBlock(Node<AsmBlock>),
|
||||
AsmBlock(Node<PAsmBlock>),
|
||||
}
|
||||
|
||||
impl Parsable for Expr {
|
||||
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||
let start = cursor.next_pos();
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PExpr {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let start = ctx.next_start();
|
||||
let next = ctx.expect_peek()?;
|
||||
let mut e1 = if next.is_symbol(Symbol::OpenParen) {
|
||||
cursor.next();
|
||||
if cursor.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||
cursor.next();
|
||||
return ParseResult::Ok(Expr::Lit(Node::new(
|
||||
Literal::Unit,
|
||||
cursor.next_pos().char_span(),
|
||||
ctx.next();
|
||||
if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||
ctx.next();
|
||||
return ParseResult::Ok(PExpr::Lit(Node::new(
|
||||
PLiteral::Unit,
|
||||
ctx.next_start().char_span(),
|
||||
)));
|
||||
}
|
||||
let res = Node::parse(cursor, output);
|
||||
let res = ctx.parse();
|
||||
if res.recover {
|
||||
cursor.seek_sym(Symbol::CloseParen);
|
||||
ctx.seek_sym(Symbol::CloseParen);
|
||||
}
|
||||
cursor.expect_sym(Symbol::CloseParen)?;
|
||||
ctx.expect_sym(Symbol::CloseParen)?;
|
||||
Self::Group(res.node.bx())
|
||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||
Self::Block(Block::parse_node(cursor, output)?)
|
||||
Self::Block(PBlock::parse_node(ctx)?)
|
||||
} else if next.is_keyword(Keyword::Asm) {
|
||||
cursor.next();
|
||||
Self::AsmBlock(Node::parse(cursor, output)?)
|
||||
ctx.next();
|
||||
Self::AsmBlock(ctx.parse()?)
|
||||
} else if let Some(op) = UnaryOp::from_token(next) {
|
||||
cursor.next();
|
||||
return Node::parse(cursor, output).map(|n| {
|
||||
ctx.next();
|
||||
return ctx.parse().map(|n| {
|
||||
let n = n.bx();
|
||||
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
|
||||
let span = start.to(n1.span.end);
|
||||
@@ -55,36 +55,36 @@ impl Parsable for Expr {
|
||||
Self::UnaryOp(op, n)
|
||||
}
|
||||
});
|
||||
} else if let Some(val) = Node::maybe_parse(cursor, output) {
|
||||
} else if let Some(val) = Node::maybe_parse(ctx) {
|
||||
Self::Lit(val)
|
||||
} else {
|
||||
let res = Node::parse(cursor, &mut ParserOutput::new());
|
||||
let res = ctx.parse();
|
||||
if res.node.is_some() {
|
||||
Self::Ident(res.node)
|
||||
} else {
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression"));
|
||||
}
|
||||
};
|
||||
let Some(mut next) = cursor.peek() else {
|
||||
let Some(mut next) = ctx.peek() else {
|
||||
return ParseResult::Ok(e1);
|
||||
};
|
||||
while next.is_symbol(Symbol::OpenParen) {
|
||||
cursor.next();
|
||||
let args = parse_list(cursor, output, Symbol::CloseParen)?;
|
||||
let end = cursor.prev_end();
|
||||
ctx.next();
|
||||
let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
let end = ctx.prev_end();
|
||||
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
|
||||
let Some(next2) = cursor.peek() else {
|
||||
let Some(next2) = ctx.peek() else {
|
||||
return ParseResult::Ok(e1);
|
||||
};
|
||||
next = next2
|
||||
}
|
||||
let end = cursor.prev_end();
|
||||
let end = ctx.prev_end();
|
||||
let mut recover = false;
|
||||
let res = if let Some(mut op) = BinaryOp::from_token(&next.token) {
|
||||
cursor.next();
|
||||
let res = if let Some(mut op) = PInfixOp::from_token(&next.token) {
|
||||
ctx.next();
|
||||
let mut n1 = Node::new(e1, start.to(end)).bx();
|
||||
let res = Node::parse(cursor, output);
|
||||
let res = ctx.parse();
|
||||
let mut n2 = res.node.bx();
|
||||
recover = res.recover;
|
||||
if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
|
||||
@@ -106,13 +106,13 @@ impl Parsable for Expr {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Expr {
|
||||
impl Debug for PExpr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Expr::Lit(c) => c.fmt(f)?,
|
||||
Expr::Ident(n) => n.fmt(f)?,
|
||||
Expr::Block(b) => b.fmt(f)?,
|
||||
Expr::BinaryOp(op, e1, e2) => {
|
||||
PExpr::Lit(c) => c.fmt(f)?,
|
||||
PExpr::Ident(n) => n.fmt(f)?,
|
||||
PExpr::Block(b) => b.fmt(f)?,
|
||||
PExpr::BinaryOp(op, e1, e2) => {
|
||||
write!(f, "({:?}", *e1)?;
|
||||
if op.pad() {
|
||||
write!(f, " {} ", op.str())?;
|
||||
@@ -121,7 +121,7 @@ impl Debug for Expr {
|
||||
}
|
||||
write!(f, "{:?})", *e2)?;
|
||||
}
|
||||
Expr::Call(n, args) => {
|
||||
PExpr::Call(n, args) => {
|
||||
n.fmt(f)?;
|
||||
f.write_char('(')?;
|
||||
if let Some(a) = args.first() {
|
||||
@@ -133,13 +133,13 @@ impl Debug for Expr {
|
||||
}
|
||||
f.write_char(')')?;
|
||||
}
|
||||
Expr::UnaryOp(op, e) => {
|
||||
PExpr::UnaryOp(op, e) => {
|
||||
write!(f, "(")?;
|
||||
write!(f, "{}", op.str())?;
|
||||
write!(f, "{:?})", *e)?;
|
||||
}
|
||||
Expr::Group(inner) => inner.fmt(f)?,
|
||||
Expr::AsmBlock(inner) => inner.fmt(f)?,
|
||||
PExpr::Group(inner) => inner.fmt(f)?,
|
||||
PExpr::AsmBlock(inner) => inner.fmt(f)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,71 +1,69 @@
|
||||
use super::{
|
||||
util::parse_list, Block, Ident, Keyword, Node, Parsable, ParseResult, ParserOutput, SelfVar,
|
||||
Symbol, TokenCursor, Type, VarDef,
|
||||
util::parse_list, PBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx,
|
||||
Symbol, PType, PVarDef,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub struct FunctionHeader {
|
||||
pub name: Node<Ident>,
|
||||
pub sel: Option<Node<SelfVar>>,
|
||||
pub args: Vec<Node<VarDef>>,
|
||||
pub ret: Option<Node<Type>>,
|
||||
pub struct PFunctionHeader {
|
||||
pub name: Node<PIdent>,
|
||||
pub args: Vec<Node<PVarDef>>,
|
||||
pub ret: Option<Node<PType>>,
|
||||
}
|
||||
|
||||
pub struct Function {
|
||||
pub header: Node<FunctionHeader>,
|
||||
pub body: Node<Block>,
|
||||
pub struct PFunction {
|
||||
pub header: Node<PFunctionHeader>,
|
||||
pub body: Node<PBlock>,
|
||||
}
|
||||
|
||||
impl Parsable for FunctionHeader {
|
||||
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||
cursor.expect_kw(Keyword::Fn)?;
|
||||
let name = Node::parse(cursor, output)?;
|
||||
cursor.expect_sym(Symbol::OpenParen)?;
|
||||
let sel = Node::maybe_parse(cursor, output);
|
||||
if sel.is_some() {
|
||||
if let Err(err) = cursor.expect_sym(Symbol::Comma) {
|
||||
output.err(err);
|
||||
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
|
||||
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
|
||||
cursor.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
let args = parse_list(cursor, output, Symbol::CloseParen)?;
|
||||
let ret = if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) {
|
||||
cursor.next();
|
||||
Some(Node::parse(cursor, output)?)
|
||||
impl Parsable for PFunctionHeader {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Fn)?;
|
||||
let name = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::OpenParen)?;
|
||||
// let sel = ctx.maybe_parse();
|
||||
// if sel.is_some() {
|
||||
// if let Err(err) = ctx.expect_sym(Symbol::Comma) {
|
||||
// ctx.err(err);
|
||||
// ctx.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
|
||||
// if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
|
||||
// ctx.next();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
let ret = if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) {
|
||||
ctx.next();
|
||||
Some(ctx.parse()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
ParseResult::Ok(Self {
|
||||
name,
|
||||
args,
|
||||
sel,
|
||||
ret,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Function {
|
||||
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||
let header = Node::parse(cursor, output)?;
|
||||
let body = Node::parse(cursor, output)?;
|
||||
impl Parsable for PFunction {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let header = ctx.parse()?;
|
||||
let body = ctx.parse()?;
|
||||
ParseResult::Ok(Self { header, body })
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FunctionHeader {
|
||||
impl Debug for PFunctionHeader {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("fn ")?;
|
||||
self.name.fmt(f)?;
|
||||
f.write_str("(")?;
|
||||
if let Some(s) = &self.sel {
|
||||
s.fmt(f)?;
|
||||
if self.args.first().is_some() {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
}
|
||||
// if let Some(s) = &self.sel {
|
||||
// s.fmt(f)?;
|
||||
// if self.args.first().is_some() {
|
||||
// f.write_str(", ")?;
|
||||
// }
|
||||
// }
|
||||
if let Some(a) = self.args.first() {
|
||||
a.fmt(f)?;
|
||||
}
|
||||
@@ -80,7 +78,7 @@ impl Debug for FunctionHeader {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Debug for Function {
|
||||
impl Debug for PFunction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.header.fmt(f)?;
|
||||
f.write_str(" ")?;
|
||||
|
||||
@@ -1,29 +1,52 @@
|
||||
use std::fmt::Debug;
|
||||
use super::{Parsable, ParseResult, ParserMsg, Token};
|
||||
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token};
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
pub struct Ident(String);
|
||||
#[derive(Clone)]
|
||||
pub struct PIdent(String);
|
||||
|
||||
impl Ident {
|
||||
pub fn val(&self) -> &String {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Ident {
|
||||
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> ParseResult<Self> {
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PIdent {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
let Token::Word(name) = &next.token else {
|
||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier"));
|
||||
};
|
||||
let name = name.to_string();
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
ParseResult::Ok(Self(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Ident {
|
||||
impl MaybeParsable for PIdent {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,35 @@
|
||||
use super::{CharCursor, MaybeParsable, ParserMsg, ParserOutput, Symbol, Token, TokenCursor};
|
||||
use super::{CharCursor, MaybeParsable, ParserCtx, ParserMsg, Symbol, Token};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum Literal {
|
||||
pub enum PLiteral {
|
||||
String(String),
|
||||
Char(char),
|
||||
Number(Number),
|
||||
Number(PNumber),
|
||||
Unit,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Number {
|
||||
pub struct PNumber {
|
||||
pub whole: String,
|
||||
pub decimal: Option<String>,
|
||||
pub ty: Option<String>,
|
||||
}
|
||||
|
||||
impl MaybeParsable for Literal {
|
||||
fn maybe_parse(
|
||||
cursor: &mut TokenCursor,
|
||||
_: &mut ParserOutput,
|
||||
) -> Result<Option<Self>, ParserMsg> {
|
||||
let inst = cursor.expect_peek()?;
|
||||
impl MaybeParsable for PLiteral {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
|
||||
let inst = ctx.expect_peek()?;
|
||||
Ok(Some(match &inst.token {
|
||||
Token::Symbol(Symbol::SingleQuote) => {
|
||||
let chars = cursor.chars();
|
||||
let chars = ctx.chars();
|
||||
let c = chars.expect_next()?;
|
||||
chars.expect('\'')?;
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
Self::Char(c)
|
||||
}
|
||||
Token::Symbol(Symbol::DoubleQuote) => {
|
||||
let res = Self::String(string_from(cursor.chars())?);
|
||||
cursor.next();
|
||||
let res = Self::String(string_from(ctx.chars())?);
|
||||
ctx.next();
|
||||
res
|
||||
}
|
||||
Token::Word(text) => {
|
||||
@@ -41,21 +38,21 @@ impl MaybeParsable for Literal {
|
||||
return Ok(None);
|
||||
}
|
||||
let (whole, ty) = parse_whole_num(text);
|
||||
let mut num = Number {
|
||||
let mut num = PNumber {
|
||||
whole,
|
||||
decimal: None,
|
||||
ty,
|
||||
};
|
||||
cursor.next();
|
||||
if num.ty.is_none() && cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) {
|
||||
cursor.next();
|
||||
if let Some(next) = cursor.peek() {
|
||||
ctx.next();
|
||||
if num.ty.is_none() && ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) {
|
||||
ctx.next();
|
||||
if let Some(next) = ctx.peek() {
|
||||
if let Token::Word(i) = &next.token {
|
||||
if i.chars().next().unwrap().is_ascii_digit() {
|
||||
let (decimal, ty) = parse_whole_num(i);
|
||||
num.decimal = Some(decimal);
|
||||
num.ty = ty;
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +107,7 @@ pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Literal {
|
||||
impl Debug for PLiteral {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::String(str) => str.fmt(f),
|
||||
@@ -121,7 +118,7 @@ impl Debug for Literal {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Number {
|
||||
impl Debug for PNumber {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.whole)?;
|
||||
if let Some(d) = &self.decimal {
|
||||
|
||||
@@ -13,6 +13,7 @@ mod util;
|
||||
mod trai;
|
||||
mod asm_fn;
|
||||
mod asm_block;
|
||||
mod asm_instr;
|
||||
|
||||
pub use block::*;
|
||||
pub use expr::*;
|
||||
@@ -28,6 +29,7 @@ pub use trai::*;
|
||||
pub use op::*;
|
||||
pub use asm_fn::*;
|
||||
pub use asm_block::*;
|
||||
pub use asm_instr::*;
|
||||
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1,79 +1,70 @@
|
||||
use super::{
|
||||
AsmFunction, Function, Impl, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
|
||||
Struct, Symbol, Token, TokenCursor, Trait,
|
||||
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg,
|
||||
PStruct, Symbol, Token, PTrait,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub struct Module {
|
||||
pub traits: Vec<Node<Trait>>,
|
||||
pub structs: Vec<Node<Struct>>,
|
||||
pub functions: Vec<Node<Function>>,
|
||||
pub asm_fns: Vec<Node<AsmFunction>>,
|
||||
pub impls: Vec<Node<Impl>>,
|
||||
pub struct PModule {
|
||||
pub traits: Vec<Node<PTrait>>,
|
||||
pub structs: Vec<Node<PStruct>>,
|
||||
pub functions: Vec<Node<PFunction>>,
|
||||
pub impls: Vec<Node<PImpl>>,
|
||||
}
|
||||
|
||||
impl Parsable for Module {
|
||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||
impl Parsable for PModule {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let mut functions = Vec::new();
|
||||
let mut structs = Vec::new();
|
||||
let mut traits = Vec::new();
|
||||
let mut impls = Vec::new();
|
||||
let mut asm_fns = Vec::new();
|
||||
loop {
|
||||
let Some(next) = cursor.peek() else {
|
||||
let Some(next) = ctx.peek() else {
|
||||
break;
|
||||
};
|
||||
if let Token::Keyword(kw) = next.token {
|
||||
match kw {
|
||||
Keyword::Fn => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
functions.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword::Struct => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
structs.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword::Trait => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
traits.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword::Impl => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
impls.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword::Asm => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
asm_fns.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
errors.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||
cursor.next();
|
||||
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||
ctx.next();
|
||||
}
|
||||
}
|
||||
} else if next.is_symbol(Symbol::Semicolon) {
|
||||
errors.hint(ParserMsg::from_instances(
|
||||
ctx.hint(ParserMsg::from_instances(
|
||||
&[next],
|
||||
"unneeded semicolon".to_string(),
|
||||
));
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
} else {
|
||||
errors.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||
cursor.next();
|
||||
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||
ctx.next();
|
||||
}
|
||||
}
|
||||
ParseResult::Ok(Self {
|
||||
@@ -81,12 +72,11 @@ impl Parsable for Module {
|
||||
structs,
|
||||
traits,
|
||||
impls,
|
||||
asm_fns,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Module {
|
||||
impl Debug for PModule {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for st in &self.structs {
|
||||
st.fmt(f)?;
|
||||
@@ -104,10 +94,6 @@ impl Debug for Module {
|
||||
func.fmt(f)?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
for func in &self.asm_fns {
|
||||
func.fmt(f)?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{Symbol, Token};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BinaryOp {
|
||||
pub enum PInfixOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
@@ -12,7 +12,7 @@ pub enum BinaryOp {
|
||||
Assign,
|
||||
}
|
||||
|
||||
impl BinaryOp {
|
||||
impl PInfixOp {
|
||||
pub fn presedence(&self) -> u32 {
|
||||
match self {
|
||||
Self::Assign => 0,
|
||||
@@ -69,7 +69,7 @@ pub enum UnaryOp {
|
||||
Deref,
|
||||
}
|
||||
|
||||
impl BinaryOp {
|
||||
impl PInfixOp {
|
||||
pub fn from_token(token: &Token) -> Option<Self> {
|
||||
let Token::Symbol(symbol) = token else {
|
||||
return None;
|
||||
|
||||
@@ -1,51 +1,45 @@
|
||||
use super::{
|
||||
Expr, Keyword, Node, Parsable, ParseResult, ParserOutput, Symbol, Token, TokenCursor, VarDef,
|
||||
};
|
||||
use std::fmt::{Debug, Write};
|
||||
use super::{PExpr, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, Token, PVarDef};
|
||||
|
||||
pub enum Statement {
|
||||
Let(Node<VarDef>, Node<Expr>),
|
||||
Return(Node<Expr>),
|
||||
Expr(Node<Expr>),
|
||||
pub enum PStatement {
|
||||
Let(Node<PVarDef>, Node<PExpr>),
|
||||
Return(Node<PExpr>),
|
||||
Expr(Node<PExpr>),
|
||||
}
|
||||
|
||||
impl Parsable for Statement {
|
||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PStatement {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
match next.token {
|
||||
Token::Keyword(Keyword::Let) => {
|
||||
cursor.next();
|
||||
let def = Node::parse(cursor, errors)?;
|
||||
cursor.expect_sym(Symbol::Equals)?;
|
||||
Node::parse(cursor, errors).map(|expr| Self::Let(def, expr))
|
||||
ctx.next();
|
||||
let def = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::Equals)?;
|
||||
ctx.parse().map(|expr| Self::Let(def, expr))
|
||||
}
|
||||
Token::Keyword(Keyword::Return) => {
|
||||
cursor.next();
|
||||
Node::parse(cursor, errors).map(Self::Return)
|
||||
ctx.next();
|
||||
ctx.parse().map(Self::Return)
|
||||
}
|
||||
_ => Node::parse(cursor, errors).map(Self::Expr),
|
||||
_ => ctx.parse().map(Self::Expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Statement {
|
||||
impl std::fmt::Debug for PStatement {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Statement::Let(n, e) => {
|
||||
PStatement::Let(n, e) => {
|
||||
f.write_str("let ")?;
|
||||
n.fmt(f)?;
|
||||
f.write_str(" = ")?;
|
||||
e.fmt(f)?;
|
||||
f.write_char(';')?;
|
||||
}
|
||||
Statement::Return(e) => {
|
||||
PStatement::Return(e) => {
|
||||
f.write_str("return ")?;
|
||||
e.fmt(f)?;
|
||||
f.write_char(';')?;
|
||||
}
|
||||
Statement::Expr(e) => {
|
||||
PStatement::Expr(e) => {
|
||||
e.fmt(f)?;
|
||||
f.write_char(';')?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{
|
||||
util::parse_list, Ident, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
|
||||
Symbol, TokenCursor, Type, VarDef,
|
||||
util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol,
|
||||
PType, PVarDef,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Struct {
|
||||
pub name: Node<Ident>,
|
||||
pub fields: StructFields,
|
||||
pub struct PStruct {
|
||||
pub name: Node<PIdent>,
|
||||
pub fields: PStructFields,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StructFields {
|
||||
Named(Vec<Node<VarDef>>),
|
||||
Tuple(Vec<Node<Type>>),
|
||||
pub enum PStructFields {
|
||||
Named(Vec<Node<PVarDef>>),
|
||||
Tuple(Vec<Node<PType>>),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Parsable for Struct {
|
||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||
cursor.expect_kw(Keyword::Struct)?;
|
||||
let name = Node::parse(cursor, errors)?;
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PStruct {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Struct)?;
|
||||
let name = ctx.parse()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||
cursor.next();
|
||||
StructFields::None
|
||||
ctx.next();
|
||||
PStructFields::None
|
||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||
cursor.next();
|
||||
StructFields::Named(parse_list(cursor, errors, Symbol::CloseCurly)?)
|
||||
ctx.next();
|
||||
PStructFields::Named(parse_list(ctx, Symbol::CloseCurly)?)
|
||||
} else if next.is_symbol(Symbol::OpenParen) {
|
||||
cursor.next();
|
||||
StructFields::Tuple(parse_list(cursor, errors, Symbol::CloseParen)?)
|
||||
ctx.next();
|
||||
PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
|
||||
} else {
|
||||
errors.err(ParserMsg::unexpected_token(next, "`;`, `(`, or `{`"));
|
||||
return ParseResult::Recover(Struct {
|
||||
let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`");
|
||||
ctx.err(msg);
|
||||
return ParseResult::Recover(PStruct {
|
||||
name,
|
||||
fields: StructFields::None,
|
||||
fields: PStructFields::None,
|
||||
});
|
||||
};
|
||||
ParseResult::Ok(Struct { name, fields })
|
||||
ParseResult::Ok(PStruct { name, fields })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
use super::{util::{parse_list, parse_list_nosep}, Function, FunctionHeader, Ident, Keyword, Node, Parsable, Symbol, Type};
|
||||
use super::{
|
||||
util::{parse_list, parse_list_nosep},
|
||||
PFunction, PFunctionHeader, PIdent, Keyword, Node, Parsable, ParserCtx, Symbol, PType,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Trait {
|
||||
pub name: Node<Ident>,
|
||||
pub fns: Vec<Node<FunctionHeader>>
|
||||
pub struct PTrait {
|
||||
pub name: Node<PIdent>,
|
||||
pub fns: Vec<Node<PFunctionHeader>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Impl {
|
||||
pub trait_: Node<Type>,
|
||||
pub for_: Node<Type>,
|
||||
pub fns: Vec<Node<Function>>
|
||||
pub struct PImpl {
|
||||
pub trait_: Node<PType>,
|
||||
pub for_: Node<PType>,
|
||||
pub fns: Vec<Node<PFunction>>,
|
||||
}
|
||||
|
||||
impl Parsable for Trait {
|
||||
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> {
|
||||
cursor.expect_kw(Keyword::Trait)?;
|
||||
let name = Node::parse(cursor, errors)?;
|
||||
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||
let fns = parse_list(cursor, errors, Symbol::CloseCurly)?;
|
||||
super::ParseResult::Ok(Self {name, fns})
|
||||
impl Parsable for PTrait {
|
||||
fn parse(ctx: &mut ParserCtx) -> super::ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Trait)?;
|
||||
let name = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
let fns = parse_list(ctx, Symbol::CloseCurly)?;
|
||||
super::ParseResult::Ok(Self { name, fns })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Impl {
|
||||
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> {
|
||||
cursor.expect_kw(Keyword::Impl)?;
|
||||
let trait_ = Node::parse(cursor, errors)?;
|
||||
cursor.expect_kw(Keyword::For)?;
|
||||
let for_ = Node::parse(cursor, errors)?;
|
||||
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||
let fns = parse_list_nosep(cursor, errors, Symbol::CloseCurly)?;
|
||||
super::ParseResult::Ok(Self {trait_, for_, fns})
|
||||
impl Parsable for PImpl {
|
||||
fn parse(ctx: &mut ParserCtx) -> super::ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Impl)?;
|
||||
let trait_ = ctx.parse()?;
|
||||
ctx.expect_kw(Keyword::For)?;
|
||||
let for_ = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
let fns = parse_list_nosep(ctx, Symbol::CloseCurly)?;
|
||||
super::ParseResult::Ok(Self { trait_, for_, fns })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{util::parse_list, Node, Parsable, ParseResult, ParserMsg, Symbol, Token};
|
||||
use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token};
|
||||
|
||||
pub struct Type {
|
||||
pub struct PType {
|
||||
pub name: String,
|
||||
pub args: Vec<Node<Type>>,
|
||||
pub args: Vec<Node<PType>>,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
impl PType {
|
||||
pub fn unit() -> Self {
|
||||
Self {
|
||||
name: "()".to_string(),
|
||||
@@ -16,15 +16,12 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Type {
|
||||
fn parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
errors: &mut super::ParserOutput,
|
||||
) -> ParseResult<Self> {
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PType {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
let res = if next.is_symbol(Symbol::Ampersand) {
|
||||
cursor.next();
|
||||
let arg = Node::parse(cursor, errors)?;
|
||||
ctx.next();
|
||||
let arg = ctx.parse()?;
|
||||
Self {
|
||||
name: "&".to_string(),
|
||||
args: vec![arg],
|
||||
@@ -34,12 +31,12 @@ impl Parsable for Type {
|
||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier"));
|
||||
};
|
||||
let n = name.to_string();
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
let mut args = Vec::new();
|
||||
if let Some(next) = cursor.peek() {
|
||||
if let Some(next) = ctx.peek() {
|
||||
if next.is_symbol(Symbol::OpenAngle) {
|
||||
cursor.next();
|
||||
args = parse_list(cursor, errors, Symbol::CloseAngle)?;
|
||||
ctx.next();
|
||||
args = parse_list(ctx, Symbol::CloseAngle)?;
|
||||
}
|
||||
}
|
||||
Self { name: n, args }
|
||||
@@ -48,7 +45,7 @@ impl Parsable for Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Type {
|
||||
impl Debug for PType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.name)?;
|
||||
if self.name == "&" {
|
||||
|
||||
@@ -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>(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
ctx: &mut ParserCtx,
|
||||
sep: Symbol,
|
||||
end: Symbol,
|
||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||
let mut vals = Vec::new();
|
||||
loop {
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
if next.is_symbol(end) {
|
||||
break;
|
||||
}
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
vals.push(res.node);
|
||||
if res.recover {
|
||||
cursor.seek_syms(&[end, sep]);
|
||||
ctx.seek_syms(&[end, sep]);
|
||||
}
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
if !next.is_symbol(sep) {
|
||||
break;
|
||||
}
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
}
|
||||
cursor.expect_sym(end)?;
|
||||
ctx.expect_sym(end)?;
|
||||
Ok(vals)
|
||||
}
|
||||
|
||||
pub fn parse_list<T: Parsable>(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
ctx: &mut ParserCtx,
|
||||
end: Symbol,
|
||||
) -> 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>(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
ctx: &mut ParserCtx,
|
||||
end: Symbol,
|
||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||
let mut vals = Vec::new();
|
||||
loop {
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
if next.is_symbol(end) {
|
||||
break;
|
||||
}
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
vals.push(res.node);
|
||||
if res.recover {
|
||||
cursor.seek_sym(end);
|
||||
ctx.seek_sym(end);
|
||||
}
|
||||
}
|
||||
cursor.expect_sym(end)?;
|
||||
ctx.expect_sym(end)?;
|
||||
Ok(vals)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use crate::ir::FilePos;
|
||||
|
||||
use super::{Node, ParserMsg, ParserOutput, TokenCursor};
|
||||
use super::{Node, ParserCtx, ParserMsg};
|
||||
|
||||
pub enum ParseResult<T> {
|
||||
Ok(T),
|
||||
@@ -33,6 +33,7 @@ impl<T> Try for ParseResult<T> {
|
||||
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
||||
match self {
|
||||
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::Err(e) => ControlFlow::Break(Some(e)),
|
||||
ParseResult::SubErr => ControlFlow::Break(None),
|
||||
@@ -111,29 +112,26 @@ impl<T> FromResidual for NodeParseResult<T> {
|
||||
}
|
||||
|
||||
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 {
|
||||
fn maybe_parse(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
) -> Result<Option<Self>, ParserMsg>;
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg>;
|
||||
}
|
||||
|
||||
impl<T: Parsable> Node<T> {
|
||||
pub fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> NodeParseResult<T> {
|
||||
let start = cursor.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
|
||||
let (inner, recover) = match T::parse(cursor, output) {
|
||||
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
|
||||
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
|
||||
let (inner, recover) = match T::parse(ctx) {
|
||||
ParseResult::Ok(v) => (Some(v), false),
|
||||
ParseResult::Recover(v) => (Some(v), true),
|
||||
ParseResult::Err(e) => {
|
||||
output.err(e);
|
||||
ctx.err(e);
|
||||
(None, true)
|
||||
}
|
||||
ParseResult::SubErr => (None, true),
|
||||
};
|
||||
let end = cursor.prev_end();
|
||||
let end = ctx.prev_end();
|
||||
NodeParseResult {
|
||||
node: Self {
|
||||
inner,
|
||||
@@ -145,16 +143,16 @@ impl<T: Parsable> Node<T> {
|
||||
}
|
||||
|
||||
impl<T: MaybeParsable> Node<T> {
|
||||
pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> Option<Self> {
|
||||
let start = cursor.next_pos();
|
||||
let inner = match T::maybe_parse(cursor, errors) {
|
||||
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
|
||||
let start = ctx.next_start();
|
||||
let inner = match T::maybe_parse(ctx) {
|
||||
Ok(v) => Some(v?),
|
||||
Err(e) => {
|
||||
errors.err(e);
|
||||
ctx.err(e);
|
||||
None
|
||||
}
|
||||
};
|
||||
let end = cursor.prev_end();
|
||||
let end = ctx.prev_end();
|
||||
Some(Self {
|
||||
inner,
|
||||
span: start.to(end),
|
||||
@@ -163,15 +161,15 @@ impl<T: MaybeParsable> Node<T> {
|
||||
}
|
||||
|
||||
pub trait NodeParsable {
|
||||
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self>
|
||||
fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
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
|
||||
Self: Sized,
|
||||
{
|
||||
Node::<Self>::parse(cursor, errors)
|
||||
Node::<Self>::parse(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{iter::Peekable, str::Chars};
|
||||
|
||||
use crate::ir::FilePos;
|
||||
use super::super::ParserMsg;
|
||||
use crate::ir::FilePos;
|
||||
|
||||
pub struct CharCursor<'a> {
|
||||
chars: Peekable<Chars<'a>>,
|
||||
|
||||
@@ -9,6 +9,7 @@ pub enum Keyword {
|
||||
Impl,
|
||||
For,
|
||||
Asm,
|
||||
Funne,
|
||||
}
|
||||
|
||||
impl Keyword {
|
||||
@@ -23,6 +24,7 @@ impl Keyword {
|
||||
"trait" => Self::Trait,
|
||||
"impl" => Self::Impl,
|
||||
"asm" => Self::Asm,
|
||||
"funne" => Self::Funne,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user