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