112 lines
2.5 KiB
Rust
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]
|
|
}
|
|
}
|