intuicio_parser/
dynamic.rs

1use crate::ParserHandle;
2use intuicio_core::prelude::*;
3use intuicio_data::prelude::*;
4use std::sync::{Arc, RwLock, RwLockWriteGuard};
5
6pub mod shorthand {
7    use super::*;
8    use crate::{
9        pratt::{PrattParserAssociativity, PrattParserRule},
10        shorthand::{inspect, map_err, omap, pratt},
11    };
12
13    pub fn dyn_inspect(parser: ParserHandle, function_name: impl ToString) -> ParserHandle {
14        let function_name = function_name.to_string();
15        dynamic_extension(move |extension| {
16            let function_name = function_name.clone();
17            inspect(parser.clone(), move |value| {
18                extension
19                    .call(&function_name)
20                    .unwrap()
21                    .arg(value.borrow().unwrap())
22                    .call_no_return();
23            })
24        })
25    }
26
27    pub fn dyn_map(parser: ParserHandle, function_name: impl ToString) -> ParserHandle {
28        let function_name = function_name.to_string();
29        dynamic_extension(move |extension| {
30            let function_name = function_name.clone();
31            omap(parser.clone(), move |value| {
32                extension
33                    .call(&function_name)
34                    .unwrap()
35                    .arg(value)
36                    .call_return()
37            })
38        })
39    }
40
41    pub fn dyn_map_err(parser: ParserHandle, function_name: impl ToString) -> ParserHandle {
42        let function_name = function_name.to_string();
43        dynamic_extension(move |extension| {
44            let function_name = function_name.clone();
45            map_err(parser.clone(), move |error| {
46                extension
47                    .call(&function_name)
48                    .unwrap()
49                    .arg_owned(error)
50                    .call_return()
51                    .consume()
52                    .ok()
53                    .unwrap()
54            })
55        })
56    }
57
58    #[derive(Debug, Clone)]
59    pub enum DynamicPrattParserRule {
60        Prefix {
61            operator_function_name: String,
62            transformer_function_name: String,
63        },
64        PrefixOp {
65            operator: String,
66            transformer_function_name: String,
67        },
68        Postfix {
69            operator_function_name: String,
70            transformer_function_name: String,
71        },
72        PostfixOp {
73            operator: String,
74            transformer_function_name: String,
75        },
76        Infix {
77            operator_function_name: String,
78            transformer_function_name: String,
79            associativity: PrattParserAssociativity,
80        },
81        InfixOp {
82            operator: String,
83            transformer_function_name: String,
84            associativity: PrattParserAssociativity,
85        },
86    }
87
88    pub fn dyn_pratt(
89        tokenizer_parser: ParserHandle,
90        rules: Vec<Vec<DynamicPrattParserRule>>,
91    ) -> ParserHandle {
92        dynamic_extension(move |extension| {
93            let rules = rules
94                .clone()
95                .into_iter()
96                .map(move |rules| {
97                    rules
98                        .into_iter()
99                        .map(|rule| match rule {
100                            DynamicPrattParserRule::Prefix {
101                                operator_function_name,
102                                transformer_function_name,
103                            } => {
104                                let extension_o = extension.clone();
105                                let extension_t = extension.clone();
106                                PrattParserRule::prefx_raw(
107                                    move |operator| {
108                                        extension_o
109                                            .call(&operator_function_name)
110                                            .unwrap()
111                                            .arg(operator.borrow().unwrap())
112                                            .call_return()
113                                            .consume()
114                                            .ok()
115                                            .unwrap()
116                                    },
117                                    move |value| {
118                                        extension_t
119                                            .call(&transformer_function_name)
120                                            .unwrap()
121                                            .arg(value)
122                                            .call_return()
123                                    },
124                                )
125                            }
126                            DynamicPrattParserRule::PrefixOp {
127                                operator,
128                                transformer_function_name,
129                            } => {
130                                let extension_t = extension.clone();
131                                PrattParserRule::prefx_raw(
132                                    move |token| {
133                                        token
134                                            .read::<String>()
135                                            .map(|op| *op == operator)
136                                            .unwrap_or_default()
137                                    },
138                                    move |value| {
139                                        extension_t
140                                            .call(&transformer_function_name)
141                                            .unwrap()
142                                            .arg(value)
143                                            .call_return()
144                                    },
145                                )
146                            }
147                            DynamicPrattParserRule::Postfix {
148                                operator_function_name,
149                                transformer_function_name,
150                            } => {
151                                let extension_o = extension.clone();
152                                let extension_t = extension.clone();
153                                PrattParserRule::postfix_raw(
154                                    move |operator| {
155                                        extension_o
156                                            .call(&operator_function_name)
157                                            .unwrap()
158                                            .arg(operator.borrow().unwrap())
159                                            .call_return()
160                                            .consume()
161                                            .ok()
162                                            .unwrap()
163                                    },
164                                    move |value| {
165                                        extension_t
166                                            .call(&transformer_function_name)
167                                            .unwrap()
168                                            .arg(value)
169                                            .call_return()
170                                    },
171                                )
172                            }
173                            DynamicPrattParserRule::PostfixOp {
174                                operator,
175                                transformer_function_name,
176                            } => {
177                                let extension_t = extension.clone();
178                                PrattParserRule::postfix_raw(
179                                    move |token| {
180                                        token
181                                            .read::<String>()
182                                            .map(|op| *op == operator)
183                                            .unwrap_or_default()
184                                    },
185                                    move |value| {
186                                        extension_t
187                                            .call(&transformer_function_name)
188                                            .unwrap()
189                                            .arg(value)
190                                            .call_return()
191                                    },
192                                )
193                            }
194                            DynamicPrattParserRule::Infix {
195                                operator_function_name,
196                                transformer_function_name,
197                                associativity,
198                            } => {
199                                let extension_o = extension.clone();
200                                let extension_t = extension.clone();
201                                PrattParserRule::infix_raw(
202                                    move |operator| {
203                                        extension_o
204                                            .call(&operator_function_name)
205                                            .unwrap()
206                                            .arg(operator.borrow().unwrap())
207                                            .call_return()
208                                            .consume()
209                                            .ok()
210                                            .unwrap()
211                                    },
212                                    move |lhs, rhs| {
213                                        extension_t
214                                            .call(&transformer_function_name)
215                                            .unwrap()
216                                            .arg(lhs)
217                                            .arg(rhs)
218                                            .call_return()
219                                    },
220                                    associativity,
221                                )
222                            }
223                            DynamicPrattParserRule::InfixOp {
224                                operator,
225                                transformer_function_name,
226                                associativity,
227                            } => {
228                                let extension_t = extension.clone();
229                                PrattParserRule::infix_raw(
230                                    move |token| {
231                                        token
232                                            .read::<String>()
233                                            .map(|op| *op == operator)
234                                            .unwrap_or_default()
235                                    },
236                                    move |lhs, rhs| {
237                                        extension_t
238                                            .call(&transformer_function_name)
239                                            .unwrap()
240                                            .arg(lhs)
241                                            .arg(rhs)
242                                            .call_return()
243                                    },
244                                    associativity,
245                                )
246                            }
247                        })
248                        .collect()
249                })
250                .collect();
251            pratt(tokenizer_parser.clone(), rules)
252        })
253    }
254}
255
256pub struct DynamicExtensionBuilder {
257    registry: Registry,
258}
259
260impl Default for DynamicExtensionBuilder {
261    fn default() -> Self {
262        Self {
263            registry: Registry::default()
264                .with_type(
265                    NativeStructBuilder::new_named_uninitialized::<DynamicManaged>(
266                        "DynamicManaged",
267                    )
268                    .build(),
269                )
270                .with_type(
271                    NativeStructBuilder::new_named_uninitialized::<DynamicManagedRef>(
272                        "DynamicManagedRef",
273                    )
274                    .build(),
275                )
276                .with_type(
277                    NativeStructBuilder::new_named_uninitialized::<DynamicManagedRefMut>(
278                        "DynamicManagedRefMut",
279                    )
280                    .build(),
281                )
282                .with_type(
283                    NativeStructBuilder::new_named_uninitialized::<DynamicManagedLazy>(
284                        "DynamicManagedLazy",
285                    )
286                    .build(),
287                )
288                .with_type(
289                    NativeStructBuilder::new_named_uninitialized::<DynamicManagedBox>(
290                        "DynamicManagedBox",
291                    )
292                    .build(),
293                ),
294        }
295    }
296}
297
298impl DynamicExtensionBuilder {
299    pub fn with(mut self, f: impl FnOnce(&Registry) -> Function) -> Self {
300        self.add(f);
301        self
302    }
303
304    pub fn add(&mut self, f: impl FnOnce(&Registry) -> Function) {
305        self.registry.add_function(f(&self.registry));
306    }
307
308    pub fn build(self) -> DynamicExtension {
309        DynamicExtension {
310            host: Arc::new(RwLock::new(Host::new(
311                Context::new(10240, 10240),
312                RegistryHandle::new(self.registry),
313            ))),
314        }
315    }
316}
317
318pub struct DynamicExtension {
319    host: Arc<RwLock<Host>>,
320}
321
322impl DynamicExtension {
323    pub fn call<'a>(&'a self, name: &str) -> Option<DynamicExtensionCall<'a>> {
324        let host = self.host.write().ok()?;
325        let handle = host.registry().find_function(FunctionQuery {
326            name: Some(name.into()),
327            ..Default::default()
328        })?;
329        Some(DynamicExtensionCall {
330            host,
331            handle,
332            args: vec![],
333            lifetimes: vec![],
334        })
335    }
336}
337
338pub enum Value {
339    Owned(DynamicManaged),
340    Ref(DynamicManagedRef),
341    RefMut(DynamicManagedRefMut),
342    Lazy(DynamicManagedLazy),
343    Box(DynamicManagedBox),
344}
345
346impl From<DynamicManaged> for Value {
347    fn from(value: DynamicManaged) -> Self {
348        Self::Owned(value)
349    }
350}
351
352impl From<DynamicManagedRef> for Value {
353    fn from(value: DynamicManagedRef) -> Self {
354        Self::Ref(value)
355    }
356}
357
358impl From<DynamicManagedRefMut> for Value {
359    fn from(value: DynamicManagedRefMut) -> Self {
360        Self::RefMut(value)
361    }
362}
363
364impl From<DynamicManagedLazy> for Value {
365    fn from(value: DynamicManagedLazy) -> Self {
366        Self::Lazy(value)
367    }
368}
369
370impl From<DynamicManagedBox> for Value {
371    fn from(value: DynamicManagedBox) -> Self {
372        Self::Box(value)
373    }
374}
375
376pub struct DynamicExtensionCall<'a> {
377    host: RwLockWriteGuard<'a, Host>,
378    handle: FunctionHandle,
379    args: Vec<Value>,
380    lifetimes: Vec<Lifetime>,
381}
382
383impl DynamicExtensionCall<'_> {
384    pub fn arg(mut self, value: impl Into<Value>) -> Self {
385        self.args.push(value.into());
386        self
387    }
388
389    pub fn arg_owned<T>(mut self, value: T) -> Self {
390        let value = DynamicManaged::new(value).ok().unwrap();
391        self.args.push(Value::Owned(value));
392        self
393    }
394
395    pub fn arg_ref<T>(mut self, value: &T) -> Self {
396        let lifetime = Lifetime::default();
397        let value = DynamicManagedRef::new(value, lifetime.borrow().unwrap());
398        self.args.push(Value::Ref(value));
399        self.lifetimes.push(lifetime);
400        self
401    }
402
403    pub fn arg_ref_mut<T>(mut self, value: &mut T) -> Self {
404        let lifetime = Lifetime::default();
405        let value = DynamicManagedRefMut::new(value, lifetime.borrow_mut().unwrap());
406        self.args.push(Value::RefMut(value));
407        self.lifetimes.push(lifetime);
408        self
409    }
410
411    pub fn arg_lazy<T>(mut self, value: &mut T) -> Self {
412        let lifetime = Lifetime::default();
413        let value = DynamicManagedLazy::new(value, lifetime.lazy());
414        self.args.push(Value::Lazy(value));
415        self.lifetimes.push(lifetime);
416        self
417    }
418
419    pub fn arg_box<T>(mut self, value: T) -> Self {
420        let value = DynamicManagedBox::new(value);
421        self.args.push(Value::Box(value));
422        self
423    }
424
425    pub fn call_return(mut self) -> DynamicManaged {
426        let (context, registry) = self.host.context_and_registry();
427        for arg in self.args.into_iter().rev() {
428            match arg {
429                Value::Owned(value) => context.stack().push(value),
430                Value::Ref(value) => context.stack().push(value),
431                Value::RefMut(value) => context.stack().push(value),
432                Value::Lazy(value) => context.stack().push(value),
433                Value::Box(value) => context.stack().push(value),
434            };
435        }
436        self.handle.invoke(context, registry);
437        context.stack().pop::<DynamicManaged>().unwrap()
438    }
439
440    pub fn call_no_return(mut self) {
441        let (context, registry) = self.host.context_and_registry();
442        for arg in self.args.into_iter().rev() {
443            match arg {
444                Value::Owned(value) => context.stack().push(value),
445                Value::Ref(value) => context.stack().push(value),
446                Value::RefMut(value) => context.stack().push(value),
447                Value::Lazy(value) => context.stack().push(value),
448                Value::Box(value) => context.stack().push(value),
449            };
450        }
451        self.handle.invoke(context, registry);
452    }
453}
454
455pub fn dynamic_extension(
456    f: impl Fn(Arc<DynamicExtension>) -> ParserHandle + Send + Sync + 'static,
457) -> ParserHandle {
458    crate::shorthand::ext::<DynamicExtension>(f)
459}
460
461#[cfg(test)]
462mod tests {
463    use super::{dynamic_extension, DynamicExtensionBuilder};
464    use crate::{
465        shorthand::{map, number_float},
466        ParserRegistry,
467    };
468    use intuicio_core::transformer::{DynamicManagedValueTransformer, ValueTransformer};
469    use intuicio_derive::intuicio_function;
470
471    #[intuicio_function(transformer = "DynamicManagedValueTransformer")]
472    fn foo(value: String) -> f32 {
473        value.parse().unwrap()
474    }
475
476    #[test]
477    fn test_dynamic_extension() {
478        let extension = DynamicExtensionBuilder::default()
479            .with(foo::define_function)
480            .build();
481        let registry = ParserRegistry::default().with_extension(extension);
482        let parser = dynamic_extension(|extension| {
483            map::<String, f32>(number_float(), move |v| {
484                extension
485                    .call("foo")
486                    .unwrap()
487                    .arg_owned(v)
488                    .call_return()
489                    .consume()
490                    .ok()
491                    .unwrap()
492            })
493        });
494        let (rest, result) = parser.parse(&registry, "42.0").unwrap();
495        assert_eq!(rest, "");
496        assert_eq!(result.consume::<f32>().ok().unwrap(), 42.0);
497    }
498}