This commit is contained in:
2026-04-08 23:28:50 -04:00
parent edabc22431
commit bdf08ce52c
11 changed files with 417 additions and 158 deletions
+179
View File
@@ -0,0 +1,179 @@
use crate::{
io::{CompilerMsg, CompilerOutput, Span},
parser::cursor::{Cursor, Lit},
};
use std::{marker::PhantomData, ops::Index};
mod expr;
pub use expr::*;
pub trait Parsable: Sized + Node {
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg>;
}
pub struct ParseCtx<'a> {
start: usize,
cursor: Cursor<'a>,
nodes: Nodes,
}
def_nodes!(
exprs: Expr,
idents: Ident,
statements: Statement,
lits: Lit,
);
impl Nodes {
pub fn parse_root(path: &str, output: &mut CompilerOutput) -> Option<(Self, Id<Expr>)> {
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 nodes = Self::default();
let mut ctx = ParseCtx {
start: 0,
nodes,
cursor: Cursor::new(&root_code, 0),
};
let root = match ctx.parse::<Expr>() {
Ok(expr) => expr,
Err(msg) => {
output.error(msg);
return None;
}
};
Some((ctx.nodes, root))
}
pub fn format<N: FmtNode>(
&self,
w: &mut impl std::io::Write,
id: Id<N>,
) -> std::io::Result<()> {
self[id].format(w, self)
}
}
impl<N: Node> Index<Id<N>> for Nodes {
type Output = N;
fn index(&self, index: Id<N>) -> &Self::Output {
&N::vec(self).vec[index.id]
}
}
impl<N: Node> Index<&Id<N>> for Nodes {
type Output = N;
fn index(&self, index: &Id<N>) -> &Self::Output {
&N::vec(self).vec[index.id]
}
}
#[derive(Debug)]
pub struct NodeVec<N> {
vec: Vec<N>,
spans: Vec<Span>,
}
impl<N> NodeVec<N> {
pub fn add(&mut self, v: N, span: Span) -> Id<N> {
let id = self.vec.len();
self.vec.push(v);
self.spans.push(span);
Id {
id,
_pd: PhantomData,
}
}
}
impl<N> Default for NodeVec<N> {
fn default() -> Self {
Self {
vec: Default::default(),
spans: Default::default(),
}
}
}
pub struct Id<T> {
id: usize,
_pd: PhantomData<T>,
}
impl<T> Clone for Id<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Id<T> {}
pub trait Node: Sized {
fn vec(nodes: &Nodes) -> &NodeVec<Self>;
fn vec_mut(nodes: &mut Nodes) -> &mut NodeVec<Self>;
}
impl ParseCtx<'_> {
pub fn parse<P: Parsable>(&mut self) -> Result<Id<P>, CompilerMsg> {
let old_start = self.start;
self.start = self.cursor.peek_start();
let res = P::parse(self).map(|r| self.push(r));
self.start = old_start;
res
}
pub fn ident(&mut self, s: String) -> Id<Ident> {
let span = self.cursor.span;
self.nodes.idents.add(Ident { inner: s }, span)
}
pub fn lit(&mut self, lit: Lit) -> Id<Lit> {
let span = self.cursor.span;
self.nodes.lits.add(lit, span)
}
pub fn push_adv<N: Node>(&mut self, node: N) -> Id<N> {
let res = self.push(node);
self.cursor.next();
res
}
pub fn push<N: Node>(&mut self, node: N) -> Id<N> {
let end = self.cursor.cur_end();
N::vec_mut(&mut self.nodes).add(
node,
Span {
file: self.cursor.file(),
start: self.start,
end,
},
)
}
}
macro_rules! def_nodes {
($($field:ident: $ty:ident,)*) => {
#[derive(Default)]
pub struct Nodes {
$($field: NodeVec<$ty>,)*
}
$(impl Node for $ty {
fn vec(nodes: &Nodes) -> &NodeVec<Self> {
&nodes.$field
}
fn vec_mut(nodes: &mut Nodes) -> &mut NodeVec<Self> {
&mut nodes.$field
}
})*
};
}
use def_nodes;
pub trait FmtNode: Node {
fn format(&self, w: &mut impl std::io::Write, nodes: &Nodes) -> std::io::Result<()>;
}