pratt_gen_core/
lib.rs

1use std::{fmt::{Debug, Display}, marker::PhantomData, ops::Deref, sync::atomic::AtomicU16};
2
3mod source;
4mod arena;
5mod token;
6mod space;
7mod span;
8mod primitive;
9pub use source::*;
10pub use arena::*;
11pub use token::*;
12pub use space::*;
13pub use span::*;
14pub use primitive::*;
15
16static COUNTER: AtomicU16 = AtomicU16::new(0);
17
18#[derive(Debug, Clone)]
19pub enum Error<'a> {
20    Mismatch {
21        range: (usize, usize),
22        token: &'static str,
23        piece: &'a str,
24    },
25    Precedence,
26    List(&'a List<'a, Error<'a>>),
27}
28
29impl<'a> Display for Error<'a> {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        use Error::*;
32        match self {
33            Precedence => {write!(f, "")}
34            Mismatch { range, token, piece } => {
35                writeln!(f, "{}..{} expected: {token:?}, found: {piece:?}", range.0, range.1)
36            }
37            List(list) => {
38                writeln!(f, "{list}")
39            }
40        }
41    }
42}
43
44#[derive(Clone, Copy)]
45pub enum List<'a, T> {
46    Null,
47    Some(&'a List<'a, T>, T)
48}
49
50impl<'a, T> List<'a, T> {
51    pub fn new() -> Self {
52        List::Null
53    }
54    pub fn push(self, arena: &'a Arena, value: T) -> Self {
55        let list = unsafe { arena.alloc(self) };
56        List::Some(list, value)
57    }
58}
59
60impl<'a, T: Debug> Debug for List<'a, T> {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        match self {
63            List::Null => write!(f, ""),
64            List::Some(List::Null, x) => write!(f, "{x:?}"),
65            List::Some(list, x) => write!(f, "{list:?}, {x:?}"),
66        }
67    }
68}
69
70impl<'a, T: Display> Display for List<'a, T> {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        match self {
73            List::Null => write!(f, ""),
74            List::Some(List::Null, x) => write!(f, "{x}"),
75            List::Some(list, x) => write!(f, "{list}{x}"),
76        }
77    }
78}
79
80pub trait ParserImpl<'a>: Sized + Copy {
81    fn num() -> u16 {
82        use once_cell::sync::Lazy;
83        use std::sync::atomic::Ordering::SeqCst;
84        static NUM: Lazy<u16> = Lazy::new(|| COUNTER.fetch_add(1, SeqCst));
85        *NUM.deref()
86    }
87    fn parser_impl(
88        source: Source<'a>, 
89        out_arena: &'a Arena,
90        err_arena: &'a Arena,
91        precedence: u16,
92    ) -> Result<(Self, Source<'a>), Error<'a>>;
93}
94
95impl<'a, X: ParserImpl<'a>> ParserImpl<'a> for &'a X {
96    fn parser_impl(
97        source: Source<'a>, 
98        out_arena: &'a Arena,
99        err_arena: &'a Arena,
100        precedence: u16,
101    ) -> Result<(Self, Source<'a>), Error<'a>> {
102        stacker::maybe_grow(32*1024, 4*1024*1024, || {
103            let (out, source) = X::parser_impl(source, out_arena, err_arena, precedence)?;
104            unsafe { Ok((out_arena.alloc(out), source)) }
105        })
106    }
107}
108
109pub fn parse<'a, X: ParserImpl<'a>>(
110    source: Source<'a>, 
111    out_arena: &'a Arena,
112    err_arena: &'a Arena
113) -> Result<X, Error<'a>> {
114    match X::parser_impl(source, out_arena, err_arena, 0) {
115        Ok((out, _)) => Ok(out),
116        Err(err) => Err(err), 
117    }
118}