use crate::{Language, ParserState, source::Source, tree::GreenNode};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Associativity {
Left,
Right,
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OperatorInfo {
pub precedence: u8,
pub associativity: Associativity,
}
impl OperatorInfo {
pub fn left(precedence: u8) -> Self {
Self { precedence, associativity: Associativity::Left }
}
pub fn right(precedence: u8) -> Self {
Self { precedence, associativity: Associativity::Right }
}
pub fn none(precedence: u8) -> Self {
Self { precedence, associativity: Associativity::None }
}
}
pub trait Pratt<L: Language> {
fn primary<'a, S: Source + ?Sized>(&self, state: &mut ParserState<'a, L, S>) -> &'a GreenNode<'a, L>;
fn prefix<'a, S: Source + ?Sized>(&self, state: &mut ParserState<'a, L, S>) -> &'a GreenNode<'a, L> {
self.primary(state)
}
fn infix<'a, S: Source + ?Sized>(&self, state: &mut ParserState<'a, L, S>, left: &'a GreenNode<'a, L>, min_precedence: u8) -> Option<&'a GreenNode<'a, L>>;
}
#[inline(always)]
pub fn binary<'a, L, S, F>(state: &mut ParserState<'a, L, S>, left: &'a GreenNode<'a, L>, op_kind: L::TokenType, op_precedence: u8, assoc: Associativity, result_kind: L::ElementType, mut parse_expr: F) -> &'a GreenNode<'a, L>
where
L: Language,
S: Source + ?Sized,
F: FnMut(&mut ParserState<'a, L, S>, u8) -> &'a GreenNode<'a, L>,
L::ElementType: From<L::TokenType>,
{
let cp = state.checkpoint_before(left);
state.expect(op_kind).ok();
let next_prec = match assoc {
Associativity::Left => op_precedence + 1,
Associativity::Right => op_precedence,
Associativity::None => op_precedence + 1,
};
let _right = parse_expr(state, next_prec);
state.finish_at(cp, result_kind)
}
#[inline(always)]
pub fn unary<'a, L, S, F>(state: &mut ParserState<'a, L, S>, op_kind: L::TokenType, op_precedence: u8, result_kind: L::ElementType, mut parse_expr: F) -> &'a GreenNode<'a, L>
where
L: Language,
S: Source + ?Sized,
F: FnMut(&mut ParserState<'a, L, S>, u8) -> &'a GreenNode<'a, L>,
L::ElementType: From<L::TokenType>,
{
let cp = state.checkpoint();
state.expect(op_kind).ok();
let _right = parse_expr(state, op_precedence);
state.finish_at(cp, result_kind)
}
#[inline(always)]
pub fn postfix<'a, L, S>(state: &mut ParserState<'a, L, S>, left: &'a GreenNode<'a, L>, op_kind: L::TokenType, result_kind: L::ElementType) -> &'a GreenNode<'a, L>
where
L: Language,
S: Source + ?Sized,
L::ElementType: From<L::TokenType>,
{
let cp = state.checkpoint_before(left);
state.expect(op_kind).ok();
state.finish_at(cp, result_kind)
}
pub struct PrattParser<L: Language, T: Pratt<L>> {
spec: T,
_marker: core::marker::PhantomData<L>,
}
impl<L: Language, T: Pratt<L>> PrattParser<L, T> {
pub const fn new(spec: T) -> Self {
Self { spec, _marker: core::marker::PhantomData }
}
pub fn parse_expr<'a, S: Source + ?Sized>(&self, state: &mut ParserState<'a, L, S>, min_precedence: u8) -> &'a GreenNode<'a, L> {
Self::parse(state, min_precedence, &self.spec)
}
pub fn parse<'a, S: Source + ?Sized>(state: &mut ParserState<'a, L, S>, min_precedence: u8, spec: &T) -> &'a GreenNode<'a, L> {
let mut left = spec.prefix(state);
while let Some(node) = spec.infix(state, left, min_precedence) {
left = node
}
left
}
}