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(®istry, "42.0").unwrap();
505 assert_eq!(rest, "");
506 assert_eq!(result.consume::<f32>().ok().unwrap(), 42.0);
507 }
508}