From d864adfd059da1614cc5f5328b0ffd4628ab16c5 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Sat, 18 Apr 2026 00:16:03 -0400 Subject: [PATCH] work --- src/ir/id.rs | 54 +++++++++++++++++++++++++++++++++++++ src/ir/mod.rs | 21 ++++++++++++++- src/ir/structs/mod.rs | 5 +++- src/ir/structs/namespace.rs | 17 ++++++++++++ src/main.rs | 12 +++------ src/parser/cursor/token.rs | 2 +- src/parser/mod.rs | 22 +++++++++++++++ src/parser/node/mod.rs | 27 ++----------------- src/parser/nodes/item.rs | 16 ++++++++++- src/parser_ir/mod.rs | 23 ++++++++++++++++ test/main.lang | 3 ++- test/other.lang | 3 +++ 12 files changed, 167 insertions(+), 38 deletions(-) create mode 100644 src/ir/id.rs create mode 100644 src/ir/structs/namespace.rs create mode 100644 src/parser_ir/mod.rs diff --git a/src/ir/id.rs b/src/ir/id.rs new file mode 100644 index 0000000..7ff7bec --- /dev/null +++ b/src/ir/id.rs @@ -0,0 +1,54 @@ +use std::ops::{Index, IndexMut}; + +pub struct Id { + idx: usize, + _pd: std::marker::PhantomData, +} + +pub struct IdVec { + vec: Vec, +} + +impl IdVec { + pub fn add(&mut self, val: T) -> Id { + let id = Id { + idx: self.vec.len(), + _pd: Default::default(), + }; + self.vec.push(val); + id + } +} + +impl Index> for IdVec { + type Output = T; + + fn index(&self, index: Id) -> &Self::Output { + &self.vec[index.idx] + } +} + +impl IndexMut> for IdVec { + fn index_mut(&mut self, index: Id) -> &mut Self::Output { + &mut self.vec[index.idx] + } +} + +impl Default for IdVec { + fn default() -> Self { + Self { + vec: Default::default(), + } + } +} + +impl Clone for Id { + fn clone(&self) -> Self { + Self { + idx: self.idx.clone(), + _pd: self._pd.clone(), + } + } +} + +impl Copy for Id {} diff --git a/src/ir/mod.rs b/src/ir/mod.rs index eb8118a..f5e2d88 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,4 +1,23 @@ +mod id; mod structs; +pub use id::*; pub use structs::*; -pub struct Ir {} +pub struct Ir { + pub root: Id, + pub namespaces: IdVec, +} + +impl Ir { + pub fn root(&mut self) -> &mut Namespace { + &mut self.namespaces[self.root] + } +} + +impl Default for Ir { + fn default() -> Self { + let mut namespaces = IdVec::default(); + let root = namespaces.add(Namespace::default()); + Self { root, namespaces } + } +} diff --git a/src/ir/structs/mod.rs b/src/ir/structs/mod.rs index 29f13b4..d1985ca 100644 --- a/src/ir/structs/mod.rs +++ b/src/ir/structs/mod.rs @@ -1 +1,4 @@ -pub struct Module {} +mod namespace; +pub use namespace::*; + +use super::Id; diff --git a/src/ir/structs/namespace.rs b/src/ir/structs/namespace.rs new file mode 100644 index 0000000..457c249 --- /dev/null +++ b/src/ir/structs/namespace.rs @@ -0,0 +1,17 @@ +use super::*; +use crate::parser::Ident; +use std::collections::HashMap; + +#[derive(Default)] +pub struct Namespace { + pub items: HashMap, +} + +pub enum Item { + Import(Id), +} + +// issue: if I try to parse a function body, I'll want to have clear statements such as +// "call trait fn func on x" or "call field func of x", but you (often) can't tell until typed +// x.func +// x'func diff --git a/src/main.rs b/src/main.rs index 622cf50..a9f7b9c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,13 @@ use crate::{ io::CompilerOutput, - parser::{Node, parse_root}, + parser::{Node, parse_file}, + parser_ir::parse_program, }; mod io; mod ir; mod parser; +mod parser_ir; fn main() { let mut args = std::env::args(); @@ -14,15 +16,9 @@ fn main() { return; }; let mut output = CompilerOutput::new(); - let root = parse_root(&path, &mut output); + let root = parse_file(&path, &mut output); if let Some(root) = root { print!("{}", root.new_dsp()); - // for item in &root.items { - // output.errors.push(io::CompilerMsg { - // spans: vec![item.span], - // msg: format!("hello"), - // }); - // } } output.write(&mut std::io::stdout()); } diff --git a/src/parser/cursor/token.rs b/src/parser/cursor/token.rs index e450344..9ddb271 100644 --- a/src/parser/cursor/token.rs +++ b/src/parser/cursor/token.rs @@ -31,7 +31,7 @@ def_tokens! { } keyword { Let: "let", - Do: "do", + Import: "import", Fn: "fn", If: "if", Loop: "loop", diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a3565f6..ff34e65 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -5,3 +5,25 @@ mod nodes; use cursor::*; pub use node::*; pub use nodes::*; + +use crate::io::CompilerOutput; + +pub fn parse_file(path: &str, output: &mut CompilerOutput) -> Option { + let code = match std::fs::read_to_string(path) { + Ok(code) => code, + Err(err) => { + output.error(format!("Failed to read input file: {err}")); + return None; + } + }; + output.files.push(path.to_string()); + let mut ctx = ParseCtx::new(Cursor::new(&code, 0)); + let root = match ctx.parse() { + Ok(v) => v, + Err(msg) => { + output.error(msg); + return None; + } + }; + Some(root) +} diff --git a/src/parser/node/mod.rs b/src/parser/node/mod.rs index d721606..3ac027d 100644 --- a/src/parser/node/mod.rs +++ b/src/parser/node/mod.rs @@ -1,13 +1,10 @@ -use crate::{ - io::{CompilerMsg, CompilerOutput}, - parser::{Cursor, nodes::*}, -}; - mod ctx; mod dsp; pub use ctx::*; pub use dsp::*; +use crate::io::CompilerMsg; + pub trait Node: Sized { fn parse(ctx: &mut ParseCtx) -> Result; fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result; @@ -18,23 +15,3 @@ pub trait Node: Sized { self.dsp(DisplayCtx { indent: 0 }) } } - -pub fn parse_root(path: &str, output: &mut CompilerOutput) -> Option { - let root_code = match std::fs::read_to_string(path) { - Ok(code) => code, - Err(err) => { - output.error(format!("Failed to read input file: {err}")); - return None; - } - }; - output.files.push(path.to_string()); - let mut ctx = ParseCtx::new(Cursor::new(&root_code, 0)); - let root = match ctx.parse() { - Ok(v) => v, - Err(msg) => { - output.error(msg); - return None; - } - }; - Some(root) -} diff --git a/src/parser/nodes/item.rs b/src/parser/nodes/item.rs index a2c3165..2a3c5fb 100644 --- a/src/parser/nodes/item.rs +++ b/src/parser/nodes/item.rs @@ -11,12 +11,18 @@ pub enum ItemTy { ty: Option, val: Expr, }, + Fn(Func), Expr(Expr), + Import(Ident), } impl Node for Item { fn parse(ctx: &mut ParseCtx) -> Result { let ty = match ctx.expect_peek()? { + Token::Fn => { + ctx.next(); + ItemTy::Fn(ctx.parse()?) + } Token::Let => { ctx.next(); let name = ctx.parse()?; @@ -28,6 +34,10 @@ impl Node for Item { let val = ctx.parse()?; ItemTy::Let { name, ty, val } } + Token::Import => { + ctx.next(); + ItemTy::Import(ctx.parse()?) + } _ => ItemTy::Expr(ctx.parse()?), }; Ok(Self { @@ -38,6 +48,7 @@ impl Node for Item { fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { match &self.ty { + ItemTy::Fn(func) => func.fmt(f, ctx)?, ItemTy::Let { name, ty, val } => { write!(f, "let {}", name.dsp(ctx))?; if let Some(ty) = ty { @@ -45,7 +56,8 @@ impl Node for Item { } write!(f, " = {}", val.dsp(ctx))?; } - ItemTy::Expr(id) => id.fmt(f, ctx)?, + ItemTy::Expr(expr) => expr.fmt(f, ctx)?, + ItemTy::Import(ident) => write!(f, "import {}", ident.dsp(ctx))?, } Ok(()) } @@ -56,6 +68,8 @@ impl Item { match &self.ty { ItemTy::Let { val, .. } => val.ends_with_block(), ItemTy::Expr(id) => id.ends_with_block(), + ItemTy::Fn(f) => f.ends_with_block(), + ItemTy::Import(ident) => false, } } pub fn needs_semicolon(&self) -> bool { diff --git a/src/parser_ir/mod.rs b/src/parser_ir/mod.rs new file mode 100644 index 0000000..703f487 --- /dev/null +++ b/src/parser_ir/mod.rs @@ -0,0 +1,23 @@ +use crate::{ + io::CompilerOutput, + ir::{Ir, Namespace}, + parser::{self, parse_file}, +}; + +pub fn parse_program(path: &str, output: &mut CompilerOutput) -> Option { + let root = parse_file(path, output)?; + let mut ir = Ir::default(); + add_defs(ir.root(), &root); + Some(ir) +} + +pub fn add_defs(namespace: &mut Namespace, body: &parser::Body) { + for item in &body.items { + match &item.ty { + parser::ItemTy::Let { name, ty, val } => todo!(), + parser::ItemTy::Fn(func) => todo!(), + parser::ItemTy::Expr(expr) => todo!(), + parser::ItemTy::Import(ident) => todo!(), + } + } +} diff --git a/test/main.lang b/test/main.lang index e5b69d5..db9a600 100644 --- a/test/main.lang +++ b/test/main.lang @@ -1,3 +1,5 @@ +modl other; + let x: i32 = 3; while true { print("hello"); @@ -9,5 +11,4 @@ let y = true; if y => print("hello"); fn thing() { - } diff --git a/test/other.lang b/test/other.lang index e69de29..92159b4 100644 --- a/test/other.lang +++ b/test/other.lang @@ -0,0 +1,3 @@ +fn thing() { + print("hello from other"); +}