prism_parser/core/
primitives.rs

1use crate::core::context::ParserContext;
2use crate::core::parser::Parser;
3use crate::core::pos::Pos;
4use crate::core::presult::PResult;
5use crate::core::presult::PResult::{PErr, POk};
6use crate::core::span::Span;
7use crate::core::state::ParserState;
8use crate::error::error_printer::ErrorLabel;
9use crate::error::error_printer::ErrorLabel::Debug;
10use crate::error::ParseError;
11
12#[inline(always)]
13pub fn single<'arn, 'grm: 'arn, E: ParseError>(
14    f: impl Fn(&char) -> bool,
15) -> impl Parser<'arn, 'grm, (Span, char), E> {
16    move |pos: Pos,
17          state: &mut ParserState<'arn, 'grm, E>,
18          _: ParserContext|
19          -> PResult<(Span, char), E> {
20        match pos.next(state.input) {
21            // We can parse the character
22            (pos_new, Some((span, e))) if f(&e) => PResult::new_ok((span, e), pos, pos_new),
23            // Error
24            (pos_new, _) => PResult::new_err(E::new(pos.span_to(pos_new)), pos),
25        }
26    }
27}
28
29#[inline(always)]
30pub fn seq2<'arn, 'grm: 'arn, 'a, O1, O2, E: ParseError>(
31    p1: &'a impl Parser<'arn, 'grm, O1, E>,
32    p2: &'a impl Parser<'arn, 'grm, O2, E>,
33) -> impl Parser<'arn, 'grm, (O1, O2), E> + 'a {
34    move |pos: Pos,
35          state: &mut ParserState<'arn, 'grm, E>,
36          context: ParserContext|
37          -> PResult<(O1, O2), E> {
38        let res1 = p1.parse(pos, state, context);
39        let end_pos = res1.end_pos();
40        res1.merge_seq(p2.parse(end_pos, state, context))
41    }
42}
43
44#[inline(always)]
45pub fn choice2<'arn, 'grm: 'arn, 'a, O, E: ParseError>(
46    p1: &'a impl Parser<'arn, 'grm, O, E>,
47    p2: &'a impl Parser<'arn, 'grm, O, E>,
48) -> impl Parser<'arn, 'grm, O, E> + 'a {
49    move |pos: Pos,
50          state: &mut ParserState<'arn, 'grm, E>,
51          context: ParserContext|
52          -> PResult<O, E> {
53        p1.parse(pos, state, context)
54            .merge_choice(p2.parse(pos, state, context))
55    }
56}
57
58#[inline(always)]
59pub fn repeat_delim<'arn, 'grm: 'arn, OP, OD, E: ParseError<L = ErrorLabel<'grm>>>(
60    item: impl Parser<'arn, 'grm, OP, E>,
61    delimiter: impl Parser<'arn, 'grm, OD, E>,
62    min: usize,
63    max: Option<usize>,
64) -> impl Parser<'arn, 'grm, Vec<OP>, E> {
65    move |pos: Pos,
66          state: &mut ParserState<'arn, 'grm, E>,
67          context: ParserContext|
68          -> PResult<Vec<OP>, E> {
69        let mut last_res: PResult<Vec<OP>, E> = PResult::new_empty(vec![], pos);
70
71        for i in 0..max.unwrap_or(usize::MAX) {
72            let pos = last_res.end_pos();
73            let part = if i == 0 {
74                item.parse(pos, state, context)
75            } else {
76                seq2(&delimiter, &item)
77                    .parse(pos, state, context)
78                    .map(|x| x.1)
79            };
80            let should_continue = part.is_ok();
81
82            if i < min {
83                last_res = last_res.merge_seq(part).map(|(mut vec, item)| {
84                    vec.push(item);
85                    vec
86                });
87            } else {
88                last_res = last_res.merge_seq_opt(part).map(|(mut vec, item)| {
89                    if let Some(item) = item {
90                        vec.push(item);
91                    }
92                    vec
93                });
94            };
95
96            if !should_continue {
97                break;
98            };
99
100            // If the result is OK and the last pos has not changed, we got into an infinite loop
101            // We break out with an infinite loop error
102            // The i != 0 check is to make sure to take the delim into account
103            if i != 0 && last_res.end_pos() <= pos {
104                let span = pos.span_to(pos);
105                let mut e = E::new(span);
106                e.add_label_explicit(Debug(span, "INFLOOP"));
107                return PResult::new_err(e, pos);
108            }
109        }
110
111        last_res
112    }
113}
114
115#[inline(always)]
116pub fn end<'arn, 'grm: 'arn, E: ParseError>() -> impl Parser<'arn, 'grm, (), E> {
117    move |pos: Pos, state: &mut ParserState<'arn, 'grm, E>, _: ParserContext| -> PResult<(), E> {
118        match pos.next(state.input) {
119            (s, Some(_)) => PResult::new_err(E::new(pos.span_to(s)), pos),
120            (s, None) => PResult::new_empty((), s),
121        }
122    }
123}
124
125#[inline(always)]
126pub fn positive_lookahead<'arn, 'grm: 'arn, O, E: ParseError>(
127    p: &impl Parser<'arn, 'grm, O, E>,
128) -> impl Parser<'arn, 'grm, O, E> + '_ {
129    move |pos: Pos,
130          state: &mut ParserState<'arn, 'grm, E>,
131          context: ParserContext|
132          -> PResult<O, E> {
133        match p.parse(pos, state, context) {
134            POk(o, _, _, err) => POk(o, pos, pos, err),
135            PErr(e, s) => PErr(e, s),
136        }
137    }
138}
139
140#[inline(always)]
141pub fn negative_lookahead<'arn, 'grm: 'arn, O, E: ParseError>(
142    p: &impl Parser<'arn, 'grm, O, E>,
143) -> impl Parser<'arn, 'grm, (), E> + '_ {
144    move |pos: Pos,
145          state: &mut ParserState<'arn, 'grm, E>,
146          context: ParserContext|
147          -> PResult<(), E> {
148        match p.parse(pos, state, context) {
149            POk(_, _, _, _) => PResult::new_err(E::new(pos.span_to(pos)), pos),
150            PErr(_, _) => PResult::new_empty((), pos),
151        }
152    }
153}