intuicio_parser/
dynamic.rs

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