diff --git a/Cargo.lock b/Cargo.lock index 9065268..f414fc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,5 +3,5 @@ version = 4 [[package]] -name = "lang" +name = "v2" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index defb8fc..4aef852 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,6 @@ [package] -name = "lang" +name = "v2" version = "0.1.0" -edition = "2021" +edition = "2024" + +[dependencies] diff --git a/README.md b/README.md deleted file mode 100644 index 9f31e6a..0000000 --- a/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# the - -my child (programming language) - -everything is subject to change rn, and this probably isn't up to date -also nothing is super well tested right now so I'm sure there are bugs I don't think exist - -`cargo run -- data/test.lang` - -currently working!!: -- functions (arguments, returning) -- assembly blocks (input, output for expression) -- structs (construction, field access, modifying, nesting) - -todo: -- generics (groundwork is there I think) -- traits (unsure exactly how I wanna do this, either way need number ones) -- actually handle jumps & LIs that are too large -- iterators? -- borrow checking -- basic optimization: use registers, remove temp var moves -- Cow str diff --git a/data/err.lang b/data/err.lang deleted file mode 100644 index 62409c4..0000000 --- a/data/err.lang +++ /dev/null @@ -1,35 +0,0 @@ -fn main() { - // let x = 3; - let y = 4 + 4 + 5; - let z = 1 * 2 - 3 / test * 4; - let r = 1-2.5 + 3; - let w = 1 * (2 - 3) / "test" - 7 - let a = test('3'); - let c = '3' ; - test(5); - return 5 + - - a; - r = )!!; - r = !3; - r = 3 + !; - let b = (test2.func)(3 + 4)(8)("a"); - let x = { - return 5; - let a = 3; - b - }; - exit(3, let, "hello"); -} - -fn test() { - let r = 3; - let a = } -} - -fn test2() { - let a anerit; -} - -fn test3() { - let x = 3 diff --git a/data/test.lang b/data/test.lang deleted file mode 100644 index 6a1e4f8..0000000 --- a/data/test.lang +++ /dev/null @@ -1,273 +0,0 @@ -println("testy"); -let x = 3; -print_dec(x); -subtest(); -start(); - -fn subtest() { - fn el() { - println("helo el"); - } - el(); -} - -struct Test { - a: 64, - b: 64, - c: 64, -} - -struct Test2 { - a: 64, - b: Test, - c: Test, -} - -fn start() { - println("Helld!"); - print_hex(rem(10, 7)); - println(""); - println("Hello World!!!!!"); - thinger(); - let x = 3; - if not(not(lt(x, 5))) { - println("tada!"); - }; - println("before:"); - x = 0; - loop { - if not(lt(x, 10)) { - break; - }; - println("RAAAAA"); - x = add(x, 1); - }; - println("after"); - let infer_me: slice<_> = "hello"; - print(tester()); - let test: Test = Test { - a: 10, - b: 4, - c: 0, - }; - structer(test); - arger("a", "b", "c"); - let z = sub(test.a, 10); - print_hex(add(mul(sub(add(10, test.b), 1), 3), z)); - print("test: 0x"); - print_hex(31); - println(""); - generic(); - exit(0); -} - -fn structer(test: Test) { - print("test {\n a: "); - print_dec(test.a); - print("\n b: "); - print_dec(test.b); - print("\n c: "); - print_dec(test.c); - println("\n}"); - print("update c: "); - test.c = add(test.a, test.b); - print_dec(test.c); - println(""); - - let test2: Test2 = Test2 { - a: 3, - b: test, - c: test, - }; - test2.c.c = 20; - print("test2.b.c: "); - print_dec(test2.b.c); - println(""); - print("test2.c.c: "); - print_dec(test2.c.c); - println(""); -} - -struct GTest { - a: T, - b: U, - c: V, -} - -fn generic() { - let gt = GTest { - a: 39, - b: "hello", - c: 40, - }; - print("generic: "); - print_dec(gt.a); - print(", "); - print(gt.b); - print_dec(gt.c); - println(""); -} - -fn thinger() { - print("estamos jugando\n"); -} - -fn unused() { - print("el unused\n"); -} - -fn println(msg: slice<8>) { - print(msg); - print("\n"); -} - -fn print(msg: slice<8>) { - asm (a1 = msg@) { - ld a2, 8, a1 - ld a1, 0, a1 - li a0, 1 - li a7, 64 - ecall - } -} - -fn print_hex(x: 64) { - let i = 64; - loop { - i = sub(i, 4); - let c = and(shr(x, i), 15); - if gt(c, 9) { - c = add(c, 7); - }; - c = add(c, 48); - asm (a1 = c@) { - li a2, 1 - li a0, 1 - li a7, 64 - ecall - }; - if lt(i, 1) { - break; - }; - } -} - -fn print_dec(x: 64) { - let i = 1; - loop { - if gt(i, x) { - if lt(i, 2) { - print("0"); - return; - }; - break; - }; - i = mul(i, 10); - }; - let found = 0; - loop { - i = div(i, 10); - let c = rem(div(x, i), 10); - if and(lt(c, 1), not(found)) { - continue; - }; - found = 1; - if gt(c, 9) { - c = add(c, 7); - }; - c = add(c, 48); - asm (a1 = c@) { - li a2, 1 - li a0, 1 - li a7, 64 - ecall - }; - if lt(i, 2) { - break; - }; - }; - if not(found) { - print("0"); - } -} - -fn add(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - add t0, t0, t1 - } -} - -fn mul(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - mul t0, t0, t1 - } -} - -fn div(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - div t0, t0, t1 - } -} - -fn sub(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - sub t0, t0, t1 - } -} - -fn rem(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - rem t0, t0, t1 - } -} - -fn shr(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - srl t0, t0, t1 - } -} - -fn shl(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - sll t0, t0, t1 - } -} - -fn lt(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - slt t0, t0, t1 - } -} - -fn gt(a: 64, b: 64) -> 64 { - lt(b, a) -} - -fn and(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - and t0, t0, t1 - } -} - -fn not(a: 64) -> 64 { - asm (t0 = a, out = t0) { - xori t0, t0, 1 - } -} - -fn arger(a: slice<8>, b: slice<8>, c: slice<8>) { - print(a); - print(b); - println(c); -} - -fn exit(status: 64) { - asm (a0 = status) { - li a7, 93 - ecall - }; -} - -fn tester() -> slice<8> { - "hola\n" -} diff --git a/data/test2.lang b/data/test2.lang deleted file mode 100644 index 206dd8e..0000000 --- a/data/test2.lang +++ /dev/null @@ -1,6 +0,0 @@ -import util; - -util.println("hello!"); -let x = 39; -util.exit(x); - diff --git a/data/util.lang b/data/util.lang deleted file mode 100644 index 8fba2eb..0000000 --- a/data/util.lang +++ /dev/null @@ -1,146 +0,0 @@ -fn exit(status: 64) { - asm (a0 = status) { - li a7, 93 - ecall - }; -} - -fn println(msg: slice<8>) { - print(msg); - print("\n"); -} - -fn print(msg: slice<8>) { - asm (a1 = msg@) { - ld a2, 8, a1 - ld a1, 0, a1 - li a0, 1 - li a7, 64 - ecall - } -} - -fn print_hex(x: 64) { - let i = 64; - loop { - i = sub(i, 4); - let c = and(shr(x, i), 15); - if gt(c, 9) { - c = add(c, 7); - }; - c = add(c, 48); - asm (a1 = c@) { - li a2, 1 - li a0, 1 - li a7, 64 - ecall - }; - if lt(i, 1) { - break; - }; - } -} - -fn print_dec(x: 64) { - let i = 1; - loop { - if gt(i, x) { - if lt(i, 2) { - print("0"); - return; - }; - break; - }; - i = mul(i, 10); - }; - let found = 0; - loop { - i = div(i, 10); - let c = rem(div(x, i), 10); - if and(lt(c, 1), not(found)) { - continue; - }; - found = 1; - if gt(c, 9) { - c = add(c, 7); - }; - c = add(c, 48); - asm (a1 = c@) { - li a2, 1 - li a0, 1 - li a7, 64 - ecall - }; - if lt(i, 2) { - break; - }; - }; - if not(found) { - print("0"); - } -} - -fn add(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - add t0, t0, t1 - } -} - -fn mul(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - mul t0, t0, t1 - } -} - -fn div(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - div t0, t0, t1 - } -} - -fn sub(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - sub t0, t0, t1 - } -} - -fn rem(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - rem t0, t0, t1 - } -} - -fn shr(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - srl t0, t0, t1 - } -} - -fn shl(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - sll t0, t0, t1 - } -} - -fn lt(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - slt t0, t0, t1 - } -} - -fn gt(a: 64, b: 64) -> 64 { - lt(b, a) -} - -fn and(a: 64, b: 64) -> 64 { - asm (t0 = a, t1 = b, out = t0) { - and t0, t0, t1 - } -} - -fn not(a: 64) -> 64 { - asm (t0 = a, out = t0) { - xori t0, t0, 1 - } -} - diff --git a/ideas b/ideas deleted file mode 100644 index 86979fc..0000000 --- a/ideas +++ /dev/null @@ -1,51 +0,0 @@ -resolution overview - loop { - resolve idents - resolve + type check / match instructions - URes.resolve(errs) can return: failed, ok(id), waiting - each instruction keeps track of progress - eg. fns: match each arg - updates to whether it's waiting or finished: ok or err - only finish if no sub tasks are waiting - finished = "macro ready" - run macros / code modification on "macro ready" (fns, structs) - eg. insert instructions - hygienic; only take in from scope - add inserted instructions to unresolved list - finished = "analysis ready" - analysis on "analysis ready" fns - eg. does this return in all code paths - finished + all correct = "ready to lower" - lower "ready to lower" fns - run lowered const fns / var expressions - } - - -move names into separate vec with origins? -make struct fields a vec, resolve to index? - -inner values that auto generate map function: - enum Thing { - A(T), - B(T, T), - C - } -or - #[derive(Map(T))] - enum Thing { ... } - // scoping here is bad :woozy: - - -{([< -std::Option:(u32)::Some(3) -func:(u32)("hello", test, 3); -std::Option:[u32]::Some(3) -func:[T]("hello", test, 3); -std::Option::::Some(3) -func::(3) -std.Option.[u32].Some(3) -func.[T]("hello", test, 3); -std::Option:::Some(3) -func:(3) - - diff --git a/src/common/file.rs b/src/common/file.rs deleted file mode 100644 index 52fce47..0000000 --- a/src/common/file.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::{collections::HashMap, path::PathBuf}; - -pub type FileID = usize; -pub type FileMap = HashMap; - -#[derive(Debug, Clone)] -pub struct SrcFile { - pub path: PathBuf, - pub text: String, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct FilePos { - pub file: FileID, - pub line: usize, - pub col: usize, -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct FileSpan { - pub file: FileID, - pub start: FilePos, - pub end: FilePos, -} - -impl FilePos { - pub fn start(file: FileID) -> Self { - Self { - line: 0, - col: 0, - file, - } - } -} - -impl FilePos { - pub fn to(self, end: FilePos) -> FileSpan { - FileSpan { - start: self, - end, - file: self.file, - } - } - pub fn char_span(self) -> FileSpan { - FileSpan::at(self) - } -} - -const BEFORE: usize = 1; -const AFTER: usize = 0; - -impl FileSpan { - const BUILTIN_FILE: usize = usize::MAX; - pub fn at(pos: FilePos) -> Self { - Self { - start: pos, - end: pos, - file: pos.file, - } - } - pub fn builtin() -> Self { - let pos = FilePos { - file: Self::BUILTIN_FILE, - line: 0, - col: 0, - }; - Self::at(pos) - } - pub fn is_builtin(&self) -> bool { - self.file == Self::BUILTIN_FILE - } - pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { - if self.is_builtin() { - return Ok(()); - } - let start = self.start.line.saturating_sub(BEFORE); - let num_before = self.start.line - start; - let mut lines = file.lines().skip(start); - let width = format!("{}", self.end.line + AFTER).len(); - let same_line = self.start.line == self.end.line; - for i in 0..num_before { - writeln!(writer, "{:>width$} | {}", start + i, lines.next().unwrap())?; - } - let line = lines.next().unwrap(); - writeln!(writer, "{:>width$} | {}", self.start.line, line)?; - let len = if same_line { - self.end.col - self.start.col + 1 - } else { - line.len() - self.start.col - }; - writeln!( - writer, - "{} | {}", - " ".repeat(width), - " ".repeat(self.start.col) + &"^".repeat(len) - )?; - if !same_line { - for _ in 0..self.end.line - self.start.line - 1 { - lines.next(); - } - let line = lines.next().unwrap(); - writeln!(writer, "{:>width$} | {}", self.end.line, line)?; - writeln!( - writer, - "{} | {}", - " ".repeat(width), - "^".repeat(self.end.col + 1) - )?; - } - // for i in 0..AFTER { - // if let Some(next) = lines.next() { - // writeln!(writer, "{:>width$} | {}", self.end.line + i + 1, next)?; - // } - // } - Ok(()) - } -} diff --git a/src/common/mod.rs b/src/common/mod.rs deleted file mode 100644 index 7a3c486..0000000 --- a/src/common/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod output; -mod file; - -pub use output::*; -pub use file::*; diff --git a/src/common/output.rs b/src/common/output.rs deleted file mode 100644 index 7b1f4fe..0000000 --- a/src/common/output.rs +++ /dev/null @@ -1,73 +0,0 @@ -use super::{FileMap, FilePos, FileSpan}; - -#[derive(Debug, Clone)] -pub struct CompilerMsg { - pub msg: String, - pub spans: Vec, -} - -pub struct CompilerOutput { - pub file_map: FileMap, - pub errs: Vec, - pub hints: Vec, -} - -impl CompilerMsg { - pub fn from_msg(msg: String) -> Self { - Self { - msg, - spans: Vec::new(), - } - } - pub fn new(msg: String, span: FileSpan) -> Self { - Self { - msg, - spans: vec![span], - } - } - pub fn at(pos: FilePos, msg: String) -> Self { - Self { - msg, - spans: vec![FileSpan::at(pos)], - } - } - pub fn write_to( - &self, - ty: &str, - writer: &mut impl std::io::Write, - map: &FileMap, - ) -> std::io::Result<()> { - let after = if self.spans.is_empty() { "" } else { ":" }; - writeln!(writer, "{}: {}{}", ty, self.msg, after)?; - for span in &self.spans { - let file = map.get(&span.file).expect("unknown file id"); - writeln!(writer, "{:?}", &file.path)?; - span.write_for(writer, &file.text)?; - } - Ok(()) - } -} - -impl CompilerOutput { - pub fn new() -> Self { - Self { - errs: Vec::new(), - hints: Vec::new(), - file_map: FileMap::new(), - } - } - pub fn err(&mut self, msg: CompilerMsg) { - self.errs.push(msg); - } - pub fn hint(&mut self, msg: CompilerMsg) { - self.hints.push(msg); - } - pub fn write_to(&self, out: &mut impl std::io::Write) { - for err in &self.errs { - err.write_to("error", out, &self.file_map).unwrap(); - } - for hint in &self.hints { - hint.write_to("hint", out, &self.file_map).unwrap(); - } - } -} diff --git a/src/compiler/arch/mod.rs b/src/compiler/arch/mod.rs deleted file mode 100644 index fb27202..0000000 --- a/src/compiler/arch/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod riscv; diff --git a/src/compiler/arch/riscv/asm.rs b/src/compiler/arch/riscv/asm.rs deleted file mode 100644 index 123a554..0000000 --- a/src/compiler/arch/riscv/asm.rs +++ /dev/null @@ -1,357 +0,0 @@ -use crate::{ - compiler::program::{Addr, Instr, SymTable}, - ir::Symbol, - util::{Bits32, LabeledFmt}, -}; - -use super::*; - -#[derive(Clone, Copy)] -pub enum LinkerInstruction { - Op { - op: Funct3, - funct: Funct7, - dest: R, - src1: R, - src2: R, - }, - OpImm { - op: Funct3, - dest: R, - src: R, - imm: i32, - }, - OpImmF7 { - op: Funct3, - funct: Funct7, - dest: R, - src: R, - imm: i32, - }, - Store { - width: Funct3, - src: R, - offset: i32, - base: R, - }, - Load { - width: Funct3, - dest: R, - offset: i32, - base: R, - }, - Mv { - dest: R, - src: R, - }, - La { - dest: R, - src: S, - }, - Jal { - dest: R, - offset: i32, - }, - Call(S), - J(S), - Branch { - to: S, - typ: Funct3, - left: R, - right: R, - }, - Ret, - ECall, - EBreak, - Li { - dest: R, - imm: i32, - }, -} -impl LinkerInstruction { - pub fn map(&self, r: impl Fn(&R) -> R2) -> LinkerInstruction { - self.try_map(|v| Some(r(v))).unwrap() - } - pub fn try_map(&self, r: impl Fn(&R) -> Option) -> Option> { - use LinkerInstruction as I; - Some(match self { - Self::ECall => I::ECall, - Self::EBreak => I::EBreak, - &Self::Li { ref dest, imm } => I::Li { dest: r(dest)?, imm }, - Self::Mv { ref dest, src } => I::Mv { - dest: r(dest)?, - src: r(src)?, - }, - Self::La { .. } => todo!(), - &Self::Load { - width, - ref dest, - ref base, - offset, - } => I::Load { - width, - dest: r(dest)?, - offset, - base: r(base)?, - }, - &Self::Store { - width, - ref src, - ref base, - offset, - } => I::Store { - width, - src: r(src)?, - offset, - base: r(base)?, - }, - &Self::Op { - op, - funct, - ref dest, - ref src1, - ref src2, - } => I::Op { - op, - funct, - dest: r(dest)?, - src1: r(src1)?, - src2: r(src2)?, - }, - &Self::OpImm { op, ref dest, ref src, imm } => I::OpImm { - op, - dest: r(dest)?, - src: r(src)?, - imm, - }, - &Self::OpImmF7 { - op, - funct, - ref dest, - ref src, - imm, - } => I::OpImmF7 { - op, - funct, - dest: r(dest)?, - src: r(src)?, - imm, - }, - Self::Ret => I::Ret, - Self::Call(..) => todo!(), - Self::Jal { .. } => todo!(), - Self::J(..) => todo!(), - Self::Branch { .. } => todo!(), - }) - } -} - -pub fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction { - opi(op32i::ADD, dest, src, imm.to_u()) -} - -pub fn ori(dest: Reg, src: Reg, imm: Bits32<11, 0>) -> RawInstruction { - opi(op32i::OR, dest, src, imm) -} - -impl Instr for LinkerInstruction { - fn push_to( - &self, - data: &mut Vec, - sym_map: &mut SymTable, - pos: Addr, - missing: bool, - ) -> Option { - let last = match self { - Self::Op { - op, - funct, - dest, - src1, - src2, - } => opr(*op, *funct, *dest, *src1, *src2), - Self::OpImm { op, dest, src, imm } => opi(*op, *dest, *src, BitsI32::new(*imm).to_u()), - Self::OpImmF7 { - op, - funct, - dest, - src, - imm, - } => opif7(*op, *funct, *dest, *src, BitsI32::new(*imm)), - Self::Store { - width, - src, - offset, - base, - } => store(*width, *src, BitsI32::new(*offset), *base), - Self::Load { - width, - dest, - offset, - base, - } => load(*width, *dest, BitsI32::new(*offset), *base), - Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)), - Self::La { dest, src } => { - if let Some(addr) = sym_map.get(*src) { - let offset = addr.val() as i32 - pos.val() as i32; - let sign = offset.signum(); - let mut lower = offset % 0x1000; - let mut upper = offset - lower; - if (((lower >> 11) & 1) == 1) ^ (sign == -1) { - let add = sign << 12; - upper += add; - lower = offset - upper; - } - assert!(upper + (lower << 20 >> 20) == offset); - data.extend(auipc(*dest, BitsI32::new(upper)).to_le_bytes()); - addi(*dest, *dest, BitsI32::new(lower)) - } else { - data.extend_from_slice(&[0; 2 * 4]); - return Some(*src); - } - } - Self::Jal { dest, offset } => jal(*dest, BitsI32::new(*offset)), - Self::J(sym) => { - if let Some(addr) = sym_map.get(*sym) { - let offset = addr.val() as i32 - pos.val() as i32; - j(BitsI32::new(offset)) - } else { - data.extend_from_slice(&[0; 4]); - return Some(*sym); - } - } - Self::Call(sym) => { - if let Some(addr) = sym_map.get(*sym) { - let offset = addr.val() as i32 - pos.val() as i32; - jal(ra, BitsI32::new(offset)) - } else { - data.extend_from_slice(&[0; 4]); - return Some(*sym); - } - } - Self::Ret => ret(), - Self::ECall => ecall(), - Self::EBreak => ebreak(), - Self::Li { dest, imm } => addi(*dest, zero, BitsI32::new(*imm)), - Self::Branch { - to, - typ, - left, - right, - } => { - if let Some(addr) = sym_map.get(*to) { - let offset = addr.val() as i32 - pos.val() as i32; - branch(*typ, *left, *right, BitsI32::new(offset)) - } else { - data.extend_from_slice(&[0; 4]); - return Some(*to); - } - } - }; - data.extend(last.to_le_bytes()); - None - } -} - -impl LinkerInstruction { - pub fn addi(dest: Reg, src: Reg, imm: i32) -> Self { - Self::OpImm { - op: op32i::ADD, - dest, - src, - imm, - } - } - pub fn sd(src: Reg, offset: i32, base: Reg) -> Self { - Self::Store { - width: width::D, - src, - offset, - base, - } - } - pub fn ld(dest: Reg, offset: i32, base: Reg) -> Self { - Self::Load { - width: width::D, - dest, - offset, - base, - } - } -} - -// this is not even remotely worth it but technically it doesn't use the heap I think xdddddddddd -impl std::fmt::Debug for LinkerInstruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.fmt_label(f, &|f, s| write!(f, "{s:?}")) - } -} - -pub struct DebugInstr<'a, R, S, L: Fn(&mut std::fmt::Formatter<'_>, &S) -> std::fmt::Result> { - instr: &'a LinkerInstruction, - label: &'a L, -} - -impl LabeledFmt for LinkerInstruction { - fn fmt_label( - &self, - f: &mut std::fmt::Formatter<'_>, - label: &dyn crate::util::Labeler, - ) -> std::fmt::Result { - match self { - Self::ECall => write!(f, "ecall"), - Self::EBreak => write!(f, "ebreak"), - 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:?}, @")?; - label(f, src) - } - Self::Load { - width, - dest, - offset, - base, - } => write!(f, "l{} {dest:?}, {offset}({base:?})", width::str(*width)), - Self::Store { - width, - src, - offset, - base, - } => write!(f, "s{} {src:?}, {offset}({base:?})", width::str(*width)), - Self::Op { - op, - funct, - dest, - src1, - src2, - } => write!(f, "{} {dest:?}, {src1:?}, {src2:?}", opstr(*op, *funct)), - Self::OpImm { op, dest, src, imm } => { - write!(f, "{}i {dest:?}, {src:?}, {imm}", opstr(*op, op32i::FUNCT7)) - } - Self::OpImmF7 { - op, - funct, - dest, - src, - imm, - } => write!(f, "{}i {dest:?}, {src:?}, {imm}", opstr(*op, *funct)), - Self::Jal { dest, offset } => write!(f, "jal {dest:?}, {offset:?}"), - Self::Call(s) => { - write!(f, "call ")?; - label(f, s) - } - Self::J(s) => { - write!(f, "j ")?; - label(f, s) - } - Self::Branch { - to, - typ, - left, - right, - } => write!(f, "b{} {left:?} {right:?} {to:?}", branch::str(*typ)), - Self::Ret => write!(f, "ret"), - } - } -} diff --git a/src/compiler/arch/riscv/compile.rs b/src/compiler/arch/riscv/compile.rs deleted file mode 100644 index 81184f2..0000000 --- a/src/compiler/arch/riscv/compile.rs +++ /dev/null @@ -1,224 +0,0 @@ -use std::collections::HashMap; - -use crate::{ - compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedFunction, UnlinkedProgram}, - ir::{arch::riscv64::RegRef, LInstruction as IRI, LProgram, Len, Size, VarID}, -}; - -use super::{LinkerInstruction as LI, *}; - -fn align(s: &Size) -> i32 { - (*s as i32 - 1).div_euclid(8) + 1 -} - -fn mov_mem( - v: &mut Vec
  • , - src: Reg, - src_offset: i32, - dest: Reg, - dest_offset: i32, - temp: Reg, - mut len: Len, -) { - let mut off = 0; - for width in width::MAIN.iter().rev().copied() { - let wl = width::len(width); - while len >= wl { - v.extend([ - LI::Load { - width, - dest: temp, - offset: src_offset + off, - base: src, - }, - LI::Store { - width, - src: temp, - offset: dest_offset + off, - base: dest, - }, - ]); - len -= wl; - off += wl as i32; - } - } -} - -pub fn compile(program: &LProgram) -> UnlinkedProgram
  • { - let mut fns = Vec::new(); - let mut data = Vec::new(); - let mut dbg = DebugInfo::new(program.labels().to_vec()); - for (sym, d) in program.ro_data() { - data.push((d.clone(), *sym)); - } - for (sym, f) in program.fns() { - let mut v = Vec::new(); - let mut stack = HashMap::new(); - let mut stack_len = 0; - let mut stack_ra = None; - let mut stack_rva = None; - if f.makes_call { - // return addr - stack_ra = Some(stack_len); - stack_len += 8; - } - for (id, s) in &f.stack { - stack.insert(id, stack_len); - stack_len += align(s); - } - for (id, s) in f.args.iter().rev() { - stack.insert(id, stack_len); - stack_len += align(s); - } - if f.ret_size > 0 { - stack_rva = Some(stack_len); - stack_len += align(&f.ret_size); - } - v.push(LI::addi(sp, sp, -stack_len)); - for (id, var) in &f.subvar_map { - // TODO: ALIGN DOES NOT MAKE SENSE HERE!!! need to choose to decide in lower or asm - stack.insert(id, stack[&var.id] + align(&var.offset)); - } - let has_stack = stack_len > 0; - if has_stack { - if let Some(stack_ra) = stack_ra { - v.push(LI::sd(ra, stack_ra, sp)); - } - } - let mut locations = HashMap::new(); - let mut irli = Vec::new(); - let mut ret = Vec::new(); - if has_stack { - if let Some(stack_ra) = stack_ra { - ret.push(LI::ld(ra, stack_ra, sp)); - } - ret.push(LI::addi(sp, sp, stack_len)); - } - ret.push(LI::Ret); - - for i in &f.instructions { - irli.push((v.len(), format!("{i:?}"))); - match i { - IRI::Mv { - dst: dest, - dst_offset: dest_offset, - src, - src_offset, - } => { - let s = align(&f.stack[src]) as u32; - mov_mem( - &mut v, - sp, - stack[src] + align(src_offset), - sp, - stack[dest] + align(dest_offset), - t0, - s, - ); - } - IRI::Ref { dst: dest, src } => { - v.push(LI::addi(t0, sp, stack[src])); - v.push(LI::sd(t0, stack[dest], sp)); - } - IRI::LoadAddr { - dst: dest, - offset, - src, - } => { - v.extend([ - LI::La { - dest: t0, - src: *src, - }, - LI::sd(t0, stack[dest] + *offset as i32, sp), - ]); - } - IRI::LoadData { - dst: dest, - offset, - src, - len, - } => { - v.push(LI::La { - dest: t0, - src: *src, - }); - mov_mem(&mut v, t0, 0, sp, stack[dest] + *offset as i32, t1, *len); - } - IRI::Call { dst: dest, f, args } => { - let mut offset = 0; - if let Some((dest, s)) = dest { - offset -= align(s); - v.push(LI::addi(t0, sp, stack[&dest])); - v.push(LI::sd(t0, offset, sp)) - } - for (arg, s) in args { - let bs = align(s); - offset -= bs; - mov_mem(&mut v, sp, stack[arg], sp, offset, t0, bs as Len); - } - v.push(LI::Call(*f)); - } - IRI::AsmBlock { - inputs, - outputs, - instructions, - } => { - for (reg, var) in inputs { - v.push(LI::ld(*reg, stack[var], sp)); - } - fn r(rr: &RegRef) -> Reg { - match rr { - RegRef::Var(..) => todo!(), - RegRef::Reg(reg) => *reg, - } - } - for i in instructions { - v.push(i.map(|v| r(v))); - } - for (reg, var) in outputs { - v.push(LI::sd(*reg, stack[var], sp)); - } - } - IRI::Ret { src } => { - if let Some(src) = src { - let Some(rva) = stack_rva else { - panic!("no return value address on stack!") - }; - v.push(LI::ld(t0, rva, sp)); - mov_mem(&mut v, sp, stack[src], t0, 0, t1, align(&f.ret_size) as u32); - } - v.extend(&ret); - } - IRI::Jump(location) => { - v.push(LI::J(*location)); - } - IRI::Branch { to, cond } => { - v.push(LI::ld(t0, stack[cond], sp)); - v.push(LI::Branch { - to: *to, - typ: branch::EQ, - left: t0, - right: zero, - }) - } - IRI::Mark(location) => { - locations.insert(v.len(), *location); - } - } - } - dbg.push_fn(irli); - fns.push(UnlinkedFunction { - instrs: v, - sym: *sym, - locations, - }); - } - UnlinkedProgram { - fns, - ro_data: data, - start: Some(program.entry()), - dbg, - sym_count: program.len(), - } -} diff --git a/src/compiler/arch/riscv/instr/base.rs b/src/compiler/arch/riscv/instr/base.rs deleted file mode 100644 index c061d29..0000000 --- a/src/compiler/arch/riscv/instr/base.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::{ - compiler::arch::riscv::Reg, - util::{Bits32, BitsI32}, -}; - -pub struct RawInstruction(u32); - -impl RawInstruction { - pub fn to_le_bytes(&self) -> impl IntoIterator { - self.0.to_le_bytes().into_iter() - } - pub fn to_be_bytes(&self) -> impl IntoIterator { - self.0.to_be_bytes().into_iter() - } -} - -pub const SYSTEM: u32 = 0b1110011; -pub const LOAD: u32 = 0b0000011; -pub const STORE: u32 = 0b0100011; -pub const AUIPC: u32 = 0b0010111; -pub const IMM_OP: u32 = 0b0010011; -pub const OP: u32 = 0b0110011; -pub const JAL: u32 = 0b1101111; -pub const JALR: u32 = 0b1100111; -pub const BRANCH: u32 = 0b1100011; - -pub type Funct3 = Bits32<2, 0>; -pub type Funct7 = Bits32<6, 0>; - -use RawInstruction as I; - -pub const fn r_type( - funct7: Bits32<6, 0>, - rs2: Reg, - rs1: Reg, - funct3: Bits32<2, 0>, - rd: Reg, - opcode: u32, -) -> I { - I((funct7.val() << 25) - + (rs2.val() << 20) - + (rs1.val() << 15) - + (funct3.val() << 12) - + (rd.val() << 7) - + opcode) -} -pub const fn i_type(imm: Bits32<11, 0>, rs1: Reg, funct: Funct3, rd: Reg, opcode: u32) -> I { - I((imm.val() << 20) + (rs1.val() << 15) + (funct.val() << 12) + (rd.val() << 7) + opcode) -} -pub const fn s_type(rs2: Reg, rs1: Reg, funct3: Funct3, imm: Bits32<11, 0>, opcode: u32) -> I { - I((imm.bits(11, 5) << 25) - + (rs2.val() << 20) - + (rs1.val() << 15) - + (funct3.val() << 12) - + (imm.bits(4, 0) << 7) - + opcode) -} -pub const fn b_type(rs2: Reg, rs1: Reg, funct3: Funct3, imm: Bits32<12, 1>, opcode: u32) -> I { - I((imm.bit(12) << 31) - + (imm.bits(10, 5) << 25) - + (rs2.val() << 20) - + (rs1.val() << 15) - + (funct3.val() << 12) - + (imm.bits(4, 1) << 8) - + (imm.bit(11) << 7) - + opcode) -} -pub const fn u_type(imm: Bits32<31, 12>, rd: Reg, opcode: u32) -> I { - I((imm.bits(31, 12) << 12) + (rd.val() << 7) + opcode) -} -pub const fn j_type(imm: Bits32<20, 1>, rd: Reg, opcode: u32) -> I { - I((imm.bit(20) << 31) - + (imm.bits(10, 1) << 21) - + (imm.bit(11) << 20) - + (imm.bits(19, 12) << 12) - + (rd.val() << 7) - + opcode) -} - -pub fn opr(op: Funct3, funct: Funct7, dest: Reg, src1: Reg, src2: Reg) -> I { - r_type(funct, src2, src1, op, dest, OP) -} -pub fn opi(op: Funct3, dest: Reg, src: Reg, imm: Bits32<11, 0>) -> RawInstruction { - i_type(imm, src, op, dest, IMM_OP) -} -pub fn opif7(op: Funct3, funct: Funct7, dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I { - i_type( - Bits32::new(imm.to_u().val() + (funct.val() << 5)), - src, - op, - dest, - IMM_OP, - ) -} diff --git a/src/compiler/arch/riscv/instr/mod.rs b/src/compiler/arch/riscv/instr/mod.rs deleted file mode 100644 index c398dbe..0000000 --- a/src/compiler/arch/riscv/instr/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -use super::*; - -mod base; -mod rv32i; -mod rv32m; -mod string; -pub use base::*; -pub use rv32i::*; -pub use rv32m::*; -pub use string::*; diff --git a/src/compiler/arch/riscv/instr/rv32i.rs b/src/compiler/arch/riscv/instr/rv32i.rs deleted file mode 100644 index be87993..0000000 --- a/src/compiler/arch/riscv/instr/rv32i.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::{compiler::arch::riscv::Reg, util::Bits32}; - -use super::*; - -pub mod op32i { - use super::*; - - pub const ADD: Funct3 = Funct3::new(0b000); - pub const SL: Funct3 = Funct3::new(0b001); - pub const SLT: Funct3 = Funct3::new(0b010); - pub const SLTU: Funct3 = Funct3::new(0b011); - pub const XOR: Funct3 = Funct3::new(0b100); - pub const SR: Funct3 = Funct3::new(0b101); - pub const OR: Funct3 = Funct3::new(0b110); - pub const AND: Funct3 = Funct3::new(0b111); - - pub const LOGICAL: Funct7 = Funct7::new(0b0000000); - pub const ARITHMETIC: Funct7 = Funct7::new(0b0100000); - pub const F7ADD: Funct7 = Funct7::new(0b0000000); - pub const F7SUB: Funct7 = Funct7::new(0b0100000); - - pub const FUNCT7: Funct7 = Funct7::new(0b0000000); -} - -pub mod width { - use crate::ir::Len; - - use super::*; - pub const MAIN: [Funct3; 4] = [B, H, W, D]; - - pub const B: Funct3 = Funct3::new(0b000); - pub const H: Funct3 = Funct3::new(0b001); - pub const W: Funct3 = Funct3::new(0b010); - pub const D: Funct3 = Funct3::new(0b011); - pub const BU: Funct3 = Funct3::new(0b100); - pub const HU: Funct3 = Funct3::new(0b101); - pub const WU: Funct3 = Funct3::new(0b110); - - pub const fn str(w: Funct3) -> &'static str { - match w { - B => "b", - H => "h", - W => "w", - D => "d", - BU => "bu", - HU => "hu", - WU => "wu", - _ => unreachable!(), - } - } - - pub const fn len(w: Funct3) -> Len { - match w { - B => 1, - H => 2, - W => 4, - D => 8, - BU => 1, - HU => 2, - WU => 4, - _ => unreachable!(), - } - } -} - -pub mod branch { - use super::*; - pub const EQ: Funct3 = Funct3::new(0b000); - pub const NE: Funct3 = Funct3::new(0b001); - pub const LT: Funct3 = Funct3::new(0b100); - pub const GE: Funct3 = Funct3::new(0b101); - pub const LTU: Funct3 = Funct3::new(0b110); - pub const GEU: Funct3 = Funct3::new(0b111); - - pub fn str(f: Funct3) -> &'static str { - match f { - EQ => "eq", - NE => "ne", - LT => "lt", - GE => "ge", - LTU => "ltu", - GEU => "geu", - _ => "?", - } - } -} - -pub const fn ecall() -> RawInstruction { - i_type(Bits32::new(0), zero, Bits32::new(0), zero, SYSTEM) -} -pub const fn ebreak() -> RawInstruction { - i_type(Bits32::new(1), zero, Bits32::new(0), zero, SYSTEM) -} -pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> RawInstruction { - u_type(imm.to_u(), dest, AUIPC) -} - -pub const fn load(width: Funct3, dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> RawInstruction { - i_type(offset.to_u(), base, width, dest, LOAD) -} - -pub const fn store(width: Funct3, src: Reg, offset: BitsI32<11, 0>, base: Reg) -> RawInstruction { - s_type(src, base, width, offset.to_u(), STORE) -} - -pub const fn jal(dest: Reg, offset: BitsI32<20, 1>) -> RawInstruction { - j_type(offset.to_u(), dest, JAL) -} -pub const fn jalr(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> RawInstruction { - i_type(offset.to_u(), base, Bits32::new(0), dest, JALR) -} - -pub const fn j(offset: BitsI32<20, 1>) -> RawInstruction { - jal(zero, offset) -} -pub const fn ret() -> RawInstruction { - jalr(zero, BitsI32::new(0), ra) -} - -pub const fn branch(typ: Funct3, left: Reg, right: Reg, offset: BitsI32<12, 1>) -> RawInstruction { - b_type(right, left, typ, offset.to_u(), BRANCH) -} diff --git a/src/compiler/arch/riscv/instr/rv32m.rs b/src/compiler/arch/riscv/instr/rv32m.rs deleted file mode 100644 index cebe3ba..0000000 --- a/src/compiler/arch/riscv/instr/rv32m.rs +++ /dev/null @@ -1,16 +0,0 @@ -use super::{Funct3, Funct7}; - -pub mod op32m { - use super::*; - pub const MUL: Funct3 = Funct3::new(0b000); - pub const MULH: Funct3 = Funct3::new(0b001); - pub const MULHSU: Funct3 = Funct3::new(0b010); - pub const MULHU: Funct3 = Funct3::new(0b011); - pub const DIV: Funct3 = Funct3::new(0b100); - pub const DIVU: Funct3 = Funct3::new(0b101); - pub const REM: Funct3 = Funct3::new(0b110); - pub const REMU: Funct3 = Funct3::new(0b111); - - pub const FUNCT7: Funct7 = Funct7::new(0b0000001); -} - diff --git a/src/compiler/arch/riscv/instr/string.rs b/src/compiler/arch/riscv/instr/string.rs deleted file mode 100644 index 51495d8..0000000 --- a/src/compiler/arch/riscv/instr/string.rs +++ /dev/null @@ -1,27 +0,0 @@ -use super::*; - -pub fn opstr(op: Funct3, funct: Funct7) -> &'static str { - match (op, funct) { - (op32i::SLT, op32i::FUNCT7) => "slt", - (op32i::SLTU, op32i::FUNCT7) => "sltu", - (op32i::XOR, op32i::FUNCT7) => "xor", - (op32i::OR, op32i::FUNCT7) => "or", - (op32i::AND, op32i::FUNCT7) => "and", - - (op32i::ADD, op32i::F7ADD) => "add", - (op32i::ADD, op32i::F7SUB) => "sub", - (op32i::SL, op32i::LOGICAL) => "sll", - (op32i::SR, op32i::LOGICAL) => "srl", - (op32i::SR, op32i::ARITHMETIC) => "sra", - - (op32m::MUL, op32m::FUNCT7) => "mul", - (op32m::MULH, op32m::FUNCT7) => "mulh", - (op32m::MULHSU, op32m::FUNCT7) => "mulhsu", - (op32m::MULHU, op32m::FUNCT7) => "mulhu", - (op32m::DIV, op32m::FUNCT7) => "div", - (op32m::DIVU, op32m::FUNCT7) => "divu", - (op32m::REM, op32m::FUNCT7) => "rem", - (op32m::REMU, op32m::FUNCT7) => "remu", - _ => "unknown", - } -} diff --git a/src/compiler/arch/riscv/mod.rs b/src/compiler/arch/riscv/mod.rs deleted file mode 100644 index 275dcdc..0000000 --- a/src/compiler/arch/riscv/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod asm; -mod compile; -mod reg; -mod instr; - -use crate::util::BitsI32; - -pub use asm::*; -pub use compile::*; -pub use reg::*; -pub use instr::*; diff --git a/src/compiler/arch/riscv/reg.rs b/src/compiler/arch/riscv/reg.rs deleted file mode 100644 index d76367a..0000000 --- a/src/compiler/arch/riscv/reg.rs +++ /dev/null @@ -1,180 +0,0 @@ -#![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); - -impl Reg { - #[inline] - pub const fn val(&self) -> u32 { - self.0 as u32 - } -} - -impl Reg { - pub fn from_str(str: &str) -> Option { - Some(match str { - "zero" => zero, - "ra" => ra, - "sp" => sp, - "gp" => gp, - "tp" => tp, - "t0" => t0, - "t1" => t1, - "t2" => t2, - "fp" => fp, - "s0" => s0, - "s1" => s1, - "a0" => a0, - "a1" => a1, - "a2" => a2, - "a3" => a3, - "a4" => a4, - "a5" => a5, - "a6" => a6, - "a7" => a7, - "s2" => s2, - "s3" => s3, - "s4" => s4, - "s5" => s5, - "s6" => s6, - "s7" => s7, - "s8" => s8, - "s9" => s9, - "s10" => s10, - "s11" => s11, - "t3" => t3, - "t4" => t4, - "t5" => t5, - "t6" => t6, - _ => { - return None; - } - }) - } -} - -impl std::fmt::Debug for Reg { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self.0 { - 0 => "zero", - 1 => "ra", - 2 => "sp", - 3 => "gp", - 4 => "tp", - 5 => "t0", - 6 => "t1", - 7 => "t2", - 8 => "fp", - 9 => "s1", - 10 => "a0", - 11 => "a1", - 12 => "a2", - 13 => "a3", - 14 => "a4", - 15 => "a5", - 16 => "a6", - 17 => "a7", - 18 => "s2", - 19 => "s3", - 20 => "s4", - 21 => "s5", - 22 => "s6", - 23 => "s7", - 24 => "s8", - 25 => "s9", - 26 => "s10", - 27 => "s11", - 28 => "t3", - 29 => "t4", - 30 => "t5", - 31 => "t6", - _ => "unknown", - } - ) - } -} - -// 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); - diff --git a/src/compiler/debug.rs b/src/compiler/debug.rs deleted file mode 100644 index 81d1d33..0000000 --- a/src/compiler/debug.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::ir::Symbol; - -pub struct DebugInfo { - pub sym_labels: Vec>, - pub ir_lower: Vec>, -} - -impl DebugInfo { - pub fn new(sym_labels: Vec>) -> Self { - Self { - ir_lower: Vec::new(), - sym_labels, - } - } - - pub fn push_fn(&mut self, instrs: Vec<(usize, String)>) { - self.ir_lower.push(instrs); - } - - pub fn sym_label(&self, s: Symbol) -> Option<&String> { - self.sym_labels[*s].as_ref() - } -} diff --git a/src/compiler/elf.rs b/src/compiler/elf.rs deleted file mode 100644 index 20ff70a..0000000 --- a/src/compiler/elf.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::{program::Addr, LinkedProgram}; - -#[repr(C)] -pub struct ELF64Header { - magic: u32, - class: u8, - endianness: u8, - ei_version: u8, - os_abi: u8, - os_abi_ver: u8, - pad: [u8; 7], - ty: u16, - machine: u16, - e_version: u32, - entry: u64, - program_header_offset: u64, - section_header_offset: u64, - flags: u32, - header_size: u16, - program_header_entry_size: u16, - program_header_num: u16, - section_header_entry_size: u16, - section_header_num: u16, - section_header_str_idx: u16, -} - -#[repr(C)] -pub struct ProgramHeader { - ty: u32, - flags: u32, - offset: u64, - vaddr: u64, - paddr: u64, - filesz: u64, - memsz: u64, - align: u64, -} - -#[repr(C)] -pub struct SectionHeader { - name_idx: u32, - ty: u32, - flags: u64, - addr: u64, - offset: u64, - size: u64, - link: u32, - info: u32, - addr_align: u64, - entry_size: u64, -} - -// this is currently specialized for riscv64; obviously add params later -pub fn create(program: &[u8], start_offset: Addr) -> Vec { - let addr_start = 0x1000; - let page_size = 0x1000; - // I don't know if I have to add addr_start here, idk how it maps the memory - let program_size = std::mem::size_of_val(program) as u64 + addr_start; - let program_header = ProgramHeader { - ty: 0x1, // LOAD - flags: 0b101, // executable, readable - offset: 0x0, - vaddr: addr_start, - paddr: addr_start, - filesz: program_size, - memsz: program_size, - align: page_size, - }; - let header_len = (size_of::() + size_of::()) as u64; - let program_pos = header_len; - let header = ELF64Header { - magic: 0x7f_45_4c_46u32.swap_bytes(), - class: 0x2, // 64 bit - endianness: 0x1, // little endian - ei_version: 0x1, - os_abi: 0x0, // system-v - os_abi_ver: 0x0, - pad: [0x0; 7], - ty: 0x2, // executable - machine: 0xf3, // risc-v - e_version: 0x1, - entry: addr_start + program_pos + start_offset.val(), - program_header_offset: size_of::() as u64, - section_header_offset: 0x0, - // C ABI (16 bit instruction align) + double precision floats - flags: 0x1 | 0x4, - header_size: size_of::() as u16, - program_header_entry_size: size_of::() as u16, - program_header_num: 0x1, - section_header_entry_size: size_of::() as u16, - section_header_num: 0x0, - section_header_str_idx: 0x0, - }; - let mut bytes: Vec = Vec::new(); - unsafe { - bytes.extend(as_u8_slice(&header)); - bytes.extend(as_u8_slice(&program_header)); - bytes.extend(program); - } - bytes -} - -unsafe fn as_u8_slice(p: &T) -> &[u8] { - core::slice::from_raw_parts((p as *const T) as *const u8, size_of::()) -} - -impl LinkedProgram { - pub fn to_elf(&self) -> Vec { - create(&self.code, self.start.expect("no start found")) - } -} diff --git a/src/compiler/instruction.rs b/src/compiler/instruction.rs deleted file mode 100644 index 053701f..0000000 --- a/src/compiler/instruction.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub enum Instruction { - -} diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs deleted file mode 100644 index db94d01..0000000 --- a/src/compiler/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod arch; -mod debug; -mod elf; -mod program; -mod target; - -use arch::riscv; -pub use program::*; - -use crate::ir::LProgram; - -pub fn compile(program: &LProgram) -> UnlinkedProgram { - arch::riscv::compile(program) -} diff --git a/src/compiler/program.rs b/src/compiler/program.rs deleted file mode 100644 index dcc0236..0000000 --- a/src/compiler/program.rs +++ /dev/null @@ -1,138 +0,0 @@ -use std::collections::HashMap; - -use crate::{ - ir::Symbol, - util::{Labelable, LabeledFmt}, -}; - -use super::debug::DebugInfo; - -pub struct LinkedProgram { - pub code: Vec, - pub start: Option, -} - -pub struct UnlinkedProgram { - pub fns: Vec>, - pub ro_data: Vec<(Vec, Symbol)>, - pub sym_count: usize, - pub start: Option, - pub dbg: DebugInfo, -} - -pub struct UnlinkedFunction { - pub instrs: Vec, - pub sym: Symbol, - pub locations: HashMap, -} - -impl UnlinkedProgram { - pub fn link(self) -> LinkedProgram { - let mut data = Vec::new(); - let mut sym_table = SymTable::new(self.sym_count); - let mut missing = HashMap::>::new(); - for (val, id) in self.ro_data { - sym_table.insert(id, Addr(data.len() as u64)); - data.extend(val); - } - data.resize(data.len() + (4 - data.len() % 4), 0); - for f in self.fns { - let mut added = vec![f.sym]; - sym_table.insert(f.sym, Addr(data.len() as u64)); - for (i, instr) in f.instrs.into_iter().enumerate() { - let i_pos = Addr(data.len() as u64); - if let Some(sym) = f.locations.get(&i) { - sym_table.insert(*sym, i_pos); - added.push(*sym); - } - if let Some(sym) = instr.push_to(&mut data, &mut sym_table, i_pos, false) { - if let Some(vec) = missing.get_mut(&sym) { - vec.push((i_pos, instr)); - } else { - missing.insert(sym, vec![(i_pos, instr)]); - } - } - } - for add in added { - if let Some(vec) = missing.remove(&add) { - for (addr, i) in vec { - let mut replace = Vec::new(); - i.push_to(&mut replace, &mut sym_table, addr, true); - let pos = addr.val() as usize; - data[pos..pos + replace.len()].copy_from_slice(&replace); - } - } - } - } - assert!(missing.is_empty()); - LinkedProgram { - code: data, - start: self - .start - .map(|s| sym_table.get(s).expect("start symbol doesn't exist")), - } - } -} - -pub trait Instr { - fn push_to( - &self, - data: &mut Vec, - syms: &mut SymTable, - pos: Addr, - missing: bool, - ) -> Option; -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Addr(u64); -impl Addr { - const NONE: Self = Self(!0); - pub fn val(&self) -> u64 { - self.0 - } -} - -pub struct SymTable(Vec); -impl SymTable { - pub fn new(len: usize) -> Self { - Self(vec![Addr::NONE; len]) - } - pub fn insert(&mut self, sym: Symbol, addr: Addr) { - self.0[*sym] = addr; - } - pub fn get(&self, sym: Symbol) -> Option { - match self.0[*sym] { - Addr::NONE => None, - addr => Some(addr), - } - } -} - -impl + LabeledFmt> std::fmt::Debug for UnlinkedProgram { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for (fun, irli) in self.fns.iter().zip(&self.dbg.ir_lower) { - writeln!(f, "{}:", self.dbg.sym_label(fun.sym).unwrap())?; - let mut liter = irli.iter(); - let mut cur = liter.next(); - for (i, instr) in fun.instrs.iter().enumerate() { - while let Some(c) = cur - && i == c.0 - { - writeln!(f, " {}:", c.1)?; - cur = liter.next(); - } - writeln!( - f, - " {:?}", - instr.labeled(&|f: &mut std::fmt::Formatter, s: &Symbol| write!( - f, - "{}", - self.dbg.sym_label(*s).unwrap_or(&format!("{:?}", *s)) - )) - )?; - } - } - Ok(()) - } -} diff --git a/src/compiler/target.rs b/src/compiler/target.rs deleted file mode 100644 index c882ec0..0000000 --- a/src/compiler/target.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub trait Target { - type Reg; -} - -pub trait RegType { - type Size; -} diff --git a/src/ir/arch/mod.rs b/src/ir/arch/mod.rs deleted file mode 100644 index ceb8572..0000000 --- a/src/ir/arch/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod riscv64; diff --git a/src/ir/arch/riscv64.rs b/src/ir/arch/riscv64.rs deleted file mode 100644 index 63d623b..0000000 --- a/src/ir/arch/riscv64.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::fmt::Debug; - -use crate::{compiler::arch::riscv::*, ir::IdentID}; - -pub type RV64Instruction = LinkerInstruction, V>; - -#[derive(Copy, Clone)] -pub enum RegRef { - Var(V), - Reg(R), -} - -impl 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), - } - } -} diff --git a/src/ir/asm.rs b/src/ir/asm.rs deleted file mode 100644 index 9c448d8..0000000 --- a/src/ir/asm.rs +++ /dev/null @@ -1,7 +0,0 @@ -use super::{arch::riscv64::RegRef, IdentID}; - -#[derive(Clone)] -pub struct IRAsmInstruction { - op: String, - args: Vec>, -} diff --git a/src/ir/id.rs b/src/ir/id.rs deleted file mode 100644 index b718caa..0000000 --- a/src/ir/id.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::{ - fmt::Debug, - marker::PhantomData, - ops::{Index, IndexMut}, -}; - -// I had an idea for why these were different... now I don't -pub type Size = u32; -pub type Len = u32; - -pub struct ID(pub usize, PhantomData); - -impl ID { - pub fn new(i: usize) -> Self { - Self(i, PhantomData) - } -} - -impl From for ID { - fn from(value: usize) -> Self { - Self(value, PhantomData) - } -} - -impl Debug for ID { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{{{}}}", self.0) - } -} - -impl PartialEq for ID { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl Eq for ID {} - -impl std::hash::Hash for ID { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -impl Clone for ID { - fn clone(&self) -> Self { - Self(self.0.clone(), PhantomData) - } -} - -impl Copy for ID {} - -// :fear: -impl Index> for Vec { - type Output = T; - - fn index(&self, i: ID) -> &Self::Output { - &self[i.0] - } -} - -impl IndexMut> for Vec { - fn index_mut(&mut self, i: ID) -> &mut Self::Output { - &mut self[i.0] - } -} - -impl Index<&ID> for Vec { - type Output = T; - - fn index(&self, i: &ID) -> &Self::Output { - &self[i.0] - } -} - -impl IndexMut<&ID> for Vec { - fn index_mut(&mut self, i: &ID) -> &mut Self::Output { - &mut self[i.0] - } -} - -impl Index<&mut ID> for Vec { - type Output = T; - - fn index(&self, i: &mut ID) -> &Self::Output { - &self[i.0] - } -} - -impl IndexMut<&mut ID> for Vec { - fn index_mut(&mut self, i: &mut ID) -> &mut Self::Output { - &mut self[i.0] - } -} - -impl Index> for [T] { - type Output = T; - - fn index(&self, i: ID) -> &Self::Output { - &self[i.0] - } -} - -impl IndexMut> for [T] { - fn index_mut(&mut self, i: ID) -> &mut Self::Output { - &mut self[i.0] - } -} - -impl Index<&ID> for [T] { - type Output = T; - - fn index(&self, i: &ID) -> &Self::Output { - &self[i.0] - } -} - -impl IndexMut<&ID> for [T] { - fn index_mut(&mut self, i: &ID) -> &mut Self::Output { - &mut self[i.0] - } -} - -impl Index<&mut ID> for [T] { - type Output = T; - - fn index(&self, i: &mut ID) -> &Self::Output { - &self[i.0] - } -} - -impl IndexMut<&mut ID> for [T] { - fn index_mut(&mut self, i: &mut ID) -> &mut Self::Output { - &mut self[i.0] - } -} diff --git a/src/ir/lower/func.rs b/src/ir/lower/func.rs deleted file mode 100644 index b5e602f..0000000 --- a/src/ir/lower/func.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::*; -use crate::{compiler::arch::riscv::Reg, ir::arch::riscv64::RegRef}; -use arch::riscv64::RV64Instruction; -use std::collections::HashMap; - -#[derive(Debug)] -pub struct IRLFunction { - pub instructions: Vec, - pub stack: HashMap, - pub subvar_map: HashMap, - pub args: Vec<(VarID, Size)>, - pub ret_size: Size, - pub makes_call: bool, -} - -#[derive(Debug)] -pub enum LInstruction { - Mv { - dst: VarID, - dst_offset: Size, - src: VarID, - src_offset: Size, - }, - Ref { - dst: VarID, - src: VarID, - }, - LoadAddr { - dst: VarID, - offset: Size, - src: Symbol, - }, - LoadData { - dst: VarID, - offset: Size, - src: Symbol, - len: Len, - }, - Call { - dst: Option<(VarID, Size)>, - f: Symbol, - args: Vec<(VarID, Size)>, - }, - AsmBlock { - instructions: Vec>, - inputs: Vec<(Reg, VarID)>, - outputs: Vec<(Reg, VarID)>, - }, - Ret { - src: Option, - }, - // TODO I feel like this should be turned into control flow instructions, maybe... - // not sure but LLVM has them so might be right play; seems optimal for optimization - Jump(Symbol), - Branch { - to: Symbol, - cond: VarID, - }, - Mark(Symbol), -} - -impl LInstruction { - pub fn is_ret(&self) -> bool { - matches!(self, Self::Ret { .. }) - } -} diff --git a/src/ir/lower/mod.rs b/src/ir/lower/mod.rs deleted file mode 100644 index 9f3b373..0000000 --- a/src/ir/lower/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod func; -mod program; -mod symbol; -mod res; - -pub use func::*; -pub use program::*; -pub use symbol::*; - -use super::*; diff --git a/src/ir/lower/program.rs b/src/ir/lower/program.rs deleted file mode 100644 index 7919c05..0000000 --- a/src/ir/lower/program.rs +++ /dev/null @@ -1,465 +0,0 @@ -use std::collections::HashMap; - -use super::{ - IRLFunction, LInstruction, Len, Symbol, SymbolSpaceBuilder, UInstruction, UProgram, VarID, -}; -use crate::ir::{ - AsmBlockArgType, Size, StructInst, SymbolSpace, Type, TypeID, UFunc, UInstrInst, VarOffset, -}; - -pub struct LProgram { - sym_space: SymbolSpace, - entry: Symbol, -} - -// NOTE: there are THREE places here where I specify size (8) - -impl LProgram { - pub fn create(p: &UProgram) -> Result { - let start = p - .names - .id::(&[], "crate") - .ok_or("no start method found")?; - let mut ssbuilder = SymbolSpaceBuilder::with_entries(&[start]); - let entry = ssbuilder.func(&start); - while let Some((sym, i)) = ssbuilder.pop_fn() { - let f = &p.fns[i.0]; - let mut fbuilder = LFunctionBuilder::new(p, &mut ssbuilder); - for i in &f.instructions { - fbuilder.insert_instr(i); - } - if fbuilder.instrs.last().is_none_or(|i| !i.is_ret()) { - fbuilder.instrs.push(LInstruction::Ret { src: None }); - } - let res = fbuilder.finish(f); - ssbuilder.write_fn(sym, res, Some(f.name.clone())); - } - let sym_space = ssbuilder.finish().expect("we failed the mission"); - Ok(Self { sym_space, entry }) - } - - pub fn entry(&self) -> Symbol { - self.entry - } -} - -pub struct LStructInst { - offsets: Vec, - types: Vec, - order: HashMap, - size: Size, -} - -impl LStructInst { - pub fn offset(&self, name: &str) -> Option { - Some(self.offsets[*self.order.get(name)?]) - } - pub fn ty(&self, name: &str) -> Option<&Type> { - Some(&self.types[*self.order.get(name)?]) - } -} - -pub struct LFunctionBuilder<'a> { - data: LFunctionBuilderData<'a>, - program: &'a UProgram, -} - -impl<'a> LFunctionBuilderData<'a> { - pub fn new(builder: &'a mut SymbolSpaceBuilder) -> Self { - Self { - instrs: Vec::new(), - struct_insts: HashMap::new(), - stack: HashMap::new(), - subvar_map: HashMap::new(), - makes_call: false, - builder, - loopp: None, - } - } -} - -pub struct LFunctionBuilderData<'a> { - builder: &'a mut SymbolSpaceBuilder, - instrs: Vec, - stack: HashMap, - subvar_map: HashMap, - struct_insts: HashMap, - makes_call: bool, - loopp: Option, -} - -#[derive(Clone, Copy)] -pub struct LoopCtx { - top: Symbol, - bot: Symbol, -} - -impl<'a> LFunctionBuilder<'a> { - pub fn new(program: &'a UProgram, builder: &'a mut SymbolSpaceBuilder) -> Self { - Self { - data: LFunctionBuilderData::new(builder), - program, - } - } - pub fn alloc_stack(&mut self, i: VarID) -> Option<()> { - if self - .data - .size_of_var(self.program, i) - .expect("unsized type") - == 0 - { - return None; - }; - self.map_subvar(i); - let var = self.data.var_offset(self.program, i).expect("var offset"); - if !self.stack.contains_key(&var.id) { - let size = self - .data - .size_of_var(self.program, var.id) - .expect("unsized type"); - self.data.stack.insert(var.id, size); - } - Some(()) - } - pub fn map_subvar(&mut self, i: VarID) { - let off = self.data.var_offset(self.program, i).expect("var offset"); - if off.id != i { - self.subvar_map.insert(i, off); - } - } - pub fn insert_instr(&mut self, i: &UInstrInst) -> Option> { - match i - .i - .resolve(self.program) - .expect("failed to resolve during lowering") - { - UInstruction::Mv { dst, src } => { - self.alloc_stack(dst)?; - self.map_subvar(src); - self.instrs.push(LInstruction::Mv { - dst, - dst_offset: 0, - src, - src_offset: 0, - }); - } - UInstruction::Ref { dst, src } => { - self.alloc_stack(dst)?; - self.map_subvar(src); - self.instrs.push(LInstruction::Ref { dst, src }); - } - UInstruction::Deref { dst, src } => { - todo!() - } - UInstruction::LoadData { dst, src } => { - self.alloc_stack(dst)?; - let data = &self.program.data[src]; - let sym = self.data.builder.ro_data( - src, - &data.content, - Some(&self.program.data[src].name), - ); - self.instrs.push(LInstruction::LoadData { - dst, - offset: 0, - len: data.content.len() as Len, - src: sym, - }); - } - UInstruction::LoadSlice { dst, src } => { - self.alloc_stack(dst)?; - let data = &self.program.data[src]; - let Type::Array(_, len) = &self.program.types[data.ty] else { - return Some(Some(format!( - "tried to load {} as slice", - self.program.type_name(&data.ty) - ))); - }; - let sym = self.data.builder.ro_data( - src, - &data.content, - Some(&self.program.data[src].name), - ); - self.instrs.push(LInstruction::LoadAddr { - dst, - offset: 0, - src: sym, - }); - - let sym = self - .builder - .anon_ro_data(&(*len as u64).to_le_bytes(), Some(format!("len: {}", len))); - self.instrs.push(LInstruction::LoadData { - dst, - offset: 8, - len: 8, - src: sym, - }); - } - UInstruction::Call { dst, f, args } => { - self.alloc_stack(dst); - self.makes_call = true; - let sym = self.builder.func(f.id); - let ret_size = self - .data - .size_of_var(self.program, dst) - .expect("unsized type"); - let dst = if ret_size > 0 { - Some((dst, ret_size)) - } else { - None - }; - let call = LInstruction::Call { - dst, - f: sym, - args: args - .into_iter() - .map(|id| { - self.map_subvar(id); - ( - id, - self.data - .size_of_var(self.program, id) - .expect("unsized type"), - ) - }) - .collect(), - }; - self.instrs.push(call); - } - UInstruction::AsmBlock { instructions, args } => { - let mut inputs = Vec::new(); - let mut outputs = Vec::new(); - for a in args { - match a.ty { - AsmBlockArgType::In => { - self.map_subvar(a.var); - inputs.push((a.reg, a.var)) - } - AsmBlockArgType::Out => { - self.alloc_stack(a.var)?; - outputs.push((a.reg, a.var)); - } - } - } - self.instrs.push(LInstruction::AsmBlock { - instructions: instructions.clone(), - inputs, - outputs, - }) - } - UInstruction::Ret { src } => { - self.map_subvar(src); - let src = if self - .data - .size_of_var(self.program, src) - .expect("unsized var") - == 0 - { - None - } else { - Some(src) - }; - self.data.instrs.push(LInstruction::Ret { src }) - } - UInstruction::Construct { - dst, - ref struc, - ref fields, - } => { - self.alloc_stack(dst)?; - for (field, &src) in fields { - self.map_subvar(src); - let i = LInstruction::Mv { - dst, - src, - dst_offset: self - .data - .field_offset(self.program, struc, field) - .expect("field offset"), - src_offset: 0, - }; - self.instrs.push(i) - } - } - UInstruction::If { cond, body } => { - self.map_subvar(cond); - let sym = self.builder.reserve(); - self.instrs.push(LInstruction::Branch { to: *sym, cond }); - for i in body { - self.insert_instr(&i); - } - self.instrs.push(LInstruction::Mark(*sym)); - } - UInstruction::Loop { body } => { - let top = self.builder.reserve(); - let bot = self.builder.reserve(); - let old = self.loopp; - self.loopp = Some(LoopCtx { - bot: *bot, - top: *top, - }); - self.instrs.push(LInstruction::Mark(*top)); - for i in body { - self.insert_instr(i); - } - self.instrs.push(LInstruction::Jump(*top)); - self.instrs.push(LInstruction::Mark(*bot)); - self.loopp = old; - } - UInstruction::Break => { - self.data.instrs.push(LInstruction::Jump( - self.data.loopp.expect("Tried to break outside of loop").bot, - )); - } - UInstruction::Continue => { - self.data.instrs.push(LInstruction::Jump( - self.data.loopp.expect("Tried to break outside of loop").top, - )); - } - }; - Some(None) - } - - pub fn finish(mut self, f: &UFunc) -> IRLFunction { - IRLFunction { - args: f - .args - .iter() - .map(|a| { - ( - *a, - self.data - .size_of_var(self.program, *a) - .expect("unsized type"), - ) - }) - .collect(), - ret_size: self - .data - .size_of_type(self.program, &f.ret) - .expect("unsized type"), - instructions: self.data.instrs, - makes_call: self.data.makes_call, - stack: self.data.stack, - subvar_map: self.data.subvar_map, - } - } -} - -impl LFunctionBuilderData<'_> { - pub fn var_offset(&mut self, p: &UProgram, mut var: VarID) -> Option { - let mut path = Vec::new(); - while let Type::Field(parent) = &p.get(var)?.ty { - var = parent.parent; - path.push(&parent.name); - } - let mut ty = &p.get(var)?.ty; - let mut offset = 0; - while let Type::Struct(sty) = ty { - let Some(name) = path.pop() else { - break; - }; - offset += self.field_offset(p, sty, &name)?; - ty = p.struct_field_type(sty, name).expect("bad field"); - } - Some(VarOffset { id: var, offset }) - } - pub fn addr_size(&self) -> Size { - 64 - } - pub fn struct_inst(&mut self, p: &UProgram, ty: &StructInst) -> &LStructInst { - // normally I'd let Some(..) here and return, but polonius does not exist :grief: - if self.struct_insts.get(ty).is_none() { - let LStructInst { id, args } = ty; - let struc = p.expect(*id); - let mut types = Vec::new(); - let mut sizes = struc - .fields - .iter() - .map(|(n, f)| { - let ty = if let Type::Generic { id } = &f.ty { - struc - .generics - .iter() - .enumerate() - .find_map(|(i, g)| if *g == *id { args.get(i) } else { None }) - .unwrap_or(&f.ty) - } else { - &f.ty - }; - types.push(ty.clone()); - (n, self.size_of_type(p, ty).expect("unsized type")) - }) - .collect::>(); - sizes.sort_by(|(n1, s1, ..), (n2, s2, ..)| s1.cmp(s2).then_with(|| n1.cmp(n2))); - let mut offset = 0; - let mut offsets = Vec::new(); - let mut order = HashMap::new(); - for (i, (name, size)) in sizes.iter().rev().enumerate() { - // TODO: alignment!!! - order.insert(name.to_string(), i); - offsets.push(offset); - offset += size; - } - self.struct_insts.insert( - ty.clone(), - LStructInst { - offsets, - order, - types, - size: offset, - }, - ); - } - self.struct_insts.get(ty).unwrap() - } - - pub fn field_offset(&mut self, p: &UProgram, sty: &StructInst, field: &str) -> Option { - let inst = self.struct_inst(p, sty); - Some(inst.offset(field)?) - } - - pub fn size_of_type(&mut self, p: &UProgram, ty: &TypeID) -> Option { - // TODO: target matters - Some(match &p.types[ty] { - Type::Bits(b) => *b, - Type::Struct(ty) => self.struct_inst(p, ty).size, - Type::Generic(id) => return None, - // function references are resolved at compile time into direct calls, - // so they don't have any size as arguments - Type::FnInst(fi) => 0, - Type::Ref(_) => self.addr_size(), - Type::Array(ty, len) => self.size_of_type(p, ty)? * len, - Type::Slice(_) => self.addr_size() * 2, - Type::Unit => 0, - _ => return None, - }) - } - - pub fn size_of_var(&mut self, p: &UProgram, var: VarID) -> Option { - self.size_of_type(p, &p.get(var)?.ty) - } -} - -impl<'a> std::ops::Deref for LFunctionBuilder<'a> { - type Target = LFunctionBuilderData<'a>; - - fn deref(&self) -> &Self::Target { - &self.data - } -} - -impl<'a> std::ops::DerefMut for LFunctionBuilder<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.data - } -} - -impl std::ops::Deref for LProgram { - type Target = SymbolSpace; - - fn deref(&self) -> &Self::Target { - &self.sym_space - } -} diff --git a/src/ir/lower/res.rs b/src/ir/lower/res.rs deleted file mode 100644 index 2794746..0000000 --- a/src/ir/lower/res.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::ir::{ - arch::riscv64::{RV64Instruction, RegRef}, - AsmBlockArg, Resolved, UInstrInst, UInstruction, UProgram, VarID, -}; - -impl UInstrInst { - pub fn resolve<'a>(&'a self, p: &'a UProgram) -> Option> { - Some(UInstrInst { - i: self.i.resolve(p)?, - origin: self.origin, - }) - } -} - -impl UInstruction { - pub fn resolve<'a>(&'a self, p: &'a UProgram) -> Option> { - use UInstruction as I; - Some(match self { - I::Mv { dst, src } => I::Mv { - dst: dst.var(p)?, - src: src.var(p)?, - }, - I::Ref { dst, src } => I::Ref { - dst: dst.var(p)?, - src: src.var(p)?, - }, - I::Deref { dst, src } => I::Deref { - dst: dst.var(p)?, - src: src.var(p)?, - }, - I::LoadData { dst, src } => I::LoadData { - dst: dst.var(p)?, - src: *src, - }, - I::LoadSlice { dst, src } => I::LoadSlice { - dst: dst.var(p)?, - src: *src, - }, - I::Call { dst, f, args } => I::Call { - dst: dst.var(p)?, - f: f.fun(p)?.clone(), - args: args.iter().map(|i| i.var(p)).try_collect()?, - }, - I::AsmBlock { instructions, args } => I::AsmBlock { - instructions: instructions - .iter() - .map(|i| i.resolve(p)) - .collect::>()?, - args: args.iter().map(|a| a.resolve(p)).try_collect()?, - }, - I::Ret { src } => I::Ret { src: src.var(p)? }, - I::Construct { dst, struc, fields } => I::Construct { - dst: dst.var(p)?, - struc: struc.struc(p)?.clone(), - fields: fields - .iter() - .map(|(name, ident)| ident.var(p).map(|i| (name.clone(), i))) - .collect::>()?, - }, - I::If { cond, body } => I::If { - cond: cond.var(p)?, - body: body.iter().map(|i| i.resolve(p)).try_collect()?, - }, - I::Loop { body } => I::Loop { - body: body.iter().map(|i| i.resolve(p)).try_collect()?, - }, - I::Break => I::Break, - I::Continue => I::Continue, - }) - } -} - -impl AsmBlockArg { - pub fn resolve(&self, p: &UProgram) -> Option> { - Some(AsmBlockArg { - var: self.var.var(p)?, - reg: self.reg, - ty: self.ty, - }) - } -} - -impl RV64Instruction { - pub fn resolve(&self, p: &UProgram) -> Option> { - self.try_map(|i| { - Some(match i { - RegRef::Var(v) => RegRef::Var(v.var(p)?), - RegRef::Reg(r) => RegRef::Reg(*r), - }) - }) - } -} diff --git a/src/ir/lower/symbol.rs b/src/ir/lower/symbol.rs deleted file mode 100644 index 8bc282e..0000000 --- a/src/ir/lower/symbol.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::collections::HashMap; - -use super::{DataID, FnID, IRLFunction}; - -#[derive(Clone, Copy, Hash, PartialEq, Eq)] -pub struct Symbol(usize); -/// intentionally does not have copy or clone; -/// this should only be consumed once -pub struct WritableSymbol(Symbol); - -impl std::ops::Deref for WritableSymbol { - type Target = Symbol; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -pub struct SymbolSpace { - ro_data: Vec<(Symbol, Vec)>, - fns: Vec<(Symbol, IRLFunction)>, - len: usize, - labels: Vec>, -} - -pub struct SymbolSpaceBuilder { - symbols: usize, - unwritten_fns: Vec<(WritableSymbol, FnID)>, - fn_map: HashMap, - data_map: HashMap, - ro_data: Vec<(Symbol, Vec)>, - fns: Vec<(Symbol, IRLFunction)>, - labels: Vec>, -} - -impl SymbolSpace { - pub fn ro_data(&self) -> &[(Symbol, Vec)] { - &self.ro_data - } - pub fn fns(&self) -> &[(Symbol, IRLFunction)] { - &self.fns - } - pub fn labels(&self) -> &[Option] { - &self.labels - } - pub fn len(&self) -> usize { - self.len - } -} - -impl SymbolSpaceBuilder { - pub fn new() -> Self { - Self { - symbols: 0, - unwritten_fns: Vec::new(), - fn_map: HashMap::new(), - data_map: HashMap::new(), - ro_data: Vec::new(), - fns: Vec::new(), - labels: Vec::new(), - } - } - pub fn with_entries(entries: &[FnID]) -> SymbolSpaceBuilder { - let mut s = Self::new(); - for e in entries { - s.func(*e); - } - s - } - pub fn pop_fn(&mut self) -> Option<(WritableSymbol, FnID)> { - self.unwritten_fns.pop() - } - pub fn anon_ro_data(&mut self, data: &[u8], label: Option) -> Symbol { - let sym = self.reserve(); - self.write_ro_data(sym, data.to_vec(), label) - } - pub fn ro_data(&mut self, id: DataID, data: &[u8], label: Option<&str>) -> Symbol { - match self.data_map.get(&id) { - Some(s) => *s, - None => { - let sym = self.reserve(); - self.data_map.insert(id, *sym); - self.write_ro_data(sym, data.to_vec(), label.map(|l| l.to_string())) - } - } - } - pub fn func(&mut self, id: FnID) -> Symbol { - match self.fn_map.get(&id) { - Some(s) => *s, - None => { - let wsym = self.reserve(); - let sym = *wsym; - self.unwritten_fns.push((wsym, id)); - self.fn_map.insert(id, sym); - sym - } - } - } - pub fn write_ro_data( - &mut self, - sym: WritableSymbol, - data: Vec, - name: Option, - ) -> Symbol { - self.ro_data.push((*sym, data)); - self.labels[sym.0 .0] = name; - *sym - } - pub fn write_fn( - &mut self, - sym: WritableSymbol, - func: IRLFunction, - name: Option, - ) -> Symbol { - self.fns.push((*sym, func)); - self.labels[sym.0 .0] = name; - *sym - } - pub fn reserve(&mut self) -> WritableSymbol { - let val = self.symbols; - self.symbols += 1; - self.labels.push(None); - WritableSymbol(Symbol(val)) - } - pub fn len(&self) -> usize { - self.symbols - } - pub fn finish(self) -> Option { - if self.unwritten_fns.is_empty() { - Some(SymbolSpace { - len: self.symbols, - fns: self.fns, - ro_data: self.ro_data, - labels: self.labels, - }) - } else { - None - } - } -} - -impl std::fmt::Debug for Symbol { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "@{}", self.0) - } -} - -impl std::ops::Deref for Symbol { - type Target = usize; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/src/ir/mod.rs b/src/ir/mod.rs deleted file mode 100644 index 2a33319..0000000 --- a/src/ir/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! the IR is split into 2 layers: upper and lower -//! upper handles all of the main language features like types, -//! and the lower is a very concrete format that can be easily -//! translated to assembly and will probably also include -//! the majority of optimization, but not sure - -mod upper; -mod lower; -mod id; -mod asm; -pub mod arch; - -pub use upper::*; -pub use lower::*; -pub use id::*; - diff --git a/src/ir/upper/ident.rs b/src/ir/upper/ident.rs deleted file mode 100644 index 6ba5e91..0000000 --- a/src/ir/upper/ident.rs +++ /dev/null @@ -1,140 +0,0 @@ -use std::fmt::Display; - -use super::*; - -/// a generic identifier for all (identifiable) kinds -/// eg. a::b::c.d.e -/// or a::Result -pub struct UIdent { - pub status: IdentStatus, - pub origin: Origin, -} - -pub enum IdentStatus { - Res(Res), - // lets you do things like import and then specialize in multiple places - // eg. import SomeStruct ...... f() -> SomeStruct // type ....... SomeStruct {} // struct - // and then have correct errors like "expected struct, found type Bla" - Ref(IdentID), - Unres { - base: ResBase, - path: Vec, - }, - Failed(Option), - Cooked, -} - -pub struct MemberIdent { - pub ty: MemberTy, - pub name: String, - pub gargs: Vec, - pub origin: Origin, -} - -#[derive(Clone, Copy)] -pub enum MemberTy { - Member, - Field, -} - -impl MemberTy { - pub fn sep(&self) -> &'static str { - match self { - MemberTy::Member => "::", - MemberTy::Field => ".", - } - } -} - -impl Display for MemberTy { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - MemberTy::Member => "member", - MemberTy::Field => "field", - }) - } -} - -#[derive(Debug, Clone)] -pub enum Res { - Var(VarID), - Fn(FnInst), - Struct(StructInst), - Type(TypeID), - Generic(GenericID), - Module(ModID), -} - -impl Res { - pub fn kind(&self) -> KindTy { - match self { - Res::Var(..) => KindTy::Var, - Res::Fn(..) => KindTy::Fn, - Res::Struct(..) => KindTy::Struct, - Res::Type(..) => KindTy::Type, - Res::Module(..) => KindTy::Module, - Res::Generic(..) => KindTy::Generic, - } - } - - pub fn display_str(&self, p: &UProgram) -> String { - let name = match self { - Res::Var(id) => &p.vars[id].name, - Res::Fn(fi) => &p.fns[fi.id].name, - Res::Struct(si) => &p.structs[si.id].name, - Res::Type(id) => &p.type_name(id), - Res::Generic(id) => &p.generics[id].name, - Res::Module(id) => &p.modules[id].name, - }; - format!("{} '{}'", self.kind(), name) - } -} - -#[derive(Clone)] -pub enum ResBase { - Unvalidated(MemRes), - Validated(Res), -} - -impl ResBase { - pub fn display_str(&self, p: &UProgram) -> String { - match self { - ResBase::Unvalidated(uv) => uv.display_str(p), - ResBase::Validated(res) => res.display_str(p), - } - } -} - -#[derive(Clone)] -pub struct MemRes { - pub mem: Member, - pub origin: Origin, - pub gargs: Vec, -} - -impl MemRes { - pub fn display_str(&self, p: &UProgram) -> String { - self.mem.id.display_str(p) - } -} - -impl IdentID { - pub fn var(&self, p: &UProgram) -> Option { - match p.idents[self].status { - IdentStatus::Res(Res::Var(id)) => Some(id), - _ => None, - } - } - pub fn fun<'a>(&self, p: &'a UProgram) -> Option<&'a FnInst> { - match &p.idents[self].status { - IdentStatus::Res(Res::Fn(i)) => Some(&i), - _ => None, - } - } - pub fn struc<'a>(&self, p: &'a UProgram) -> Option<&'a StructInst> { - match &p.idents[self].status { - IdentStatus::Res(Res::Struct(i)) => Some(&i), - _ => None, - } - } -} diff --git a/src/ir/upper/instr.rs b/src/ir/upper/instr.rs deleted file mode 100644 index b9ed0ea..0000000 --- a/src/ir/upper/instr.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::collections::HashMap; - -use super::{arch::riscv64::RV64Instruction, *}; -use crate::compiler::arch::riscv::Reg; - -pub trait ResStage { - type Var; - type Func; - type Struct; - type Type; -} - -pub struct Unresolved; -impl ResStage for Unresolved { - type Var = VarRes; - type Func = IdentID; - type Struct = IdentID; - type Type = TypeRes; -} - -pub struct Resolved; -impl ResStage for Resolved { - type Var = VarID; - type Func = FnInst; - type Struct = StructInst; - type Type = TypeID; -} - -pub enum UInstruction { - Mv { - dst: S::Var, - src: S::Var, - }, - Ref { - dst: S::Var, - src: S::Var, - }, - Deref { - dst: S::Var, - src: S::Var, - }, - LoadData { - dst: S::Var, - src: DataID, - }, - LoadSlice { - dst: S::Var, - src: DataID, - }, - Call { - dst: S::Var, - f: S::Func, - args: Vec, - }, - AsmBlock { - instructions: Vec>, - args: Vec>, - }, - Ret { - src: S::Var, - }, - Construct { - dst: S::Var, - struc: S::Struct, - fields: HashMap, - }, - If { - cond: S::Var, - body: Vec, - }, - Loop { - body: Vec, - }, - Break, - Continue, -} - -pub struct UInstrInst { - pub i: UInstruction, - pub origin: Origin, -} - -#[derive(Debug, Clone)] -pub struct AsmBlockArg { - pub var: V, - pub reg: Reg, - pub ty: AsmBlockArgType, -} - -#[derive(Debug, Clone, Copy)] -pub enum AsmBlockArgType { - In, - Out, -} diff --git a/src/ir/upper/kind.rs b/src/ir/upper/kind.rs deleted file mode 100644 index 247d8b0..0000000 --- a/src/ir/upper/kind.rs +++ /dev/null @@ -1,161 +0,0 @@ -//! all main IR Upper data structures stored in UProgram - -use super::*; -use crate::{ - common::FileSpan, - ir::{Len, ID}, -}; -use std::{ - collections::HashMap, - fmt::{Debug, Display}, -}; - -pub type NamePath = Vec; - -pub type FnID = ID; -pub type VarID = ID; -pub type IdentID = ID; -pub type TypeID = ID; -pub type GenericID = ID; -pub type StructID = ID; -pub type DataID = ID; -pub type ModID = ID; -pub type InstrID = ID; - -pub type VarRes = URes; -pub type TypeRes = URes; - -pub struct UFunc { - pub name: String, - pub origin: Origin, - pub args: Vec, - pub gargs: Vec, - pub ret: TypeRes, - pub instructions: Vec, -} - -pub struct StructField { - pub ty: TypeRes, - pub origin: Origin, - // pub vis: Visibility -} - -pub struct UStruct { - pub name: String, - pub origin: Origin, - pub fields: HashMap, - pub gargs: Vec, -} - -pub struct UGeneric { - pub name: String, - pub origin: Origin, -} - -pub struct UVar { - pub name: String, - pub origin: Origin, - pub ty: TypeRes, - pub parent: Option, - pub children: HashMap, -} - -pub enum VarTy { - Ident(IdentID), - Res(TypeID), -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -pub struct VarOffset { - pub id: VarID, - pub offset: Len, -} - -#[derive(Clone)] -pub struct UData { - pub name: String, - pub ty: TypeID, - pub content: Vec, -} - -#[derive(Clone)] -pub struct UModule { - pub name: String, - pub members: HashMap, - pub parent: Option, - pub func: FnID, -} - -#[derive(Clone)] -pub struct Member { - pub id: MemberID, - // pub visibility: Visibility -} - -#[derive(Clone)] -pub enum MemberID { - Fn(FnID), - Struct(StructID), - Var(VarID), - Module(ModID), - Type(TypeDef), -} - -#[derive(Clone)] -pub struct TypeDef { - pub gargs: Vec, - pub ty: TypeID, -} - -impl MemberID { - pub fn kind(&self) -> KindTy { - match self { - MemberID::Fn(_) => KindTy::Fn, - MemberID::Struct(_) => KindTy::Struct, - MemberID::Var(_) => KindTy::Var, - MemberID::Module(_) => KindTy::Module, - MemberID::Type(_) => KindTy::Type, - } - } - pub fn display_str(&self, p: &UProgram) -> String { - let name = match self { - MemberID::Var(id) => &p.vars[id].name, - MemberID::Fn(id) => &p.fns[id].name, - MemberID::Struct(id) => &p.structs[id].name, - MemberID::Module(id) => &p.modules[id].name, - MemberID::Type(def) => &p.type_name(def.ty), - }; - format!("{} '{}'", self.kind(), name) - } -} - -pub enum URes { - Res(T), - Unres(IdentID), -} - -pub type Origin = FileSpan; - -// "effective" (externally visible) kinds -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum KindTy { - Type, - Var, - Struct, - Fn, - Module, - Generic, -} - -impl Display for KindTy { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - KindTy::Type => "type", - KindTy::Var => "variable", - KindTy::Fn => "function", - KindTy::Struct => "struct", - KindTy::Module => "module", - KindTy::Generic => "generic", - }) - } -} diff --git a/src/ir/upper/mod.rs b/src/ir/upper/mod.rs deleted file mode 100644 index 6f6d5dd..0000000 --- a/src/ir/upper/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod instr; -mod kind; -mod program; -mod ty; -mod resolve; -mod error; -mod ident; - -use super::*; - -pub use instr::*; -pub use kind::*; -pub use program::*; -pub use ty::*; -pub use error::*; -pub use resolve::*; -pub use ident::*; diff --git a/src/ir/upper/program.rs b/src/ir/upper/program.rs deleted file mode 100644 index 0ed6b30..0000000 --- a/src/ir/upper/program.rs +++ /dev/null @@ -1,178 +0,0 @@ -use super::*; - -pub struct UProgram { - pub fns: Vec, - pub structs: Vec, - pub modules: Vec, - pub data: Vec, - pub generics: Vec, - pub vars: Vec, - pub idents: Vec, - pub types: Vec, - pub instrs: Vec, - - pub unres_idents: Vec, - pub unres_instrs: Vec<(FnID, InstrID)>, - pub tc: TypeCache, -} - -pub struct TypeCache { - pub unit: TypeID, - pub error: TypeID, -} - -impl UProgram { - pub fn new() -> Self { - let mut types = Vec::new(); - let tc = TypeCache { - unit: push_id(&mut types, Type::Unit), - error: push_id(&mut types, Type::Error), - }; - Self { - fns: Vec::new(), - vars: Vec::new(), - idents: Vec::new(), - structs: Vec::new(), - types: Vec::new(), - generics: Vec::new(), - data: Vec::new(), - modules: Vec::new(), - instrs: Vec::new(), - unres_idents: Vec::new(), - unres_instrs: Vec::new(), - tc, - } - } - - pub fn infer(&mut self) -> TypeID { - self.def_ty(Type::Infer) - } - - pub fn def_var(&mut self, v: UVar) -> VarID { - push_id(&mut self.vars, v) - } - - pub fn def_fn(&mut self, f: UFunc) -> FnID { - push_id(&mut self.fns, f) - } - - pub fn def_ty(&mut self, t: Type) -> TypeID { - push_id(&mut self.types, t) - } - - pub fn def_ident(&mut self, i: UIdent) -> IdentID { - let id = push_id(&mut self.idents, i); - if let IdentStatus::Unres { .. } = self.idents[id].status { - self.unres_idents.push(id); - } - id - } - - pub fn def_generic(&mut self, g: UGeneric) -> GenericID { - push_id(&mut self.generics, g) - } - - pub fn def_data(&mut self, d: UData) -> DataID { - push_id(&mut self.data, d) - } - - pub fn def_struct(&mut self, s: UStruct) -> StructID { - push_id(&mut self.structs, s) - } - - pub fn def_module(&mut self, m: UModule) -> ModID { - push_id(&mut self.modules, m) - } - - pub fn res_ty(&self, i: IdentID) -> Option { - self.idents[i].status; - } - - pub fn type_name(&self, ty: impl Typed) -> String { - match ty.ty(self) { - Type::Struct(ty) => { - format!( - "{}{}", - self.structs[ty.id].name, - self.gparams_str(&ty.gargs) - ) - } - Type::FnInst(ty) => { - format!( - "fn{}({}) -> {}", - &self.gparams_str(&ty.gargs), - &self.type_list_str(self.fns[ty.id].args.iter().map(|v| self.vars[v].ty)), - &self.type_name(self.fns[ty.id].ret) - ) - } - Type::Ref(t) => format!("{}&", self.type_name(t)), - Type::Bits(size) => format!("b{}", size), - Type::Array(t, len) => format!("[{}; {len}]", self.type_name(t)), - Type::Unit => "()".to_string(), - Type::Slice(t) => format!("&[{}]", self.type_name(t)), - Type::Infer => "{inferred}".to_string(), - Type::Generic(id) => self.generics[id].name.clone(), - Type::Deref(t) => format!("{}^", self.type_name(t)), - Type::Error => "{error}".to_string(), - Type::Ptr(id) => self.type_name(id), - } - } - - pub fn type_list_str(&self, mut args: impl Iterator) -> String { - let mut str = String::new(); - if let Some(arg) = args.next() { - str += &self.type_name(arg); - } - for arg in args { - str = str + ", " + &self.type_name(arg); - } - str - } - - pub fn gparams_str(&self, args: &[TypeID]) -> String { - let mut str = String::new(); - if !args.is_empty() { - str += "<"; - } - str += &self.type_list_str(args.iter().cloned()); - if !args.is_empty() { - str += ">"; - } - str - } -} - -pub fn push_id(v: &mut Vec, t: T) -> ID { - let id = ID::new(v.len()); - v.push(t); - id -} - -// I'm done with names... -pub trait Typed { - fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type; -} - -impl Typed for &Type { - fn ty(&self, _: &UProgram) -> &Type { - self - } -} - -impl Typed for TypeID { - fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type { - &p.types[self] - } -} - -impl Typed for &TypeID { - fn ty<'a>(&'a self, p: &'a UProgram) -> &'a Type { - &p.types[*self] - } -} - -impl Typed for &Box { - fn ty<'a>(&'a self, _: &'a UProgram) -> &'a Type { - &**self - } -} diff --git a/src/ir/upper/resolve/error.rs b/src/ir/upper/resolve/error.rs deleted file mode 100644 index 8fa919c..0000000 --- a/src/ir/upper/resolve/error.rs +++ /dev/null @@ -1,213 +0,0 @@ -use crate::common::{CompilerMsg, CompilerOutput}; - -use super::{ - IdentStatus, KindTy, MemberTy, Origin, Res, ResBase, StructID, Type, TypeID, UProgram, -}; - -pub fn report_errs(p: &UProgram, output: &mut CompilerOutput, mut errs: Vec) { - for ident in &p.idents { - match &ident.status { - IdentStatus::Unres { path, base } => { - let mem = path.last().unwrap(); - errs.push(ResErr::UnknownMember { - ty: mem.ty, - name: mem.name.clone(), - origin: mem.origin, - parent: base.clone(), - }) - } - IdentStatus::Failed(err) => { - if let Some(err) = err { - errs.push(err.clone()) - } - } - _ => (), - } - } - for err in errs { - match err { - ResErr::Type { - dst, - src, - errs, - origin, - } => { - let mut msg = type_assign_err(p, dst, src); - for inner in errs { - if inner.dst != dst && inner.src != src { - msg.push_str("\n "); - msg.push_str(&type_assign_err(p, inner.dst, inner.src)); - } - } - output.err(CompilerMsg::new(msg, origin)); - } - ResErr::NotCallable { origin, ty } => { - output.err(CompilerMsg::new( - format!("Cannot call type '{}'", p.type_name(ty)), - origin, - )); - } - ResErr::CannotDeref { origin, ty } => { - output.err(CompilerMsg::new( - format!("Cannot dereference type '{}'", p.type_name(ty)), - origin, - )); - } - ResErr::CondType { origin, ty } => { - output.err(CompilerMsg::new( - format!("Condition types must be '64'; found '{}'", p.type_name(ty)), - origin, - )); - } - ResErr::BadControlFlow { origin, op } => { - output.err(CompilerMsg::new( - format!("Cannot {} here (outside of loop)", op.str()), - origin, - )); - } - ResErr::MissingField { origin, id, name } => { - output.err(CompilerMsg::new( - format!( - "Missing field '{name}' in creation of struct '{}'", - p.structs[id].name - ), - origin, - )); - } - ResErr::UnknownStructField { origin, id, name } => { - output.err(CompilerMsg::new( - format!("Unknown field '{name}' in struct '{}'", p.structs[id].name), - origin, - )); - } - ResErr::NoReturn { fid } => output.err(CompilerMsg::new( - format!("Function must return a value"), - p.fns[fid].origin, - )), - ResErr::GenericCount { - origin, - expected, - found, - } => output.err(CompilerMsg::new( - if expected == 0 { - format!("No generic arguments expected") - } else { - format!("Expected {expected} generic arguments, found {found}") - }, - origin, - )), - ResErr::KindMismatch { - origin, - found, - expected, - } => output.err(CompilerMsg::new( - format!("Expected {expected}, found {}", found.display_str(p)), - origin, - )), - ResErr::UnknownMember { - origin, - ty, - name, - parent, - } => output.err(CompilerMsg::new( - format!("Unknown {ty} {name} of {}", parent.display_str(p)), - origin, - )), - } - } - for var in &p.vars { - if let Some(ty) = var.ty() { - match &p.types[ty] { - Type::Infer => output.err(CompilerMsg::new( - format!("Type of {:?} cannot be inferred", var.name), - var.origin, - )), - _ => (), - } - } - } -} - -#[derive(Clone)] -pub enum ResErr { - UnknownMember { - origin: Origin, - ty: MemberTy, - name: String, - parent: ResBase, - }, - KindMismatch { - origin: Origin, - expected: KindTy, - found: Res, - }, - GenericCount { - origin: Origin, - expected: usize, - found: usize, - }, - NotCallable { - origin: Origin, - ty: TypeID, - }, - CannotDeref { - origin: Origin, - ty: TypeID, - }, - CondType { - origin: Origin, - ty: TypeID, - }, - NoReturn { - fid: usize, - }, - BadControlFlow { - op: ControlFlowOp, - origin: Origin, - }, - MissingField { - origin: Origin, - id: StructID, - name: String, - }, - UnknownStructField { - origin: Origin, - id: StructID, - name: String, - }, - Type { - dst: TypeID, - src: TypeID, - errs: Vec, - origin: Origin, - }, -} - -#[derive(Debug, Clone)] -pub enum ControlFlowOp { - Break, - Continue, -} - -impl ControlFlowOp { - pub fn str(&self) -> &'static str { - match self { - ControlFlowOp::Break => "break", - ControlFlowOp::Continue => "continue", - } - } -} - -#[derive(Debug, Clone)] -pub struct TypeMismatch { - pub dst: TypeID, - pub src: TypeID, -} - -pub fn type_assign_err(p: &UProgram, dst: TypeID, src: TypeID) -> String { - format!( - "Cannot assign type {} to {}", - p.type_name(src), - p.type_name(dst) - ) -} diff --git a/src/ir/upper/resolve/ident.rs b/src/ir/upper/resolve/ident.rs deleted file mode 100644 index f35f939..0000000 --- a/src/ir/upper/resolve/ident.rs +++ /dev/null @@ -1,195 +0,0 @@ -use super::*; - -impl UProgram { - pub fn resolve_idents(&mut self, errs: &mut Vec) -> ResolveRes { - let mut resolve_res = ResolveRes::Finished; - 'main: for i in std::mem::take(&mut self.unres_idents) { - let mut j = i; - // take from ref if possible - while let IdentStatus::Ref(other) = &self.idents[j].status { - match &self.idents[other].status { - IdentStatus::Res(res) => self.idents[i].status = IdentStatus::Res(res.clone()), - &IdentStatus::Ref(id) => j = id, - IdentStatus::Unres { .. } => { - self.unres_idents.push(i); - continue 'main; - } - IdentStatus::Failed(..) => self.idents[i].status = IdentStatus::Cooked, - IdentStatus::Cooked => self.idents[i].status = IdentStatus::Cooked, - } - } - let status = &mut self.idents[i].status; - // TOOD: there are some clones here that shouldn't be needed - let IdentStatus::Unres { path, base } = status else { - continue; - }; - - while let Some(mem) = path.pop() { - let res = match base { - ResBase::Unvalidated(u) => { - match u.validate( - &self.fns, - &self.structs, - &self.generics, - &mut self.types, - errs, - ) { - Ok(res) => res, - Err(err) => { - *status = IdentStatus::Failed(err); - continue 'main; - } - } - } - ResBase::Validated(res) => res.clone(), - }; - *base = match (res, mem.ty) { - (Res::Module(id), MemberTy::Member) => { - let Some(m) = self.modules[id].members.get(&mem.name) else { - self.unres_idents.push(i); - continue 'main; - }; - ResBase::Unvalidated(MemRes { - mem: m.clone(), - origin: mem.origin, - gargs: mem.gargs, - }) - } - (Res::Var(id), MemberTy::Field) => { - // trait resolution here - let Some(&child) = self.vars[id].children.get(&mem.name) else { - self.unres_idents.push(i); - continue 'main; - }; - ResBase::Unvalidated(MemRes { - mem: Member { - id: MemberID::Var(child), - }, - origin: mem.origin, - gargs: mem.gargs, - }) - } - _ => { - *status = IdentStatus::Failed(Some(ResErr::UnknownMember { - origin: mem.origin, - ty: mem.ty, - name: mem.name.clone(), - parent: base.clone(), - })); - continue 'main; - } - }; - } - let res = match base { - ResBase::Unvalidated(u) => { - match u.validate( - &self.fns, - &self.structs, - &self.generics, - &mut self.types, - errs, - ) { - Ok(res) => res, - Err(err) => { - *status = IdentStatus::Failed(err); - continue 'main; - } - } - } - ResBase::Validated(res) => res.clone(), - }; - *status = IdentStatus::Res(res); - resolve_res = ResolveRes::Unfinished; - } - resolve_res - } -} - -impl MemRes { - pub fn validate( - &self, - fns: &[UFunc], - structs: &[UStruct], - generics: &[UGeneric], - types: &mut Vec, - errs: &mut Vec, - ) -> Result> { - let no_gargs = || { - if self.gargs.len() > 0 { - Err(ResErr::GenericCount { - origin: self.origin, - expected: 0, - found: self.gargs.len(), - }) - } else { - Ok(()) - } - }; - Ok(match &self.mem.id { - &MemberID::Fn(id) => { - validate_gargs( - &fns[id].gargs, - &self.gargs, - generics, - types, - errs, - self.origin, - )?; - Res::Fn(FnInst { - id, - gargs: self.gargs.clone(), - }) - } - &MemberID::Struct(id) => { - validate_gargs( - &structs[id].gargs, - &self.gargs, - generics, - types, - errs, - self.origin, - )?; - Res::Struct(StructInst { - id, - gargs: self.gargs.clone(), - }) - } - &MemberID::Var(id) => { - no_gargs()?; - Res::Var(id) - } - &MemberID::Module(id) => { - no_gargs()?; - Res::Module(id) - } - MemberID::Type(def) => { - validate_gargs(&def.gargs, &self.gargs, generics, types, errs, self.origin)?; - inst_typedef(def, &self.gargs, types); - Res::Type(def.ty) - } - }) - } -} - -pub fn validate_gargs( - dst: &[GenericID], - src: &[TypeID], - generics: &[UGeneric], - types: &[Type], - errs: &mut Vec, - origin: Origin, -) -> Result<(), Option> { - if dst.len() != src.len() { - return Err(Some(ResErr::GenericCount { - origin, - expected: dst.len(), - found: src.len(), - })); - } - for (dst, src) in dst.iter().zip(src.iter()) { - let g = &generics[dst]; - let t = &types[src]; - // TODO: validate trait constraints - } - Ok(()) -} diff --git a/src/ir/upper/resolve/instantiate.rs b/src/ir/upper/resolve/instantiate.rs deleted file mode 100644 index 767395f..0000000 --- a/src/ir/upper/resolve/instantiate.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::collections::HashMap; - -use super::*; - -pub fn inst_fn_var( - fi: FnInst, - fns: &[UFunc], - origin: Origin, - vars: &mut Vec, - types: &mut Vec, -) -> VarID { - let name = fns[fi.id].name.clone(); - let ty = push_id(types, Type::FnInst(fi)); - push_id( - vars, - UVar { - name, - origin, - ty: VarTy::Res(ty), - parent: None, - children: HashMap::new(), - }, - ) -} - -pub fn inst_struct_var( - si: StructInst, - structs: &[UStruct], - origin: Origin, - vars: &mut Vec, - types: &mut Vec, -) -> VarID { - let name = structs[si.id].name.clone(); - let ty = push_id(types, Type::Struct(si)); - let id = push_id( - vars, - UVar { - name, - origin, - ty: VarTy::Res(ty), - parent: None, - children: HashMap::new(), - }, - ); - id -} - -/// gargs assumed to be valid -pub fn inst_typedef(def: &TypeDef, gargs: &[TypeID], types: &mut Vec) -> TypeID { - let gmap = inst_gmap(&def.gargs, &gargs); - inst_type(def.ty, types, &gmap) -} - -pub fn inst_gmap(dst: &[GenericID], src: &[TypeID]) -> HashMap { - let mut gmap = HashMap::new(); - for (&gid, &tid) in dst.iter().zip(src) { - gmap.insert(gid, tid); - } - gmap -} - -pub fn inst_type(id: TypeID, types: &mut Vec, gmap: &HashMap) -> TypeID { - if gmap.len() == 0 { - return id; - } - match inst_type_(id, types, gmap) { - Some(new) => new, - None => id, - } -} - -fn inst_type_( - id: TypeID, - types: &mut Vec, - gmap: &HashMap, -) -> Option { - let ty = match types[id].clone() { - Type::Bits(_) => return None, - Type::Struct(struct_ty) => Type::Struct(StructInst { - id: struct_ty.id, - gargs: inst_all(&struct_ty.gargs, types, gmap)?, - }), - Type::FnInst(fn_ty) => Type::FnInst(FnInst { - id: fn_ty.id, - gargs: inst_all(&fn_ty.gargs, types, gmap)?, - }), - Type::Ref(id) => Type::Ref(inst_type_(id, types, gmap)?), - Type::Slice(id) => Type::Slice(inst_type_(id, types, gmap)?), - Type::Array(id, len) => Type::Array(inst_type_(id, types, gmap)?, len), - Type::Unit => return None, - Type::Generic(gid) => return gmap.get(&gid).map(|id| Some(*id)).unwrap_or_else(|| None), - Type::Infer => Type::Infer, - Type::Deref(id) => Type::Deref(inst_type_(id, types, gmap)?), - Type::Ptr(id) => Type::Ptr(inst_type_(id, types, gmap)?), - Type::Error => return None, - }; - Some(push_id(types, ty)) -} - -fn inst_all( - ids: &[TypeID], - types: &mut Vec, - gmap: &HashMap, -) -> Option> { - let mut vec = None; - for (i, &id) in ids.iter().enumerate() { - if let Some(id) = inst_type_(id, types, gmap) { - vec.get_or_insert_with(|| ids.iter().take(i).cloned().collect::>()) - .push(id); - } else if let Some(vec) = &mut vec { - vec.push(id) - } - } - vec -} diff --git a/src/ir/upper/resolve/instr.rs b/src/ir/upper/resolve/instr.rs deleted file mode 100644 index b57c961..0000000 --- a/src/ir/upper/resolve/instr.rs +++ /dev/null @@ -1,182 +0,0 @@ -use std::collections::HashSet; - -use super::*; - -pub enum UResEvent { - VarUse(VarID), -} - -impl UProgram { - pub fn resolve_instrs(&mut self, errs: &mut Vec) -> ResolveRes { - let mut data = ResData { - changed: false, - types: &mut self.types, - s: Sources { - idents: &mut self.idents, - vars: &mut self.vars, - fns: &self.fns, - structs: &self.structs, - generics: &self.generics, - data: &self.data, - modules: &self.modules, - }, - errs, - }; - for ids in std::mem::take(&mut self.unres_instrs) { - if let ResolveRes::Unfinished = resolve_instr(ids, &mut self.instrs, &mut data) { - self.unres_instrs.push(ids); - }; - } - ResolveRes::Finished - } -} - -#[derive(Clone, Copy)] -struct ResolveCtx { - ret: IdentID, - breakable: bool, - i: InstrID, -} - -pub fn resolve_instr<'a>( - (fi, ii): (FnID, InstrID), - instrs: &mut Vec, - data: &mut ResData<'a>, -) -> ResolveRes { - let instr = &mut instrs[ii]; - match &mut instr.i { - UInstruction::Call { dst, f, args } => { - let fi = data.res::(*f); - for &a in args { - data.res::(a); - } - data.res::(dst); - match fi { - Ok(fi) => { - let f = &data.s.fns[fi.id]; - for (&src, &dst) in args.iter().zip(&f.args) { - data.s.constraints.push(UResEvent::AssignVVI { dst, src }); - } - } - Err(r) => return r, - } - ResolveRes::Finished - } - UInstruction::Mv { dst, src } => { - res |= data.match_types::(dst, src, src); - } - UInstruction::Ref { dst, src } => { - let dstty = &data.types[data.res_var_ty(dst)?]; - let &Type::Ref(dest_ty) = dstty else { - compiler_error() - }; - res |= data.match_types::(dest_ty, src, src); - } - UInstruction::Deref { dst, src } => { - let srcid = data.res_var_ty(src)?; - let &Type::Ref(src_ty) = data.types[srcid] else { - let origin = src.origin(data); - data.errs.push(ResErr::CannotDeref { origin, ty: srcid }); - return None; - }; - res |= data.match_types::(dst, src_ty, src); - } - UInstruction::LoadData { dst, src } => { - let srcid = src.type_id(&data.s); - res |= data.match_types::(dst, srcid, dst); - } - UInstruction::LoadSlice { dst, src } => { - let (dstty, dstid) = data.res_var_ty(dst, ctx)?; - let &Type::Slice(dstty) = dstty else { - compiler_error() - }; - let srcid = src.type_id(&data.s); - let Type::Array(srcty, _) = data.types[srcid] else { - compiler_error() - }; - res |= data.match_types(dstty, srcty, dst); - } - UInstruction::AsmBlock { instructions, args } => { - // TODO - } - UInstruction::Ret { src } => { - res |= data.match_types::(ctx.ret, src, src); - } - UInstruction::Construct { dst, struc, fields } => { - let si = data.res::(dst, ctx)?; - let sid = si.id; - let st = &data.s.structs[sid]; - let mut used = HashSet::new(); - for (name, field) in &st.fields { - if let Some(src) = fields.get(name) { - used.insert(name); - res |= data.match_types::(field.ty, src, src); - } else { - let origin = dst.origin(data); - data.errs.push(ResErr::MissingField { - origin, - id: sid, - name: name.clone(), - }); - } - } - for (name, _) in fields { - if !used.contains(name) { - let origin = dst.origin(data); - data.errs.push(ResErr::UnknownStructField { - origin, - id: sid, - name: name.clone(), - }); - } - } - } - UInstruction::If { cond, body } => { - if let Some(ty) = data.res_var_ty(cond, ctx) { - if !matches!(ty.0, RType::Bits(64)) { - let id = ty.1; - let origin = cond.origin(data); - data.errs.push(ResErr::CondType { origin, ty: id }); - } - } - for i in body { - resolve_instr( - data, - ResolveCtx { - ret: ctx.ret, - breakable: ctx.breakable, - i, - }, - ); - } - } - UInstruction::Loop { body } => { - for i in body { - resolve_instr( - data, - ResolveCtx { - ret: ctx.ret, - breakable: true, - i, - }, - ); - } - } - UInstruction::Break => { - if !ctx.breakable { - data.errs.push(ResErr::BadControlFlow { - op: ControlFlowOp::Break, - origin: ctx.i.origin, - }); - } - } - UInstruction::Continue => { - if !ctx.breakable { - data.errs.push(ResErr::BadControlFlow { - op: ControlFlowOp::Continue, - origin: ctx.i.origin, - }); - } - } - } -} diff --git a/src/ir/upper/resolve/matc.rs b/src/ir/upper/resolve/matc.rs deleted file mode 100644 index d3a474b..0000000 --- a/src/ir/upper/resolve/matc.rs +++ /dev/null @@ -1,146 +0,0 @@ -use super::*; - -pub fn match_types(data: &mut ResData, dst: TypeID, src: TypeID) -> MatchRes { - let Some(dst) = clean_type(data.types, dst) else { - return MatchRes::Finished; - }; - let Some(src) = clean_type(data.types, src) else { - return MatchRes::Finished; - }; - // prevents this from blowing up I think: - // let mut x, y; - // x = y; - // y = x; - if dst == src { - return MatchRes::Finished; - } - let error = || MatchRes::Error(vec![TypeMismatch { dst, src }]); - match (data.types[dst].clone(), data.types[src].clone()) { - // prefer changing dst over src - (Type::Infer, _) => { - data.changed = true; - data.types[dst] = Type::Ptr(src); - MatchRes::Finished - } - (_, Type::Infer) => { - data.changed = true; - data.types[src] = Type::Ptr(dst); - MatchRes::Finished - } - (Type::Struct(dest), Type::Struct(src)) => { - if dest.id != src.id { - return error(); - } - match_all(data, dest.gargs.iter().cloned(), src.gargs.iter().cloned()) - } - // ( - // Type::Fn { - // args: dst_args, - // ret: dst_ret, - // }, - // Type::Fn { - // args: src_args, - // ret: src_ret, - // }, - // ) => { - // let dst = dst_args.into_iter().chain(once(dst_ret)); - // let src = src_args.into_iter().chain(once(src_ret)); - // match_all(data, dst, src) - // } - (Type::Ref(dest), Type::Ref(src)) => match_types(data, dest, src), - (Type::Slice(dest), Type::Slice(src)) => match_types(data, dest, src), - (Type::Array(dest, dlen), Type::Array(src, slen)) => { - if dlen == slen { - match_types(data, dest, src) - } else { - error() - } - } - _ => error(), - } -} - -fn match_all( - data: &mut ResData, - dst: impl Iterator, - src: impl Iterator, -) -> MatchRes { - let mut finished = true; - let mut errors = Vec::new(); - for (dst, src) in dst.zip(src) { - match match_types(data, dst, src) { - MatchRes::Unfinished => finished = false, - MatchRes::Error(errs) => errors.extend(errs), - MatchRes::Finished => (), - } - } - if finished { - if errors.is_empty() { - MatchRes::Finished - } else { - MatchRes::Error(errors) - } - } else { - MatchRes::Unfinished - } -} - -impl<'a> ResData<'a> { - pub fn match_types( - &mut self, - dst: impl MaybeTypeID, - src: impl MaybeTypeID, - origin: impl HasOrigin, - ) -> ResolveRes { - let dst = dst.type_id(&self.s)?; - let src = src.type_id(&self.s)?; - let res = match_types(self, dst, src); - match res { - MatchRes::Unfinished => ResolveRes::Unfinished, - MatchRes::Finished => ResolveRes::Finished, - MatchRes::Error(es) => { - self.errs.push(ResErr::Type { - errs: es, - origin: origin.origin(self), - dst, - src, - }); - ResolveRes::Finished - } - } - } -} - -pub enum MatchRes { - Unfinished, - Finished, - Error(Vec), -} - -impl FromResidual> for MatchRes { - fn from_residual(residual: Result) -> Self { - match residual { - Ok(_) => unreachable!(), - Err(r) => r, - } - } -} - -pub trait MaybeTypeID { - fn type_id(&self, s: &Sources) -> Result; -} - -impl MaybeTypeID for T { - fn type_id(&self, s: &Sources) -> Result { - Ok(self.type_id(s)) - } -} - -impl MaybeTypeID for VarID { - fn type_id(&self, s: &Sources) -> Result { - match s.vars[self].ty { - VarTy::Ident(id) => todo!(), - VarTy::Res(id) => Ok(id), - } - } -} diff --git a/src/ir/upper/resolve/mod.rs b/src/ir/upper/resolve/mod.rs deleted file mode 100644 index 9115a25..0000000 --- a/src/ir/upper/resolve/mod.rs +++ /dev/null @@ -1,293 +0,0 @@ -use super::*; -use crate::{ - common::CompilerOutput, - ir::{MemRes, Member}, -}; -use std::{ - convert::Infallible, - ops::{BitOrAssign, FromResidual}, -}; - -mod error; -mod ident; -mod instantiate; -mod instr; -mod matc; - -pub use error::*; -use instantiate::*; - -impl UProgram { - pub fn resolve(&mut self, output: &mut CompilerOutput) { - self.unres_instrs = (0..self.instrs.len()).map(|i| InstrID::from(i)).collect(); - let mut res = ResolveRes::Unfinished; - let mut errs = Vec::new(); - while res == ResolveRes::Unfinished { - res = ResolveRes::Finished; - res |= self.resolve_idents(&mut errs); - res |= self.resolve_instrs(&mut errs); - } - for (fid, f) in self.fns.iter().enumerate() { - // this currently works bc expressions create temporary variables - // although you can't do things like loop {return 3} (need to analyze control flow) - if let Some(ty) = self.res_ty(f.ret) - && self.types[ty] != Type::Unit - && f.instructions - .last() - .is_none_or(|i| !matches!(self.instrs[i].i, UInstruction::Ret { .. })) - { - errs.push(ResErr::NoReturn { fid }); - } - } - report_errs(self, output, errs); - } -} - -fn compiler_error() -> ! { - // TODO: this is probably a compiler error / should never happen - panic!("how could this happen to me (you)"); -} - -struct Sources<'a> { - idents: &'a mut [UIdent], - vars: &'a mut Vec, - fns: &'a [UFunc], - structs: &'a [UStruct], - generics: &'a [UGeneric], - data: &'a [UData], - modules: &'a [UModule], -} - -struct ResData<'a> { - changed: bool, - types: &'a mut Vec, - s: Sources<'a>, - errs: &'a mut Vec, -} - -impl<'a> ResData<'a> { - pub fn res(&mut self, i: IdentID) -> Result { - i.res_as::(&mut self.s, &mut self.types) - } - - pub fn res_ty(&mut self, x: impl Resolvable) -> Result { - let id = Resolvable::::try_res(&x, &mut self.s, self.types, self.errs)?; - resolved_type(self.types, id) - } - - pub fn res_var_ty(&mut self, i: IdentID) -> Result { - let id = self.res::(i)?; - let id = match self.s.vars[id].ty { - VarTy::Res(t) => Ok(t), - VarTy::Ident(i) => i.res_as::(&mut self.s, self.types), - }?; - resolved_type(self.types, id) - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum ResolveRes { - Finished, - Unfinished, -} - -impl BitOrAssign for ResolveRes { - fn bitor_assign(&mut self, rhs: Self) { - match rhs { - ResolveRes::Finished => (), - ResolveRes::Unfinished => *self = ResolveRes::Unfinished, - } - } -} - -impl FromResidual> for ResolveRes { - fn from_residual(_: Option) -> Self { - Self::Unfinished - } -} - -trait Resolvable { - fn try_res( - &self, - s: &mut Sources, - types: &mut Vec, - errs: &mut Vec, - ) -> Result; -} - -impl IdentID { - fn res_as( - &self, - s: &mut Sources, - types: &mut Vec, - ) -> Result { - let origin = s.idents[self].origin; - let res = match &s.idents[self].status { - IdentStatus::Res(res) => res.clone(), - IdentStatus::Ref { .. } => return Err(ResolveRes::Unfinished), - IdentStatus::Unres { .. } => return Err(ResolveRes::Unfinished), - IdentStatus::Failed(..) => return Err(ResolveRes::Finished), - IdentStatus::Cooked => return Err(ResolveRes::Finished), - }; - match K::from_res(res, types, s, origin) { - Ok(res) => Ok(res), - Err(res) => { - s.idents[self].status = IdentStatus::Failed(Some(ResErr::KindMismatch { - origin, - expected: K::ty(), - found: res, - })); - Err(ResolveRes::Finished) - } - } - } -} - -impl Resolvable for &IdentID { - fn try_res( - &self, - s: &mut Sources, - types: &mut Vec, - errs: &mut Vec, - ) -> Result { - Resolvable::::try_res(*self, s, types, errs) - } -} - -impl Resolvable for VarID { - fn try_res( - &self, - s: &mut Sources, - types: &mut Vec, - errs: &mut Vec, - ) -> Result<::Res, ResolveRes> { - Ok(*self) - } -} - -impl Resolvable for TypeID { - fn try_res( - &self, - s: &mut Sources, - types: &mut Vec, - errs: &mut Vec, - ) -> Result<::Res, ResolveRes> { - Ok(*self) - } -} - -pub trait ResKind { - type Res; - fn ty() -> KindTy; - fn from_res( - res: Res, - types: &mut Vec, - s: &mut Sources, - origin: Origin, - ) -> Result; -} - -impl ResKind for UFunc { - type Res = FnInst; - fn ty() -> KindTy { - KindTy::Fn - } - fn from_res(res: Res, _: &mut Vec, _: &mut Sources, _: Origin) -> Result { - match res { - Res::Fn(fi) => Ok(fi), - _ => Err(res), - } - } -} - -impl ResKind for UVar { - type Res = VarID; - fn ty() -> KindTy { - KindTy::Var - } - fn from_res( - res: Res, - types: &mut Vec, - s: &mut Sources, - origin: Origin, - ) -> Result { - Ok(match res { - Res::Fn(fty) => inst_fn_var(fty, s.fns, origin, s.vars, types), - Res::Var(id) => id, - _ => return Err(res), - }) - } -} - -impl ResKind for UStruct { - type Res = StructInst; - fn ty() -> KindTy { - KindTy::Struct - } - fn from_res(res: Res, _: &mut Vec, _: &mut Sources, _: Origin) -> Result { - match res { - Res::Struct(si) => Ok(si), - _ => Err(res), - } - } -} - -impl ResKind for Type { - type Res = TypeID; - fn ty() -> KindTy { - KindTy::Type - } - fn from_res( - res: Res, - types: &mut Vec, - s: &mut Sources, - _: Origin, - ) -> Result { - Ok(match res { - Res::Struct(si) => push_id(types, Type::Struct(si)), - Res::Type(id) => id, - _ => return Err(res), - }) - } -} - -pub trait TypeIDed { - fn type_id(&self, s: &Sources) -> TypeID; -} - -impl TypeIDed for TypeID { - fn type_id(&self, _: &Sources) -> TypeID { - *self - } -} - -impl TypeIDed for DataID { - fn type_id(&self, s: &Sources) -> TypeID { - s.data[self].ty - } -} - -impl TypeIDed for &T { - fn type_id(&self, s: &Sources) -> TypeID { - (*self).type_id(s) - } -} - -impl FromResidual> for ResolveRes { - fn from_residual(residual: Result) -> Self { - match residual { - Ok(_) => unreachable!(), - Err(r) => r, - } - } -} - -trait HasOrigin { - fn origin(&self, data: &ResData) -> Origin; -} - -impl HasOrigin for &IdentID { - fn origin(&self, data: &ResData) -> Origin { - data.s.idents[*self].origin - } -} diff --git a/src/ir/upper/ty.rs b/src/ir/upper/ty.rs deleted file mode 100644 index c1a5d57..0000000 --- a/src/ir/upper/ty.rs +++ /dev/null @@ -1,101 +0,0 @@ -use super::{FnID, GenericID, Len, ResolveRes, StructID, TypeID, UProgram, VarID}; - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct FieldRef { - pub parent: VarID, - pub name: String, -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct StructInst { - pub id: StructID, - /// assumed to be valid - pub gargs: Vec, -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct FnInst { - pub id: FnID, - /// assumed to be valid - pub gargs: Vec, -} - -#[derive(Clone, PartialEq)] -pub enum Type { - Bits(u32), - Struct(StructInst), - // this can be added for constraints later (F: fn(...) -> ...) - // Fn { args: Vec, ret: TypeID }, - // "fake" types - FnInst(FnInst), - Ref(TypeID), - Slice(TypeID), - Array(TypeID, Len), - Unit, - Infer, - Generic(GenericID), - Deref(TypeID), - Ptr(TypeID), - Error, -} - -impl Type { - pub fn rf(self, p: &mut UProgram) -> Self { - p.def_ty(self).rf() - } - pub fn derf(self, p: &mut UProgram) -> Self { - p.def_ty(self).derf() - } - pub fn arr(self, p: &mut UProgram, len: Len) -> Self { - p.def_ty(self).arr(len) - } - pub fn slice(self, p: &mut UProgram) -> Self { - p.def_ty(self).slice() - } -} - -impl TypeID { - pub fn rf(self) -> Type { - Type::Ref(self) - } - pub fn derf(self) -> Type { - Type::Deref(self) - } - pub fn arr(self, len: Len) -> Type { - Type::Array(self, len) - } - pub fn slice(self) -> Type { - Type::Slice(self) - } -} - -impl Type { - pub fn bx(self) -> Box { - Box::new(self) - } -} - -pub fn clean_type(types: &[Type], id: TypeID) -> Option { - match &types[id] { - &Type::Ptr(id) => clean_type(types, id), - &Type::Deref(did) => match &types[clean_type(types, did)?] { - &Type::Ref(id) => clean_type(types, id), - _ => Some(id), - }, - Type::Error => None, - _ => Some(id), - } -} - -pub fn resolved_type(types: &[Type], id: TypeID) -> Result { - match &types[id] { - &Type::Ptr(id) => resolved_type(types, id), - &Type::Deref(id) => match &types[resolved_type(types, id)?] { - &Type::Ref(id) => resolved_type(types, id), - Type::Infer => Err(ResolveRes::Unfinished), - _ => Err(ResolveRes::Finished), - }, - Type::Error => Err(ResolveRes::Finished), - _ => Ok(id), - } -} diff --git a/src/main.rs b/src/main.rs index 440a16d..79b9b7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,178 +1,8 @@ -#![feature(box_patterns)] #![feature(try_trait_v2)] +#![feature(associated_type_defaults)] #![feature(trait_alias)] -#![feature(let_chains)] -#![feature(iterator_try_collect)] -// dawg what -#![feature(str_as_str)] - -pub const FILE_EXT: &str = "lang"; - -use common::{CompilerOutput, SrcFile}; -use ir::{LProgram, UProgram}; -use parser::{Import, Imports, PModule, ParserCtx}; -use std::{ - collections::HashSet, - fs::{create_dir_all, OpenOptions}, - io::stdout, - os::unix::fs::OpenOptionsExt, - path::{Path, PathBuf}, - process::Command, -}; - -mod common; -mod compiler; -mod ir; mod parser; -mod util; fn main() { - let file = std::env::args_os().nth(1); - // TODO: professional arg parsing - let gdb = std::env::args().nth(2).is_some_and(|a| a == "--debug"); - let asm = std::env::args().nth(2).is_some_and(|a| a == "--asm"); - if let Some(path) = file { - let path = PathBuf::from(path); - run_file(&path, gdb, asm); - } else { - run_stdin(); - } -} - -impl UProgram { - pub fn from_path(path: &Path) -> (Self, CompilerOutput) { - let parent = path.parent().expect("bruh"); - let mut program = Self::new(); - let mut output = CompilerOutput::new(); - - let mut imports = Imports::new(); - imports.insert(Import(vec![path - .file_name() - .expect("bruh") - .to_str() - .expect("bruh") - .to_string()])); - let mut imported = HashSet::new(); - let mut fid = 0; - - while !imports.is_empty() { - let iter = std::mem::take(&mut imports); - for i in iter { - let import_path = &i.0; - if imported.contains(&i) { - continue; - } - let mut file_path = parent.to_path_buf(); - file_path.extend(import_path); - file_path.set_extension(FILE_EXT); - let text = std::fs::read_to_string(&file_path).expect("failed to read file"); - output.file_map.insert( - fid, - SrcFile { - path: file_path, - text: text.clone(), - }, - ); - let mut ctx = ParserCtx::new(fid, text.as_str(), &mut output); - fid += 1; - let res = PModule::parse(&mut ctx); - // println!("Parsed:"); - // println!("{:#?}", res.node); - res.lower(import_path.clone(), &mut program, &mut imports, &mut output); - imported.insert(i); - } - } - (program, output) - } -} - -fn run_file(path: &Path, gdb: bool, asm: bool) { - let (mut program, mut output) = UProgram::from_path(path); - program.resolve(&mut output); - // println!("vars:"); - // for (id, def) in program.iter_vars() { - // println!(" {id:?} = {}: {}", program.names.path(id), program.type_name(&def.ty)); - // } - // for (id, f) in program.iter_fns() { - // println!("{}:{id:?} = {:#?}", program.names.path(id), f); - // } - if !output.errs.is_empty() { - output.write_to(&mut stdout()); - return; - } - let program = LProgram::create(&program).expect("morir"); - let unlinked = compiler::compile(&program); - if asm { - println!("{:?}", unlinked); - } else { - let bin = unlinked.link().to_elf(); - println!("compiled"); - save_run(&bin, gdb); - } - output.write_to(&mut stdout()); -} - -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); - } - } - } -} - -pub fn run_stdin() { - println!("todo"); - // for line in BufReader::new(std::io::stdin()).lines() { - // let str = &line.expect("failed to read line"); - // 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"); - // } - // } - // ctx.output.write_for(&mut stdout(), str); - // } + parser::parse(include_str!("test.lang")); } diff --git a/src/parser/ctx.rs b/src/parser/ctx.rs new file mode 100644 index 0000000..16f730c --- /dev/null +++ b/src/parser/ctx.rs @@ -0,0 +1,108 @@ +use super::*; + +pub struct ParserCtx<'a> { + pub cursor: TokenCursor<'a>, + pub msgs: &'a mut Vec, +} + +impl<'a> ParserCtx<'a> { + pub fn new(cursor: impl Into>, msgs: &'a mut Vec) -> Self { + Self { + cursor: cursor.into(), + msgs, + } + } + + pub fn parse>(&mut self) -> Option> { + self.parse_with(()) + } + + pub fn parse_with(&mut self, data: T::Data) -> Option> { + let data = match T::parse(self, data) { + ParseResult::Ok(t) => Some(t), + ParseResult::Node(n) => return Some(n), + ParseResult::Break(msg) => { + self.msgs.push(msg); + return None; + } + ParseResult::Continue(msg) => { + self.msgs.push(msg); + None + } + ParseResult::SubErr => { + return None; + } + }; + Some(Node { data }) + } + + pub fn seek(&mut self, token: impl Into) -> bool { + let token = token.into(); + while let Some(next) = self.next() { + if next == token { + return true; + } + } + false + } + + pub fn expect_next(&mut self) -> Option { + let res = self.cursor.next(); + if res.is_none() { + self.msgs.push(CompilerMsg::new( + "Unexpected end of input", + self.cursor.prev_end(), + )); + } + res + } + + pub fn expect_peek(&self) -> Result<&Token, CompilerMsg> { + match self.cursor.peek() { + Some(t) => Ok(t), + None => Err(self.unexpected_end()), + } + } + + pub fn expect(&mut self, token: impl Into) -> Result<(), CompilerMsg> { + let token = token.into(); + if self.next_is_ref(&token) { + Ok(()) + } else { + Err(self.unexpected(format!("token {:?}", token))) + } + } + + fn unexpected_end(&self) -> CompilerMsg { + CompilerMsg::new("Unexpected end of input", self.next_start()) + } + + pub fn peek(&self) -> Option<&Token> { + self.cursor.peek() + } + + pub fn unexpected<'b>(&self, expected: impl std::fmt::Display) -> CompilerMsg { + if let Some((next, span)) = self.peek_span() { + CompilerMsg::new( + format!("Unexpected token {:?}, expected {}", next, expected), + span, + ) + } else { + self.unexpected_end() + } + } +} + +impl<'a> std::ops::Deref for ParserCtx<'a> { + type Target = TokenCursor<'a>; + + fn deref(&self) -> &Self::Target { + &self.cursor + } +} + +impl<'a> std::ops::DerefMut for ParserCtx<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cursor + } +} diff --git a/src/parser/io/mod.rs b/src/parser/io/mod.rs new file mode 100644 index 0000000..5ae01ff --- /dev/null +++ b/src/parser/io/mod.rs @@ -0,0 +1,37 @@ +use super::*; + +#[derive(Debug)] +pub struct CompilerMsg { + msg: String, + span: CharSpan, +} + +#[derive(Debug, Clone, Copy)] +pub struct CharSpan { + start: CharPos, + end: CharPos, +} + +impl CharPos { + pub fn to(self, end: CharPos) -> CharSpan { + CharSpan { start: self, end } + } +} + +impl CompilerMsg { + pub fn new(msg: impl Into, span: impl Into) -> Self { + Self { + msg: msg.into(), + span: span.into(), + } + } +} + +impl From for CharSpan { + fn from(value: CharPos) -> Self { + Self { + start: value, + end: value, + } + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 5bc0935..f40007f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,5 +1,19 @@ -// mod v1; -// mod v2; -mod v3; +mod ctx; +mod token; +mod tree; +mod io; -pub use v3::*; +pub use ctx::*; +use token::*; +pub use tree::*; +pub use io::*; + +pub fn parse(file: &str) { + let mut msgs = Vec::new(); + let mut parser = ParserCtx::new(file, &mut msgs); + if let Some(block) = parser.parse_with::(false) { + println!("{block:#?}"); + } else { + println!("{msgs:?}"); + } +} diff --git a/src/parser/token/chr.rs b/src/parser/token/chr.rs new file mode 100644 index 0000000..bfdedb4 --- /dev/null +++ b/src/parser/token/chr.rs @@ -0,0 +1,71 @@ +use std::{iter::Peekable, str::Chars}; + +#[derive(Clone)] +pub struct CharIter<'a> { + iter: Peekable>, + pos: CharPos, + next_pos: CharPos, +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct CharPos { + line: usize, + col: usize, +} + +impl<'a> CharIter<'a> { + pub fn new(text: &'a str) -> Self { + Self { + iter: text.chars().peekable(), + pos: CharPos::default(), + next_pos: CharPos::default(), + } + } + + pub fn next(&mut self) -> Option { + let next = self.iter.next(); + self.advance(next) + } + + fn advance(&mut self, c: Option) -> Option { + self.pos = self.next_pos; + if let Some(c) = c { + if c == '\n' { + self.next_pos.line += 1; + self.next_pos.col = 0; + } else { + self.next_pos.col += 1; + } + } + c + } + + pub fn peek(&mut self) -> Option { + self.iter.peek().copied() + } + + pub fn next_if(&mut self, f: impl FnOnce(&char) -> bool) -> Option { + let next = self.iter.next_if(f); + self.advance(next) + } + + pub fn pos(&self) -> CharPos { + self.pos + } + + pub fn until(&mut self, until: char) -> Option { + let mut str = String::new(); + let mut next = self.next()?; + while next != until { + str.push(next); + next = self.next()?; + } + Some(str) + } +} + +impl<'a> From<&'a str> for CharIter<'a> { + fn from(value: &'a str) -> Self { + Self::new(value) + } +} diff --git a/src/parser/token/kw.rs b/src/parser/token/kw.rs new file mode 100644 index 0000000..87d9dc7 --- /dev/null +++ b/src/parser/token/kw.rs @@ -0,0 +1,24 @@ +use super::*; + +#[derive(Debug, Clone, PartialEq)] +pub enum Keyword { + Let, + Fn, +} + +impl Keyword { + pub fn parse(ident: &str) -> Option { + Some(match ident { + "let" => Self::Let, + "fn" => Self::Fn, + _ => return None, + }) + } +} + +impl From for Token { + fn from(value: Keyword) -> Self { + Token::Keyword(value) + } +} + diff --git a/src/parser/token/lit.rs b/src/parser/token/lit.rs new file mode 100644 index 0000000..d91cd8f --- /dev/null +++ b/src/parser/token/lit.rs @@ -0,0 +1,4 @@ +#[derive(Debug, Clone, PartialEq)] +pub enum Literal { + String(String), +} diff --git a/src/parser/token/mod.rs b/src/parser/token/mod.rs new file mode 100644 index 0000000..b648d5a --- /dev/null +++ b/src/parser/token/mod.rs @@ -0,0 +1,134 @@ +use super::io::*; + +mod chr; +mod kw; +mod lit; +mod symbol; + +pub use chr::*; +pub use kw::*; +pub use lit::*; +pub use symbol::*; + +#[derive(Debug, Clone, PartialEq)] +pub enum Token { + Lit(Literal), + Keyword(Keyword), + Ident(String), + Symbol(Symbol), +} + +#[derive(Clone)] +pub struct TokenCursor<'a> { + iter: CharIter<'a>, + prev_sym: Option, + next: Option<(Token, CharSpan)>, + next_start: CharPos, + prev_end: CharPos, +} + +impl<'a> TokenCursor<'a> { + pub fn new(iter: impl Into>) -> Self { + let mut s = Self { + next: None, + prev_sym: None, + iter: iter.into(), + next_start: CharPos::default(), + prev_end: CharPos::default(), + }; + s.next(); + s + } + + pub fn next(&mut self) -> Option { + self.next_span().map(|n| n.0) + } + + pub fn next_span(&mut self) -> Option<(Token, CharSpan)> { + self.prev_end = self.iter.pos(); + self.prev_sym = self.next.as_ref().and_then(|n| match n.0 { + Token::Symbol(s) => Some(s), + _ => None, + }); + while self.iter.next_if(|c| c.is_whitespace()).is_some() {} + self.next_start = self.iter.pos(); + std::mem::replace(&mut self.next, Self::get_next(&mut self.iter)) + } + + fn get_next(iter: &mut CharIter) -> Option<(Token, CharSpan)> { + while iter.next_if(|c| c.is_whitespace()).is_some() {} + if let Some(c) = iter.next() { + let start = iter.pos(); + let val = Self::get_next_inner(iter, c); + let span = start.to(iter.pos()); + val.map(|v| (v, span)) + } else { + None + } + } + + fn get_next_inner(iter: &mut CharIter, c: char) -> Option { + if c == '"' { + return iter.until('"').map(|s| Token::Lit(Literal::String(s))); + } + if let Some(sym) = Symbol::parse(c, iter) { + return Some(Token::Symbol(sym)); + } + let mut ident = c.to_string(); + while let Some(c) = iter.next_if(|c| !c.is_whitespace() && Symbol::parse_char(*c).is_none()) + { + ident.push(c); + } + Some(if let Some(kw) = Keyword::parse(&ident) { + Token::Keyword(kw) + } else { + Token::Ident(ident) + }) + } + + pub fn peek(&self) -> Option<&Token> { + self.peek_span().map(|v| v.0) + } + + pub fn peek_span(&self) -> Option<(&Token, CharSpan)> { + self.next.as_ref().map(|(t, s)| (t, *s)) + } + + pub fn next_if(&mut self, f: impl FnOnce(&Token) -> bool) -> Option { + if self.peek().is_some_and(f) { + self.next() + } else { + None + } + } + + pub fn next_is(&mut self, token: impl Into) -> bool { + self.next_is_ref(&token.into()) + } + + pub fn peek_is(&mut self, token: impl Into) -> bool { + self.peek().is_some_and(|t| *t == token.into()) + } + + pub fn next_is_ref(&mut self, token: &Token) -> bool { + self.next_if(|t| t == token).is_some() + } + + pub fn next_start(&self) -> CharPos { + self.next_start + } + + pub fn prev_end(&self) -> CharPos { + self.prev_end + } + + pub fn prev_sym(&self) -> Option { + self.prev_sym + } +} + +impl<'a, T: Into>> From for TokenCursor<'a> { + fn from(value: T) -> Self { + Self::new(value.into()) + } +} diff --git a/src/parser/token/symbol.rs b/src/parser/token/symbol.rs new file mode 100644 index 0000000..315def9 --- /dev/null +++ b/src/parser/token/symbol.rs @@ -0,0 +1,83 @@ +use super::*; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Symbol { + // 1 char + OpenParen, + CloseParen, + OpenCurly, + CloseCurly, + Plus, + Minus, + Slash, + Asterisk, + Equal, + Colon, + Semicolon, + SingleQuote, + Comma, + // 2 chars + Arrow, + DoubleArrow, +} + +impl Symbol { + pub fn parse(c: char, iter: &mut CharIter) -> Option { + Self::parse_char(c).map(|s| s.parse_rest(iter)) + } + pub fn parse_char(c: char) -> Option { + Some(match c { + '(' => Symbol::OpenParen, + ')' => Symbol::CloseParen, + '{' => Symbol::OpenCurly, + '}' => Symbol::CloseCurly, + '+' => Symbol::Plus, + '-' => Symbol::Minus, + '/' => Symbol::Slash, + '*' => Symbol::Asterisk, + '=' => Symbol::Equal, + ':' => Symbol::Colon, + ';' => Symbol::Semicolon, + '\'' => Symbol::SingleQuote, + ',' => Symbol::Comma, + _ => return None, + }) + } + pub fn parse_rest(mut self, iter: &mut CharIter) -> Self { + let Some(next) = iter.peek() else { + return self; + }; + match (self, next) { + (Symbol::Minus, '>') => self = Symbol::Arrow, + (Symbol::Equal, '>') => self = Symbol::DoubleArrow, + _ => return self, + } + iter.next(); + self + } + pub fn str(&self) -> &'static str { + match self { + Symbol::OpenParen => "(", + Symbol::CloseParen => ")", + Symbol::OpenCurly => "{", + Symbol::CloseCurly => "}", + Symbol::Plus => "+", + Symbol::Minus => "-", + Symbol::Slash => "/", + Symbol::Asterisk => "*", + Symbol::Equal => "=", + Symbol::Colon => ":", + Symbol::Semicolon => ";", + Symbol::SingleQuote => "'", + Symbol::Arrow => "->", + Symbol::DoubleArrow => "=>", + Symbol::Comma => ",", + } + } +} + +impl From for Token { + fn from(value: Symbol) -> Self { + Token::Symbol(value) + } +} diff --git a/src/parser/tree/block.rs b/src/parser/tree/block.rs new file mode 100644 index 0000000..d22c876 --- /dev/null +++ b/src/parser/tree/block.rs @@ -0,0 +1,30 @@ +use super::*; + +#[derive(Debug)] +pub struct PBlock { + statements: Vec>, + return_last: bool, +} + +impl Parsable for PBlock { + type Data = bool; + + fn parse(ctx: &mut ParserCtx, curlies: bool) -> ParseResult { + let end = if curlies { + ctx.expect(Symbol::OpenCurly)?; + Some(Symbol::CloseCurly) + } else { + None + }; + let res = ctx.parse_list( + end, + SepCheck::new(Symbol::Semicolon) + .dup(true) + .skip_if(|ctx, _| ctx.prev_sym().is_some_and(|s| s == Symbol::CloseCurly)), + )?; + ParseResult::Ok(Self { + statements: res.nodes, + return_last: res.last_sep, + }) + } +} diff --git a/src/parser/tree/expr.rs b/src/parser/tree/expr.rs new file mode 100644 index 0000000..8f2f70d --- /dev/null +++ b/src/parser/tree/expr.rs @@ -0,0 +1,52 @@ +use super::*; + +#[derive(Debug)] +pub enum PExpr { + Ident(String), + Lit(Literal), + Block(Node), + Group(BNode), + Unit, +} + +impl Parsable for PExpr { + fn parse(ctx: &mut ParserCtx, _: ()) -> ParseResult { + Self::parse_unit(ctx) + } +} + +impl PExpr { + fn parse_unit(ctx: &mut ParserCtx) -> ParseResult { + ParseResult::Ok(match ctx.expect_peek()? { + Token::Lit(lit) => { + let res = PExpr::Lit(lit.clone()); + ctx.next(); + res + } + Token::Ident(ident) => { + let res = PExpr::Ident(ident.to_string()); + ctx.next(); + res + } + Token::Symbol(symbol) => match symbol { + Symbol::OpenParen => { + ctx.expect_next()?; + if ctx.next_is(Symbol::CloseParen) { + PExpr::Unit + } else { + let inner = ctx.parse(); + let Some(inner) = inner else { + ctx.seek(Symbol::CloseParen); + return ParseResult::SubErr; + }; + ctx.expect(Symbol::CloseParen)?; + PExpr::Group(inner.bx()) + } + } + Symbol::OpenCurly => PExpr::Block(ctx.parse_with(true)?), + _ => return ctx.unexpected("expression").res(), + }, + _ => return ctx.unexpected("expression").res(), + }) + } +} diff --git a/src/parser/tree/func.rs b/src/parser/tree/func.rs new file mode 100644 index 0000000..06b7ff3 --- /dev/null +++ b/src/parser/tree/func.rs @@ -0,0 +1,25 @@ +use super::*; + +#[derive(Debug)] +pub struct PFunc { + name: Node, + args: Vec>, + body: Node, +} + +impl Parsable for PFunc { + type Data = (); + + fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult { + ctx.expect(Keyword::Fn)?; + let name = ctx.parse()?; + ctx.expect(Symbol::OpenParen)?; + let args = ctx.parse_list(Some(Symbol::CloseParen), SepCheck::new(Symbol::Comma))?; + let body = ctx.parse()?; + ParseResult::Ok(Self { + name, + args: args.nodes, + body, + }) + } +} diff --git a/src/parser/tree/ident.rs b/src/parser/tree/ident.rs new file mode 100644 index 0000000..cced107 --- /dev/null +++ b/src/parser/tree/ident.rs @@ -0,0 +1,25 @@ +use super::*; +use std::ops::Deref; + +#[derive(Debug)] +pub struct PIdent(String); + +impl Deref for PIdent { + type Target = String; + + fn deref(&self) -> &String { + &self.0 + } +} + +impl Parsable for PIdent { + fn parse(ctx: &mut ParserCtx, _: ()) -> ParseResult { + if let Token::Ident(ident) = ctx.expect_peek()? { + let ident = ident.clone(); + ctx.next(); + ParseResult::Ok(Self(ident)) + } else { + ctx.unexpected("identifier").res() + } + } +} diff --git a/src/parser/tree/list.rs b/src/parser/tree/list.rs new file mode 100644 index 0000000..e749148 --- /dev/null +++ b/src/parser/tree/list.rs @@ -0,0 +1,128 @@ +use super::*; + +pub struct ListRes { + pub nodes: Vec>, + pub last_sep: bool, +} + +pub trait BetweenFn { + fn run(&mut self, ctx: &mut ParserCtx, prev: &Node) -> bool; +} + +impl ParserCtx<'_> { + pub fn parse_list>( + &mut self, + end: Option>, + mut between: impl BetweenFn, + ) -> Option> { + let end = end.map(|t| t.into()); + let mut nodes = Vec::new(); + let mut last_sep = false; + macro_rules! abort { + () => { + if end.is_some_and(|t| self.seek(t)) { + break; + } else { + return None; + } + }; + } + macro_rules! check_end { + () => { + if end.as_ref().is_some_and(|t| self.next_is_ref(t)) + || (end.is_none() && self.peek().is_none()) + { + break; + } + }; + } + loop { + check_end!(); + last_sep = false; + nodes.push(match self.parse() { + Some(node) => node, + None => abort!(), + }); + check_end!(); + if between.run(self, nodes.last().unwrap()) { + abort!(); + } + last_sep = true; + } + Some(ListRes { nodes, last_sep }) + } +} + +pub struct SepCheck { + pub sep: Token, + pub dup: bool, +} + +impl BetweenFn for SepCheck { + fn run(&mut self, ctx: &mut ParserCtx, prev: &Node) -> bool { + let Some(next) = ctx.expect_next() else { + return true; + }; + if next != self.sep { + ctx.msgs + .push(ctx.unexpected(format!("Expected {:?}", self.sep))); + return true; + } + if self.dup { + while ctx.next_is_ref(&self.sep) {} + } + false + } +} + +impl SepCheck { + pub fn new(sep: impl Into) -> Self { + Self { + sep: sep.into(), + dup: false, + } + } + pub fn dup(mut self, dup: bool) -> Self { + self.dup = dup; + self + } +} + +pub trait SkipFn = Fn(&mut ParserCtx, &Node) -> bool; + +// I hate everything. sepcheck is fine, this is not +pub struct SkipIf, B: BetweenFn> { + f: F, + inner: B, + _pd: std::marker::PhantomData, +} + +impl, B: BetweenFn> SkipIf { + pub fn new(f: F, run: B) -> Self { + Self { + f, + inner: run, + _pd: std::marker::PhantomData, + } + } +} + +impl, B: BetweenFn> BetweenFn for SkipIf { + fn run(&mut self, ctx: &mut ParserCtx, prev: &Node) -> bool { + if (self.f)(ctx, prev) { + false + } else { + self.inner.run(ctx, prev) + } + } +} + +pub trait BetweenFnUtil: BetweenFn + Sized { + fn skip_if>(self, f: F) -> SkipIf; +} + +impl, T> BetweenFnUtil for B { + fn skip_if>(self, f: F) -> SkipIf { + SkipIf::new(f, self) + } +} diff --git a/src/parser/tree/mod.rs b/src/parser/tree/mod.rs new file mode 100644 index 0000000..78404f6 --- /dev/null +++ b/src/parser/tree/mod.rs @@ -0,0 +1,21 @@ +mod block; +mod expr; +mod func; +mod ident; +mod list; +mod node; +mod statement; +mod ty; +mod vardef; + +pub use block::*; +pub use expr::*; +pub use func::*; +pub use ident::*; +pub use list::*; +pub use node::*; +pub use statement::*; +pub use ty::*; +pub use vardef::*; + +use super::*; diff --git a/src/parser/tree/node.rs b/src/parser/tree/node.rs new file mode 100644 index 0000000..0506412 --- /dev/null +++ b/src/parser/tree/node.rs @@ -0,0 +1,63 @@ +use super::*; + +pub struct Node { + pub data: Option, +} + +pub type BNode = Box>; + +pub enum ParseResult { + Ok(T), + Node(Node), + Continue(CompilerMsg), + Break(CompilerMsg), + SubErr, +} + +pub trait Parsable: Sized { + type Data = (); + fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult; +} + +impl Node { + pub fn bx(self) -> Box { + Box::new(self) + } + pub fn map(self, f: impl FnOnce(T) -> U) -> Node { + Node { + data: self.data.map(f), + } + } +} + +use std::convert::Infallible; +impl std::ops::FromResidual> for ParseResult { + fn from_residual(residual: Option) -> Self { + match residual { + None => ParseResult::SubErr, + } + } +} +impl std::ops::FromResidual> for ParseResult { + fn from_residual(residual: Result) -> Self { + match residual { + Err(msg) => ParseResult::Break(msg), + } + } +} + +impl CompilerMsg { + pub fn res(self) -> ParseResult { + ParseResult::Break(self) + } +} + +impl std::fmt::Debug for Node { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(d) = &self.data { + d.fmt(f) + } else { + f.write_str("{error}") + } + } +} diff --git a/src/parser/tree/statement.rs b/src/parser/tree/statement.rs new file mode 100644 index 0000000..d26a47f --- /dev/null +++ b/src/parser/tree/statement.rs @@ -0,0 +1,27 @@ +use super::*; + +#[derive(Debug)] +pub enum PStatement { + Expr(PExpr), + Let(Node, Node), + Fn(PFunc), +} + +impl Parsable for PStatement { + fn parse(ctx: &mut ParserCtx, _: ()) -> ParseResult { + let res = match ctx.expect_peek()? { + Token::Keyword(kw) => match kw { + Keyword::Let => { + ctx.next(); + let name = ctx.parse()?; + ctx.expect(Symbol::Equal)?; + let body = ctx.parse()?; + Self::Let(name, body) + } + Keyword::Fn => return ParseResult::Node(ctx.parse()?.map(PStatement::Fn)), + }, + _ => return ParseResult::Node(ctx.parse()?.map(PStatement::Expr)), + }; + ParseResult::Ok(res) + } +} diff --git a/src/parser/tree/ty.rs b/src/parser/tree/ty.rs new file mode 100644 index 0000000..c997721 --- /dev/null +++ b/src/parser/tree/ty.rs @@ -0,0 +1,12 @@ +use super::*; + +#[derive(Debug)] +pub struct PType { + name: Node, +} + +impl Parsable for PType { + fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult { + ParseResult::Ok(Self { name: ctx.parse()? }) + } +} diff --git a/src/parser/tree/vardef.rs b/src/parser/tree/vardef.rs new file mode 100644 index 0000000..2f8bc99 --- /dev/null +++ b/src/parser/tree/vardef.rs @@ -0,0 +1,18 @@ +use super::*; + +#[derive(Debug)] +pub struct PVarDef { + name: Node, + ty: Option>, +} + +impl Parsable for PVarDef { + fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult { + let name = ctx.parse()?; + let mut ty = None; + if ctx.next_is(Symbol::Colon) { + ty = Some(ctx.parse()?); + } + ParseResult::Ok(Self { name, ty }) + } +} diff --git a/src/parser/v1/cursor.rs b/src/parser/v1/cursor.rs deleted file mode 100644 index 70bf0d9..0000000 --- a/src/parser/v1/cursor.rs +++ /dev/null @@ -1,91 +0,0 @@ -use super::error::ParserError; -use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance}; -use super::FilePos; - -pub struct TokenCursor<'a> { - cursor: CharCursor<'a>, - next: Option, - next_pos: FilePos, - prev_end: FilePos, -} - -impl<'a> TokenCursor<'a> { - pub fn next(&mut self) -> Option { - self.prev_end = self.cursor.prev_pos(); - self.next_pos = self.cursor.next_pos(); - std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor)) - } - pub fn expect_next(&mut self) -> Result { - self.peek().ok_or(ParserError::unexpected_end())?; - Ok(self.next().unwrap()) - } - pub fn expect_token(&mut self, t: Token) -> Result<(), ParserError> { - let next = self.expect_next()?; - if t == next.token { - Ok(()) - } else { - Err(ParserError::unexpected_token(&next, &format!("{t:?}"))) - } - } - pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> { - 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 seek_syms(&mut self, syms: &[Symbol]) { - while self - .peek() - .is_some_and(|n| !syms.iter().any(|s| n.is_symbol(*s))) - { - self.next(); - } - } - pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> { - loop { - if f(self.peek()?) { - return self.peek(); - } - self.next(); - } - } - pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserError> { - self.expect_token(Token::Keyword(kw)) - } - pub fn peek(&self) -> Option<&TokenInstance> { - self.next.as_ref() - } - pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserError> { - self.peek().ok_or(ParserError::unexpected_end()) - } - pub fn chars(&mut self) -> &mut CharCursor<'a> { - &mut self.cursor - } - pub fn prev_end(&self) -> FilePos { - self.prev_end - } - pub fn next_pos(&self) -> FilePos { - self.next_pos - } -} - -impl<'a> From<&'a str> for TokenCursor<'a> { - fn from(string: &'a str) -> Self { - Self::from(CharCursor::from(string)) - } -} - -impl<'a> From> for TokenCursor<'a> { - fn from(mut cursor: CharCursor<'a>) -> Self { - let cur = TokenInstance::parse(&mut cursor); - Self { - cursor, - next: cur, - next_pos: FilePos::start(), - prev_end: FilePos::start(), - } - } -} diff --git a/src/parser/v1/error.rs b/src/parser/v1/error.rs deleted file mode 100644 index 79c6d55..0000000 --- a/src/parser/v1/error.rs +++ /dev/null @@ -1,62 +0,0 @@ -use super::{ - token::{FileSpan, TokenInstance}, - FilePos, -}; - -#[derive(Debug, Clone)] -pub struct ParserError { - pub msg: String, - pub spans: Vec, -} - -pub struct ParserErrors { - pub errs: Vec, -} - -impl ParserError { - pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self { - ParserError { - msg, - spans: instances.iter().map(|i| i.span).collect(), - } - } - pub fn from_msg(msg: String) -> Self { - Self { - msg, - spans: Vec::new(), - } - } - pub fn at(pos: FilePos, msg: String) -> Self { - Self { - msg, - spans: vec![FileSpan::at(pos)], - } - } - pub fn unexpected_end() -> Self { - Self::from_msg("unexpected end of input".to_string()) - } - pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self { - let t = &inst.token; - ParserError::from_instances( - &[inst], - format!("unexpected token {t:?}; expected {expected}"), - ) - } - pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { - let after = if self.spans.is_empty() { "" } else { ":" }; - writeln!(writer, "error: {}{}", self.msg, after)?; - for span in &self.spans { - span.write_for(writer, file)?; - } - Ok(()) - } -} - -impl ParserErrors { - pub fn new() -> Self { - Self { errs: Vec::new() } - } - pub fn add(&mut self, err: ParserError) { - self.errs.push(err); - } -} diff --git a/src/parser/v1/mod.rs b/src/parser/v1/mod.rs deleted file mode 100644 index 376ba9c..0000000 --- a/src/parser/v1/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::io::{stdout, BufRead, BufReader}; - -mod cursor; -mod error; -mod node; -mod nodes; -mod parse; -mod token; - -pub use cursor::*; -pub use error::*; -pub use node::*; -pub use nodes::*; -pub use parse::*; -use token::*; - -pub fn parse_file(file: &str) { - let mut errors = ParserErrors::new(); - let res = Module::parse_node(&mut TokenCursor::from(file), &mut errors); - println!("{:?}", res.node); - if errors.errs.is_empty() { - let module = res.node.resolve().expect("what"); - } - let out = &mut stdout(); - for err in errors.errs { - err.write_for(out, file).unwrap(); - } -} - -pub fn run_stdin() { - for line in BufReader::new(std::io::stdin()).lines() { - let mut errors = ParserErrors::new(); - let str = &line.expect("failed to read line"); - let mut cursor = TokenCursor::from(&str[..]); - if let Ok(expr) = Statement::parse_node(&mut cursor, &mut errors).node.as_ref() { - if cursor.next().is_none() { - println!("{:?}", expr); - } else { - println!("uhhhh ehehe"); - } - } - let out = &mut stdout(); - for err in errors.errs { - err.write_for(out, str).unwrap(); - } - } -} diff --git a/src/parser/v1/node.rs b/src/parser/v1/node.rs deleted file mode 100644 index d879373..0000000 --- a/src/parser/v1/node.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::{ - fmt::Debug, - ops::{Deref, DerefMut}, -}; - -use super::FileSpan; - -pub trait MaybeResolved { - type Inner; -} - -pub struct Resolved; -impl MaybeResolved for Resolved { - type Inner = T; -} - -pub struct Unresolved; -impl MaybeResolved for Unresolved { - type Inner = Result; -} - -pub struct Node { - pub inner: ::Inner, - pub span: FileSpan, -} - -impl Node { - pub fn new(inner: T, span: FileSpan) -> Self { - Self { - inner: Ok(inner), - span, - } - } - pub fn bx(self) -> Node, Unresolved> { - Node { - inner: self.inner.map(|v| Box::new(v)), - span: self.span, - } - } -} - -impl Deref for Node { - type Target = ::Inner; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for Node { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl Debug for Node { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.inner { - Ok(v) => v.fmt(f), - Err(_) => f.write_str("{error}"), - } - } -} - -impl Debug for Node { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f) - } -} - -pub trait Resolvable { - fn resolve(self) -> Result; -} - -impl, Res> Resolvable> for Node { - fn resolve(self) -> Result, ()> { - if let Ok(inner) = self.inner { - return Ok(Node { - inner: inner.resolve()?, - span: self.span, - }); - } - Err(()) - } -} - -impl, Res> Resolvable> for Box { - fn resolve(self) -> Result, ()> { - Ok(Box::new((*self).resolve()?)) - } -} diff --git a/src/parser/v1/nodes/body.rs b/src/parser/v1/nodes/body.rs deleted file mode 100644 index 2ee99c7..0000000 --- a/src/parser/v1/nodes/body.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::fmt::{Debug, Write}; - -use super::{ - token::Symbol, MaybeResolved, Node, NodeParsable, Parsable, ParseResult, ParserError, - ParserErrors, Resolvable, Resolved, Statement, TokenCursor, Unresolved, -}; -use crate::util::Padder; - -pub struct Body { - pub statements: Vec, R>>, -} - -impl Parsable for Body { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { - let mut statements = Vec::new(); - cursor.expect_sym(Symbol::OpenCurly)?; - if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { - cursor.next(); - return ParseResult::Ok(Self { statements }); - } - let mut expect_semi = false; - let mut recover = false; - loop { - let Some(next) = cursor.peek() else { - recover = true; - errors.add(ParserError::unexpected_end()); - break; - }; - if next.is_symbol(Symbol::CloseCurly) { - cursor.next(); - break; - } - if next.is_symbol(Symbol::Semicolon) { - cursor.next(); - expect_semi = false; - continue; - } else if expect_semi { - errors.add(ParserError { - msg: "expected ';'".to_string(), - spans: vec![cursor.next_pos().char_span()], - }); - } - let res = Statement::parse_node(cursor, errors); - statements.push(res.node); - expect_semi = true; - if res.recover { - cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); - if cursor.peek().is_none() { - recover = true; - break; - } - } - } - ParseResult::from_recover(Self { statements }, recover) - } -} - -impl Resolvable> for Body { - fn resolve(self) -> Result, ()> { - Ok(Body { - statements: self - .statements - .into_iter() - .map(|s| s.resolve()) - .collect::>()?, - }) - } -} - -impl Debug for Body { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.statements.first().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"))?; - } - f.write_char('}')?; - } else { - f.write_str("{}")?; - } - Ok(()) - } -} diff --git a/src/parser/v1/nodes/expr.rs b/src/parser/v1/nodes/expr.rs deleted file mode 100644 index dcaf788..0000000 --- a/src/parser/v1/nodes/expr.rs +++ /dev/null @@ -1,176 +0,0 @@ -use std::fmt::{Debug, Write}; - -use super::{ - BinaryOperator, Body, Ident, Literal, MaybeResolved, Node, NodeParsable, Parsable, ParseResult, - ParserError, ParserErrors, Resolvable, Resolved, Symbol, TokenCursor, UnaryOperator, - Unresolved, -}; - -type BoxNode = Node>, R>; - -pub enum Expr { - Lit(Node), - Ident(Node), - BinaryOp(BinaryOperator, BoxNode, BoxNode), - UnaryOp(UnaryOperator, BoxNode), - Block(Node, R>), - Call(BoxNode, Vec, R>>), - Group(BoxNode), -} - -impl Parsable for Expr { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { - let start = cursor.next_pos(); - let next = cursor.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(), - ))); - } - let res = Node::parse(cursor, errors); - if res.recover { - cursor.seek_sym(Symbol::CloseParen); - } - cursor.expect_sym(Symbol::CloseParen)?; - Self::Group(res.node.bx()) - } else if next.is_symbol(Symbol::OpenCurly) { - Self::Block(Body::parse_node(cursor, errors)?) - } else if let Some(op) = UnaryOperator::from_token(next) { - cursor.next(); - return Node::parse(cursor, errors).map(|n| { - let n = n.bx(); - if let Ok(box Self::BinaryOp(op2, n1, n2)) = n.inner { - let span = start.to(n1.span.end); - Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2) - } else { - Self::UnaryOp(op, n) - } - }); - } else if let Some(val) = Node::maybe_parse(cursor, errors) { - Self::Lit(val) - } else { - let res = Node::parse(cursor, &mut ParserErrors::new()); - if res.node.is_ok() { - Self::Ident(res.node) - } else { - let next = cursor.expect_peek()?; - return ParseResult::Err(ParserError::unexpected_token(next, "an expression")); - } - }; - let Some(mut next) = cursor.peek() else { - return ParseResult::Ok(e1); - }; - while next.is_symbol(Symbol::OpenParen) { - cursor.next(); - let mut args = Vec::new(); - loop { - let next = cursor.expect_peek()?; - if next.is_symbol(Symbol::CloseParen) { - break; - } - let res = Node::, Unresolved>::parse(cursor, errors); - args.push(res.node); - if res.recover { - cursor.seek_syms(&[Symbol::CloseParen, Symbol::Comma]); - } - let next = cursor.expect_peek()?; - if !next.is_symbol(Symbol::Comma) { - break; - } - cursor.next(); - } - cursor.expect_sym(Symbol::CloseParen)?; - let end = cursor.prev_end(); - e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args); - let Some(next2) = cursor.peek() else { - return ParseResult::Ok(e1); - }; - next = next2 - } - let end = cursor.prev_end(); - let mut recover = false; - let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) { - cursor.next(); - let mut n1 = Node::new(e1, start.to(end)).bx(); - let res = Node::parse(cursor, errors); - let mut n2 = res.node.bx(); - recover = res.recover; - if let Ok(box Self::BinaryOp(op2, _, _)) = n2.as_ref() { - if op.presedence() > op2.presedence() { - let Ok(box Self::BinaryOp(op2, n21, n22)) = n2.inner else { - unreachable!(); - }; - let end = n21.span.end; - n1 = Node::new(Self::BinaryOp(op, n1, n21), start.to(end)).bx(); - op = op2; - n2 = n22; - } - } - Self::BinaryOp(op, n1, n2) - } else { - e1 - }; - ParseResult::from_recover(res, recover) - } -} - -impl Resolvable> for Expr { - fn resolve(self) -> Result, ()> { - Ok(match self { - Expr::Lit(l) => Expr::Lit(l.resolve()?), - Expr::Ident(n) => Expr::Ident(n.resolve()?), - Expr::BinaryOp(o, e1, e2) => Expr::BinaryOp(o, e1.resolve()?, e2.resolve()?), - Expr::UnaryOp(o, e) => Expr::UnaryOp(o, e.resolve()?), - Expr::Block(b) => Expr::Block(b.resolve()?), - Expr::Call(f, args) => Expr::Call( - f.resolve()?, - args.into_iter() - .map(|arg| arg.resolve()) - .collect::>()?, - ), - Expr::Group(e) => Expr::Group(e.resolve()?), - }) - } -} - -impl Debug for Expr { - 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) => { - write!(f, "({:?}", *e1)?; - if op.pad() { - write!(f, " {} ", op.str())?; - } else { - write!(f, "{}", op.str())?; - } - write!(f, "{:?})", *e2)?; - } - Expr::Call(n, args) => { - n.fmt(f)?; - f.write_char('(')?; - if let Some(a) = args.first() { - a.fmt(f)?; - } - for arg in args.iter().skip(1) { - f.write_str(", ")?; - arg.fmt(f)?; - } - f.write_char(')')?; - } - Expr::UnaryOp(op, e) => { - write!(f, "(")?; - write!(f, "{}", op.str())?; - write!(f, "{:?})", *e)?; - } - Expr::Group(inner) => inner.fmt(f)?, - } - Ok(()) - } -} diff --git a/src/parser/v1/nodes/func.rs b/src/parser/v1/nodes/func.rs deleted file mode 100644 index 74f432c..0000000 --- a/src/parser/v1/nodes/func.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::{ - Body, Ident, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, - Resolved, Symbol, TokenCursor, Unresolved, -}; -use std::fmt::Debug; - -pub struct Function { - pub name: Node, - pub body: Node, R>, -} - -impl Parsable for Function { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { - cursor.expect_kw(Keyword::Fn)?; - let name = Node::parse(cursor, errors)?; - cursor.expect_sym(Symbol::OpenParen)?; - cursor.expect_sym(Symbol::CloseParen)?; - Node::parse(cursor, errors).map(|body| Self { name, body }) - } -} - -impl Debug for Function { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("fn ")?; - self.name.fmt(f)?; - f.write_str("() ")?; - self.body.fmt(f)?; - Ok(()) - } -} - -impl Resolvable> for Function { - fn resolve(self) -> Result, ()> { - Ok(Function { - name: self.name.resolve()?, - body: self.body.resolve()?, - }) - } -} diff --git a/src/parser/v1/nodes/ident.rs b/src/parser/v1/nodes/ident.rs deleted file mode 100644 index 92d1b09..0000000 --- a/src/parser/v1/nodes/ident.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::fmt::Debug; -use super::{Parsable, ParseResult, ParserError, Resolvable, Token}; - -pub struct Ident(String); - -impl Ident { - pub fn val(&self) -> &String { - &self.0 - } -} - -impl Parsable for Ident { - fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult { - let next = cursor.expect_peek()?; - let Token::Ident(name) = &next.token else { - return ParseResult::Err(ParserError::unexpected_token(next, "an identifier")); - }; - let name = name.to_string(); - cursor.next(); - ParseResult::Ok(Self(name)) - } -} - -impl Debug for Ident { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl Resolvable for Ident { - fn resolve(self) -> Result { - Ok(self) - } -} diff --git a/src/parser/v1/nodes/lit.rs b/src/parser/v1/nodes/lit.rs deleted file mode 100644 index 0ef626c..0000000 --- a/src/parser/v1/nodes/lit.rs +++ /dev/null @@ -1,120 +0,0 @@ -use super::{ - CharCursor, MaybeParsable, ParserError, ParserErrors, Resolvable, Symbol, Token, TokenCursor, -}; -use std::fmt::Debug; - -#[derive(Clone, PartialEq, Eq)] -pub enum Literal { - String(String), - Char(char), - Number(Number), - Unit, -} - -#[derive(Clone, PartialEq, Eq)] -pub struct Number { - pub whole: String, - pub decimal: Option, - pub ty: Option, -} - -impl MaybeParsable for Literal { - fn maybe_parse( - cursor: &mut TokenCursor, - _: &mut ParserErrors, - ) -> Result, ParserError> { - let inst = cursor.expect_peek()?; - let mut res = match &inst.token { - Token::Symbol(Symbol::SingleQuote) => { - let chars = cursor.chars(); - let c = chars.expect_next()?; - chars.expect('\'')?; - Self::Char(c) - } - Token::Symbol(Symbol::DoubleQuote) => Self::String(string_from(cursor.chars())?), - Token::Ident(text) => { - let first = text.chars().next().unwrap(); - if first.is_ascii_digit() { - Self::Number(Number { - whole: text.to_string(), - decimal: None, - ty: None, - }) - } else { - return Ok(None); - } - } - _ => return Ok(None), - }; - cursor.next(); - if let (Some(next), Self::Number(num)) = (cursor.peek(), &mut res) { - if next.token.is_symbol(Symbol::Dot) { - cursor.next(); - if let Some(next) = cursor.peek() { - if let Token::Ident(i) = &next.token { - if i.chars().next().unwrap().is_ascii_digit() { - num.decimal = Some(i.to_string()); - cursor.next(); - } - } - } - } - } - Ok(Some(res)) - } -} -pub fn string_from(cursor: &mut CharCursor) -> Result { - let mut str = String::new(); - loop { - let c = cursor.expect_next()?; - if c == '"' { - return Ok(str); - } - str.push(match c { - '\\' => { - let next = cursor.expect_next()?; - match next { - '"' => '"', - '\'' => '\'', - 't' => '\t', - 'n' => '\n', - '0' => '\0', - _ => { - todo!(); - } - } - } - _ => c, - }) - } -} - -impl Resolvable for Literal { - fn resolve(self) -> Result { - Ok(self) - } -} - -impl Debug for Literal { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::String(str) => str.fmt(f), - Self::Char(c) => c.fmt(f), - Self::Number(n) => n.fmt(f), - Self::Unit => f.write_str("()"), - } - } -} - -impl Debug for Number { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.whole)?; - if let Some(d) = &self.decimal { - write!(f, ".{}", d)?; - } - if let Some(ty) = &self.ty { - write!(f, "T{}", ty)?; - } - Ok(()) - } -} diff --git a/src/parser/v1/nodes/mod.rs b/src/parser/v1/nodes/mod.rs deleted file mode 100644 index 365b9a4..0000000 --- a/src/parser/v1/nodes/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod body; -mod expr; -mod func; -mod module; -mod op; -mod statement; -mod lit; -mod ident; - -pub use body::*; -pub use expr::*; -pub use func::*; -pub use module::*; -pub use op::*; -pub use statement::*; -pub use lit::*; -pub use ident::*; - -use super::*; diff --git a/src/parser/v1/nodes/module.rs b/src/parser/v1/nodes/module.rs deleted file mode 100644 index fe8f469..0000000 --- a/src/parser/v1/nodes/module.rs +++ /dev/null @@ -1,48 +0,0 @@ -use super::{ - Function, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserError, ParserErrors, - Resolvable, Resolved, TokenCursor, Unresolved, -}; -use std::fmt::Debug; - -pub struct Module { - pub functions: Vec, R>>, -} - -impl Parsable for Module { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { - let mut functions = Vec::new(); - loop { - let Some(next) = cursor.peek() else { - return ParseResult::Ok(Self { functions }); - }; - if next.is_keyword(Keyword::Fn) { - let res = Node::parse(cursor, errors); - functions.push(res.node); - if res.recover { - return ParseResult::Recover(Self { functions }); - } - } else { - errors.add(ParserError::unexpected_token(next, "fn")); - cursor.next(); - } - } - } -} - -impl Debug for Module { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.functions.fmt(f) - } -} - -impl Resolvable> for Module { - fn resolve(self) -> Result, ()> { - Ok(Module { - functions: self - .functions - .into_iter() - .map(|f| f.resolve()) - .collect::>()?, - }) - } -} diff --git a/src/parser/v1/nodes/op.rs b/src/parser/v1/nodes/op.rs deleted file mode 100644 index e066530..0000000 --- a/src/parser/v1/nodes/op.rs +++ /dev/null @@ -1,96 +0,0 @@ -use super::{Symbol, Token}; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum BinaryOperator { - Add, - Sub, - Mul, - Div, - LessThan, - GreaterThan, - Access, - Assign, -} - -impl BinaryOperator { - pub fn presedence(&self) -> u32 { - match self { - Self::Assign => 0, - Self::LessThan => 1, - Self::GreaterThan => 1, - Self::Add => 2, - Self::Sub => 3, - Self::Mul => 4, - Self::Div => 5, - Self::Access => 6, - } - } - pub fn str(&self) -> &str { - match self { - Self::Add => "+", - Self::Sub => "-", - Self::Mul => "*", - Self::Div => "/", - Self::LessThan => "<", - Self::GreaterThan => ">", - Self::Access => ".", - Self::Assign => "=", - } - } - pub fn from_token(token: &Token) -> Option { - let Token::Symbol(symbol) = token else { - return None; - }; - Some(match symbol { - Symbol::OpenAngle => Self::LessThan, - Symbol::CloseAngle => Self::GreaterThan, - Symbol::Plus => Self::Add, - Symbol::Minus => Self::Sub, - Symbol::Asterisk => Self::Mul, - Symbol::Slash => Self::Div, - Symbol::Dot => Self::Access, - Symbol::Equals => Self::Assign, - _ => { - return None; - } - }) - } - pub fn pad(&self) -> bool { - match self { - Self::Add => true, - Self::Sub => true, - Self::Mul => true, - Self::Div => true, - Self::LessThan => true, - Self::GreaterThan => true, - Self::Access => false, - Self::Assign => true, - } - } -} - -pub enum UnaryOperator { - Not, - Ref, -} - -impl UnaryOperator { - pub fn str(&self) -> &str { - match self { - Self::Not => "!", - Self::Ref => "&", - } - } - pub fn from_token(token: &Token) -> Option { - let Token::Symbol(symbol) = token else { - return None; - }; - Some(match symbol { - Symbol::Ampersand => Self::Ref, - Symbol::Bang => Self::Not, - _ => { - return None; - } - }) - } -} diff --git a/src/parser/v1/nodes/statement.rs b/src/parser/v1/nodes/statement.rs deleted file mode 100644 index 9cfede9..0000000 --- a/src/parser/v1/nodes/statement.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::fmt::{Debug, Write}; -use super::{ - Expr, Ident, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, Symbol, Token, TokenCursor, Unresolved -}; - -pub enum Statement { - Let(Node, Node, R>), - Return(Node, R>), - Expr(Node, R>), -} - -impl Parsable for Statement { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { - let next = cursor.expect_peek()?; - match next.token { - Token::Keyword(Keyword::Let) => { - cursor.next(); - let name = Node::parse(cursor, errors)?; - cursor.expect_sym(Symbol::Equals)?; - Node::parse(cursor, errors).map(|expr| Self::Let(name, expr)) - } - Token::Keyword(Keyword::Return) => { - cursor.next(); - Node::parse(cursor, errors).map(Self::Return) - } - _ => Node::parse(cursor, errors).map(Self::Expr), - } - } -} - -impl Resolvable> for Statement { - fn resolve(self) -> Result, ()> { - Ok(match self { - Self::Let(i, e) => Statement::Let(i.resolve()?, e.resolve()?), - Self::Return(e) => Statement::Return(e.resolve()?), - Self::Expr(e) => Statement::Expr(e.resolve()?), - }) - } -} - -impl Debug for Statement { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Statement::Let(n, e) => { - f.write_str("let ")?; - n.fmt(f); - f.write_str(" = ")?; - e.fmt(f)?; - f.write_char(';')?; - } - Statement::Return(e) => { - f.write_str("return ")?; - e.fmt(f)?; - f.write_char(';')?; - } - Statement::Expr(e) => { - e.fmt(f)?; - f.write_char(';')?; - } - } - Ok(()) - } -} diff --git a/src/parser/v1/parse.rs b/src/parser/v1/parse.rs deleted file mode 100644 index e732c6c..0000000 --- a/src/parser/v1/parse.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::{ - convert::Infallible, - ops::{ControlFlow, FromResidual, Try}, -}; - -use super::{Node, ParserError, ParserErrors, TokenCursor, Unresolved}; - -pub enum ParseResult { - Ok(T), - Recover(T), - Err(ParserError), - SubErr, -} - -impl ParseResult { - pub fn from_recover(data: T, recover: bool) -> Self { - if recover { - Self::Recover(data) - } else { - Self::Ok(data) - } - } -} - -impl Try for ParseResult { - type Output = Result; - type Residual = Option; - fn from_output(output: Self::Output) -> Self { - match output { - Ok(v) => Self::Ok(v), - Err(v) => Self::Recover(v), - } - } - fn branch(self) -> ControlFlow { - match self { - ParseResult::Ok(v) => ControlFlow::Continue(Ok(v)), - ParseResult::Recover(v) => ControlFlow::Continue(Err(v)), - ParseResult::Err(e) => ControlFlow::Break(Some(e)), - ParseResult::SubErr => ControlFlow::Break(None), - } - } -} - -impl FromResidual for ParseResult { - fn from_residual(residual: ::Residual) -> Self { - match residual { - Some(err) => Self::Err(err), - None => Self::SubErr, - } - } -} - -impl FromResidual> for ParseResult { - fn from_residual(residual: Result) -> Self { - match residual { - Err(e) => Self::Err(e), - } - } -} - -impl FromResidual> for ParseResult { - fn from_residual(residual: ParseResult) -> Self { - match residual { - ParseResult::Err(e) => Self::Err(e), - ParseResult::SubErr => Self::SubErr, - _ => unreachable!() - } - } -} - -pub struct NodeParseResult { - pub node: Node, - pub recover: bool, -} - -impl NodeParseResult { - pub fn map) -> U, U>(self, op: F) -> ParseResult { - let res = op(self.node); - if self.recover { - ParseResult::Recover(res) - } else { - ParseResult::Ok(res) - } - } -} - -impl Try for NodeParseResult { - type Output = Node; - type Residual = ParseResult; - - fn from_output(output: Self::Output) -> Self { - Self { - node: output, - recover: false, - } - } - - fn branch(self) -> ControlFlow { - if self.recover { - ControlFlow::Break(ParseResult::SubErr) - } else { - ControlFlow::Continue(self.node) - } - } -} - -impl FromResidual for NodeParseResult { - fn from_residual(_: ::Residual) -> Self { - // I hope this is unreachable ??? - unreachable!() - } -} - -pub trait Parsable: Sized { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult; -} - -pub trait MaybeParsable: Sized { - fn maybe_parse( - cursor: &mut TokenCursor, - errors: &mut ParserErrors, - ) -> Result, ParserError>; -} - -impl Node { - pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult { - let start = cursor.next_pos(); - let (inner, recover) = match T::parse(cursor, errors) { - ParseResult::Ok(v) => (Ok(v), false), - ParseResult::Recover(v) => (Ok(v), true), - ParseResult::Err(e) => { - errors.add(e); - (Err(()), true) - } - ParseResult::SubErr => (Err(()), true), - }; - let end = cursor.prev_end(); - NodeParseResult { - node: Self { - inner, - span: start.to(end), - }, - recover, - } - } -} - -impl Node { - pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Option { - let start = cursor.next_pos(); - let inner = match T::maybe_parse(cursor, errors) { - Ok(v) => Ok(v?), - Err(e) => { - errors.add(e); - Err(()) - } - }; - let end = cursor.prev_end(); - Some(Self { - inner, - span: start.to(end), - }) - } -} - -pub trait NodeParsable { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult - where - Self: Sized; -} -impl NodeParsable for T { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult - where - Self: Sized, - { - Node::::parse(cursor, errors) - } -} diff --git a/src/parser/v1/token/cursor.rs b/src/parser/v1/token/cursor.rs deleted file mode 100644 index 02796f6..0000000 --- a/src/parser/v1/token/cursor.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::{iter::Peekable, str::Chars}; - -use super::super::ParserError; -use super::FilePos; - -pub struct CharCursor<'a> { - chars: Peekable>, - next_pos: FilePos, - prev_pos: FilePos, -} - -impl CharCursor<'_> { - pub fn next(&mut self) -> Option { - let res = self.peek()?; - self.advance(); - Some(res) - } - pub fn expect(&mut self, c: char) -> Result<(), ParserError> { - let next = self.expect_next()?; - if next == c { - Ok(()) - } else { - Err(ParserError::at( - self.prev_pos, - format!("unexpected char '{next}'; expected '{c}'"), - )) - } - } - pub fn skip_whitespace(&mut self) { - while self.peek().is_some_and(|c| c.is_whitespace()) { - self.advance(); - } - } - pub fn peek(&mut self) -> Option { - self.chars.peek().copied() - } - pub fn advance(&mut self) { - let Some(next) = self.chars.next() else { - return; - }; - self.prev_pos = self.next_pos; - if next == '\n' { - self.next_pos.col = 0; - self.next_pos.line += 1; - } else { - self.next_pos.col += 1; - } - } - pub fn expect_next(&mut self) -> Result { - self.next().ok_or(ParserError::unexpected_end()) - } - pub fn next_pos(&self) -> FilePos { - self.next_pos - } - pub fn prev_pos(&self) -> FilePos { - self.prev_pos - } -} - -impl<'a> From<&'a str> for CharCursor<'a> { - fn from(value: &'a str) -> Self { - Self { - chars: value.chars().peekable(), - next_pos: FilePos::start(), - prev_pos: FilePos::start(), - } - } -} diff --git a/src/parser/v1/token/file.rs b/src/parser/v1/token/file.rs deleted file mode 100644 index 6402f4a..0000000 --- a/src/parser/v1/token/file.rs +++ /dev/null @@ -1,80 +0,0 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct FilePos { - pub line: usize, - pub col: usize, -} - -#[derive(Debug, Clone, Copy)] -pub struct FileSpan { - pub start: FilePos, - pub end: FilePos, -} - -impl FilePos { - pub fn start() -> Self { - Self { line: 0, col: 0 } - } -} - -impl FilePos { - pub fn to(self, end: FilePos) -> FileSpan { - FileSpan { start: self, end } - } - pub fn char_span(self) -> FileSpan { - FileSpan::at(self) - } -} - -const BEFORE: usize = 1; -const AFTER: usize = 0; - -impl FileSpan { - pub fn at(pos: FilePos) -> Self { - Self { - start: pos, - end: pos, - } - } - pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { - let start = self.start.line.saturating_sub(BEFORE); - let num_before = self.start.line - start; - let mut lines = file.lines().skip(start); - let width = format!("{}", self.end.line + AFTER).len(); - let same_line = self.start.line == self.end.line; - for i in 0..num_before { - writeln!(writer, "{:>width$} | {}", start + i, lines.next().unwrap())?; - } - let line = lines.next().unwrap(); - writeln!(writer, "{:>width$} | {}", self.start.line, line)?; - let len = if same_line { - self.end.col - self.start.col + 1 - } else { - line.len() - self.start.col - }; - writeln!( - writer, - "{} | {}", - " ".repeat(width), - " ".repeat(self.start.col) + &"^".repeat(len) - )?; - if !same_line { - for _ in 0..self.end.line - self.start.line - 1 { - lines.next(); - } - let line = lines.next().unwrap(); - writeln!(writer, "{:>width$} | {}", self.end.line, line)?; - writeln!( - writer, - "{} | {}", - " ".repeat(width), - "^".repeat(self.end.col + 1) - )?; - } - // for i in 0..AFTER { - // if let Some(next) = lines.next() { - // writeln!(writer, "{:>width$} | {}", self.end.line + i + 1, next)?; - // } - // } - Ok(()) - } -} diff --git a/src/parser/v1/token/keyword.rs b/src/parser/v1/token/keyword.rs deleted file mode 100644 index f22782c..0000000 --- a/src/parser/v1/token/keyword.rs +++ /dev/null @@ -1,19 +0,0 @@ -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Keyword { - Fn, - Let, - If, - Return, -} - -impl Keyword { - pub fn from_string(str: &str) -> Option { - Some(match str { - "fn" => Self::Fn, - "let" => Self::Let, - "if" => Self::If, - "return" => Self::Return, - _ => return None, - }) - } -} diff --git a/src/parser/v1/token/mod.rs b/src/parser/v1/token/mod.rs deleted file mode 100644 index 59e25f6..0000000 --- a/src/parser/v1/token/mod.rs +++ /dev/null @@ -1,90 +0,0 @@ -mod cursor; -mod file; -mod keyword; -mod symbol; - -use std::ops::Deref; - -pub use cursor::*; -pub use file::*; -pub use keyword::*; -pub use symbol::*; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Token { - Symbol(Symbol), - Ident(String), - Keyword(Keyword), -} - -#[derive(Debug, Clone)] -pub struct TokenInstance { - pub token: Token, - pub span: FileSpan, -} - -impl TokenInstance { - pub fn parse(cursor: &mut CharCursor) -> Option { - cursor.skip_whitespace(); - cursor.peek()?; - let start = cursor.next_pos(); - if let Some(s) = Symbol::parse(cursor) { - if s == Symbol::DoubleSlash { - while cursor.next() != Some('\n') {} - return Self::parse(cursor); - } - let end = cursor.prev_pos(); - return Some(Self { - token: Token::Symbol(s), - span: FileSpan { start, end }, - }); - } - let mut word = String::new(); - while let Some(c) = cursor.peek() { - if c.is_whitespace() || Symbol::from_char(c).is_some() { - break; - } - word.push(c); - cursor.advance(); - } - let end = cursor.prev_pos(); - let token = if let Some(keyword) = Keyword::from_string(&word) { - Token::Keyword(keyword) - } else { - Token::Ident(word) - }; - Some(Self { - token, - span: FileSpan { start, end }, - }) - } -} - -impl Token { - pub fn is_symbol(&self, symbol: Symbol) -> bool { - match self { - Token::Symbol(s) => *s == symbol, - _ => false, - } - } - pub fn is_symbol_and(&self, f: impl Fn(Symbol) -> bool) -> bool { - match self { - Token::Symbol(s) => f(*s), - _ => false, - } - } - pub fn is_keyword(&self, kw: Keyword) -> bool { - match self { - Token::Keyword(k) => *k == kw, - _ => false, - } - } -} - -impl Deref for TokenInstance { - type Target = Token; - - fn deref(&self) -> &Self::Target { - &self.token - } -} diff --git a/src/parser/v1/token/symbol.rs b/src/parser/v1/token/symbol.rs deleted file mode 100644 index 2ed689a..0000000 --- a/src/parser/v1/token/symbol.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::fmt::Debug; - -use super::CharCursor; - -#[derive(PartialEq, Eq, Clone, Copy)] -pub enum Symbol { - Semicolon, - Colon, - DoubleColon, - Equals, - DoubleEquals, - Arrow, - DoubleArrow, - Plus, - Minus, - Asterisk, - Slash, - DoubleSlash, - Dot, - OpenParen, - CloseParen, - OpenCurly, - CloseCurly, - OpenSquare, - CloseSquare, - OpenAngle, - CloseAngle, - SingleQuote, - DoubleQuote, - Bang, - Ampersand, - DoubleAmpersand, - Pipe, - DoublePipe, - Comma, -} - -impl Symbol { - pub fn parse(cursor: &mut CharCursor) -> Option { - Self::from_char(cursor.peek()?).map(|mut s| { - cursor.advance(); - s.finish(cursor); - s - }) - } - pub fn from_char(c: char) -> Option { - Some(match c { - '(' => Self::OpenParen, - ')' => Self::CloseParen, - '[' => Self::OpenSquare, - ']' => Self::CloseSquare, - '{' => Self::OpenCurly, - '}' => Self::CloseCurly, - '<' => Self::OpenAngle, - '>' => Self::CloseAngle, - ';' => Self::Semicolon, - ':' => Self::Colon, - '+' => Self::Plus, - '-' => Self::Minus, - '*' => Self::Asterisk, - '/' => Self::Slash, - '=' => Self::Equals, - '.' => Self::Dot, - '\'' => Self::SingleQuote, - '"' => Self::DoubleQuote, - '!' => Self::Bang, - '&' => Self::Ampersand, - '|' => Self::Pipe, - ',' => Self::Comma, - _ => return None, - }) - } - pub fn finish(&mut self, cursor: &mut CharCursor) { - let Some(next) = cursor.peek() else { - return; - }; - *self = match self { - Self::Colon => match next { - ':' => Self::DoubleColon, - _ => return, - }, - Self::Minus => match next { - '>' => Self::Arrow, - _ => return, - }, - Self::Equals => match next { - '=' => Self::DoubleEquals, - '>' => Self::DoubleArrow, - _ => return, - }, - Self::Slash => match next { - '/' => Self::DoubleSlash, - _ => return, - }, - Self::Ampersand => match next { - '&' => Self::DoubleAmpersand, - _ => return, - }, - Self::Pipe => match next { - '&' => Self::DoublePipe, - _ => return, - }, - _ => return, - }; - cursor.advance(); - } - pub fn str(&self) -> &str { - match self { - Self::Semicolon => ";", - Self::Colon => ":", - Self::DoubleColon => "::", - Self::Equals => "=", - Self::DoubleEquals => "==", - Self::Arrow => "->", - Self::DoubleArrow => "=>", - Self::Plus => "+", - Self::Minus => "-", - Self::Asterisk => "*", - Self::Slash => "/", - Self::DoubleSlash => "//", - Self::Dot => ".", - Self::OpenParen => "(", - Self::CloseParen => ")", - Self::OpenCurly => "{", - Self::CloseCurly => "}", - Self::OpenSquare => "[", - Self::CloseSquare => "]", - Self::OpenAngle => "<", - Self::CloseAngle => ">", - Self::SingleQuote => "'", - Self::DoubleQuote => "\"", - Self::Bang => "!", - Self::Comma => ",", - Self::Ampersand => "&", - Self::DoubleAmpersand => "&&", - Self::Pipe => "|", - Self::DoublePipe => "||", - } - } -} - -impl Debug for Symbol { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "'{}'", self.str()) - } -} diff --git a/src/parser/v2/body.rs b/src/parser/v2/body.rs deleted file mode 100644 index 1e25afc..0000000 --- a/src/parser/v2/body.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::collections::HashSet; -use std::fmt::{Debug, Write}; -use std::sync::LazyLock; - -use crate::util::Padder; - -use super::util::WHITESPACE_SET; -use super::CharCursor; -use super::Expr; -use super::ParserError; - -static NAME_END: LazyLock> = LazyLock::new(|| { - let mut set = WHITESPACE_SET.clone(); - set.extend(&['(']); - set -}); - -pub struct Body { - statements: Vec, -} - -pub enum Statement { - Let(String, Expr), - Return(Expr), - Expr(Expr), -} - -impl Body { - pub fn parse(cursor: &mut CharCursor) -> Result { - cursor.skip_whitespace(); - let mut statements = Vec::new(); - cursor.expect_char('{')?; - loop { - cursor.skip_whitespace(); - let next = cursor.expect_peek()?; - if next == '}' { - cursor.next(); - return Ok(Self { statements }); - } - statements.push(Statement::parse(cursor)?); - } - } -} - -impl Statement { - pub fn parse(cursor: &mut CharCursor) -> Result { - cursor.skip_whitespace(); - Ok(if cursor.advance_if_str("let", &WHITESPACE_SET) { - cursor.skip_whitespace(); - let name = cursor.until(&NAME_END); - if name.is_empty() { - return Err(ParserError::at( - cursor.pos(), - "Expected variable name".to_string(), - )); - } - cursor.skip_whitespace(); - cursor.expect_char('=')?; - let expr = Expr::parse(cursor)?; - cursor.skip_whitespace(); - cursor.expect_char(';')?; - Self::Let(name, expr) - } else if cursor.advance_if_str("return", &WHITESPACE_SET) { - let expr = Expr::parse(cursor)?; - cursor.skip_whitespace(); - cursor.expect_char(';')?; - Self::Return(expr) - } else { - let expr = Expr::parse(cursor)?; - match cursor.expect_peek()? { - ';' => { - cursor.next(); - Self::Expr(expr) - } - '}' => Self::Return(expr), - _ => { - cursor.next(); - return Err(ParserError::at( - cursor.prev_pos(), - "unexpected end of statement; expected a ';' or '}'".to_string(), - )); - } - } - }) - } -} - -impl Debug for Statement { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Statement::Let(n, e) => { - write!(f, "let {n} = {e:?};")?; - } - Statement::Return(e) => { - write!(f, "return {e:?};")?; - } - Statement::Expr(e) => { - write!(f, "{e:?};")?; - } - } - Ok(()) - } -} - -impl Debug for Body { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.statements.first().is_some() { - write!(f, "{{\n ")?; - let mut padder = Padder::new(f); - for s in &self.statements { - // they don't expose wrap_buf :grief: - writeln!(padder, "{s:?}")?; - } - write!(f, "}}")?; - } else { - write!(f, "{{}}")?; - } - Ok(()) - } -} diff --git a/src/parser/v2/cursor.rs b/src/parser/v2/cursor.rs deleted file mode 100644 index 2b636e1..0000000 --- a/src/parser/v2/cursor.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::{collections::HashSet, iter::Peekable, str::Chars}; - -use super::{error::ParserError, util::WHITESPACE_SET}; - -#[derive(Debug, Clone, Copy)] -pub struct FilePos { - pub line: usize, - pub col: usize, -} - -#[derive(Debug, Clone, Copy)] -pub struct FileRegion { - pub start: FilePos, - pub end: FilePos, -} - -pub struct CharCursor<'a> { - chars: Peekable>, - pos: FilePos, - prev_pos: FilePos, -} - -impl CharCursor<'_> { - pub fn until(&mut self, set: &HashSet) -> String { - let mut str = String::new(); - loop { - let Some(next) = self.peek() else { - return str; - }; - if set.contains(&next) { - return str; - } - str.push(next); - self.advance(); - } - } - pub fn skip_whitespace(&mut self) { - while self.peek().is_some_and(|c| c.is_whitespace()) { - self.advance(); - } - let mut copy = self.chars.clone(); - if let Some('/') = copy.next() { - if let Some('/') = copy.next() { - self.advance(); - self.advance(); - while self.next() != Some('\n') {} - self.skip_whitespace(); - } - } - } - pub fn next(&mut self) -> Option { - let res = self.peek()?; - self.advance(); - Some(res) - } - pub fn peek(&mut self) -> Option { - self.chars.peek().copied() - } - pub fn advance(&mut self) { - self.prev_pos = self.pos; - if self.peek().is_some_and(|c| c == '\n') { - self.pos.col = 0; - self.pos.line += 1; - } else { - self.pos.col += 1; - } - self.chars.next(); - } - pub fn advance_if(&mut self, c: char) -> bool { - if let Some(c2) = self.peek() { - if c2 == c { - self.advance(); - return true; - } - } - false - } - pub fn advance_if_str(&mut self, exp: &str, end: &HashSet) -> bool { - let mut new = self.chars.clone(); - for e in exp.chars() { - let Some(c) = new.next() else { - return false; - }; - if e != c { - return false; - } - } - if new.peek().is_some_and(|c| !end.contains(c)) { - return false; - } - for _ in 0..exp.len() { - self.advance(); - } - true - } - pub fn expect_char(&mut self, c: char) -> Result<(), ParserError> { - let next = self.expect_next()?; - if next == c { - Ok(()) - } else { - Err(ParserError::at( - self.prev_pos, - format!("unexpected char '{next}'; expected '{c}'"), - )) - } - } - pub fn expect_next(&mut self) -> Result { - self.next().ok_or(ParserError::unexpected_end()) - } - pub fn expect_peek(&mut self) -> Result { - self.peek().ok_or(ParserError::unexpected_end()) - } - pub fn pos(&self) -> FilePos { - self.pos - } - pub fn prev_pos(&self) -> FilePos { - self.prev_pos - } -} - -impl<'a> From<&'a str> for CharCursor<'a> { - fn from(value: &'a str) -> Self { - Self { - chars: value.chars().peekable(), - pos: FilePos::start(), - prev_pos: FilePos::start(), - } - } -} - -impl FilePos { - pub fn start() -> Self { - Self { line: 0, col: 0 } - } -} diff --git a/src/parser/v2/error.rs b/src/parser/v2/error.rs deleted file mode 100644 index 0dbd4b3..0000000 --- a/src/parser/v2/error.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::{FilePos, FileRegion}; - -#[derive(Debug)] -pub struct ParserError { - pub msg: String, - pub regions: Vec, -} - -impl ParserError { - pub fn from_msg(msg: String) -> Self { - Self { - msg, - regions: Vec::new(), - } - } - pub fn at(pos: FilePos, msg: String) -> Self { - Self { - msg, - regions: vec![FileRegion { - start: pos, - end: pos, - }], - } - } - pub fn unexpected_end() -> Self { - Self::from_msg("Unexpected end of input".to_string()) - } -} - -const BEFORE: usize = 1; -const AFTER: usize = 1; - -pub fn print_error(err: ParserError, file: &str) { - let after = if err.regions.is_empty() {""} else {":"}; - println!("error: {}{}", err.msg, after); - for reg in err.regions { - print_region(file, reg); - } -} - -pub fn print_region(file: &str, reg: FileRegion) { - let start = reg.start.line.saturating_sub(BEFORE); - let num_before = reg.start.line - start; - let mut lines = file.lines().skip(start); - let len = reg.end.col - reg.start.col + 1; - let width = format!("{}", reg.end.line + AFTER).len(); - for i in 0..num_before + 1 { - println!("{:>width$} | {}", start + i, lines.next().unwrap()); - } - println!( - "{} | {}", - " ".repeat(width), - " ".repeat(reg.start.col) + &"^".repeat(len) - ); - for i in 0..AFTER { - if let Some(next) = lines.next() { - println!("{:>width$} | {}", reg.end.line + i + 1, next); - } - } -} diff --git a/src/parser/v2/expr.rs b/src/parser/v2/expr.rs deleted file mode 100644 index 8f6cb3c..0000000 --- a/src/parser/v2/expr.rs +++ /dev/null @@ -1,247 +0,0 @@ -use super::{util::WHITESPACE_SET, Body, CharCursor, ParserError}; -use std::{collections::HashSet, fmt::Debug, sync::LazyLock}; - -static SYMBOLS: LazyLock> = LazyLock::new(|| { - let mut set = HashSet::new(); - for o in Operator::ALL { - for c in o.str().chars() { - set.insert(c); - } - } - set -}); - -static IDENT_END: LazyLock> = LazyLock::new(|| { - let mut set = WHITESPACE_SET.clone(); - let symbols = &SYMBOLS; - set.extend(symbols.iter().chain(&[';', '(', ')'])); - set -}); - -#[derive(Debug)] -pub enum Val { - String(String), - Number(String), - Unit, -} - -pub enum Expr { - Block(Body), - Val(Val), - Ident(String), - BinaryOp(Operator, Box, Box), - Call(Box, Vec), -} - -#[derive(Debug, PartialEq, Eq)] -pub enum Operator { - Add, - Sub, - Mul, - Div, - LessThan, - GreaterThan, - Offset, -} - -impl Expr { - pub fn parse(cursor: &mut CharCursor) -> Result { - cursor.skip_whitespace(); - let Some(next) = cursor.peek() else { - return Ok(Self::Val(Val::Unit)); - }; - let mut e1 = match next { - '(' => { - cursor.advance(); - let expr = Self::parse(cursor)?; - cursor.skip_whitespace(); - cursor.expect_char(')')?; - expr - } - '{' => { - Self::Block(Body::parse(cursor)?) - } - _ => { - if let Some(val) = Val::parse_nonunit(cursor)? { - Self::Val(val) - } else { - let name = cursor.until(&IDENT_END); - Self::Ident(name) - } - } - }; - cursor.skip_whitespace(); - let Some(mut next) = cursor.peek() else { - return Ok(e1); - }; - while next == '(' { - cursor.advance(); - let inner = Self::parse(cursor)?; - cursor.skip_whitespace(); - cursor.expect_char(')')?; - e1 = Self::Call(Box::new(e1), vec![inner]); - let Some(next2) = cursor.peek() else { - return Ok(e1); - }; - next = next2 - } - if let Some(op) = Operator::parse(cursor) { - let e2 = Self::parse(cursor)?; - return Ok(if let Self::BinaryOp(op_next, e2, e3) = e2 { - if op.presedence() > op_next.presedence() { - Self::BinaryOp(op_next, Box::new(Self::BinaryOp(op, Box::new(e1), e2)), e3) - } else { - Self::BinaryOp(op, Box::new(e1), Box::new(Self::BinaryOp(op_next, e2, e3))) - } - } else { - Self::BinaryOp(op, Box::new(e1), Box::new(e2)) - }); - }; - Ok(e1) - } -} - -impl Val { - pub fn parse_nonunit(cursor: &mut CharCursor) -> Result, ParserError> { - let Some(next) = cursor.peek() else { - return Ok(None); - }; - Ok(Some(match next { - '"' => { - cursor.advance(); - let mut str = String::new(); - loop { - let mut next = cursor.expect_next()?; - if next == '"' { - break; - } - if next == '\\' { - next = match cursor.expect_next()? { - '"' => '"', - c => { - return Err(ParserError::at( - cursor.pos(), - format!("unexpected escape char '{c}'"), - )) - } - } - } - str.push(next); - } - Self::String(str) - } - '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => { - let mut str = String::new(); - loop { - let Some(next) = cursor.peek() else { - break; - }; - match next { - '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => { - str.push(next); - } - _ => break, - } - cursor.advance(); - } - Self::Number(str) - } - _ => { - return Ok(None); - } - })) - } -} - -impl Operator { - const ALL: [Self; 7] = [ - Self::Add, - Self::Sub, - Self::Mul, - Self::Div, - Self::Offset, - Self::GreaterThan, - Self::LessThan, - ]; - pub fn presedence(&self) -> u32 { - match self { - Operator::LessThan => 0, - Operator::GreaterThan => 0, - Operator::Add => 1, - Operator::Sub => 2, - Operator::Mul => 3, - Operator::Div => 4, - Operator::Offset => 5, - } - } - pub fn str(&self) -> &str { - match self { - Self::Add => "+", - Self::Sub => "-", - Self::Mul => "*", - Self::Div => "/", - Self::LessThan => "<", - Self::GreaterThan => ">", - Self::Offset => ".", - } - } - pub fn parse(cursor: &mut CharCursor) -> Option { - let res = match cursor.peek()? { - '+' => Operator::Add, - '-' => Operator::Sub, - '*' => Operator::Mul, - '/' => Operator::Div, - '.' => Operator::Offset, - _ => return None, - }; - for _ in 0..res.str().len() { - cursor.advance(); - } - Some(res) - } - pub fn pad(&self) -> bool { - match self { - Operator::Add => true, - Operator::Sub => true, - Operator::Mul => true, - Operator::Div => true, - Operator::LessThan => true, - Operator::GreaterThan => true, - Operator::Offset => false, - } - } -} - -impl Debug for Expr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Expr::Block(b) => write!(f, "{:?}", b)?, - Expr::Ident(n) => f.write_str(n)?, - Expr::BinaryOp(op, e1, e2) => { - write!(f, "({:?}", *e1)?; - if op.pad() { - write!(f, " {} ", op.str())?; - } else { - write!(f, "{}", op.str())?; - } - write!(f, "{:?})", *e2)?; - } - Expr::Call(n, args) => { - n.fmt(f)?; - write!(f, "(")?; - if let Some(a) = args.first() { - a.fmt(f)?; - } - for arg in args.iter().skip(1) { - write!(f, ", ")?; - arg.fmt(f)?; - } - write!(f, ")")?; - } - Expr::Val(v) => { - write!(f, "{:?}", v)?; - } - } - Ok(()) - } -} diff --git a/src/parser/v2/mod.rs b/src/parser/v2/mod.rs deleted file mode 100644 index 27c633e..0000000 --- a/src/parser/v2/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::io::{BufRead, BufReader}; - -mod body; -mod cursor; -mod error; -mod expr; -mod module; -mod util; - -pub use body::*; -pub use cursor::*; -pub use error::*; -pub use expr::*; -pub use module::*; - -pub fn parse_file(file: &str) { - match Module::parse(&mut CharCursor::from(file)) { - Err(err) => print_error(err, file), - Ok(module) => println!("{module:#?}"), - } -} - -pub fn run_stdin() { - for line in BufReader::new(std::io::stdin()).lines() { - let str = &line.expect("failed to read line"); - let mut cursor = CharCursor::from(&str[..]); - match Statement::parse(&mut cursor) { - Ok(expr) => println!("{:?}", expr), - Err(err) => print_error(err, str), - } - } -} diff --git a/src/parser/v2/module.rs b/src/parser/v2/module.rs deleted file mode 100644 index fd76fee..0000000 --- a/src/parser/v2/module.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::{collections::HashSet, fmt::Debug, sync::LazyLock}; -use super::{util::WHITESPACE_SET, Body, CharCursor, ParserError}; - -#[derive(Debug)] -pub struct Module { - functions: Vec, -} - -pub struct Function { - pub name: String, - pub body: Body, -} - -static NAME_END: LazyLock> = LazyLock::new(|| { - let mut set = WHITESPACE_SET.clone(); - set.extend(&['(']); - set -}); - -impl Module { - pub fn parse(cursor: &mut CharCursor) -> Result { - let mut functions = Vec::new(); - loop { - let next = cursor.until(&WHITESPACE_SET); - if next.is_empty() { - return Ok(Self { functions }); - } - if next == "fn" { - functions.push(Function::parse(cursor)?); - } else { - return Err(ParserError::at(cursor.pos(), "expected fn".to_string())); - } - } - } -} - -impl Function { - pub fn parse(cursor: &mut CharCursor) -> Result { - cursor.skip_whitespace(); - let name = cursor.until(&NAME_END); - if name.is_empty() { - return Err(ParserError::at(cursor.pos(), "expected function name".to_string())); - } - cursor.expect_char('(')?; - cursor.expect_char(')')?; - let body = Body::parse(cursor)?; - Ok(Self { name, body }) - } -} - -impl Debug for Function { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("fn ")?; - f.write_str(&self.name)?; - f.write_str("() ")?; - self.body.fmt(f)?; - Ok(()) - } -} diff --git a/src/parser/v2/util.rs b/src/parser/v2/util.rs deleted file mode 100644 index 200a568..0000000 --- a/src/parser/v2/util.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::{collections::HashSet, sync::LazyLock}; - -pub const WHITESPACE: [char; 25] = [ - '\u{0009}', '\u{000A}', '\u{000B}', '\u{000C}', '\u{000D}', '\u{0020}', '\u{0085}', '\u{00A0}', - '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}', '\u{2004}', '\u{2005}', '\u{2006}', - '\u{2007}', '\u{2008}', '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', '\u{205F}', - '\u{3000}', -]; - -pub static WHITESPACE_SET: LazyLock> = LazyLock::new(|| HashSet::from_iter(WHITESPACE)); diff --git a/src/parser/v3/ctx.rs b/src/parser/v3/ctx.rs deleted file mode 100644 index 2b9bb10..0000000 --- a/src/parser/v3/ctx.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::ops::{Deref, DerefMut}; - -use crate::common::FileID; - -use super::{ - CompilerMsg, CompilerOutput, Node, NodeParseResult, Parsable, ParsableWith, TokenCursor, -}; - -pub struct ParserCtx<'a> { - pub cursor: TokenCursor<'a>, - pub output: &'a mut CompilerOutput, -} - -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: CompilerMsg) { - self.output.err(msg); - } - pub fn hint(&mut self, msg: CompilerMsg) { - self.output.hint(msg); - } - pub fn parse(&mut self) -> NodeParseResult { - Node::parse(self) - } - pub fn maybe_parse(&mut self) -> Option> - where - Option: Parsable, - { - Node::maybe_parse(self) - } - pub fn parse_with(&mut self, data: T::Data) -> NodeParseResult { - Node::parse_with(self, data) - } - pub fn new(file: FileID, string: &'a str, output: &'a mut CompilerOutput) -> Self { - Self { - cursor: TokenCursor::from_file_str(file, string), - output, - } - } -} diff --git a/src/parser/v3/cursor.rs b/src/parser/v3/cursor.rs deleted file mode 100644 index d9f30d4..0000000 --- a/src/parser/v3/cursor.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::common::FileID; - -use super::{ - token::{CharCursor, Keyword, Symbol, Token, TokenInstance}, - CompilerMsg, FilePos, -}; - -pub struct TokenCursor<'a> { - cursor: CharCursor<'a>, - next: Option, - next_start: FilePos, - prev_end: FilePos, -} - -impl<'a> TokenCursor<'a> { - pub fn next(&mut self) -> Option { - self.prev_end = self.cursor.prev_pos(); - let next = TokenInstance::parse(&mut self.cursor); - self.next_start = next - .as_ref() - .map(|i| i.span.end) - .unwrap_or(FilePos::start(self.file())); - std::mem::replace(&mut self.next, next) - } - pub fn expect_next(&mut self) -> Result { - self.peek().ok_or(CompilerMsg::unexpected_end())?; - Ok(self.next().unwrap()) - } - pub fn expect_token(&mut self, t: Token) -> Result<(), CompilerMsg> { - let next = self.expect_next()?; - if t == next.token { - Ok(()) - } else { - Err(CompilerMsg::unexpected_token(&next, &format!("{t:?}"))) - } - } - pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), CompilerMsg> { - self.expect_token(Token::Symbol(symbol)) - } - pub fn next_on_new_line(&mut self) -> bool { - 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 - .peek() - .is_some_and(|n| !syms.iter().any(|s| n.is_symbol(*s))) - { - 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()?) { - return self.peek(); - } - self.next(); - } - } - pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), CompilerMsg> { - self.expect_token(Token::Keyword(kw)) - } - pub fn peek(&self) -> Option<&TokenInstance> { - self.next.as_ref() - } - pub fn expect_peek(&mut self) -> Result<&TokenInstance, CompilerMsg> { - self.peek().ok_or(CompilerMsg::unexpected_end()) - } - pub fn chars(&mut self) -> &mut CharCursor<'a> { - &mut self.cursor - } - pub fn prev_end(&self) -> FilePos { - self.prev_end - } - pub fn next_start(&self) -> FilePos { - self.next_start - } - pub fn from_file_str(id: FileID, string: &'a str) -> Self { - Self::from(CharCursor::from_file_str(id, string)) - } - pub fn file(&self) -> FileID { - self.cursor.file() - } -} - -impl<'a> From> for TokenCursor<'a> { - fn from(mut cursor: CharCursor<'a>) -> Self { - let cur = TokenInstance::parse(&mut cursor); - Self { - next_start: FilePos::start(cursor.file()), - prev_end: FilePos::start(cursor.file()), - cursor, - next: cur, - } - } -} diff --git a/src/parser/v3/error.rs b/src/parser/v3/error.rs deleted file mode 100644 index 060bb4d..0000000 --- a/src/parser/v3/error.rs +++ /dev/null @@ -1,29 +0,0 @@ -use super::Node; -use super::PIdent; -use super::CompilerMsg; -use super::TokenInstance; - -impl CompilerMsg { - pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self { - CompilerMsg { - msg, - spans: instances.iter().map(|i| i.span).collect(), - } - } - pub fn unexpected_end() -> Self { - Self::from_msg("unexpected end of input".to_string()) - } - pub fn identifier_not_found(id: &Node) -> Self { - Self { - msg: format!("Identifier '{}' not found", id.as_ref().unwrap()), - spans: vec![id.origin], - } - } - pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self { - let t = &inst.token; - CompilerMsg::from_instances( - &[inst], - format!("unexpected token {t:?}; expected {expected}"), - ) - } -} diff --git a/src/parser/v3/import.rs b/src/parser/v3/import.rs deleted file mode 100644 index 8fbc8fa..0000000 --- a/src/parser/v3/import.rs +++ /dev/null @@ -1,5 +0,0 @@ -use std::collections::HashSet; - -#[derive(Clone, Eq, PartialEq, Hash)] -pub struct Import(pub Vec); -pub type Imports = HashSet; diff --git a/src/parser/v3/lower/arch/mod.rs b/src/parser/v3/lower/arch/mod.rs deleted file mode 100644 index 1bb80e6..0000000 --- a/src/parser/v3/lower/arch/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod riscv64; -pub use super::*; diff --git a/src/parser/v3/lower/arch/riscv64.rs b/src/parser/v3/lower/arch/riscv64.rs deleted file mode 100644 index caadad5..0000000 --- a/src/parser/v3/lower/arch/riscv64.rs +++ /dev/null @@ -1,216 +0,0 @@ -use super::{FnLowerCtx, Node, PAsmArg, PIdent, PInstruction}; -use crate::{ - compiler::arch::riscv::*, - ir::{ - arch::riscv64::{RV64Instruction, RegRef}, - UIdent, - }, -}; - -impl RV64Instruction { - pub fn parse(inst: &PInstruction, ctx: &mut FnLowerCtx) -> Option { - let args = &inst.args[..]; - let opstr = &**inst.op.inner.as_ref()?; - // TODO: surely this can be abstracted... - let opi = |ctx: &mut FnLowerCtx<'_, '_, '_>, op: Funct3| -> Option { - let [dest, src, imm] = args else { - ctx.err(format!("{opstr} requires 3 arguments")); - return None; - }; - let dest = RegRef::from_arg(dest, ctx)?; - let src = RegRef::from_arg(src, ctx)?; - let imm = i32_from_arg(imm, ctx)?; - Some(Self::OpImm { op, dest, src, imm }) - }; - let op = |ctx: &mut FnLowerCtx<'_, '_, '_>, op: Funct3, funct: Funct7| -> Option { - let [dest, src1, src2] = args else { - ctx.err(format!("{opstr} requires 3 arguments")); - return None; - }; - let dest = RegRef::from_arg(dest, ctx)?; - let src1 = RegRef::from_arg(src1, ctx)?; - let src2 = RegRef::from_arg(src2, ctx)?; - Some(Self::Op { - op, - funct, - dest, - src1, - src2, - }) - }; - let opif7 = |ctx: &mut FnLowerCtx<'_>, op: Funct3, funct: Funct7| -> Option { - let [dest, src, imm] = args else { - ctx.err(format!("{opstr} requires 3 arguments")); - return None; - }; - let dest = RegRef::from_arg(dest, ctx)?; - let src = RegRef::from_arg(src, ctx)?; - let imm = i32_from_arg(imm, ctx)?; - Some(Self::OpImmF7 { - op, - funct, - dest, - src, - imm, - }) - }; - let store = |ctx: &mut FnLowerCtx<'_>, width: Funct3| -> Option { - let [src, offset, base] = args else { - ctx.err(format!("{opstr} requires 3 arguments")); - return None; - }; - let src = RegRef::from_arg(src, ctx)?; - let offset = i32_from_arg(offset, ctx)?; - let base = RegRef::from_arg(base, ctx)?; - Some(Self::Store { - width, - src, - offset, - base, - }) - }; - let load = |ctx: &mut FnLowerCtx<'_>, width: Funct3| -> Option { - let [dest, offset, base] = args else { - ctx.err(format!("{opstr} requires 3 arguments")); - return None; - }; - let dest = RegRef::from_arg(dest, ctx)?; - let offset = i32_from_arg(offset, ctx)?; - let base = RegRef::from_arg(base, ctx)?; - Some(Self::Load { - width, - dest, - offset, - base, - }) - }; - Some(match opstr { - "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 = i32_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 } - } - "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 } - } - - "lb" => load(ctx, width::B)?, - "lh" => load(ctx, width::H)?, - "lw" => load(ctx, width::W)?, - "ld" => load(ctx, width::D)?, - "lbu" => load(ctx, width::BU)?, - "lhu" => load(ctx, width::HU)?, - "lwu" => load(ctx, width::WU)?, - - "sb" => store(ctx, width::B)?, - "sh" => store(ctx, width::H)?, - "sw" => store(ctx, width::W)?, - "sd" => store(ctx, width::D)?, - - "addi" => opi(ctx, op32i::ADD)?, - "slti" => opi(ctx, op32i::SLT)?, - "sltiu" => opi(ctx, op32i::SLTU)?, - "xori" => opi(ctx, op32i::XOR)?, - "ori" => opi(ctx, op32i::OR)?, - "andi" => opi(ctx, op32i::AND)?, - - "slli" => opif7(ctx, op32i::SL, op32i::LOGICAL)?, - "srli" => opif7(ctx, op32i::SR, op32i::LOGICAL)?, - "srla" => opif7(ctx, op32i::SR, op32i::ARITHMETIC)?, - - "add" => op(ctx, op32i::ADD, op32i::F7ADD)?, - "sub" => op(ctx, op32i::ADD, op32i::F7SUB)?, - "sll" => op(ctx, op32i::SL, op32i::FUNCT7)?, - "slt" => op(ctx, op32i::SLT, op32i::FUNCT7)?, - "sltu" => op(ctx, op32i::SLTU, op32i::FUNCT7)?, - "xor" => op(ctx, op32i::XOR, op32i::FUNCT7)?, - "srl" => op(ctx, op32i::SR, op32i::LOGICAL)?, - "sra" => op(ctx, op32i::SR, op32i::ARITHMETIC)?, - "or" => op(ctx, op32i::OR, op32i::FUNCT7)?, - "and" => op(ctx, op32i::AND, op32i::FUNCT7)?, - - "mul" => op(ctx, op32m::MUL, op32m::FUNCT7)?, - "mulh" => op(ctx, op32m::MULH, op32m::FUNCT7)?, - "mulhsu" => op(ctx, op32m::MULHSU, op32m::FUNCT7)?, - "mulhu" => op(ctx, op32m::MULHU, op32m::FUNCT7)?, - "div" => op(ctx, op32m::DIV, op32m::FUNCT7)?, - "divu" => op(ctx, op32m::DIVU, op32m::FUNCT7)?, - "rem" => op(ctx, op32m::REM, op32m::FUNCT7)?, - "remu" => op(ctx, op32m::REMU, op32m::FUNCT7)?, - - w => { - ctx.err_at(inst.op.origin, format!("Unknown instruction '{}'", w)); - return None; - } - }) - } -} - -pub fn arg_to_var(node: &Node, ctx: &mut FnLowerCtx) -> Option { - let PAsmArg::Ref(node) = node.inner.as_ref()? else { - ctx.err_at( - node.origin, - "Expected variable / function reference".to_string(), - ); - return None; - }; - ctx.ident(node) -} - -impl RegRef { - pub fn from_arg(node: &Node, ctx: &mut FnLowerCtx) -> Option { - Some(match node.inner.as_ref()? { - PAsmArg::Value(node) => { - let reg = Reg::from_ident(node, ctx)?; - Self::Reg(reg) - } - PAsmArg::Ref(node) => Self::Var(ctx.ident(node)?), - }) - } -} - -impl Reg { - pub fn from_ident(node: &Node, ctx: &mut FnLowerCtx) -> Option { - let s = &**node.inner.as_ref()?; - let res = Reg::from_str(s); - if res.is_none() { - ctx.err_at(node.origin, format!("Unknown reg name '{}'", s)); - } - res - } -} - -fn i32_from_arg(node: &Node, ctx: &mut FnLowerCtx) -> Option { - let PAsmArg::Value(node) = node.inner.as_ref()? else { - ctx.err_at(node.origin, "Expected an i32, found reference".to_string()); - return None; - }; - let word = node.inner.as_ref()?; - match word.parse::() { - Ok(x) => Some(x), - Err(_) => { - ctx.err_at(node.origin, format!("Expected an i64, found {}", word)); - None - } - } -} diff --git a/src/parser/v3/lower/asm.rs b/src/parser/v3/lower/asm.rs deleted file mode 100644 index 68f8f7f..0000000 --- a/src/parser/v3/lower/asm.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::{ - compiler::arch::riscv::Reg, - ir::{ - arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, IdentID, Type, UInstruction, - }, - parser::PAsmBlockArg, -}; - -use super::{FnLowerCtx, FnLowerable, PAsmBlock, PInstruction, PUAsmBlockArg}; - -type PLAsmBlockArg = PAsmBlockArg; - -impl FnLowerable for PInstruction { - type Output = RV64Instruction; - - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - RV64Instruction::parse(self, ctx) - } -} - -impl FnLowerable for PAsmBlock { - type Output = IdentID; - - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - let mut args = Vec::new(); - let mut output = None; - for a in &self.args { - if let Some(a) = a.lower(ctx) { - match a { - PAsmBlockArg::In { reg, var } => args.push(AsmBlockArg { - reg, - var, - ty: AsmBlockArgType::In, - }), - PAsmBlockArg::Out { reg } => { - if output.is_some() { - ctx.err("cannot evaluate to more than one register".to_string()); - continue; - } - let var = ctx.temp(Type::Bits(64)); - args.push(AsmBlockArg { - var, - reg, - ty: AsmBlockArgType::Out, - }); - output = Some(var) - } - } - } - } - let block = UInstruction::AsmBlock { - instructions: { - let mut v = Vec::new(); - for i in &self.instructions { - if let Some(i) = i.lower(ctx) { - v.push(i); - } - } - v - }, - args, - }; - ctx.push(block); - output - } -} - -impl FnLowerable for PUAsmBlockArg { - type Output = PLAsmBlockArg; - - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - Some(match self { - PAsmBlockArg::In { reg, var } => PLAsmBlockArg::In { - reg: Reg::from_ident(reg, ctx)?, - var: var.as_ref()?.lower(ctx)?, - }, - PAsmBlockArg::Out { reg } => PLAsmBlockArg::Out { - reg: Reg::from_ident(reg, ctx)?, - }, - }) - } -} diff --git a/src/parser/v3/lower/block.rs b/src/parser/v3/lower/block.rs deleted file mode 100644 index cd8be59..0000000 --- a/src/parser/v3/lower/block.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::{ - ir::{IdentID, Type, UIdent, UInstruction, UVar}, - parser::{PConstStatement, PStatementLike}, -}; - -use super::{FnLowerCtx, FnLowerable, Import, PBlock, PStatement}; - -impl FnLowerable for PBlock { - type Output = IdentID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - ctx.ident_stack.push(); - let mut last = None; - let mut statements = Vec::new(); - let mut fn_nodes = Vec::new(); - let mut struct_nodes = Vec::new(); - let mut import_nodes = Vec::new(); - // first sort statements - for s in &self.statements { - let Some(s) = s.as_ref() else { - continue; - }; - match s { - PStatementLike::Statement(s) => statements.push(s), - PStatementLike::Const(pconst_statement) => match pconst_statement { - PConstStatement::Fn(f) => fn_nodes.push(f), - PConstStatement::Struct(s) => struct_nodes.push(s), - PConstStatement::Import(i) => import_nodes.push(i), - }, - } - } - // then lower imports - for i_n in &import_nodes { - if let Some(i) = i_n.as_ref() { - let name = &i.0; - let path = ctx.path_for(name); - let import = Import(path.clone()); - if ctx.imports.insert(import) { - ctx.def_var(UVar { - name: name.clone(), - ty: Type::Module(path), - origin: i_n.origin, - }); - } - } - } - // then lower const things - let mut structs = Vec::new(); - for s in &struct_nodes { - structs.push(s.lower(ctx.ctx)); - } - for (s, id) in struct_nodes.iter().zip(structs) { - if let Some(id) = id { - s.lower(ctx.ctx); - } - } - let mut fns = Vec::new(); - for f in &fn_nodes { - fns.push(f.lower(ctx.ctx)); - } - for (f, id) in fn_nodes.iter().zip(fns) { - if let Some(id) = id { - f.lower(ctx.ctx); - } - } - // then lower statements - for s in statements { - last = s.lower(ctx); - } - ctx.ident_stack.pop(); - last - } -} - -impl FnLowerable for PStatement { - type Output = IdentID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - match self { - PStatement::Let(def, e) => { - let def = def.lower(ctx.ctx)?; - let res = e.lower(ctx); - if let Some(res) = res { - ctx.push(UInstruction::Mv { dst: def, src: res }); - } - None - } - PStatement::Return(e) => { - if let Some(e) = e { - let src = e.lower(ctx)?; - ctx.push_at(UInstruction::Ret { src }, src.origin); - } else { - let src = ctx.temp(Type::Unit); - ctx.push_at(UInstruction::Ret { src }, src.origin); - } - None - } - PStatement::Expr(e) => e.lower(ctx), - } - } -} diff --git a/src/parser/v3/lower/def.rs b/src/parser/v3/lower/def.rs deleted file mode 100644 index efe0bd0..0000000 --- a/src/parser/v3/lower/def.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::collections::HashMap; - -use crate::ir::{UVar, VarID}; - -use super::{ModuleLowerCtx, Node, PVarDef}; - -impl Node { - pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> Option { - let s = self.as_ref()?; - let name = s.name.as_ref().map_or("{error}", |v| v).to_string(); - let ty = match &s.ty { - Some(ty) => ty.lower(ctx), - None => ctx.infer(), - }; - Some(ctx.def_var(UVar { - name, - ty, - origin: self.origin, - parent: None, - children: HashMap::new(), - })) - } -} diff --git a/src/parser/v3/lower/expr.rs b/src/parser/v3/lower/expr.rs deleted file mode 100644 index 3b0dc19..0000000 --- a/src/parser/v3/lower/expr.rs +++ /dev/null @@ -1,206 +0,0 @@ -use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp}; -use crate::{ - ir::{IdentID, IdentStatus, MemRes, Member, MemberID, MemberIdent, Type, UData, UInstruction}, - parser::InfixOp, -}; - -impl FnLowerable for PExpr { - type Output = IdentID; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - let mut e = self; - let mut path = Vec::new(); - let mut gargs = None; - loop { - match e { - PExpr::Member(node, ty, ident) => { - e = if let Some(t) = node.as_ref() { - ctx.origin = node.origin; - path.push((ty, ident, gargs.unwrap_or_default())); - &**t - } else { - return None; - }; - } - PExpr::Generic(node, nodes) => match gargs { - None => gargs = Some(nodes.iter().map(|t| t.lower(ctx)).collect::>()), - Some(_) => { - // this should cover the more specific area of ::<...> - // but too lazy rn - ctx.err("Cannot specify generics here".to_string()); - return None; - } - }, - _ => break, - } - } - while let PExpr::Member(node, ty, ident) = e {} - if path.len() > 0 { - // UIdent { - // origin: ctx.origin, - // status: IdentStatus::Unres { base: (), path: () }, - // } - } - let origin = ctx.origin; - Some(match e { - PExpr::Lit(l) => match l { - super::PLiteral::String(s) => { - let sty = Type::Bits(8).slice(ctx.p); - let dst = ctx.temp_var(origin, sty); - let data = s.as_bytes().to_vec(); - let dty = Type::Bits(8).arr(ctx.ctx.p, data.len() as u32); - let dty = ctx.def_ty(dty); - let src = ctx.def_data(UData { - name: format!("string \"{}\"", s.replace("\n", "\\n")), - ty: dty, - content: data, - }); - ctx.push(UInstruction::LoadSlice { dst, src }); - dst - } - super::PLiteral::Char(c) => { - let ty = ctx.def_ty(Type::Bits(8)); - let dst = ctx.temp_var(origin, ty.clone()); - let src = ctx.def_data(UData { - name: format!("char '{c}'"), - ty, - content: c.to_string().as_bytes().to_vec(), - }); - ctx.push(UInstruction::LoadData { dst, src }); - dst - } - super::PLiteral::Number(n) => { - // TODO: temp - let ty = ctx.def_ty(Type::Bits(64)); - let dst = ctx.temp_var(origin, ty.clone()); - let src = ctx.def_data(UData { - name: format!("num {n:?}"), - ty, - content: n.whole.parse::().unwrap().to_le_bytes().to_vec(), - }); - ctx.push(UInstruction::LoadData { dst, src }); - dst - } - super::PLiteral::Unit => ctx.temp_var(origin, Type::Unit), - }, - PExpr::Ident(i) => ctx.ident(i), - PExpr::BinaryOp(op, e1, e2) => match op { - InfixOp::Add => todo!(), - InfixOp::Sub => todo!(), - InfixOp::Mul => todo!(), - InfixOp::Div => todo!(), - InfixOp::LessThan => todo!(), - InfixOp::GreaterThan => todo!(), - InfixOp::Assign => { - let res1 = e1.lower(ctx)?; - let res2 = e2.lower(ctx)?; - ctx.push(UInstruction::Mv { - dst: res1, - src: res2, - }); - res1 - } - }, - PExpr::PostfixOp(e, op) => { - let res = e.lower(ctx)?; - match op { - PostfixOp::Ref => { - let ty = Type::Ref(ctx.ctx.infer()); - let dest = ctx.temp(ty); - ctx.push(UInstruction::Ref { - dst: dest, - src: res, - }); - dest - } - PostfixOp::Deref => { - let ty = Type::Deref(ctx.ctx.infer()); - let dst = ctx.temp(ty); - ctx.push(UInstruction::Deref { dst, src: res }); - dst - } - PostfixOp::Not => todo!(), - } - } - PExpr::Block(b) => b.lower(ctx)?, - PExpr::AsmBlock(b) => b.lower(ctx)?, - PExpr::Call(e, args) => { - let fe = e.lower(ctx)?; - let mut nargs = Vec::new(); - for arg in args.iter() { - let arg = arg.lower(ctx)?; - nargs.push(arg); - } - let dest = ctx.temp(Type::Infer); - ctx.push(UInstruction::Call { - dst: dest, - f: fe, - args: nargs, - }); - dest - } - PExpr::Group(e) => e.lower(ctx)?, - PExpr::Construct(e, map) => { - let dst = ctx.temp(Type::Infer); - let struc = e.lower(ctx)?; - let fields = map.lower(ctx)?; - ctx.push(UInstruction::Construct { dst, struc, fields }); - dst - } - PExpr::If(cond, body) => { - let cond = cond.lower(ctx)?; - ctx.ident_stack.push(); - let mut body_ctx = ctx.branch(); - body.lower(&mut body_ctx); - let body = body_ctx.instructions; - ctx.ident_stack.pop(); - ctx.push(UInstruction::If { cond, body }); - return None; - } - PExpr::Loop(body) => { - ctx.ident_stack.push(); - let mut body_ctx = ctx.branch(); - body.lower(&mut body_ctx); - let body = body_ctx.instructions; - ctx.ident_stack.pop(); - ctx.push(UInstruction::Loop { body }); - return None; - } - PExpr::Break => { - ctx.push(UInstruction::Break); - return None; - } - PExpr::Continue => { - ctx.push(UInstruction::Continue); - return None; - } - PExpr::Member(e, ty, name) => { - let id = e.lower(ctx)?; - let name_str = name.as_ref()?.0; - let cur = &mut ctx.p.idents[id]; - match cur.status { - IdentStatus::Res(res) => { - cur.status = IdentStatus::Unres { - base: MemRes { - mem: Member { - id: MemberID - }, - origin: (), - gargs: (), - }, - path: (), - } - } - IdentStatus::Unres { base, path } => path.push(MemberIdent { - ty: *ty, - name: name_str, - origin: name.origin, - gargs: Vec::new(), - }), - IdentStatus::Failed(res_err) => return None, - IdentStatus::Cooked => return None, - } - return None; - } - }) - } -} diff --git a/src/parser/v3/lower/func.rs b/src/parser/v3/lower/func.rs deleted file mode 100644 index 1b14b67..0000000 --- a/src/parser/v3/lower/func.rs +++ /dev/null @@ -1,181 +0,0 @@ -use std::ops::{Deref, DerefMut}; - -use super::{CompilerMsg, FileSpan, ModuleLowerCtx, Node, PFunction, Typable}; -use crate::{ - ir::{ - FnID, IdentID, IdentStatus, MemRes, Member, MemberID, MemberIdent, MemberPath, MemberTy, - Origin, Res, Type, UFunc, UIdent, UInstrInst, UInstruction, - }, - parser, -}; - -impl Node { - pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> Option { - self.as_ref().map(|s| s.lower(ctx, self.origin)).flatten() - } -} - -impl PFunction { - pub fn lower(&self, ctx: &mut ModuleLowerCtx, origin: Origin) -> Option { - let header = self.header.as_ref()?; - let name = header.name.as_ref()?.0.clone(); - let (generics, args, ret) = if let Some(header) = self.header.as_ref() { - ( - header - .gargs - .iter() - .flat_map(|a| a.lower(ctx).map(|g| (g.0, g.1, a.origin))) - .collect(), - header - .args - .iter() - .flat_map(|a| Some(a.lower(ctx)?)) - .collect(), - match &header.ret { - Some(ty) => ty.lower(ctx), - None => ctx.def_ty(Type::Unit), - }, - ) - } else { - (Vec::new(), Vec::new(), ctx.tc.error) - }; - let gargs = generics.iter().map(|g| g.1).collect(); - let generics = generics - .into_iter() - .map(|g| { - ( - g.0, - ctx.def_ident(UIdent { - status: IdentStatus::Res(Res::Generic(g.1)), - origin: g.2, - }), - ) - }) - .collect::>(); - ctx.ident_stack.extend(generics.into_iter()); - let instructions = { - let mut fctx = FnLowerCtx { - instructions: Vec::new(), - ctx, - origin: self.body.origin, - }; - let res = self.body.lower(&mut fctx); - let mut instructions = fctx.instructions; - if let Some(src) = res { - let origin = ctx.idents[src].origin; - instructions.push(UInstrInst { - origin, - i: UInstruction::Ret { src }, - }); - } - instructions - }; - let f = UFunc { - origin, - gargs, - name, - args, - ret, - instructions, - }; - Some(ctx.def_fn(f)) - } -} - -pub struct FnLowerCtx<'a, 'b> { - pub ctx: &'a mut ModuleLowerCtx<'b>, - pub instructions: Vec, - pub origin: FileSpan, -} - -impl<'a, 'b> FnLowerCtx<'a, 'b> { - pub fn ident(&mut self, node: &Node) -> IdentID { - let inst = UIdent { - status: if let Some(n) = node.as_ref() { - if let Some(&res) = self.ident_stack.search(&n.0) { - return res; - } else { - IdentStatus::Unres { - path: vec![MemberIdent { - ty: MemberTy::Member, - name: n.0.clone(), - origin: node.origin, - gargs: Vec::new(), - }], - base: MemRes { - mem: Member { - id: MemberID::Module(self.module), - }, - origin: self.origin, - gargs: Vec::new(), - }, - } - } - } else { - IdentStatus::Cooked - }, - origin: node.origin, - }; - self.def_ident(inst) - } - pub fn err(&mut self, msg: String) { - let origin = self.origin; - self.output.err(CompilerMsg::new(msg, origin)) - } - pub fn err_at(&mut self, span: FileSpan, msg: String) { - self.output.err(CompilerMsg::new(msg, span)) - } - pub fn temp(&mut self, ty: T) -> IdentID { - self.ctx.temp_var(self.origin, ty) - } - pub fn push(&mut self, i: UInstruction) { - self.push_at(i, self.origin); - } - pub fn push_at(&mut self, i: UInstruction, span: FileSpan) { - self.instructions.push(UInstrInst { i, origin: span }); - } - pub fn branch<'c>(&'c mut self) -> FnLowerCtx<'c, 'b> { - FnLowerCtx { - ctx: self.ctx, - instructions: Vec::new(), - origin: self.origin, - } - } -} - -impl<'b> Deref for FnLowerCtx<'_, 'b> { - type Target = ModuleLowerCtx<'b>; - - fn deref(&self) -> &Self::Target { - self.ctx - } -} - -impl DerefMut for FnLowerCtx<'_, '_> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.ctx - } -} - -pub trait FnLowerable { - type Output; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option; -} - -impl FnLowerable for Node { - type Output = T::Output; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - let old_span = ctx.origin; - ctx.origin = self.origin; - let res = self.as_ref()?.lower(ctx); - ctx.origin = old_span; - res - } -} - -impl FnLowerable for Box { - type Output = T::Output; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - self.as_ref().lower(ctx) - } -} diff --git a/src/parser/v3/lower/map.rs b/src/parser/v3/lower/map.rs deleted file mode 100644 index 2c78b65..0000000 --- a/src/parser/v3/lower/map.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::collections::HashMap; - -use crate::{ir::IdentID, parser::PMap}; - -use super::{FnLowerCtx, FnLowerable}; - -impl FnLowerable for PMap { - type Output = HashMap; - fn lower(&self, ctx: &mut FnLowerCtx) -> Option { - Some( - self.0 - .iter() - .flat_map(|n| { - let def = n.as_ref()?; - let name = def.name.as_ref()?.to_string(); - let expr = def.val.as_ref()?.lower(ctx)?; - Some((name, expr)) - }) - .collect(), - ) - } -} diff --git a/src/parser/v3/lower/mod.rs b/src/parser/v3/lower/mod.rs deleted file mode 100644 index 6eb1e90..0000000 --- a/src/parser/v3/lower/mod.rs +++ /dev/null @@ -1,134 +0,0 @@ -mod arch; -mod asm; -mod block; -mod def; -mod expr; -mod func; -mod map; -mod struc; -mod ty; - -use std::{ - collections::HashMap, - ops::{Deref, DerefMut}, -}; - -use super::*; -use crate::{ - ir::{ - IdentID, IdentStatus, ModID, Origin, Res, Type, TypeID, UFunc, UIdent, UModule, UProgram, - UVar, - }, - util::NameStack, -}; -pub use func::{FnLowerCtx, FnLowerable}; - -impl PModule { - pub fn lower( - &self, - path: Vec, - p: &mut UProgram, - imports: &mut Imports, - output: &mut CompilerOutput, - ) -> ModID { - let name = path.last().unwrap().clone(); - let f = UFunc { - name: name.clone(), - args: Vec::new(), - instructions: Vec::new(), - gargs: Vec::new(), - ret: p.def_ty(Type::Unit), - origin: self.block.origin, - }; - let fid = p.def_fn(f); - let mid = p.def_module(UModule { - name, - members: HashMap::new(), - parent: None, - func: fid, - }); - let mut ctx = ModuleLowerCtx { - p, - output, - module: mid, - temp: 0, - ident_stack: NameStack::new(), - }; - let mut fctx = FnLowerCtx { - ctx: &mut ctx, - instructions: Vec::new(), - origin: self.block.origin, - }; - self.block.lower(&mut fctx); - p.fns[fid].instructions = fctx.instructions; - mid - } -} - -pub struct ModuleLowerCtx<'a> { - pub p: &'a mut UProgram, - pub output: &'a mut CompilerOutput, - pub module: ModID, - pub temp: usize, - pub ident_stack: NameStack, -} - -impl<'a> ModuleLowerCtx<'a> { - pub fn new(program: &'a mut UProgram, output: &'a mut CompilerOutput, id: ModID) -> Self { - Self { - p: program, - output, - module: id, - temp: 0, - ident_stack: NameStack::new(), - } - } - pub fn temp_var(&mut self, origin: Origin, ty: impl Typable) -> IdentID { - self.temp_var_inner(origin, ty) - } - fn temp_var_inner(&mut self, origin: Origin, ty: impl Typable) -> IdentID { - let var = UVar { - name: format!("temp{}", self.temp), - ty: ty.ty(self), - origin, - parent: None, - children: HashMap::new(), - }; - let id = self.p.def_var(var); - self.temp += 1; - self.def_ident(UIdent { - status: IdentStatus::Res(Res::Var(id)), - origin, - }) - } -} - -pub trait Typable { - fn ty(self, p: &mut UProgram) -> TypeID; -} - -impl Typable for Type { - fn ty(self, p: &mut UProgram) -> TypeID { - p.def_ty(self) - } -} - -impl Typable for TypeID { - fn ty(self, p: &mut UProgram) -> TypeID { - self - } -} - -impl Deref for ModuleLowerCtx<'_> { - type Target = UProgram; - - fn deref(&self) -> &Self::Target { - self.p - } -} - -impl DerefMut for ModuleLowerCtx<'_> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.p - } -} diff --git a/src/parser/v3/lower/struc.rs b/src/parser/v3/lower/struc.rs deleted file mode 100644 index 62d4077..0000000 --- a/src/parser/v3/lower/struc.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::{ - common::FileSpan, - ir::{StructField, StructID, UStruct}, - parser::{PStruct, PStructFields}, -}; - -use super::ModuleLowerCtx; - -impl PStruct { - pub fn lower(&self, ctx: &mut ModuleLowerCtx, span: FileSpan) -> Option { - ctx.ident_stack.push(); - let gmap: Vec<_> = self.generics.iter().flat_map(|a| a.lower(ctx)).collect(); - let gargs = gmap.iter().map(|(_, id)| *id).collect(); - let fields = match &self.fields { - PStructFields::Named(nodes) => nodes - .iter() - .flat_map(|n| { - let def = n.as_ref()?; - let name = def.name.as_ref()?.to_string(); - let tynode = def.ty.as_ref()?; - let ty = tynode.lower(ctx); - Some((name, ty)) - }) - .collect(), - PStructFields::Tuple(nodes) => nodes - .iter() - .enumerate() - .flat_map(|(i, n)| { - let ty = n.as_ref()?.lower(ctx, span); - Some((format!("{i}"), ty)) - }) - .collect(), - PStructFields::None => vec![], - } - .into_iter() - .map(|(name, ty)| (name, StructField { ty })) - .collect(); - let name = self.name.as_ref()?.to_string(); - ctx.ident_stack.pop(); - Some(ctx.def_struct(UStruct { - name, - gargs, - fields, - origin: span, - })) - } -} diff --git a/src/parser/v3/lower/ty.rs b/src/parser/v3/lower/ty.rs deleted file mode 100644 index 229c880..0000000 --- a/src/parser/v3/lower/ty.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::{ - ir::{GenericID, MemberIdent, MemberPath, Type, TypeID, UGeneric, UProgram}, - parser::PGenericDef, -}; - -use super::{FileSpan, ModuleLowerCtx, Node, PType}; - -impl Node> { - pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> TypeID { - self.as_ref() - .map(|t| t.lower(ctx, self.origin)) - .unwrap_or(ctx.tc.error) - } -} -impl Node { - pub fn lower(&self, ctx: &mut ModuleLowerCtx) -> TypeID { - self.as_ref() - .map(|t| t.lower(ctx, self.origin)) - .unwrap_or(ctx.tc.error) - } -} - -impl PType { - pub fn lower(&self, ctx: &mut ModuleLowerCtx, mut origin: FileSpan) -> TypeID { - let mut ty = self; - let mut path = Vec::new(); - while let PType::Member(node, ident) = ty { - ty = if let Some(t) = node.as_ref() { - let Some(name) = ident.as_ref() else { - return ctx.tc.error; - }; - origin = node.origin; - path.push(MemberIdent { - name: name.0.clone(), - origin: ident.origin, - }); - &**t - } else { - return ctx.tc.error; - }; - } - if !path.is_empty() { - let PType::Ident(id) = ty else { - return ctx.tc.error; - }; - path.push(MemberIdent { - name: id.0.clone(), - origin, - }); - path.reverse(); - let ty = Type::Unres(MemberPath { - id: ctx.module, - path, - }); - return ctx.def_ty(ty); - } - let ty = match ty { - PType::Member(_, _) => unreachable!(), - PType::Ident(node) => { - path.push(MemberIdent { - name: node.0.clone(), - origin, - }); - path.reverse(); - Type::Unres(MemberPath { - id: ctx.module, - path, - }) - } - PType::Ref(node) => node.lower(ctx).rf(), - PType::Generic(node, nodes) => todo!(), - }; - ctx.def_ty(ty) - } -} - -impl Node { - pub fn lower(&self, p: &mut UProgram) -> Option<(String, GenericID)> { - let s = self.as_ref()?; - let name = s.name.as_ref()?.to_string(); - Some(( - name.clone(), - p.def_generic(UGeneric { - name, - origin: self.origin, - }), - )) - } -} diff --git a/src/parser/v3/mod.rs b/src/parser/v3/mod.rs deleted file mode 100644 index d15d6b4..0000000 --- a/src/parser/v3/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -mod ctx; -mod cursor; -mod error; -mod lower; -mod node; -mod nodes; -mod parse; -mod token; -mod import; - -use crate::common::{CompilerMsg, CompilerOutput, FileSpan, FilePos}; -pub use ctx::*; -pub use cursor::*; -pub use node::*; -pub use nodes::*; -pub use parse::*; -pub use token::*; -pub use import::*; - -// idea: create generic "map" and "tuple" types which are used for function calls, tuples, struct -// creation, etc. instead of specializing at the parsing level diff --git a/src/parser/v3/node.rs b/src/parser/v3/node.rs deleted file mode 100644 index 6a30dd4..0000000 --- a/src/parser/v3/node.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::{ - fmt::Debug, - ops::{Deref, DerefMut}, -}; - -use crate::ir::Origin; - -pub struct Node { - pub inner: Option, - pub origin: Origin, -} - -impl Node { - pub fn new(inner: T, span: Origin) -> Self { - Self { - inner: Some(inner), - origin: span, - } - } - pub fn bx(self) -> Node> { - Node { - inner: self.inner.map(|v| Box::new(v)), - origin: self.origin, - } - } - pub fn map T2>(self, f: F) -> Node { - Node { - inner: self.inner.map(f), - origin: self.origin, - } - } -} - -impl Deref for Node { - type Target = Option; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for Node { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl Debug for Node { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.inner { - Some(v) => v.fmt(f), - None => f.write_str("{error}"), - } - } -} diff --git a/src/parser/v3/nodes/asm_block.rs b/src/parser/v3/nodes/asm_block.rs deleted file mode 100644 index 8bbf9c9..0000000 --- a/src/parser/v3/nodes/asm_block.rs +++ /dev/null @@ -1,67 +0,0 @@ -use super::{ - util::parse_list, Node, PExpr, PIdent, PInstruction, Parsable, ParseResult, ParserCtx, Symbol, -}; - -pub struct PAsmBlock { - pub instructions: Vec>, - pub args: Vec>, -} - -pub enum PAsmBlockArg { - In { reg: R, var: V }, - Out { reg: R }, -} - -pub type PUAsmBlockArg = PAsmBlockArg, Node>; - -impl Parsable for PAsmBlock { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let args = if ctx.expect_peek()?.is_symbol(Symbol::OpenParen) { - ctx.next(); - parse_list(ctx, Symbol::CloseParen)? - } else { - Vec::new() - }; - ctx.expect_sym(Symbol::OpenCurly)?; - let mut instructions = Vec::new(); - while !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); - } - } - ctx.expect_sym(Symbol::CloseCurly)?; - ParseResult::Ok(Self { instructions, args }) - } -} - -impl Parsable for PUAsmBlockArg { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let reg = ctx.parse::()?; - ParseResult::Ok(if reg.inner.as_ref().is_some_and(|s| s.0 == "out") { - ctx.expect_sym(Symbol::Equals)?; - let reg = ctx.parse()?; - Self::Out { reg } - } else { - ctx.expect_sym(Symbol::Equals)?; - let var = ctx.parse()?; - Self::In { reg, var } - }) - } -} - -impl std::fmt::Debug for PAsmBlock { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("asm {")?; - for i in &self.instructions { - f.write_str("\n ")?; - i.fmt(f)?; - } - if !self.instructions.is_empty() { - f.write_str("\n")?; - } - f.write_str("}")?; - Ok(()) - } -} diff --git a/src/parser/v3/nodes/asm_fn.rs b/src/parser/v3/nodes/asm_fn.rs deleted file mode 100644 index 319a068..0000000 --- a/src/parser/v3/nodes/asm_fn.rs +++ /dev/null @@ -1,63 +0,0 @@ -use super::{ - util::parse_list, PAsmBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, PType, PVarDef, -}; - -// #[derive(Debug)] -// pub struct AsmFunctionHeader { -// pub name: Node, -// pub args: Vec>, -// } -// -// #[derive(Debug)] -// pub struct AsmFunction { -// pub header: Node, -// pub body: Node, -// } -// -// impl Parsable for AsmFunctionHeader { -// fn parse(ctx: &mut ParserCtx) -> ParseResult { -// ctx.expect_kw(Keyword::Asm)?; -// ctx.expect_kw(Keyword::Fn)?; -// let name = ctx.parse()?; -// ctx.expect_sym(Symbol::OpenParen)?; -// let args = parse_list(ctx, Symbol::CloseParen)?; -// ParseResult::Ok(Self { name, args }) -// } -// } -// -// impl Parsable for AsmFunction { -// fn parse(ctx: &mut ParserCtx) -> ParseResult { -// let header = ctx.parse()?; -// let body = ctx.parse()?; -// ParseResult::Ok(Self { header, body }) -// } -// } -// -// pub struct AsmVarDef { -// pub reg: Node, -// pub name: Node, -// pub ty: Option>, -// } -// -// impl Parsable for AsmVarDef { -// fn parse(ctx: &mut ParserCtx) -> ParseResult { -// let reg = ctx.parse()?; -// let name = ctx.parse()?; -// if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) { -// ctx.next(); -// ctx.parse().map(|ty| Self { reg, name, ty: Some(ty) }) -// } else { -// ParseResult::Ok(Self { reg, name, ty: None }) -// } -// } -// } -// -// impl std::fmt::Debug for AsmVarDef { -// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -// self.name.fmt(f)?; -// if let Some(ty) = &self.ty { -// write!(f, ": {:?}", ty)?; -// } -// Ok(()) -// } -// } diff --git a/src/parser/v3/nodes/asm_instr.rs b/src/parser/v3/nodes/asm_instr.rs deleted file mode 100644 index 53ef927..0000000 --- a/src/parser/v3/nodes/asm_instr.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::{CompilerMsg, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol}; - -pub struct PInstruction { - pub op: Node, - pub args: Vec>, -} - -pub enum PAsmArg { - Value(PIdent), - Ref(Node), -} - -impl Parsable for PInstruction { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let op = ctx.parse()?; - let mut args = Vec::new(); - if !ctx.next_on_new_line() { - let arg = ctx.parse()?; - args.push(arg); - loop { - if ctx.next_on_new_line() { - break; - } - ctx.expect_sym(Symbol::Comma)?; - let arg = ctx.parse()?; - args.push(arg); - } - } - ParseResult::Ok(Self { op, args }) - } -} - -impl Parsable for PAsmArg { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - if let Some(ident) = ctx.maybe_parse() { - return ParseResult::Wrap(ident.map(Self::Value)); - } - - let mut next = ctx.expect_peek()?; - if next.is_symbol(Symbol::Minus) { - ctx.next(); - if let Some(mut ident) = ctx.maybe_parse::() { - // TODO: this is so messed up - if let Some(i) = ident.node.as_mut() { - i.0.insert(0, '-') - } - return ParseResult::Wrap(ident.map(Self::Value)); - } - next = ctx.expect_peek()?; - } - - if !next.is_symbol(Symbol::OpenCurly) { - return ParseResult::Err(CompilerMsg::unexpected_token( - next, - "An identifier or {identifier}", - )); - } - ctx.next(); - - let res = ctx.parse(); - if res.recover { - ctx.seek_sym(Symbol::CloseCurly); - return ParseResult::SubErr; - } - - ctx.expect_sym(Symbol::CloseCurly)?; - ParseResult::Ok(Self::Ref(res.node)) - } -} - -impl std::fmt::Debug for PAsmArg { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Value(v) => v.fmt(f), - Self::Ref(r) => write!(f, "{{{:?}}}", r), - } - } -} - -impl std::fmt::Debug for PInstruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.op.fmt(f)?; - let mut iter = self.args.iter(); - if let Some(arg) = iter.next() { - f.write_str(" ")?; - arg.fmt(f)?; - } - for arg in iter { - f.write_str(", ")?; - arg.fmt(f)?; - } - Ok(()) - } -} diff --git a/src/parser/v3/nodes/block.rs b/src/parser/v3/nodes/block.rs deleted file mode 100644 index 5817400..0000000 --- a/src/parser/v3/nodes/block.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::fmt::{Debug, Write}; - -use super::{ - token::Symbol, CompilerMsg, Node, NodeParsable, PStatementLike, ParseResult, ParserCtx, -}; -use crate::{ - parser::{ParsableWith, TokenInstance}, - util::Padder, -}; - -pub struct PBlock { - pub statements: Vec>, - pub ret_last: bool, -} - -impl ParsableWith for PBlock { - type Data = Option; - fn parse(ctx: &mut ParserCtx, end: Option) -> ParseResult { - let mut statements = Vec::new(); - let is_end = |t: &TokenInstance| -> bool { end.map(|e| t.is_symbol(e)).unwrap_or(false) }; - if ctx.peek().is_none_or(is_end) { - ctx.next(); - return ParseResult::Ok(Self { - statements, - ret_last: false, - }); - } - let mut expect_semi = false; - let mut recover = false; - loop { - let Some(next) = ctx.peek() else { - if end.is_some() { - recover = true; - ctx.err(CompilerMsg::unexpected_end()); - } - break; - }; - if is_end(next) { - ctx.next(); - break; - } - if next.is_symbol(Symbol::Semicolon) { - ctx.next(); - expect_semi = false; - continue; - } else if expect_semi { - ctx.err(CompilerMsg { - msg: "expected ';'".to_string(), - spans: vec![ctx.next_start().char_span()], - }); - } - let res = PStatementLike::parse_node(ctx); - expect_semi = res - .node - .as_ref() - .is_some_and(|s| matches!(s, PStatementLike::Statement(..))); - statements.push(res.node); - if res.recover { - ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]); - if ctx.peek().is_none() { - recover = true; - break; - } - } - } - ParseResult::from_recover( - Self { - statements, - ret_last: expect_semi, - }, - recover, - ) - } -} - -impl Debug for PBlock { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if !self.statements.is_empty() { - f.write_str("{\n ")?; - let mut padder = Padder::new(f); - let mut end = self.statements.len(); - if self.ret_last { - end -= 1; - } - for i in 0..end { - let s = &self.statements[i]; - // they don't expose wrap_buf :grief: - padder.write_str(&format!("{s:?};\n"))?; - } - if self.ret_last - && let Some(s) = self.statements.last() - { - padder.write_str(&format!("{s:?}\n"))?; - } - f.write_char('}')?; - } else { - f.write_str("{}")?; - } - Ok(()) - } -} diff --git a/src/parser/v3/nodes/def.rs b/src/parser/v3/nodes/def.rs deleted file mode 100644 index e484d45..0000000 --- a/src/parser/v3/nodes/def.rs +++ /dev/null @@ -1,112 +0,0 @@ -use std::fmt::Debug; - -use super::{ - CompilerMsg, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx, - Symbol, Token, -}; - -pub struct PVarDef { - pub name: Node, - pub ty: Option>, -} - -pub struct PFieldDef { - pub name: Node, - pub val: Option>, -} - -impl Parsable for PVarDef { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let name = ctx.parse()?; - ParseResult::Ok(if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) { - ctx.next(); - Self { - name, - ty: Some(ctx.parse()?), - } - } else { - Self { name, ty: None } - }) - } -} - -impl Parsable for PFieldDef { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let name = ctx.parse()?; - ParseResult::Ok(if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) { - ctx.next(); - Self { - name, - val: Some(ctx.parse()?), - } - } else { - Self { name, val: None } - }) - } -} - -pub struct SelfVar { - pub ty: SelfType, -} - -#[derive(PartialEq)] -pub enum SelfType { - Ref, - Take, -} - -// impl Parsable for Option { -// fn maybe_parse(ctx: &mut ParserCtx) -> Result, CompilerMsg> { -// if let Some(mut next) = ctx.peek() { -// let mut ty = SelfType::Take; -// if next.is_symbol(Symbol::Ampersand) { -// ctx.next(); -// ty = SelfType::Ref; -// next = ctx.expect_peek()?; -// } -// if let Token::Word(name) = &next.token { -// if name == "self" { -// ctx.next(); -// return Ok(Some(Self { ty })); -// } -// } -// if ty != SelfType::Take { -// return Err(CompilerMsg::unexpected_token(next, "self")); -// } -// } -// Ok(None) -// } -// } - -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 { - write!(f, ": {:?}", ty)?; - } - Ok(()) - } -} - -impl Debug for PFieldDef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.name.fmt(f)?; - if let Some(val) = &self.val { - write!(f, ": {:?}", val)?; - } - Ok(()) - } -} - -impl Debug for SelfVar { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self.ty { - SelfType::Ref => "&self", - SelfType::Take => "self", - } - ) - } -} diff --git a/src/parser/v3/nodes/expr.rs b/src/parser/v3/nodes/expr.rs deleted file mode 100644 index 5101319..0000000 --- a/src/parser/v3/nodes/expr.rs +++ /dev/null @@ -1,207 +0,0 @@ -use std::fmt::{Debug, Write}; - -use crate::{common::FilePos, ir::MemberTy, parser::NodeParsableWith}; - -use super::{ - op::{InfixOp, PostfixOp}, - util::parse_list, - CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PIdent, PLiteral, PMap, PType, Parsable, - ParseResult, ParserCtx, Symbol, -}; - -type BoxNode = Node>; - -pub enum PExpr { - Lit(PLiteral), - Ident(Node), - BinaryOp(InfixOp, BoxNode, BoxNode), - PostfixOp(BoxNode, PostfixOp), - Block(Node), - Call(BoxNode, Vec>), - Group(BoxNode), - Member(BoxNode, MemberTy, Node), - Generic(BoxNode, Vec>), - AsmBlock(Node), - Construct(BoxNode, Node), - If(BoxNode, BoxNode), - Loop(BoxNode), - Break, - Continue, -} - -impl Parsable for PExpr { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let start = ctx.next_start(); - let mut e1 = Self::parse_unit_postfix(ctx)?; - while let Some(op) = ctx - .peek() - .map(|next| InfixOp::from_token(&next.token)) - .flatten() - { - let span = start.to(ctx.prev_end()); - ctx.next(); - let n2 = ctx.parse()?.bx(); - let (n1, op, n2) = fix_precedence(Node::new(e1, span).bx(), op, n2, start); - e1 = Self::BinaryOp(op, n1, n2); - } - return ParseResult::Ok(e1); - } -} - -impl PExpr { - fn parse_unit_postfix(ctx: &mut ParserCtx) -> ParseResult { - let start = ctx.next_start(); - // first get unit - let mut e1 = Self::parse_unit(ctx)?; - // then apply post ops - loop { - let span = start.to(ctx.prev_end()); - let Some(next) = ctx.peek() else { - break; - }; - if next.is_symbol(Symbol::OpenParen) { - ctx.next(); - let args = parse_list(ctx, Symbol::CloseParen)?; - e1 = Self::Call(Node::new(e1, span).bx(), args); - continue; - } else if next.is_symbol(Symbol::OpenCurly) { - ctx.next(); - let map = ctx.parse()?; - e1 = Self::Construct(Node::new(e1, span).bx(), map); - continue; - } else if next.is_symbol(Symbol::Dot) { - ctx.next(); - let field = ctx.parse()?; - e1 = Self::Member(Node::new(e1, span).bx(), MemberTy::Field, field); - continue; - } else if next.is_symbol(Symbol::DoubleColon) { - ctx.next(); - if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::OpenAngle)) { - ctx.next(); - let gargs = parse_list(ctx, Symbol::CloseAngle)?; - e1 = Self::Generic(Node::new(e1, span).bx(), gargs); - } else { - let field = ctx.parse()?; - e1 = Self::Member(Node::new(e1, span).bx(), MemberTy::Member, field); - } - continue; - } else if let Some(op) = PostfixOp::from_token(next) { - ctx.next(); - e1 = Self::PostfixOp(Node::new(e1, span).bx(), op); - continue; - } - break; - } - return ParseResult::Ok(e1); - } - fn parse_unit(ctx: &mut ParserCtx) -> ParseResult { - let next = ctx.expect_peek()?; - return ParseResult::Ok(if next.is_symbol(Symbol::OpenParen) { - ctx.next(); - if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) { - ctx.next(); - return ParseResult::Ok(PExpr::Lit(PLiteral::Unit)); - } - let res = ctx.parse(); - if res.recover { - ctx.seek_sym(Symbol::CloseParen); - } - ctx.expect_sym(Symbol::CloseParen)?; - Self::Group(res.node.bx()) - } else if next.is_symbol(Symbol::OpenCurly) { - ctx.next(); - Self::Block(PBlock::parse_node(ctx, Some(Symbol::CloseCurly))?) - } else if next.is_keyword(Keyword::If) { - ctx.next(); - let cond = ctx.parse()?.bx(); - let body = ctx.parse()?.bx(); - Self::If(cond, body) - } else if next.is_keyword(Keyword::Loop) { - ctx.next(); - let body = ctx.parse()?.bx(); - Self::Loop(body) - } else if next.is_keyword(Keyword::Break) { - ctx.next(); - Self::Break - } else if next.is_keyword(Keyword::Continue) { - ctx.next(); - Self::Continue - } else if next.is_keyword(Keyword::Asm) { - ctx.next(); - Self::AsmBlock(ctx.parse()?) - } else if let Some(res) = ctx.maybe_parse::() { - return ParseResult::Wrap(res.map(Self::Lit)); - } else { - let res = ctx.parse(); - if res.node.is_some() { - Self::Ident(res.node) - } else { - let next = ctx.expect_peek()?; - return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression")); - } - }); - } -} - -pub fn fix_precedence( - mut n1: BoxNode, - mut op: InfixOp, - mut n2: BoxNode, - start: FilePos, -) -> (BoxNode, InfixOp, BoxNode) { - if let Some(box PExpr::BinaryOp(op2, _, _)) = n2.as_ref() { - if op.precedence() > op2.precedence() { - let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else { - unreachable!(); - }; - let span = start.to(n21.origin.end); - let (n11, op1, n12) = fix_precedence(n1, op, n21, start); - n1 = Node::new(PExpr::BinaryOp(op1, n11, n12), span).bx(); - op = op2; - n2 = n22; - } - } - (n1, op, n2) -} - -impl Debug for PExpr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - 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())?; - } else { - write!(f, "{}", op.str())?; - } - write!(f, "{:?})", *e2)?; - } - PExpr::Call(n, args) => { - n.fmt(f)?; - f.write_char('(')?; - if let Some(a) = args.first() { - a.fmt(f)?; - } - for arg in args.iter().skip(1) { - f.write_str(", ")?; - arg.fmt(f)?; - } - f.write_char(')')?; - } - PExpr::PostfixOp(e, op) => write!(f, "({:?}{})", e, op.str())?, - PExpr::Group(inner) => inner.fmt(f)?, - PExpr::AsmBlock(inner) => inner.fmt(f)?, - PExpr::Construct(node, inner) => write!(f, "{:?}{:?}", node, inner)?, - PExpr::If(cond, res) => write!(f, "if {cond:?} then {res:?}")?, - PExpr::Loop(res) => write!(f, "loop -> {res:?}")?, - PExpr::Break => write!(f, "break")?, - PExpr::Continue => write!(f, "continue")?, - PExpr::Member(e1, ty, name) => write!(f, "{:?}{}{:?}", e1, ty.sep(), name)?, - PExpr::Generic(e1, gargs) => write!(f, "{:?}<{:?}>", e1, gargs)?, - } - Ok(()) - } -} diff --git a/src/parser/v3/nodes/func.rs b/src/parser/v3/nodes/func.rs deleted file mode 100644 index ba1a8ce..0000000 --- a/src/parser/v3/nodes/func.rs +++ /dev/null @@ -1,96 +0,0 @@ -use super::{ - util::parse_list, Node, PBlock, PGenericDef, PIdent, PType, PVarDef, Parsable, ParseResult, - ParserCtx, Symbol, -}; -use std::fmt::Debug; - -pub struct PFunctionHeader { - pub name: Node, - pub args: Vec>, - pub gargs: Vec>, - pub ret: Option>, -} - -pub struct PFunction { - pub header: Node, - pub body: Node, -} - -impl Parsable for PFunctionHeader { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let name = ctx.parse()?; - let generic_args = if ctx.expect_peek()?.is_symbol(Symbol::OpenAngle) { - ctx.next(); - parse_list(ctx, Symbol::CloseAngle)? - } else { - Vec::new() - }; - 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, - gargs: generic_args, - ret, - }) - } -} - -impl Parsable for PFunction { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let header = ctx.parse()?; - ctx.expect_sym(Symbol::OpenCurly)?; - let body = ctx.parse_with(Some(Symbol::CloseCurly))?; - ParseResult::Ok(Self { header, body }) - } -} - -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(a) = self.args.first() { - a.fmt(f)?; - } - for arg in self.args.iter().skip(1) { - f.write_str(", ")?; - arg.fmt(f)?; - } - f.write_str(")")?; - if let Some(ret) = &self.ret { - write!(f, " -> {:?}", ret)?; - } - Ok(()) - } -} -impl Debug for PFunction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.header.fmt(f)?; - f.write_str(" ")?; - self.body.fmt(f)?; - Ok(()) - } -} diff --git a/src/parser/v3/nodes/ident.rs b/src/parser/v3/nodes/ident.rs deleted file mode 100644 index 0816dba..0000000 --- a/src/parser/v3/nodes/ident.rs +++ /dev/null @@ -1,54 +0,0 @@ -use super::{CompilerMsg, Parsable, ParseResult, ParserCtx, Token}; -use std::{ - fmt::{Debug, Display}, - ops::Deref, -}; - -#[derive(Clone)] -pub struct PIdent(pub String); - -impl Parsable for PIdent { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let next = ctx.expect_peek()?; - let Token::Word(name) = &next.token else { - return ParseResult::Err(CompilerMsg::unexpected_token(next, "an identifier")); - }; - let name = name.to_string(); - ctx.next(); - ParseResult::Ok(Self(name)) - } -} - -impl Parsable for Option { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let Some(next) = ctx.peek() else { - return ParseResult::Ok(None); - }; - let Token::Word(name) = &next.token else { - return ParseResult::Ok(None); - }; - let name = name.to_string(); - ctx.next(); - ParseResult::Ok(Some(PIdent(name))) - } -} - -impl Debug for PIdent { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl Deref for PIdent { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for PIdent { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} diff --git a/src/parser/v3/nodes/lit.rs b/src/parser/v3/nodes/lit.rs deleted file mode 100644 index 96b76f8..0000000 --- a/src/parser/v3/nodes/lit.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::parser::{Parsable, ParseResult}; - -use super::{PString, ParserCtx, Symbol, Token}; -use std::fmt::Debug; - -#[derive(Clone, PartialEq, Eq)] -pub enum PLiteral { - String(String), - Char(char), - Number(PNumber), - Unit, -} - -#[derive(Clone, PartialEq, Eq)] -pub struct PNumber { - pub whole: String, - pub decimal: Option, - pub ty: Option, -} - -impl Parsable for Option { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let inst = ctx.expect_peek()?; - ParseResult::Ok(Some(match &inst.token { - Token::Symbol(Symbol::SingleQuote) => { - let chars = ctx.chars(); - let c = chars.expect_next()?; - chars.expect('\'')?; - ctx.next(); - PLiteral::Char(c) - } - Token::Symbol(Symbol::DoubleQuote) => { - ctx.next(); - let s = ctx.parse::()?; - return match s.inner { - Some(s) => ParseResult::Ok(Some(PLiteral::String(s.0))), - None => ParseResult::SubErr, - }; - } - Token::Word(text) => { - let first = text.chars().next().unwrap(); - if !first.is_ascii_digit() { - return ParseResult::Ok(None); - } - let (whole, ty) = parse_whole_num(text); - let mut num = PNumber { - whole, - decimal: None, - ty, - }; - 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; - ctx.next(); - } - } - } - } - PLiteral::Number(num) - } - _ => return ParseResult::Ok(None), - })) - } -} - -pub fn parse_whole_num(text: &str) -> (String, Option) { - let mut whole = String::new(); - let mut ty = String::new(); - for c in text.chars() { - if ty.is_empty() { - if c.is_ascii_digit() { - whole.push(c); - } else if c != '_' { - ty.push(c); - } - } else { - ty.push(c); - } - } - (whole, if ty.is_empty() { None } else { Some(ty) }) -} - -impl Debug for PLiteral { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::String(str) => str.fmt(f), - Self::Char(c) => c.fmt(f), - Self::Number(n) => n.fmt(f), - Self::Unit => f.write_str("()"), - } - } -} - -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 { - write!(f, ".{}", d)?; - } - if let Some(ty) = &self.ty { - write!(f, "_{}", ty)?; - } - Ok(()) - } -} diff --git a/src/parser/v3/nodes/mod.rs b/src/parser/v3/nodes/mod.rs deleted file mode 100644 index 8c0c55e..0000000 --- a/src/parser/v3/nodes/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -mod asm_block; -mod asm_fn; -mod asm_instr; -mod block; -mod def; -mod expr; -mod func; -mod ident; -mod lit; -mod op; -mod statement; -mod string; -mod struc; -mod trai; -mod ty; -mod util; - -pub use asm_block::*; -pub use asm_fn::*; -pub use asm_instr::*; -pub use block::*; -pub use def::*; -pub use expr::*; -pub use func::*; -pub use ident::*; -pub use lit::*; -pub use op::*; -pub use statement::*; -pub use struc::*; -pub use trai::*; -pub use ty::*; -pub use string::*; - -use super::*; - -pub struct PModule { - pub block: Node, -} - -impl PModule { - pub fn parse(ctx: &mut ParserCtx) -> Self { - Self { - block: PBlock::parse_node(ctx, None).node, - } - } -} diff --git a/src/parser/v3/nodes/op.rs b/src/parser/v3/nodes/op.rs deleted file mode 100644 index b3b2c48..0000000 --- a/src/parser/v3/nodes/op.rs +++ /dev/null @@ -1,97 +0,0 @@ -use super::{Symbol, Token}; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum InfixOp { - Add, - Sub, - Mul, - Div, - LessThan, - GreaterThan, - Assign, -} - -impl InfixOp { - pub fn precedence(&self) -> u32 { - match self { - Self::Assign => 0, - Self::LessThan => 1, - Self::GreaterThan => 1, - Self::Add => 2, - Self::Sub => 3, - Self::Mul => 4, - Self::Div => 5, - } - } - pub fn str(&self) -> &str { - match self { - Self::Add => "+", - Self::Sub => "-", - Self::Mul => "*", - Self::Div => "/", - Self::LessThan => "<", - Self::GreaterThan => ">", - Self::Assign => "=", - } - } - pub fn pad(&self) -> bool { - match self { - Self::Add => true, - Self::Sub => true, - Self::Mul => true, - Self::Div => true, - Self::LessThan => true, - Self::GreaterThan => true, - Self::Assign => true, - } - } -} - -pub enum PostfixOp { - Not, - Ref, - Deref, -} - -impl InfixOp { - pub fn from_token(token: &Token) -> Option { - let Token::Symbol(symbol) = token else { - return None; - }; - Some(match symbol { - Symbol::OpenAngle => Self::LessThan, - Symbol::CloseAngle => Self::GreaterThan, - Symbol::Plus => Self::Add, - Symbol::Minus => Self::Sub, - Symbol::Asterisk => Self::Mul, - Symbol::Slash => Self::Div, - Symbol::Equals => Self::Assign, - _ => { - return None; - } - }) - } -} - -impl PostfixOp { - pub fn str(&self) -> &str { - match self { - Self::Not => "!", - Self::Ref => "@", - Self::Deref => "^", - } - } - pub fn from_token(token: &Token) -> Option { - let Token::Symbol(symbol) = token else { - return None; - }; - Some(match symbol { - Symbol::At => Self::Ref, - Symbol::Bang => Self::Not, - Symbol::Carrot => Self::Deref, - _ => { - return None; - } - }) - } -} diff --git a/src/parser/v3/nodes/statement.rs b/src/parser/v3/nodes/statement.rs deleted file mode 100644 index 8a717a7..0000000 --- a/src/parser/v3/nodes/statement.rs +++ /dev/null @@ -1,104 +0,0 @@ -use super::{ - Keyword, Node, PExpr, PFunction, PIdent, PStruct, PVarDef, Parsable, ParseResult, ParserCtx, - Symbol, Token, -}; - -pub enum PStatement { - Let(Node, Node), - Return(Option>), - Expr(Node), -} - -pub enum PConstStatement { - Fn(Node), - Struct(Node), - Import(Node), -} - -pub enum PStatementLike { - Statement(PStatement), - Const(PConstStatement), -} - -impl Parsable for PStatementLike { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let next = ctx.expect_peek()?; - match next.token { - Token::Keyword(Keyword::Let) => { - ctx.next(); - let def = ctx.parse()?; - ctx.expect_sym(Symbol::Equals)?; - ctx.parse() - .map_res(|expr| Self::Statement(PStatement::Let(def, expr))) - } - Token::Keyword(Keyword::Return) => { - ctx.next(); - if ctx.peek().is_some_and(|t| t.is_symbol(Symbol::Semicolon)) { - ParseResult::Ok(Self::Statement(PStatement::Return(None))) - } else { - ctx.parse() - .map_res(|res| Self::Statement(PStatement::Return(Some(res)))) - } - } - Token::Keyword(Keyword::Fn) => { - ctx.next(); - ParseResult::Ok(Self::Const(PConstStatement::Fn(ctx.parse()?))) - } - Token::Keyword(Keyword::Struct) => { - ctx.next(); - ParseResult::Ok(Self::Const(PConstStatement::Struct(ctx.parse()?))) - } - Token::Keyword(Keyword::Import) => { - ctx.next(); - ParseResult::Ok(Self::Const(PConstStatement::Import(ctx.parse()?))) - } - _ => ctx.parse().map_res(|n| Self::Statement(PStatement::Expr(n))), - } - } -} - -impl std::fmt::Debug for PStatement { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PStatement::Let(n, e) => { - f.write_str("let ")?; - n.fmt(f)?; - f.write_str(" = ")?; - e.fmt(f)?; - } - PStatement::Return(e) => { - f.write_str("return ")?; - e.fmt(f)?; - } - PStatement::Expr(e) => { - e.fmt(f)?; - } - } - Ok(()) - } -} -impl std::fmt::Debug for PConstStatement { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Fn(fun) => { - fun.fmt(f)?; - } - Self::Struct(s) => { - s.fmt(f)?; - } - Self::Import(s) => { - writeln!(f, "import {:?}", s); - } - } - Ok(()) - } -} - -impl std::fmt::Debug for PStatementLike { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Statement(s) => s.fmt(f), - Self::Const(c) => c.fmt(f), - } - } -} diff --git a/src/parser/v3/nodes/string.rs b/src/parser/v3/nodes/string.rs deleted file mode 100644 index 2d4b5a6..0000000 --- a/src/parser/v3/nodes/string.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{ - common::CompilerMsg, - parser::{Parsable, ParseResult}, -}; - -pub struct PString(pub String); - -impl Parsable for PString { - fn parse(ctx: &mut crate::parser::ParserCtx) -> ParseResult { - let cursor = ctx.cursor.chars(); - let mut str = String::new(); - loop { - let c = cursor.expect_next()?; - if c == '"' { - return ParseResult::Ok(Self(str)); - } - str.push(match c { - '\\' => { - let start = cursor.prev_pos(); - let next = cursor.expect_next()?; - match next { - '"' => '"', - '\'' => '\'', - 't' => '\t', - 'n' => '\n', - '0' => '\0', - other => { - let end = cursor.prev_pos(); - ctx.output.err(CompilerMsg { - msg: format!("Unknown escape sequence '\\{}'", other), - spans: vec![start.to(end)], - }); - other - } - } - } - _ => c, - }) - } - } -} diff --git a/src/parser/v3/nodes/struc.rs b/src/parser/v3/nodes/struc.rs deleted file mode 100644 index d3ee8ac..0000000 --- a/src/parser/v3/nodes/struc.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::fmt::{Debug, Write}; - -use crate::{parser::ParsableWith, util::Padder}; - -use super::{ - util::parse_list, CompilerMsg, Node, PFieldDef, PGenericDef, PIdent, PType, PVarDef, Parsable, - ParseResult, ParserCtx, Symbol, -}; - -#[derive(Debug)] -pub struct PStruct { - pub name: Node, - pub generics: Vec>, - pub fields: PStructFields, -} - -pub struct PMap(pub Vec>); - -#[derive(Debug)] -pub enum PStructFields { - Named(Vec>), - Tuple(Vec>), - None, -} - -impl Parsable for PStruct { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let name = ctx.parse()?; - let mut next = ctx.expect_peek()?; - let args = if next.is_symbol(Symbol::OpenAngle) { - ctx.next(); - let res = parse_list(ctx, Symbol::CloseAngle)?; - next = ctx.expect_peek()?; - res - } else { - Vec::new() - }; - let fields = if next.is_symbol(Symbol::Semicolon) { - ctx.next(); - PStructFields::None - } else if next.is_symbol(Symbol::OpenCurly) { - ctx.next(); - PStructFields::Named(parse_list(ctx, Symbol::CloseCurly)?) - } else if next.is_symbol(Symbol::OpenParen) { - ctx.next(); - PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?) - } else { - let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`"); - ctx.err(msg); - return ParseResult::Recover(PStruct { - name, - generics: args, - fields: PStructFields::None, - }); - }; - ParseResult::Ok(PStruct { - name, - generics: args, - fields, - }) - } -} - -impl Parsable for PMap { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - ctx.expect_sym(Symbol::OpenCurly); - ParseResult::Ok(Self(parse_list(ctx, Symbol::CloseCurly)?)) - } -} - -impl Debug for PMap { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "{{")?; - let mut padder = Padder::new(f); - for arg in &self.0 { - padder.write_str(&format!("{arg:?},\n"))?; - } - writeln!(f, "}}")?; - Ok(()) - } -} diff --git a/src/parser/v3/nodes/trai.rs b/src/parser/v3/nodes/trai.rs deleted file mode 100644 index 5e9a763..0000000 --- a/src/parser/v3/nodes/trai.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::{ - util::{parse_list, parse_list_nosep}, - PFunction, PFunctionHeader, PIdent, Keyword, Node, Parsable, ParserCtx, Symbol, PType, -}; - -#[derive(Debug)] -pub struct PTrait { - pub name: Node, - pub fns: Vec>, -} - -#[derive(Debug)] -pub struct PImpl { - pub trait_: Node, - pub for_: Node, - pub fns: Vec>, -} - -impl Parsable for PTrait { - fn parse(ctx: &mut ParserCtx) -> super::ParseResult { - ctx.expect_kw(Keyword::Trait)?; - let name = ctx.parse()?; - ctx.expect_sym(Symbol::OpenCurly)?; - let fns = parse_list(ctx, Symbol::CloseCurly)?; - super::ParseResult::Ok(Self { name, fns }) - } -} - -impl Parsable for PImpl { - fn parse(ctx: &mut ParserCtx) -> super::ParseResult { - ctx.expect_kw(Keyword::Impl)?; - let trait_ = ctx.parse()?; - ctx.expect_kw(Keyword::For)?; - let for_ = ctx.parse()?; - ctx.expect_sym(Symbol::OpenCurly)?; - let fns = parse_list_nosep(ctx, Symbol::CloseCurly)?; - super::ParseResult::Ok(Self { trait_, for_, fns }) - } -} diff --git a/src/parser/v3/nodes/ty.rs b/src/parser/v3/nodes/ty.rs deleted file mode 100644 index ab086c1..0000000 --- a/src/parser/v3/nodes/ty.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::fmt::Debug; - -use super::{util::parse_list, Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol}; - -type BoxNode = Node>; - -pub enum PType { - Member(BoxNode, Node), - Ref(BoxNode), - Generic(BoxNode, Vec>), - Ident(PIdent), -} - -pub struct PGenericDef { - pub name: Node, -} - -impl Parsable for PType { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - let start = ctx.next_start(); - let mut cur = ctx.parse()?.map(PType::Ident); - loop { - let span = start.to(ctx.prev_end()); - let Some(next) = ctx.peek() else { - break; - }; - if next.is_symbol(Symbol::Ampersand) { - ctx.next(); - cur = Node::new(PType::Ref(cur.bx()), span); - continue; - } else if next.is_symbol(Symbol::OpenAngle) { - ctx.next(); - let args = parse_list(ctx, Symbol::CloseAngle)?; - cur = Node::new(PType::Generic(cur.bx(), args), span); - continue; - } else if next.is_symbol(Symbol::DoubleColon) { - ctx.next(); - let mem = ctx.parse()?; - cur = Node::new(PType::Member(cur.bx(), mem), span); - } - break; - } - ParseResult::Node(cur) - } -} - -impl Parsable for PGenericDef { - fn parse(ctx: &mut ParserCtx) -> ParseResult { - ParseResult::Ok(Self { name: ctx.parse()? }) - } -} - -impl Debug for PType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PType::Member(node, name) => write!(f, "{:?}.{:?}", node, name)?, - PType::Ref(node) => write!(f, "{:?}&", node)?, - PType::Generic(node, args) => write!(f, "{:?}<{:?}>", node, args)?, - PType::Ident(node) => node.fmt(f)?, - } - Ok(()) - } -} - -impl Debug for PGenericDef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.name)?; - Ok(()) - } -} diff --git a/src/parser/v3/nodes/util.rs b/src/parser/v3/nodes/util.rs deleted file mode 100644 index e5e9c85..0000000 --- a/src/parser/v3/nodes/util.rs +++ /dev/null @@ -1,54 +0,0 @@ -use super::{Node, Parsable, ParserCtx, CompilerMsg, Symbol}; - -pub fn parse_list_sep( - ctx: &mut ParserCtx, - sep: Symbol, - end: Symbol, -) -> Result>, CompilerMsg> { - let mut vals = Vec::new(); - loop { - let next = ctx.expect_peek()?; - if next.is_symbol(end) { - break; - } - let res = ctx.parse(); - vals.push(res.node); - if res.recover { - ctx.seek_syms(&[end, sep]); - } - let next = ctx.expect_peek()?; - if !next.is_symbol(sep) { - break; - } - ctx.next(); - } - ctx.expect_sym(end)?; - Ok(vals) -} - -pub fn parse_list( - ctx: &mut ParserCtx, - end: Symbol, -) -> Result>, CompilerMsg> { - parse_list_sep(ctx, Symbol::Comma, end) -} - -pub fn parse_list_nosep( - ctx: &mut ParserCtx, - end: Symbol, -) -> Result>, CompilerMsg> { - let mut vals = Vec::new(); - loop { - let next = ctx.expect_peek()?; - if next.is_symbol(end) { - break; - } - let res = ctx.parse(); - vals.push(res.node); - if res.recover { - ctx.seek_sym(end); - } - } - ctx.expect_sym(end)?; - Ok(vals) -} diff --git a/src/parser/v3/parse.rs b/src/parser/v3/parse.rs deleted file mode 100644 index 3acfd48..0000000 --- a/src/parser/v3/parse.rs +++ /dev/null @@ -1,252 +0,0 @@ -use std::{ - convert::Infallible, - ops::{ControlFlow, FromResidual, Try}, -}; - -use super::{CompilerMsg, FilePos, Node, ParserCtx}; - -pub enum ParseResult { - Ok(T), - Wrap(NodeParseResult), - Node(Node), - Recover(T), - Err(CompilerMsg), - SubErr, -} - -impl ParseResult { - pub fn from_recover(data: T, recover: bool) -> Self { - if recover { - Self::Recover(data) - } else { - Self::Ok(data) - } - } -} - -impl Try for ParseResult { - type Output = T; - type Residual = Option; - fn from_output(output: Self::Output) -> Self { - Self::Ok(output) - } - fn branch(self) -> ControlFlow { - match self { - ParseResult::Ok(v) => ControlFlow::Continue(v), - // TODO: this is messed up; need to break w a Result> or smth :woozy: - ParseResult::Recover(v) => ControlFlow::Break(None), - ParseResult::Wrap(n) => { - if n.recover { - ControlFlow::Break(None) - } else { - match n.node.inner { - Some(v) => ControlFlow::Continue(v), - None => ControlFlow::Break(None), - } - } - } - ParseResult::Node(n) => match n.inner { - Some(v) => ControlFlow::Continue(v), - None => ControlFlow::Break(None), - }, - ParseResult::Err(e) => ControlFlow::Break(Some(e)), - ParseResult::SubErr => ControlFlow::Break(None), - } - } -} - -impl FromResidual for ParseResult { - fn from_residual(residual: ::Residual) -> Self { - match residual { - Some(err) => Self::Err(err), - None => Self::SubErr, - } - } -} - -impl FromResidual> for ParseResult { - fn from_residual(residual: Result) -> Self { - match residual { - Err(e) => Self::Err(e), - } - } -} - -impl FromResidual> for ParseResult { - fn from_residual(residual: ParseResult) -> Self { - match residual { - ParseResult::Err(e) => Self::Err(e), - ParseResult::SubErr => Self::SubErr, - _ => unreachable!(), - } - } -} - -pub struct NodeParseResult { - pub node: Node, - pub recover: bool, -} - -impl NodeParseResult { - pub fn map_res) -> U, U>(self, op: F) -> ParseResult { - let res = op(self.node); - if self.recover { - ParseResult::Recover(res) - } else { - ParseResult::Ok(res) - } - } - pub fn map U, U>(self, op: F) -> NodeParseResult { - NodeParseResult { - node: Node { - inner: self.node.inner.map(op), - origin: self.node.origin, - }, - recover: self.recover, - } - } -} - -impl Try for NodeParseResult { - type Output = Node; - type Residual = ParseResult; - - fn from_output(output: Self::Output) -> Self { - Self { - node: output, - recover: false, - } - } - - fn branch(self) -> ControlFlow { - if self.recover { - ControlFlow::Break(ParseResult::SubErr) - } else { - ControlFlow::Continue(self.node) - } - } -} - -impl FromResidual for NodeParseResult { - fn from_residual(_: ::Residual) -> Self { - // I hope this is unreachable ??? - unreachable!() - } -} - -pub trait Parsable: Sized { - fn parse(ctx: &mut ParserCtx) -> ParseResult; -} - -pub trait ParsableWith: Sized { - type Data; - - fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult; -} - -impl ParsableWith for T { - type Data = (); - - fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult { - T::parse(ctx) - } -} - -impl Node { - pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult { - let start = ctx - .peek() - .map(|t| t.span.start) - .unwrap_or(FilePos::start(ctx.cursor.file())); - let (inner, recover) = match T::parse(ctx, data) { - ParseResult::Ok(v) => (Some(v), false), - ParseResult::Recover(v) => (Some(v), true), - ParseResult::Wrap(r) => return r, - ParseResult::Node(node) => { - return NodeParseResult { - node, - recover: false, - } - } - ParseResult::Err(e) => { - ctx.err(e); - (None, true) - } - ParseResult::SubErr => (None, true), - }; - let end = ctx.prev_end(); - NodeParseResult { - node: Self { - inner, - origin: start.to(end), - }, - recover, - } - } -} - -impl Node { - pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult { - Node::parse_with(ctx, ()) - } -} - -impl Node> -where - Option: Parsable, -{ - pub fn maybe_parse(ctx: &mut ParserCtx) -> Option> { - let res = Node::>::parse_with(ctx, ()); - let origin = res.node.origin; - let recover = res.recover; - match res.node.inner { - Some(val) => match val { - Some(v) => Some(NodeParseResult { - node: Node { - inner: Some(v), - origin, - }, - recover, - }), - None => None, - }, - None => Some(NodeParseResult { - node: Node { - inner: None, - origin, - }, - recover, - }), - } - } -} - -pub trait NodeParsable { - fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult - where - Self: Sized; -} -impl NodeParsable for T { - fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult - where - Self: Sized, - { - Node::::parse(ctx) - } -} - -pub trait NodeParsableWith { - type Data; - fn parse_node(ctx: &mut ParserCtx, data: Self::Data) -> NodeParseResult - where - Self: Sized; -} -impl, D> NodeParsableWith for T { - type Data = D; - fn parse_node(ctx: &mut ParserCtx, data: Self::Data) -> NodeParseResult - where - Self: Sized, - { - Node::::parse_with(ctx, data) - } -} diff --git a/src/parser/v3/token/cursor.rs b/src/parser/v3/token/cursor.rs deleted file mode 100644 index dbe4a74..0000000 --- a/src/parser/v3/token/cursor.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::{iter::Peekable, str::Chars}; - -use crate::common::FileID; - -use super::super::{CompilerMsg, FilePos}; - -pub struct CharCursor<'a> { - file: FileID, - chars: Peekable>, - next_pos: FilePos, - prev_pos: FilePos, -} - -impl<'a> CharCursor<'a> { - pub fn next(&mut self) -> Option { - let res = self.peek()?; - self.advance(); - Some(res) - } - pub fn expect(&mut self, c: char) -> Result<(), CompilerMsg> { - let next = self.expect_next()?; - if next == c { - Ok(()) - } else { - Err(CompilerMsg::at( - self.prev_pos, - format!("unexpected char '{next}'; expected '{c}'"), - )) - } - } - pub fn skip_whitespace(&mut self) { - while self.peek().is_some_and(|c| c.is_whitespace()) { - self.advance(); - } - } - pub fn peek(&mut self) -> Option { - self.chars.peek().copied() - } - pub fn advance(&mut self) { - let Some(next) = self.chars.next() else { - return; - }; - self.prev_pos = self.next_pos; - if next == '\n' { - self.next_pos.col = 0; - self.next_pos.line += 1; - } else { - self.next_pos.col += 1; - } - } - pub fn expect_next(&mut self) -> Result { - self.next().ok_or(CompilerMsg::unexpected_end()) - } - pub fn next_pos(&self) -> FilePos { - self.next_pos - } - pub fn prev_pos(&self) -> FilePos { - self.prev_pos - } - pub fn from_file_str(file: FileID, value: &'a str) -> Self { - Self { - chars: value.chars().peekable(), - next_pos: FilePos::start(file), - prev_pos: FilePos::start(file), - file, - } - } - pub fn file(&self) -> FileID { - self.file - } -} diff --git a/src/parser/v3/token/keyword.rs b/src/parser/v3/token/keyword.rs deleted file mode 100644 index 3a0d4de..0000000 --- a/src/parser/v3/token/keyword.rs +++ /dev/null @@ -1,39 +0,0 @@ -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Keyword { - Fn, - Let, - If, - Return, - Loop, - Break, - Continue, - Struct, - Trait, - Impl, - For, - Asm, - Import, - Funne, -} - -impl Keyword { - pub fn from_string(str: &str) -> Option { - Some(match str { - "fn" => Self::Fn, - "struct" => Self::Struct, - "let" => Self::Let, - "if" => Self::If, - "for" => Self::For, - "return" => Self::Return, - "break" => Self::Break, - "continue" => Self::Continue, - "loop" => Self::Loop, - "trait" => Self::Trait, - "impl" => Self::Impl, - "asm" => Self::Asm, - "import" => Self::Import, - "funne" => Self::Funne, - _ => return None, - }) - } -} diff --git a/src/parser/v3/token/mod.rs b/src/parser/v3/token/mod.rs deleted file mode 100644 index d608a5f..0000000 --- a/src/parser/v3/token/mod.rs +++ /dev/null @@ -1,97 +0,0 @@ -mod cursor; -mod keyword; -mod symbol; - -use std::ops::Deref; - -use super::FileSpan; -pub use cursor::*; -pub use keyword::*; -pub use symbol::*; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Token { - Symbol(Symbol), - Word(String), - Keyword(Keyword), -} - -#[derive(Debug, Clone)] -pub struct TokenInstance { - pub token: Token, - pub span: FileSpan, -} - -impl TokenInstance { - pub fn parse(cursor: &mut CharCursor) -> Option { - cursor.skip_whitespace(); - cursor.peek()?; - let start = cursor.next_pos(); - if let Some(s) = Symbol::parse(cursor) { - if s == Symbol::DoubleSlash { - while cursor.next() != Some('\n') {} - return Self::parse(cursor); - } - let end = cursor.prev_pos(); - return Some(Self { - token: Token::Symbol(s), - span: FileSpan { - start, - end, - file: cursor.file(), - }, - }); - } - let mut word = String::new(); - while let Some(c) = cursor.peek() { - if c.is_whitespace() || Symbol::from_char(c).is_some() { - break; - } - word.push(c); - cursor.advance(); - } - let end = cursor.prev_pos(); - let token = if let Some(keyword) = Keyword::from_string(&word) { - Token::Keyword(keyword) - } else { - Token::Word(word) - }; - Some(Self { - token, - span: FileSpan { - start, - end, - file: cursor.file(), - }, - }) - } -} - -impl Token { - pub fn is_symbol(&self, symbol: Symbol) -> bool { - match self { - Token::Symbol(s) => *s == symbol, - _ => false, - } - } - pub fn is_symbol_and(&self, f: impl Fn(Symbol) -> bool) -> bool { - match self { - Token::Symbol(s) => f(*s), - _ => false, - } - } - pub fn is_keyword(&self, kw: Keyword) -> bool { - match self { - Token::Keyword(k) => *k == kw, - _ => false, - } - } -} - -impl Deref for TokenInstance { - type Target = Token; - - fn deref(&self) -> &Self::Target { - &self.token - } -} diff --git a/src/parser/v3/token/symbol.rs b/src/parser/v3/token/symbol.rs deleted file mode 100644 index 10fe1d8..0000000 --- a/src/parser/v3/token/symbol.rs +++ /dev/null @@ -1,161 +0,0 @@ -use std::fmt::Debug; - -use super::CharCursor; - -#[derive(PartialEq, Eq, Clone, Copy)] -pub enum Symbol { - Semicolon, - Colon, - DoubleColon, - Equals, - DoubleEquals, - Arrow, - DoubleArrow, - Plus, - Minus, - Asterisk, - Slash, - DoubleSlash, - Dot, - DoubleDot, - OpenParen, - CloseParen, - OpenCurly, - CloseCurly, - OpenSquare, - CloseSquare, - OpenAngle, - CloseAngle, - SingleQuote, - DoubleQuote, - Bang, - Ampersand, - DoubleAmpersand, - Pipe, - DoublePipe, - Comma, - Hash, - At, - Carrot, -} - -impl Symbol { - pub fn parse(cursor: &mut CharCursor) -> Option { - Self::from_char(cursor.peek()?).map(|mut s| { - cursor.advance(); - s.finish(cursor); - s - }) - } - pub fn from_char(c: char) -> Option { - Some(match c { - '(' => Self::OpenParen, - ')' => Self::CloseParen, - '[' => Self::OpenSquare, - ']' => Self::CloseSquare, - '{' => Self::OpenCurly, - '}' => Self::CloseCurly, - '<' => Self::OpenAngle, - '>' => Self::CloseAngle, - ';' => Self::Semicolon, - ':' => Self::Colon, - '+' => Self::Plus, - '-' => Self::Minus, - '*' => Self::Asterisk, - '/' => Self::Slash, - '=' => Self::Equals, - '.' => Self::Dot, - '\'' => Self::SingleQuote, - '"' => Self::DoubleQuote, - '!' => Self::Bang, - '&' => Self::Ampersand, - '|' => Self::Pipe, - ',' => Self::Comma, - '#' => Self::Hash, - '@' => Self::At, - '^' => Self::Carrot, - _ => return None, - }) - } - pub fn finish(&mut self, cursor: &mut CharCursor) { - let Some(next) = cursor.peek() else { - return; - }; - *self = match self { - Self::Colon => match next { - ':' => Self::DoubleColon, - _ => return, - }, - Self::Minus => match next { - '>' => Self::Arrow, - _ => return, - }, - Self::Equals => match next { - '=' => Self::DoubleEquals, - '>' => Self::DoubleArrow, - _ => return, - }, - Self::Slash => match next { - '/' => Self::DoubleSlash, - _ => return, - }, - Self::Ampersand => match next { - '&' => Self::DoubleAmpersand, - _ => return, - }, - Self::Pipe => match next { - '&' => Self::DoublePipe, - _ => return, - }, - Self::Dot => match next { - '.' => Self::DoubleDot, - _ => return, - }, - _ => return, - }; - cursor.advance(); - } - pub fn str(&self) -> &str { - match self { - Self::Semicolon => ";", - Self::Colon => ":", - Self::DoubleColon => "::", - Self::Equals => "=", - Self::DoubleEquals => "==", - Self::Arrow => "->", - Self::DoubleArrow => "=>", - Self::Plus => "+", - Self::Minus => "-", - Self::Asterisk => "*", - Self::Slash => "/", - Self::DoubleSlash => "//", - Self::Dot => ".", - Self::DoubleDot => "..", - Self::OpenParen => "(", - Self::CloseParen => ")", - Self::OpenCurly => "{", - Self::CloseCurly => "}", - Self::OpenSquare => "[", - Self::CloseSquare => "]", - Self::OpenAngle => "<", - Self::CloseAngle => ">", - Self::SingleQuote => "'", - Self::DoubleQuote => "\"", - Self::Bang => "!", - Self::Comma => ",", - Self::Ampersand => "&", - Self::DoubleAmpersand => "&&", - Self::Pipe => "|", - Self::DoublePipe => "||", - Self::Hash => "#", - Self::At => "@", - Self::Carrot => "^", - } - } -} - -impl Debug for Symbol { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "'{}'", self.str()) - } -} diff --git a/src/test.lang b/src/test.lang new file mode 100644 index 0000000..e2f4e7d --- /dev/null +++ b/src/test.lang @@ -0,0 +1,8 @@ +let x = "test"; +let y = "test"; + +fn test(x: u32) "hello"; +fn test3() { + arst +} +fn test2() "hello"; diff --git a/src/util/bits.rs b/src/util/bits.rs deleted file mode 100644 index c3a12af..0000000 --- a/src/util/bits.rs +++ /dev/null @@ -1,73 +0,0 @@ -pub const fn u(x: i32) -> u32 { - unsafe { std::mem::transmute(x) } -} - -pub const fn base_mask(len: u8) -> u32 { - (2 << len) - 1 -} - -pub const fn mask(h: u8, l: u8) -> u32 { - base_mask(h - l) << l -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Bits32(u32); -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct BitsI32(u32); - -impl Bits32 { - pub const fn new(val: u32) -> Self { - let lsh = 31 - H; - let rsh = lsh + L; - debug_assert!(((val << lsh) >> rsh) == (val >> L)); - Self(val) - } - pub const fn val(&self) -> u32 { - self.0 - } - pub const fn bit(&self, i: u8) -> u32 { - (self.0 >> i) & 1 - } - pub const fn bits(&self, h: u8, l: u8) -> u32 { - (self.0 >> l) & base_mask(h - l) - } -} - -impl BitsI32 { - pub const fn new(val: i32) -> Self { - let lsh = 31 - H; - let rsh = lsh + L; - assert!(((val << lsh) >> rsh) == (val >> L)); - Self(u(val) & mask(H, L)) - } - pub const fn tryy(val: i32) -> Option { - let lsh = 31 - H; - let rsh = lsh + L; - if ((val << lsh) >> rsh) == (val >> L) { - Some(Self(u(val) & mask(H, L))) - } else { - None - } - } - pub const fn to_u(self) -> Bits32 { - Bits32(self.0) - } -} - -// I hate (love) rust https://github.com/rust-lang/rust-project-goals/issues/106 -// pub struct Bits< -// T: Shl + Shr, -// const S: bool, -// const H: u8, -// const L: u8, -// >(T); -// pub struct U32Bits(u32); -// -// impl + const Shr, const S: bool, const H: u8, const L: u8> -// Bits -// { -// pub const fn new(val: T) -> Self { -// assert!(in_bit_range(val, H, L)); -// Self(val + L) -// } -// } diff --git a/src/util/label.rs b/src/util/label.rs deleted file mode 100644 index e504d08..0000000 --- a/src/util/label.rs +++ /dev/null @@ -1,40 +0,0 @@ -// this is not even remotely worth it but technically it doesn't use the heap I think xdddddddddd - -use std::marker::PhantomData; -pub trait Labeler = Fn(&mut std::fmt::Formatter<'_>, &S) -> std::fmt::Result; - -pub trait Labelable { - fn labeled>(&self, l: L) -> Labeled - where - Self: Sized; -} - -pub struct Labeled<'a, T, L: Labeler, S> { - data: &'a T, - labeler: L, - pd: PhantomData, -} - -pub trait LabeledFmt { - fn fmt_label( - &self, - f: &mut std::fmt::Formatter<'_>, - label: &dyn Labeler, - ) -> std::fmt::Result; -} - -impl, S> Labelable for T { - fn labeled>(&self, l: L) -> Labeled { - Labeled { - data: self, - labeler: l, - pd: PhantomData, - } - } -} - -impl, L: Labeler, S> std::fmt::Debug for Labeled<'_, T, L, S> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.data.fmt_label(f, &self.labeler) - } -} diff --git a/src/util/mod.rs b/src/util/mod.rs deleted file mode 100644 index 4e563a5..0000000 --- a/src/util/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod padder; -mod bits; -mod label; -mod name_stack; - -pub use padder::*; -pub use bits::*; -pub use label::*; -pub use name_stack::*; diff --git a/src/util/name_stack.rs b/src/util/name_stack.rs deleted file mode 100644 index f42a863..0000000 --- a/src/util/name_stack.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::collections::HashMap; - -pub struct NameStack { - base: HashMap, - levels: Vec>, -} - -impl NameStack { - pub fn new() -> Self { - Self { - base: HashMap::new(), - levels: Vec::new(), - } - } - pub fn search(&self, name: &str) -> Option<&T> { - for level in self.levels.iter().rev() { - if let Some(v) = level.get(name) { - return Some(v); - } - } - self.base.get(name) - } - pub fn push(&mut self) { - self.levels.push(HashMap::new()); - } - pub fn pop(&mut self) { - self.levels.pop(); - } - fn cur(&mut self) -> &mut HashMap { - self.levels.last_mut().unwrap_or(&mut self.base) - } - pub fn insert(&mut self, name: String, v: T) -> bool { - let cur = self.cur(); - if cur.contains_key(&name) { - return true; - } - cur.insert(name, v); - false - } - pub fn extend(&mut self, iter: impl Iterator) { - for (name, v) in iter { - self.insert(name, v); - } - } -} diff --git a/src/util/padder.rs b/src/util/padder.rs deleted file mode 100644 index 9fb957c..0000000 --- a/src/util/padder.rs +++ /dev/null @@ -1,38 +0,0 @@ -use core::fmt; - -pub struct Padder<'buf> { - buf: &'buf mut (dyn fmt::Write + 'buf), - on_newline: bool, -} - -impl fmt::Write for Padder<'_> { - fn write_str(&mut self, s: &str) -> fmt::Result { - for s in s.split_inclusive('\n') { - if self.on_newline { - self.buf.write_str(" ")?; - } - - self.on_newline = s.ends_with('\n'); - self.buf.write_str(s)?; - } - - Ok(()) - } - - fn write_char(&mut self, c: char) -> fmt::Result { - if self.on_newline { - self.buf.write_str(" ")?; - } - self.on_newline = c == '\n'; - self.buf.write_char(c) - } -} - -impl<'buf> Padder<'buf> { - pub fn new(buf: &'buf mut (dyn fmt::Write + 'buf)) -> Self { - Self { - buf, - on_newline: false, - } - } -}