1use std::rc::Rc;
4
5use xee_interpreter::context::{self, StaticContext};
6use xee_interpreter::error::SpannedResult as Result;
7use xee_interpreter::interpreter::Program;
8use xee_interpreter::sequence::{Item, Sequence};
9
10use crate::{Documents, Itemable};
11
12#[cfg(doc)]
14use crate::context::DynamicContextBuilder;
15#[cfg(doc)]
16use crate::Queries;
17
18pub trait Query<V> {
22 fn program(&self) -> &Program;
24
25 fn static_context(&self) -> &StaticContext {
27 self.program().static_context()
28 }
29
30 fn execute_with_context(
34 &self,
35 documents: &mut Documents,
36 context: &context::DynamicContext,
37 ) -> Result<V>;
38
39 fn dynamic_context_builder(&self, documents: &Documents) -> context::DynamicContextBuilder {
45 let mut context = self.program().dynamic_context_builder();
46 context.documents(documents.documents().clone());
47 context
48 }
49
50 fn map<T, F>(self, f: F) -> MapQuery<V, T, Self, F>
55 where
56 Self: Sized,
57 F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
58 {
59 MapQuery {
60 query: self,
61 f,
62 v: std::marker::PhantomData,
63 t: std::marker::PhantomData,
64 }
65 }
66
67 fn execute(&self, documents: &mut Documents, item: impl Itemable) -> Result<V> {
69 let context_item = item.to_item(documents)?;
70 self.execute_build_context(documents, move |builder| {
71 builder.context_item(context_item);
72 })
73 }
74
75 fn execute_build_context(
80 &self,
81 documents: &mut Documents,
82 build: impl FnOnce(&mut context::DynamicContextBuilder),
83 ) -> Result<V> {
84 let mut dynamic_context_builder = self.dynamic_context_builder(documents);
85 build(&mut dynamic_context_builder);
86 let context = dynamic_context_builder.build();
87 self.execute_with_context(documents, &context)
88 }
89}
90
91pub trait RecurseQuery<C, V> {
95 fn program(&self) -> &Program;
97
98 fn static_context(&self) -> &StaticContext {
100 self.program().static_context()
101 }
102
103 fn execute_with_context(
108 &self,
109 document: &mut Documents,
110 context: &context::DynamicContext,
111 recurse: &Recurse<V>,
112 ) -> Result<C>;
113
114 fn dynamic_context_builder(&self, document: &Documents) -> context::DynamicContextBuilder {
120 let mut context = self.program().dynamic_context_builder();
121 context.documents(document.documents.clone());
122 context
123 }
124
125 fn execute(&self, document: &mut Documents, item: &Item, recurse: &Recurse<V>) -> Result<C> {
130 self.execute_build_context(document, recurse, |builder| {
131 builder.context_item(item.clone());
132 })
133 }
134
135 fn execute_build_context(
140 &self,
141 document: &mut Documents,
142 recurse: &Recurse<V>,
143 build: impl FnOnce(&mut context::DynamicContextBuilder),
144 ) -> Result<C> {
145 let mut dynamic_context_builder = self.dynamic_context_builder(document);
146 build(&mut dynamic_context_builder);
147 let context = dynamic_context_builder.build();
148 self.execute_with_context(document, &context, recurse)
149 }
150}
151
152pub trait Convert<V>: Fn(&mut Documents, &Item) -> Result<V> {}
158impl<V, T> Convert<V> for T where T: Fn(&mut Documents, &Item) -> Result<V> {}
159
160type RecurseFn<'s, V> = &'s dyn Fn(&mut Documents, &Item, &Recurse<'s, V>) -> Result<V>;
168
169pub struct Recurse<'s, V> {
171 f: RecurseFn<'s, V>,
172}
173
174impl<'s, V> Recurse<'s, V> {
175 pub fn new(f: RecurseFn<'s, V>) -> Self {
177 Self { f }
178 }
179
180 pub fn execute(&self, document: &mut Documents, item: &Item) -> Result<V> {
182 (self.f)(document, item, self)
183 }
184}
185
186#[derive(Debug, Clone)]
197pub struct OneQuery<V, F>
198where
199 F: Convert<V>,
200{
201 pub(crate) program: Rc<Program>,
202 pub(crate) convert: F,
203 pub(crate) phantom: std::marker::PhantomData<V>,
204}
205
206impl<V, F> OneQuery<V, F>
207where
208 F: Convert<V>,
209{
210 pub fn execute_with_context(
212 &self,
213 document: &mut Documents,
214 context: &context::DynamicContext,
215 ) -> Result<V> {
216 let sequence = self.program.runnable(context).many(document.xot_mut())?;
217 let item = sequence.one()?;
218 (self.convert)(document, &item)
219 }
220}
221
222impl<V, F> Query<V> for OneQuery<V, F>
223where
224 F: Convert<V>,
225{
226 fn program(&self) -> &Program {
227 &self.program
228 }
229
230 fn execute_with_context(
231 &self,
232 document: &mut Documents,
233 context: &context::DynamicContext,
234 ) -> Result<V> {
235 OneQuery::execute_with_context(self, document, context)
236 }
237}
238
239#[derive(Debug, Clone)]
241pub struct OneRecurseQuery {
242 pub(crate) program: Rc<Program>,
243}
244
245impl OneRecurseQuery {
246 pub fn execute_with_context<V>(
251 &self,
252 document: &mut Documents,
253 context: &context::DynamicContext,
254 recurse: &Recurse<V>,
255 ) -> Result<V> {
256 let sequence = self.program.runnable(context).many(document.xot_mut())?;
257 let item = sequence.one()?;
258 recurse.execute(document, &item)
259 }
260}
261
262impl<V> RecurseQuery<V, V> for OneRecurseQuery {
263 fn program(&self) -> &Program {
264 &self.program
265 }
266
267 fn execute_with_context(
268 &self,
269 document: &mut Documents,
270 context: &context::DynamicContext,
271 recurse: &Recurse<V>,
272 ) -> Result<V> {
273 OneRecurseQuery::execute_with_context(self, document, context, recurse)
274 }
275}
276
277#[derive(Debug, Clone)]
289pub struct OptionQuery<V, F>
290where
291 F: Convert<V>,
292{
293 pub(crate) program: Rc<Program>,
294 pub(crate) convert: F,
295 pub(crate) phantom: std::marker::PhantomData<V>,
296}
297
298impl<V, F> OptionQuery<V, F>
299where
300 F: Convert<V>,
301{
302 pub fn execute_with_context(
305 &self,
306 document: &mut Documents,
307 context: &context::DynamicContext,
308 ) -> Result<Option<V>> {
309 let sequence = self.program.runnable(context).many(document.xot_mut())?;
310 let item = sequence.option()?;
311 item.map(|item| (self.convert)(document, &item)).transpose()
312 }
313}
314
315impl<V, F> Query<Option<V>> for OptionQuery<V, F>
316where
317 F: Convert<V>,
318{
319 fn program(&self) -> &Program {
320 &self.program
321 }
322
323 fn execute_with_context(
324 &self,
325 document: &mut Documents,
326 context: &context::DynamicContext,
327 ) -> Result<Option<V>> {
328 Self::execute_with_context(self, document, context)
329 }
330}
331
332#[derive(Debug, Clone)]
334pub struct OptionRecurseQuery {
335 pub(crate) program: Rc<Program>,
336}
337
338impl OptionRecurseQuery {
339 pub fn execute_with_context<V>(
341 &self,
342 document: &mut Documents,
343 context: &context::DynamicContext,
344 recurse: &Recurse<V>,
345 ) -> Result<Option<V>> {
346 let sequence = self.program.runnable(context).many(document.xot_mut())?;
347 let item = sequence.option()?;
348 item.map(|item| recurse.execute(document, &item))
349 .transpose()
350 }
351}
352
353impl<V> RecurseQuery<Option<V>, V> for OptionRecurseQuery {
354 fn program(&self) -> &Program {
355 &self.program
356 }
357
358 fn execute_with_context(
359 &self,
360 document: &mut Documents,
361 context: &context::DynamicContext,
362 recurse: &Recurse<V>,
363 ) -> Result<Option<V>> {
364 OptionRecurseQuery::execute_with_context(self, document, context, recurse)
365 }
366}
367
368#[derive(Debug, Clone)]
379pub struct ManyQuery<V, F>
380where
381 F: Convert<V>,
382{
383 pub(crate) program: Rc<Program>,
384 pub(crate) convert: F,
385 pub(crate) phantom: std::marker::PhantomData<V>,
386}
387
388impl<V, F> ManyQuery<V, F>
389where
390 F: Convert<V>,
391{
392 fn execute_with_context(
393 &self,
394 document: &mut Documents,
395 context: &context::DynamicContext,
396 ) -> Result<Vec<V>> {
397 let sequence = self.program.runnable(context).many(document.xot_mut())?;
398 let items = sequence
399 .iter()
400 .map(|item| (self.convert)(document, &item))
401 .collect::<Result<Vec<V>>>()?;
402 Ok(items)
403 }
404}
405
406impl<V, F> Query<Vec<V>> for ManyQuery<V, F>
407where
408 F: Convert<V>,
409{
410 fn program(&self) -> &Program {
411 &self.program
412 }
413
414 fn execute_with_context(
415 &self,
416 document: &mut Documents,
417 context: &context::DynamicContext,
418 ) -> Result<Vec<V>> {
419 Self::execute_with_context(self, document, context)
420 }
421}
422
423#[derive(Debug, Clone)]
425pub struct ManyRecurseQuery {
426 pub(crate) program: Rc<Program>,
427}
428
429impl ManyRecurseQuery {
430 pub fn execute_with_context<V>(
435 &self,
436 document: &mut Documents,
437 context: &context::DynamicContext,
438 recurse: &Recurse<V>,
439 ) -> Result<Vec<V>> {
440 let sequence = self.program.runnable(context).many(document.xot_mut())?;
441 let items = sequence
442 .iter()
443 .map(|item| recurse.execute(document, &item))
444 .collect::<Result<Vec<V>>>()?;
445 Ok(items)
446 }
447}
448
449impl<V> RecurseQuery<Vec<V>, V> for ManyRecurseQuery {
450 fn program(&self) -> &Program {
451 &self.program
452 }
453
454 fn execute_with_context(
455 &self,
456 document: &mut Documents,
457 context: &context::DynamicContext,
458 recurse: &Recurse<V>,
459 ) -> Result<Vec<V>> {
460 ManyRecurseQuery::execute_with_context(self, document, context, recurse)
461 }
462}
463
464#[derive(Debug, Clone)]
474pub struct SequenceQuery {
475 pub(crate) program: Rc<Program>,
476}
477
478impl SequenceQuery {
479 pub fn execute_with_context(
481 &self,
482 document: &mut Documents,
483 context: &context::DynamicContext,
484 ) -> Result<Sequence> {
485 self.program.runnable(context).many(document.xot_mut())
486 }
487}
488
489impl Query<Sequence> for SequenceQuery {
490 fn program(&self) -> &Program {
491 &self.program
492 }
493
494 fn execute_with_context(
495 &self,
496 document: &mut Documents,
497 context: &context::DynamicContext,
498 ) -> Result<Sequence> {
499 Self::execute_with_context(self, document, context)
500 }
501}
502
503#[derive(Debug, Clone)]
505pub struct MapQuery<V, T, Q: Query<V> + Sized, F>
506where
507 F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
508{
509 query: Q,
510 f: F,
511 v: std::marker::PhantomData<V>,
512 t: std::marker::PhantomData<T>,
513}
514
515impl<V, T, Q, F> MapQuery<V, T, Q, F>
516where
517 Q: Query<V> + Sized,
518 F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
519{
520 pub fn execute(&self, document: &mut Documents, item: &Item) -> Result<T> {
522 let mut dynamic_context_builder = self.query.program().dynamic_context_builder();
523 dynamic_context_builder.context_item(item.clone());
524 let context = dynamic_context_builder.build();
525 self.execute_with_context(document, &context)
526 }
527
528 pub fn execute_with_context(
530 &self,
531 document: &mut Documents,
532 context: &context::DynamicContext,
533 ) -> Result<T> {
534 let v = self.query.execute_with_context(document, context)?;
535 (self.f)(v, document, context)
537 }
538}
539
540impl<V, T, Q: Query<V> + Sized, F> Query<T> for MapQuery<V, T, Q, F>
541where
542 F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
543{
544 fn program(&self) -> &Program {
545 self.query.program()
546 }
547
548 fn execute_with_context(
549 &self,
550 document: &mut Documents,
551 context: &context::DynamicContext,
552 ) -> Result<T> {
553 let v = self.query.execute_with_context(document, context)?;
554 (self.f)(v, document, context)
555 }
556}