use std::rc::Rc;
use xee_interpreter::context::{self, StaticContext};
use xee_interpreter::error::SpannedResult as Result;
use xee_interpreter::interpreter::Program;
use xee_interpreter::sequence::{Item, Sequence};
use crate::{Documents, Itemable};
#[cfg(doc)]
use crate::context::DynamicContextBuilder;
#[cfg(doc)]
use crate::Queries;
pub trait Query<V> {
fn program(&self) -> &Program;
fn static_context(&self) -> &StaticContext {
self.program().static_context()
}
fn execute_with_context(
&self,
documents: &mut Documents,
context: &context::DynamicContext,
) -> Result<V>;
fn dynamic_context_builder(&self, documents: &Documents) -> context::DynamicContextBuilder {
let mut context = self.program().dynamic_context_builder();
context.documents(documents.documents().clone());
context
}
fn map<T, F>(self, f: F) -> MapQuery<V, T, Self, F>
where
Self: Sized,
F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
{
MapQuery {
query: self,
f,
v: std::marker::PhantomData,
t: std::marker::PhantomData,
}
}
fn execute(&self, documents: &mut Documents, item: impl Itemable) -> Result<V> {
let context_item = item.to_item(documents)?;
self.execute_build_context(documents, move |builder| {
builder.context_item(context_item);
})
}
fn execute_build_context(
&self,
documents: &mut Documents,
build: impl FnOnce(&mut context::DynamicContextBuilder),
) -> Result<V> {
let mut dynamic_context_builder = self.dynamic_context_builder(documents);
build(&mut dynamic_context_builder);
let context = dynamic_context_builder.build();
self.execute_with_context(documents, &context)
}
}
pub trait RecurseQuery<C, V> {
fn program(&self) -> &Program;
fn static_context(&self) -> &StaticContext {
self.program().static_context()
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
recurse: &Recurse<V>,
) -> Result<C>;
fn dynamic_context_builder(&self, document: &Documents) -> context::DynamicContextBuilder {
let mut context = self.program().dynamic_context_builder();
context.documents(document.documents.clone());
context
}
fn execute(&self, document: &mut Documents, item: &Item, recurse: &Recurse<V>) -> Result<C> {
self.execute_build_context(document, recurse, |builder| {
builder.context_item(item.clone());
})
}
fn execute_build_context(
&self,
document: &mut Documents,
recurse: &Recurse<V>,
build: impl FnOnce(&mut context::DynamicContextBuilder),
) -> Result<C> {
let mut dynamic_context_builder = self.dynamic_context_builder(document);
build(&mut dynamic_context_builder);
let context = dynamic_context_builder.build();
self.execute_with_context(document, &context, recurse)
}
}
pub trait Convert<V>: Fn(&mut Documents, &Item) -> Result<V> {}
impl<V, T> Convert<V> for T where T: Fn(&mut Documents, &Item) -> Result<V> {}
type RecurseFn<'s, V> = &'s dyn Fn(&mut Documents, &Item, &Recurse<'s, V>) -> Result<V>;
pub struct Recurse<'s, V> {
f: RecurseFn<'s, V>,
}
impl<'s, V> Recurse<'s, V> {
pub fn new(f: RecurseFn<'s, V>) -> Self {
Self { f }
}
pub fn execute(&self, document: &mut Documents, item: &Item) -> Result<V> {
(self.f)(document, item, self)
}
}
#[derive(Debug, Clone)]
pub struct OneQuery<V, F>
where
F: Convert<V>,
{
pub(crate) program: Rc<Program>,
pub(crate) convert: F,
pub(crate) phantom: std::marker::PhantomData<V>,
}
impl<V, F> OneQuery<V, F>
where
F: Convert<V>,
{
pub fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<V> {
let sequence = self.program.runnable(context).many(document.xot_mut())?;
let item = sequence.one()?;
(self.convert)(document, &item)
}
}
impl<V, F> Query<V> for OneQuery<V, F>
where
F: Convert<V>,
{
fn program(&self) -> &Program {
&self.program
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<V> {
OneQuery::execute_with_context(self, document, context)
}
}
#[derive(Debug, Clone)]
pub struct OneRecurseQuery {
pub(crate) program: Rc<Program>,
}
impl OneRecurseQuery {
pub fn execute_with_context<V>(
&self,
document: &mut Documents,
context: &context::DynamicContext,
recurse: &Recurse<V>,
) -> Result<V> {
let sequence = self.program.runnable(context).many(document.xot_mut())?;
let item = sequence.one()?;
recurse.execute(document, &item)
}
}
impl<V> RecurseQuery<V, V> for OneRecurseQuery {
fn program(&self) -> &Program {
&self.program
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
recurse: &Recurse<V>,
) -> Result<V> {
OneRecurseQuery::execute_with_context(self, document, context, recurse)
}
}
#[derive(Debug, Clone)]
pub struct OptionQuery<V, F>
where
F: Convert<V>,
{
pub(crate) program: Rc<Program>,
pub(crate) convert: F,
pub(crate) phantom: std::marker::PhantomData<V>,
}
impl<V, F> OptionQuery<V, F>
where
F: Convert<V>,
{
pub fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<Option<V>> {
let sequence = self.program.runnable(context).many(document.xot_mut())?;
let item = sequence.option()?;
item.map(|item| (self.convert)(document, &item)).transpose()
}
}
impl<V, F> Query<Option<V>> for OptionQuery<V, F>
where
F: Convert<V>,
{
fn program(&self) -> &Program {
&self.program
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<Option<V>> {
Self::execute_with_context(self, document, context)
}
}
#[derive(Debug, Clone)]
pub struct OptionRecurseQuery {
pub(crate) program: Rc<Program>,
}
impl OptionRecurseQuery {
pub fn execute_with_context<V>(
&self,
document: &mut Documents,
context: &context::DynamicContext,
recurse: &Recurse<V>,
) -> Result<Option<V>> {
let sequence = self.program.runnable(context).many(document.xot_mut())?;
let item = sequence.option()?;
item.map(|item| recurse.execute(document, &item))
.transpose()
}
}
impl<V> RecurseQuery<Option<V>, V> for OptionRecurseQuery {
fn program(&self) -> &Program {
&self.program
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
recurse: &Recurse<V>,
) -> Result<Option<V>> {
OptionRecurseQuery::execute_with_context(self, document, context, recurse)
}
}
#[derive(Debug, Clone)]
pub struct ManyQuery<V, F>
where
F: Convert<V>,
{
pub(crate) program: Rc<Program>,
pub(crate) convert: F,
pub(crate) phantom: std::marker::PhantomData<V>,
}
impl<V, F> ManyQuery<V, F>
where
F: Convert<V>,
{
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<Vec<V>> {
let sequence = self.program.runnable(context).many(document.xot_mut())?;
let items = sequence
.iter()
.map(|item| (self.convert)(document, &item))
.collect::<Result<Vec<V>>>()?;
Ok(items)
}
}
impl<V, F> Query<Vec<V>> for ManyQuery<V, F>
where
F: Convert<V>,
{
fn program(&self) -> &Program {
&self.program
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<Vec<V>> {
Self::execute_with_context(self, document, context)
}
}
#[derive(Debug, Clone)]
pub struct ManyRecurseQuery {
pub(crate) program: Rc<Program>,
}
impl ManyRecurseQuery {
pub fn execute_with_context<V>(
&self,
document: &mut Documents,
context: &context::DynamicContext,
recurse: &Recurse<V>,
) -> Result<Vec<V>> {
let sequence = self.program.runnable(context).many(document.xot_mut())?;
let items = sequence
.iter()
.map(|item| recurse.execute(document, &item))
.collect::<Result<Vec<V>>>()?;
Ok(items)
}
}
impl<V> RecurseQuery<Vec<V>, V> for ManyRecurseQuery {
fn program(&self) -> &Program {
&self.program
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
recurse: &Recurse<V>,
) -> Result<Vec<V>> {
ManyRecurseQuery::execute_with_context(self, document, context, recurse)
}
}
#[derive(Debug, Clone)]
pub struct SequenceQuery {
pub(crate) program: Rc<Program>,
}
impl SequenceQuery {
pub fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<Sequence> {
self.program.runnable(context).many(document.xot_mut())
}
}
impl Query<Sequence> for SequenceQuery {
fn program(&self) -> &Program {
&self.program
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<Sequence> {
Self::execute_with_context(self, document, context)
}
}
#[derive(Debug, Clone)]
pub struct MapQuery<V, T, Q: Query<V> + Sized, F>
where
F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
{
query: Q,
f: F,
v: std::marker::PhantomData<V>,
t: std::marker::PhantomData<T>,
}
impl<V, T, Q, F> MapQuery<V, T, Q, F>
where
Q: Query<V> + Sized,
F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
{
pub fn execute(&self, document: &mut Documents, item: &Item) -> Result<T> {
let mut dynamic_context_builder = self.query.program().dynamic_context_builder();
dynamic_context_builder.context_item(item.clone());
let context = dynamic_context_builder.build();
self.execute_with_context(document, &context)
}
pub fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<T> {
let v = self.query.execute_with_context(document, context)?;
(self.f)(v, document, context)
}
}
impl<V, T, Q: Query<V> + Sized, F> Query<T> for MapQuery<V, T, Q, F>
where
F: Fn(V, &mut Documents, &context::DynamicContext) -> Result<T> + Clone,
{
fn program(&self) -> &Program {
self.query.program()
}
fn execute_with_context(
&self,
document: &mut Documents,
context: &context::DynamicContext,
) -> Result<T> {
let v = self.query.execute_with_context(document, context)?;
(self.f)(v, document, context)
}
}