haar_lib/parser/ll1/
mod.rs1use std::{collections::HashMap, hash::Hash};
3
4#[derive(Clone, Debug)]
6pub struct Input<Char> {
7 input: Vec<Char>,
8 pos: usize,
9}
10
11impl Input<char> {
12 pub fn new(s: &str) -> Self {
14 Self {
15 input: s.chars().collect(),
16 pos: 0,
17 }
18 }
19}
20
21impl<Char> Input<Char>
22where
23 Char: Copy + Eq,
24{
25 pub fn consume_eq(&mut self, e: Char) -> Option<Char> {
27 let c = *self.input.get(self.pos)?;
28 (c == e).then(|| {
29 self.pos += 1;
30 c
31 })
32 }
33
34 pub fn consume(&mut self) -> Option<Char> {
36 let ret = *self.input.get(self.pos)?;
37 self.pos += 1;
38 Some(ret)
39 }
40
41 pub fn peek(&self) -> Option<Char> {
43 self.input.get(self.pos).copied()
44 }
45}
46
47type Procedure<'a, S, Char, Output> = Box<dyn 'a + Fn(&S, &mut Input<Char>) -> Option<Output>>;
48type FirstChecker<'a, Char> = Box<dyn 'a + Fn(Char) -> bool>;
49
50type EmptyRule<'a, S, Char, Output> = Procedure<'a, S, Char, Output>;
51type NonEmptyRule<'a, S, Char, Output> = (FirstChecker<'a, Char>, Procedure<'a, S, Char, Output>);
52
53struct Rules<'a, S, Char, Output> {
54 empty_rule: Option<EmptyRule<'a, S, Char, Output>>,
55 non_empty_rules: Vec<NonEmptyRule<'a, S, Char, Output>>,
56}
57
58impl<S, Char, Output> Default for Rules<'_, S, Char, Output> {
59 fn default() -> Self {
60 Self {
61 empty_rule: None,
62 non_empty_rules: vec![],
63 }
64 }
65}
66
67#[allow(clippy::type_complexity)]
68#[derive(Default)]
69pub struct LL1Parser<'a, State, Char, Output> {
71 rules: HashMap<State, Rules<'a, Self, Char, Output>>,
72}
73
74impl<'a, State, Char, Output> LL1Parser<'a, State, Char, Output>
75where
76 State: Copy + Eq + Hash,
77 Char: Copy + Eq,
78{
79 pub fn new() -> Self {
81 Self {
82 rules: HashMap::new(),
83 }
84 }
85
86 pub fn add_rule<F1, FP>(&mut self, state: State, check_first: F1, proc: FP)
92 where
93 F1: 'a + Fn(Char) -> bool,
94 FP: 'a + Fn(&Self, &mut Input<Char>) -> Option<Output>,
95 {
96 self.rules
97 .entry(state)
98 .or_default()
99 .non_empty_rules
100 .push((Box::new(check_first), Box::new(proc)));
101 }
102
103 pub fn add_rule_empty<FP>(&mut self, state: State, proc: FP)
105 where
106 FP: 'a + Fn(&Self, &mut Input<Char>) -> Option<Output>,
107 {
108 self.rules
109 .entry(state)
110 .or_default()
111 .empty_rule
112 .replace(Box::new(proc));
113 }
114
115 pub fn parse(&self, state: State, input: &mut Input<Char>) -> Option<Output> {
117 for (check_first, proc) in self.rules.get(&state)?.non_empty_rules.iter() {
118 if let Some(c) = input.peek() {
119 if check_first(c) {
120 return proc(self, input);
121 }
122 }
123 }
124
125 if let Some(proc) = self.rules.get(&state)?.empty_rule.as_ref() {
126 return proc(self, input);
127 }
128
129 None
130 }
131}
132
133#[cfg(test)]
134mod test_yc_265;