Files
lang/src/parser/node/parse.rs
T
2026-04-17 00:09:00 -04:00

112 lines
2.5 KiB
Rust

use std::ops::Index;
use crate::{
io::{CompilerMsg, Span},
parser::{
Id, Ident, Node, Nodes,
cursor::{Cursor, Lit, Token},
},
};
pub trait Parsable: Sized + Node {
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg>;
}
pub struct ParseCtx<'a> {
start: usize,
cursor: Cursor<'a>,
pub nodes: Nodes,
}
impl<'a> ParseCtx<'a> {
pub fn new(cursor: Cursor<'a>) -> Self {
Self {
start: 0,
nodes: Nodes::default(),
cursor,
}
}
pub fn parse<N: Parsable>(&mut self) -> Result<Id<N>, CompilerMsg> {
self.parse_with(N::parse)
}
pub fn parse_with<N: Node>(
&mut self,
f: impl FnOnce(&mut Self) -> Result<N, CompilerMsg>,
) -> Result<Id<N>, CompilerMsg> {
let old_start = self.start;
self.start = self.cursor.peek_start();
let res = f(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,
},
)
}
pub fn list<N: Parsable>(&mut self, sep: Token, end: Token) -> Result<Vec<Id<N>>, CompilerMsg> {
let mut list = Vec::new();
if self.next_if(&end) {
return Ok(list);
}
list.push(self.parse()?);
while self.next_if(&sep) {
list.push(self.parse()?);
}
self.expect(end)?;
Ok(list)
}
pub fn finish(self) -> Nodes {
self.nodes
}
}
impl<'a> std::ops::Deref for ParseCtx<'a> {
type Target = Cursor<'a>;
fn deref(&self) -> &Self::Target {
&self.cursor
}
}
impl<'a> std::ops::DerefMut for ParseCtx<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cursor
}
}
impl<N: Node> Index<Id<N>> for ParseCtx<'_> {
type Output = N;
fn index(&self, index: Id<N>) -> &Self::Output {
&self.nodes[index]
}
}