use std::rc::Rc;
use ibig::ibig;
use iri_string::types::IriReferenceStr;
use xot::Xot;
use crate::context::DocumentsRef;
use crate::context::DynamicContext;
use crate::context::StaticContext;
use crate::error::SpannedError;
use crate::function::Function;
use crate::interpreter::interpret::ContextInfo;
use crate::sequence;
use crate::stack;
use crate::{error, string};
use super::program::FunctionInfo;
use super::Interpreter;
use super::Program;
#[derive(Debug)]
pub struct Runnable<'a> {
program: &'a Program,
pub(crate) dynamic_context: &'a DynamicContext<'a>,
}
impl<'a> Runnable<'a> {
pub(crate) fn new(program: &'a Program, dynamic_context: &'a DynamicContext) -> Self {
Self {
program,
dynamic_context,
}
}
fn run_value(&self, xot: &'a mut Xot) -> error::SpannedResult<stack::Value> {
let arguments = self.dynamic_context.arguments().unwrap();
let mut interpreter = Interpreter::new(self, xot);
let context_info = if let Some(context_item) = self.dynamic_context.context_item() {
ContextInfo {
item: context_item.clone().into(),
position: ibig!(1).into(),
size: ibig!(1).into(),
}
} else {
ContextInfo {
item: stack::Value::Absent,
position: stack::Value::Absent,
size: stack::Value::Absent,
}
};
interpreter.start(context_info, arguments);
interpreter.run(0)?;
let state = interpreter.state();
assert_eq!(
state.stack().len(),
1,
"stack must only have 1 value but found {:?}",
state.stack()
);
let value = state.stack().last().unwrap().clone();
match value {
stack::Value::Absent => Err(SpannedError {
error: error::Error::XPDY0002,
span: Some(self.program.span().into()),
}),
_ => Ok(value),
}
}
pub fn many(&self, xot: &'a mut Xot) -> error::SpannedResult<sequence::Sequence> {
Ok(self.run_value(xot)?.try_into()?)
}
pub fn one(&self, xot: &'a mut Xot) -> error::SpannedResult<sequence::Item> {
let sequence = self.many(xot)?;
sequence.one().map_err(|error| SpannedError {
error,
span: Some(self.program.span().into()),
})
}
pub fn option(&self, xot: &'a mut Xot) -> error::SpannedResult<Option<sequence::Item>> {
let sequence = self.many(xot)?;
let items = sequence.iter();
sequence::option(items).map_err(|error| SpannedError {
error,
span: Some(self.program.span().into()),
})
}
pub(crate) fn program(&self) -> &'a Program {
self.program
}
pub fn dynamic_context(&self) -> &'a DynamicContext {
self.dynamic_context
}
pub fn documents(&self) -> DocumentsRef {
self.dynamic_context.documents()
}
pub fn static_context(&self) -> &StaticContext {
self.program.static_context()
}
pub fn default_collation_uri(&self) -> &IriReferenceStr {
self.dynamic_context
.static_context()
.default_collation_uri()
}
pub fn default_collation(&self) -> error::Result<Rc<string::Collation>> {
self.dynamic_context.static_context().default_collation()
}
pub fn implicit_timezone(&self) -> chrono::FixedOffset {
self.dynamic_context.implicit_timezone()
}
pub fn function_info<'b>(&self, function: &'b Function) -> FunctionInfo<'a, 'b> {
self.program.function_info(function)
}
}