prism_parser/parser/
parser_instance.rs

1use crate::core::adaptive::{AdaptError, GrammarState};
2use crate::core::cache::Allocs;
3use crate::core::context::ParserContext;
4use crate::core::pos::Pos;
5use crate::core::recovery::parse_with_recovery;
6use crate::core::state::ParserState;
7use crate::error::aggregate_error::AggregatedParseError;
8use crate::error::error_printer::ErrorLabel;
9use crate::error::ParseError;
10use crate::grammar::action_result::ActionResult;
11use crate::grammar::GrammarFile;
12use crate::parser::parser_layout::full_input_layout;
13use crate::parser::parser_rule;
14use crate::parser::var_map::VarMap;
15use crate::META_GRAMMAR;
16use bumpalo::Bump;
17
18pub struct ParserInstance<'arn, 'grm: 'arn, E: ParseError<L = ErrorLabel<'grm>>> {
19    context: ParserContext,
20    state: ParserState<'arn, 'grm, E>,
21
22    grammar_state: GrammarState<'arn, 'grm>,
23    rules: VarMap<'arn, 'grm>,
24}
25
26impl<'arn, 'grm: 'arn, E: ParseError<L = ErrorLabel<'grm>>> ParserInstance<'arn, 'grm, E> {
27    pub fn new(
28        input: &'grm str,
29        bump: Allocs<'arn>,
30        from: &'arn GrammarFile<'arn, 'grm>,
31    ) -> Result<Self, AdaptError<'grm>> {
32        let context = ParserContext::new();
33        let state = ParserState::new(input, bump);
34
35        let (grammar_state, meta_vars) = GrammarState::new_with(&META_GRAMMAR, bump);
36        let visible_rules = VarMap::from_iter(
37            [
38                (
39                    "grammar",
40                    *meta_vars
41                        .get("grammar")
42                        .expect("Meta grammar contains 'grammar' rule"),
43                ),
44                (
45                    "prule_action",
46                    *meta_vars
47                        .get("prule_action")
48                        .expect("Meta grammar contains 'prule_action' rule"),
49                ),
50            ],
51            bump,
52        );
53
54        let (grammar_state, rules) =
55            grammar_state.adapt_with(from, visible_rules, None, state.alloc)?;
56
57        Ok(Self {
58            context,
59            state,
60            grammar_state,
61            rules,
62        })
63    }
64}
65
66impl<'arn, 'grm: 'arn, E: ParseError<L = ErrorLabel<'grm>> + 'grm> ParserInstance<'arn, 'grm, E> {
67    pub fn run(
68        &'arn mut self,
69        rule: &'grm str,
70    ) -> Result<&'arn ActionResult<'arn, 'grm>, AggregatedParseError<'grm, E>> {
71        let rule = self
72            .rules
73            .get(rule)
74            .expect("Rule exists")
75            .as_rule_id()
76            .expect("Rule is a rule");
77        let result = parse_with_recovery(
78            &full_input_layout(
79                &self.grammar_state,
80                self.rules,
81                &parser_rule::parser_rule(&self.grammar_state, rule, &[]),
82            ),
83            Pos::start(),
84            &mut self.state,
85            self.context,
86        );
87        result.map_err(|errors| AggregatedParseError {
88            input: self.state.input,
89            errors,
90        })
91    }
92}
93
94pub fn run_parser_rule<'arn, 'grm, E: ParseError<L = ErrorLabel<'grm>> + 'grm, T>(
95    rules: &'arn GrammarFile<'arn, 'grm>,
96    rule: &'grm str,
97    input: &'grm str,
98    ar_map: impl for<'c> FnOnce(&'c ActionResult<'c, 'grm>, Allocs<'c>) -> T,
99) -> Result<T, AggregatedParseError<'grm, E>> {
100    let bump = Bump::new();
101    let allocs: Allocs<'_> = Allocs::new(&bump);
102    let mut instance = ParserInstance::new(input, allocs, rules).unwrap();
103    instance.run(rule).map(|ar| ar_map(ar, allocs))
104}
105
106#[macro_export]
107macro_rules! run_parser_rule_here {
108    ($id: ident = $rules: expr, $rule: expr, $error: ty, $input: expr) => {
109        let bump = ::bumpalo::Bump::new();
110        let alloc = $crate::core::cache::Allocs::new(&bump);
111        let mut instance =
112            $crate::parser::parser_instance::ParserInstance::<$error>::new($input, alloc, $rules)
113                .unwrap();
114        let $id = instance.run($rule);
115    };
116}