intuicio_parser/
lib.rs

1pub mod alternation;
2pub mod dynamic;
3pub mod extendable;
4pub mod extension;
5pub mod generator;
6pub mod inject;
7pub mod inspect;
8pub mod list;
9pub mod literal;
10pub mod map;
11pub mod not;
12pub mod one_or_more;
13pub mod open_close;
14pub mod optional;
15pub mod pratt;
16pub mod predict;
17pub mod regex;
18pub mod repeat;
19pub mod sequence;
20pub mod slot;
21pub mod template;
22pub mod zero_or_more;
23
24pub mod shorthand {
25    use super::*;
26
27    pub use crate::{
28        alternation::shorthand::*, dynamic::shorthand::*, extendable::shorthand::*,
29        extension::shorthand::*, inject::shorthand::*, inspect::shorthand::*, list::shorthand::*,
30        literal::shorthand::*, map::shorthand::*, not::shorthand::*, one_or_more::shorthand::*,
31        open_close::shorthand::*, optional::shorthand::*, pratt::shorthand::*,
32        predict::shorthand::*, regex::shorthand::*, repeat::shorthand::*, sequence::shorthand::*,
33        slot::shorthand::*, template::shorthand::*, zero_or_more::shorthand::*,
34    };
35
36    pub fn eos() -> ParserHandle {
37        EndOfSourceParser.into_handle()
38    }
39
40    pub fn source(parser: ParserHandle) -> ParserHandle {
41        SourceParser::new(parser).into_handle()
42    }
43
44    pub fn debug(id: impl ToString, parser: ParserHandle) -> ParserHandle {
45        DebugParser::new(id, parser).into_handle()
46    }
47
48    pub fn ignore() -> ParserHandle {
49        ().into_handle()
50    }
51}
52
53use intuicio_data::managed::DynamicManaged;
54use std::{
55    any::{Any, TypeId},
56    collections::HashMap,
57    error::Error,
58    sync::{Arc, RwLock},
59};
60
61pub type ParserOutput = DynamicManaged;
62pub type ParserHandle = Arc<dyn Parser>;
63pub type ParseResult<'a> = Result<(&'a str, ParserOutput), Box<dyn Error>>;
64
65pub struct ParserNoValue;
66
67pub trait Parser: Send + Sync {
68    fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a>;
69
70    #[allow(unused_variables)]
71    fn extend(&self, parser: ParserHandle) {}
72}
73
74pub trait ParserExt: Sized {
75    fn into_handle(self) -> ParserHandle;
76}
77
78impl<T: Parser + 'static> ParserExt for T {
79    fn into_handle(self) -> ParserHandle {
80        Arc::new(self)
81    }
82}
83
84impl Parser for () {
85    fn parse<'a>(&self, _: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
86        Ok((input, ParserOutput::new(ParserNoValue).ok().unwrap()))
87    }
88}
89
90pub struct EndOfSourceParser;
91
92impl Parser for EndOfSourceParser {
93    fn parse<'a>(&self, _: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
94        if input.is_empty() {
95            Ok((input, ParserOutput::new(ParserNoValue).ok().unwrap()))
96        } else {
97            Err("Expected end of source".into())
98        }
99    }
100}
101
102pub struct SourceParser {
103    parser: ParserHandle,
104}
105
106impl SourceParser {
107    pub fn new(parser: ParserHandle) -> Self {
108        Self { parser }
109    }
110}
111
112impl Parser for SourceParser {
113    fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
114        let before = input.len();
115        let (new_input, _) = self.parser.parse(registry, input)?;
116        let after = new_input.len();
117        let size = before - after;
118        Ok((
119            new_input,
120            ParserOutput::new(input[0..size].to_string()).ok().unwrap(),
121        ))
122    }
123}
124
125pub struct DebugParser {
126    id: String,
127    parser: ParserHandle,
128}
129
130impl DebugParser {
131    pub fn new(id: impl ToString, parser: ParserHandle) -> Self {
132        Self {
133            id: id.to_string(),
134            parser,
135        }
136    }
137}
138
139impl Parser for DebugParser {
140    fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
141        static mut IDENT: usize = 0;
142        unsafe {
143            IDENT += 1;
144        }
145        let ident = " ".repeat(unsafe { IDENT });
146        println!("{}< DEBUG `{}` | Before: {:?}", ident, self.id, input);
147        match self.parser.parse(registry, input) {
148            Ok((input, result)) => {
149                println!("{}> DEBUG `{}` | OK After: {:?}", ident, self.id, input);
150                unsafe {
151                    IDENT -= 1;
152                }
153                Ok((input, result))
154            }
155            Err(error) => {
156                println!(
157                    "{}> DEBUG `{}` | ERR After: {:?} | ERROR: {:?}",
158                    ident, self.id, input, error
159                );
160                unsafe {
161                    IDENT -= 1;
162                }
163                Err(error)
164            }
165        }
166    }
167}
168
169#[derive(Default)]
170pub struct ParserRegistry {
171    parsers: RwLock<HashMap<String, ParserHandle>>,
172    extensions: RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
173}
174
175impl ParserRegistry {
176    pub fn with_parser(self, id: impl ToString, parser: ParserHandle) -> Self {
177        self.add_parser(id, parser);
178        self
179    }
180
181    pub fn with_extension<T: Send + Sync + 'static>(self, data: T) -> Self {
182        self.add_extension::<T>(data);
183        self
184    }
185
186    pub fn add_parser(&self, id: impl ToString, parser: ParserHandle) {
187        if let Ok(mut parsers) = self.parsers.try_write() {
188            parsers.insert(id.to_string(), parser);
189        }
190    }
191
192    pub fn remove_parser(&self, id: impl AsRef<str>) -> Option<ParserHandle> {
193        if let Ok(mut parsers) = self.parsers.try_write() {
194            parsers.remove(id.as_ref())
195        } else {
196            None
197        }
198    }
199
200    pub fn get_parser(&self, id: impl AsRef<str>) -> Option<ParserHandle> {
201        self.parsers.try_read().ok()?.get(id.as_ref()).cloned()
202    }
203
204    pub fn parse<'a>(&self, id: impl AsRef<str>, input: &'a str) -> ParseResult<'a> {
205        if let Some(parser) = self.get_parser(id.as_ref()) {
206            parser.parse(self, input)
207        } else {
208            Err(format!("Parser `{}` not found in registry", id.as_ref()).into())
209        }
210    }
211
212    pub fn extend(&self, id: impl AsRef<str>, parser: ParserHandle) -> Result<(), Box<dyn Error>> {
213        if let Some(extendable) = self.get_parser(id.as_ref()) {
214            extendable.extend(parser);
215            Ok(())
216        } else {
217            Err(format!("Parser '{}' not found in registry", id.as_ref()).into())
218        }
219    }
220
221    pub fn add_extension<T: Send + Sync + 'static>(&self, data: T) -> bool {
222        if let Ok(mut extensions) = self.extensions.try_write() {
223            extensions.insert(TypeId::of::<T>(), Arc::new(data));
224            true
225        } else {
226            false
227        }
228    }
229
230    pub fn remove_extension<T: 'static>(&self) -> bool {
231        if let Ok(mut extensions) = self.extensions.try_write() {
232            extensions.remove(&TypeId::of::<T>());
233            true
234        } else {
235            false
236        }
237    }
238
239    pub fn extension<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
240        self.extensions
241            .try_read()
242            .ok()?
243            .get(&TypeId::of::<T>())?
244            .clone()
245            .downcast::<T>()
246            .ok()
247    }
248}
249
250#[cfg(test)]
251mod tests {
252    use crate::{
253        EndOfSourceParser, ParserRegistry, SourceParser,
254        shorthand::{eos, ignore, lit, number_int, seq, source},
255    };
256
257    fn is_async<T: Send + Sync>() {}
258
259    #[test]
260    fn test_end_of_source() {
261        is_async::<EndOfSourceParser>();
262
263        let registry = ParserRegistry::default();
264        let sentence = seq([lit("foo"), eos()]);
265        let (rest, _) = sentence.parse(&registry, "foo").unwrap();
266        assert_eq!(rest, "");
267        let sentence = eos();
268        assert!(sentence.parse(&registry, "foo").is_err());
269    }
270
271    #[test]
272    fn test_source() {
273        is_async::<SourceParser>();
274
275        let registry = ParserRegistry::default();
276        let sentence = source(number_int());
277        let (rest, result) = sentence.parse(&registry, "42 bar").unwrap();
278        assert_eq!(rest, " bar");
279        assert_eq!(result.read::<String>().unwrap().as_str(), "42");
280    }
281
282    #[test]
283    fn test_ignore() {
284        is_async::<()>();
285
286        let registry = ParserRegistry::default();
287        let sentence = ignore();
288        let (rest, _) = sentence.parse(&registry, "foo").unwrap();
289        assert_eq!(rest, "foo");
290    }
291}