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; } 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(&mut self) -> Result, CompilerMsg> { self.parse_with(N::parse) } pub fn parse_with( &mut self, f: impl FnOnce(&mut Self) -> Result, ) -> Result, 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 { let span = self.cursor.span; self.nodes.idents.add(Ident { inner: s }, span) } pub fn lit(&mut self, lit: Lit) -> Id { let span = self.cursor.span; self.nodes.lits.add(lit, span) } pub fn push_adv(&mut self, node: N) -> Id { let res = self.push(node); self.cursor.next(); res } pub fn push(&mut self, node: N) -> Id { 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(&mut self, sep: Token, end: Token) -> Result>, 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 Index> for ParseCtx<'_> { type Output = N; fn index(&self, index: Id) -> &Self::Output { &self.nodes[index] } }