prism_parser/grammar/
from_action_result.rs

1use crate::core::cache::Allocs;
2use crate::grammar::action_result::ActionResult;
3use crate::grammar::action_result::ActionResult::*;
4use crate::grammar::escaped_string::EscapedString;
5use crate::grammar::rule_action::RuleAction;
6use crate::grammar::{AnnotatedRuleExpr, Block, GrammarFile, Rule, RuleExpr};
7use crate::grammar::{CharClass, RuleAnnotation};
8use std::borrow::Cow;
9
10#[macro_export]
11macro_rules! result_match {
12    {match $e1:expr => $p1:pat_param, $(match $es:expr => $ps:pat_param,)* create $body:expr} => {
13        match $e1 {
14            $p1 => {
15                result_match! { $(match $es => $ps,)* create $body }
16            },
17            _ => None,
18        }
19    };
20    {create $body:expr} => {
21        Some($body)
22    };
23}
24
25pub fn parse_grammarfile<'arn_in, 'arn_out, 'grm>(
26    r: &'arn_in ActionResult<'arn_in, 'grm>,
27    src: &'grm str,
28    allocs: Allocs<'arn_out>,
29    parse_a: impl Fn(
30        &'arn_in ActionResult<'arn_in, 'grm>,
31        &'grm str,
32    ) -> Option<RuleAction<'arn_out, 'grm>>,
33) -> Option<GrammarFile<'arn_out, 'grm>> {
34    result_match! {
35        match r => Construct(_, "GrammarFile", rules),
36        match &rules[..] => [rules],
37        create GrammarFile {
38            rules: allocs.try_alloc_extend(rules.iter_list().map(|rule| parse_rule(rule, src, allocs, &parse_a)))?,
39        }
40    }
41}
42
43fn parse_rule<'arn_in, 'arn_out, 'grm>(
44    r: &'arn_in ActionResult<'arn_in, 'grm>,
45    src: &'grm str,
46    allocs: Allocs<'arn_out>,
47    parse_a: &impl Fn(
48        &'arn_in ActionResult<'arn_in, 'grm>,
49        &'grm str,
50    ) -> Option<RuleAction<'arn_out, 'grm>>,
51) -> Option<Rule<'arn_out, 'grm>> {
52    result_match! {
53        match r => Construct(_, "Rule", rule_body),
54        match &rule_body[..] => [name, extend, args, blocks],
55        create Rule {
56            name: parse_identifier(name, src)?,
57            adapt: extend.iter_list().next().is_some(),
58            args: allocs.try_alloc_extend(args.iter_list().map(|n| parse_identifier(n, src)))?,
59            blocks: allocs.try_alloc_extend(blocks.iter_list().map(|block| parse_block(block, src, allocs, parse_a)))?,
60        }
61    }
62}
63
64fn parse_block<'arn_in, 'arn_out, 'grm>(
65    r: &'arn_in ActionResult<'arn_in, 'grm>,
66    src: &'grm str,
67    allocs: Allocs<'arn_out>,
68    parse_a: &impl Fn(
69        &'arn_in ActionResult<'arn_in, 'grm>,
70        &'grm str,
71    ) -> Option<RuleAction<'arn_out, 'grm>>,
72) -> Option<Block<'arn_out, 'grm>> {
73    result_match! {
74        match r => Construct(_, "Block", b),
75        match &b[..] => [name, extend, cs],
76        create Block { name: parse_identifier(name, src)?,
77            adapt: extend.iter_list().next().is_some(),
78            constructors: parse_constructors(cs, src, allocs, parse_a)? }
79    }
80}
81
82fn parse_constructors<'arn_in, 'arn_out, 'grm>(
83    r: &'arn_in ActionResult<'arn_in, 'grm>,
84    src: &'grm str,
85    allocs: Allocs<'arn_out>,
86    parse_a: &impl Fn(
87        &'arn_in ActionResult<'arn_in, 'grm>,
88        &'grm str,
89    ) -> Option<RuleAction<'arn_out, 'grm>>,
90) -> Option<&'arn_out [AnnotatedRuleExpr<'arn_out, 'grm>]> {
91    result_match! {
92        create allocs.try_alloc_extend(r.iter_list().map(|c| parse_annotated_rule_expr(c, src, allocs, parse_a)))?
93    }
94}
95
96fn parse_annotated_rule_expr<'arn_in, 'arn_out, 'grm>(
97    r: &'arn_in ActionResult<'arn_in, 'grm>,
98    src: &'grm str,
99    allocs: Allocs<'arn_out>,
100    parse_a: &impl Fn(
101        &'arn_in ActionResult<'arn_in, 'grm>,
102        &'grm str,
103    ) -> Option<RuleAction<'arn_out, 'grm>>,
104) -> Option<AnnotatedRuleExpr<'arn_out, 'grm>> {
105    result_match! {
106        match r => Construct(_, "AnnotatedExpr", body),
107        match &body[..] => [annots, e],
108        create AnnotatedRuleExpr(allocs.try_alloc_extend(annots.iter_list().map(|annot| parse_rule_annotation(annot, src)))?, parse_rule_expr(e, src, allocs, parse_a)?)
109    }
110}
111
112fn parse_rule_annotation<'arn_in, 'grm>(
113    r: &'arn_in ActionResult<'arn_in, 'grm>,
114    src: &'grm str,
115) -> Option<RuleAnnotation<'grm>> {
116    Some(match r {
117        Construct(_, "Error", b) => RuleAnnotation::Error(parse_string(&b[0], src)?),
118        Construct(_, "DisableLayout", _) => RuleAnnotation::DisableLayout,
119        Construct(_, "EnableLayout", _) => RuleAnnotation::EnableLayout,
120        Construct(_, "DisableRecovery", _) => RuleAnnotation::DisableRecovery,
121        Construct(_, "EnableRecovery", _) => RuleAnnotation::EnableRecovery,
122        _ => return None,
123    })
124}
125
126fn parse_rule_expr<'arn_in, 'arn_out, 'grm>(
127    r: &'arn_in ActionResult<'arn_in, 'grm>,
128    src: &'grm str,
129    allocs: Allocs<'arn_out>,
130    parse_a: &impl Fn(
131        &'arn_in ActionResult<'arn_in, 'grm>,
132        &'grm str,
133    ) -> Option<RuleAction<'arn_out, 'grm>>,
134) -> Option<RuleExpr<'arn_out, 'grm>> {
135    Some(match r {
136        Construct(_, "Action", b) => RuleExpr::Action(
137            allocs.alloc(parse_rule_expr(&b[0], src, allocs, parse_a)?),
138            parse_a(&b[1], src)?,
139        ),
140        Construct(_, "Choice", b) => RuleExpr::Choice(result_match! {
141            create allocs.try_alloc_extend(b[0].iter_list().map(|sub| parse_rule_expr(sub, src, allocs, parse_a)))?
142        }?),
143        Construct(_, "Sequence", b) => RuleExpr::Sequence(result_match! {
144            create allocs.try_alloc_extend(b[0].iter_list().map(|sub| parse_rule_expr(sub, src, allocs, parse_a)))?
145        }?),
146        Construct(_, "NameBind", b) => RuleExpr::NameBind(
147            parse_identifier(&b[0], src)?,
148            allocs.alloc(parse_rule_expr(&b[1], src, allocs, parse_a)?),
149        ),
150        Construct(_, "Repeat", b) => RuleExpr::Repeat {
151            expr: allocs.alloc(parse_rule_expr(&b[0], src, allocs, parse_a)?),
152            min: parse_u64(&b[1], src)?,
153            max: parse_option(&b[2], src, parse_u64)?,
154            delim: allocs.alloc(parse_rule_expr(&b[3], src, allocs, parse_a)?),
155        },
156        Construct(_, "Literal", b) => RuleExpr::Literal(parse_string(&b[0], src)?),
157        Construct(_, "CharClass", b) => RuleExpr::CharClass(parse_charclass(&b[0], src, allocs)?),
158        Construct(_, "SliceInput", b) => {
159            RuleExpr::SliceInput(allocs.alloc(parse_rule_expr(&b[0], src, allocs, parse_a)?))
160        }
161        Construct(_, "PosLookahead", b) => {
162            RuleExpr::PosLookahead(allocs.alloc(parse_rule_expr(&b[0], src, allocs, parse_a)?))
163        }
164        Construct(_, "NegLookahead", b) => {
165            RuleExpr::NegLookahead(allocs.alloc(parse_rule_expr(&b[0], src, allocs, parse_a)?))
166        }
167        Construct(_, "This", _) => RuleExpr::This,
168        Construct(_, "Next", _) => RuleExpr::Next,
169        Construct(_, "Guid", _) => RuleExpr::Guid,
170        Construct(_, "RunVar", b) => RuleExpr::RunVar(
171            parse_identifier(&b[0], src)?,
172            result_match! {
173                create allocs.try_alloc_extend(b[1].iter_list().map(|sub| {
174                    parse_rule_expr(sub, src, allocs, parse_a)
175                }))?
176            }?,
177        ),
178        Construct(_, "AtAdapt", b) => {
179            RuleExpr::AtAdapt(parse_identifier(&b[0], src)?, parse_identifier(&b[1], src)?)
180        }
181        _ => return None,
182    })
183}
184
185pub(crate) fn parse_identifier<'grm>(
186    r: &ActionResult<'_, 'grm>,
187    src: &'grm str,
188) -> Option<&'grm str> {
189    match r {
190        Value(span) => Some(&src[*span]),
191        // If the identifier of a block is a literal, it does not contain escaped chars
192        Literal(s) => match s.to_cow() {
193            Cow::Borrowed(s) => Some(s),
194            Cow::Owned(_) => None,
195        },
196        _ => None,
197    }
198}
199
200pub(crate) fn parse_string<'arn, 'grm>(
201    r: &'arn ActionResult<'arn, 'grm>,
202    src: &'grm str,
203) -> Option<EscapedString<'grm>> {
204    result_match! {
205        match r => Value(span),
206        create EscapedString::from_escaped(&src[*span])
207    }
208}
209
210fn parse_string_char(r: &ActionResult<'_, '_>, src: &str) -> Option<char> {
211    Some(match r {
212        Value(span) => src[*span].chars().next().unwrap(),
213        Literal(c) => c.chars().next().unwrap(),
214        _ => return None,
215    })
216}
217
218fn parse_charclass<'arn_out>(
219    r: &ActionResult<'_, '_>,
220    src: &str,
221    allocs: Allocs<'arn_out>,
222) -> Option<CharClass<'arn_out>> {
223    result_match! {
224        match r => Construct(_, "CharClass", b),
225        create CharClass {
226            neg: b[0].iter_list().next().is_some(),
227            ranges: allocs.try_alloc_extend(b[1].iter_list().map(|p| result_match! {
228                match p => Construct(_, "Range", pb),
229                create (parse_string_char(&pb[0], src)?, parse_string_char(&pb[1], src)?)
230            }))?
231        }
232    }
233}
234
235fn parse_option<'arn, 'grm, T>(
236    r: &ActionResult<'arn, 'grm>,
237    src: &str,
238    sub: impl Fn(&ActionResult<'arn, 'grm>, &str) -> Option<T>,
239) -> Option<Option<T>> {
240    match r {
241        Construct(_, "None", []) => Some(None),
242        Construct(_, "Some", b) => Some(Some(sub(&b[0], src)?)),
243        _ => None,
244    }
245}
246
247fn parse_u64(r: &ActionResult<'_, '_>, src: &str) -> Option<u64> {
248    match r {
249        Literal(v) => v.parse().ok(),
250        Value(span) => src[*span].parse().ok(),
251        _ => None,
252    }
253}
254
255pub fn parse_rule_action<'arn, 'grm>(
256    r: &ActionResult<'_, 'grm>,
257    src: &'grm str,
258    allocs: Allocs<'arn>,
259) -> Option<RuleAction<'arn, 'grm>> {
260    Some(match r {
261        Construct(_, "Construct", b) => RuleAction::Construct(
262            parse_identifier(&b[0], src).unwrap(),
263            result_match! {
264                create allocs.try_alloc_extend(b[1].iter_list().map(|sub| parse_rule_action(sub, src, allocs)))?
265            }?,
266        ),
267        Construct(_, "InputLiteral", b) => RuleAction::InputLiteral(parse_string(&b[0], src)?),
268        Construct(_, "Name", b) => RuleAction::Name(parse_identifier(&b[0], src)?),
269        _ => return None,
270    })
271}