xee_interpreter/interpreter/
runnable.rs1use std::rc::Rc;
2
3use ibig::ibig;
4use iri_string::types::IriReferenceStr;
5use xot::Xot;
6
7use crate::context::DocumentsRef;
8use crate::context::DynamicContext;
9use crate::context::StaticContext;
10use crate::error::SpannedError;
11use crate::function::Function;
12use crate::interpreter::interpret::ContextInfo;
13use crate::sequence;
14use crate::stack;
15use crate::{error, string};
16
17use super::program::FunctionInfo;
18use super::Interpreter;
19use super::Program;
20
21#[derive(Debug)]
22pub struct Runnable<'a> {
23 program: &'a Program,
24 pub(crate) dynamic_context: &'a DynamicContext<'a>,
29}
30
31impl<'a> Runnable<'a> {
32 pub(crate) fn new(program: &'a Program, dynamic_context: &'a DynamicContext) -> Self {
33 Self {
34 program,
35 dynamic_context,
36 }
37 }
38
39 fn run_value(&self, xot: &'a mut Xot) -> error::SpannedResult<stack::Value> {
40 let arguments = self.dynamic_context.arguments().unwrap();
41 let mut interpreter = Interpreter::new(self, xot);
42
43 let context_info = if let Some(context_item) = self.dynamic_context.context_item() {
44 ContextInfo {
45 item: context_item.clone().into(),
46 position: ibig!(1).into(),
47 size: ibig!(1).into(),
48 }
49 } else {
50 ContextInfo {
51 item: stack::Value::Absent,
52 position: stack::Value::Absent,
53 size: stack::Value::Absent,
54 }
55 };
56
57 interpreter.start(context_info, arguments);
58 interpreter.run(0)?;
59
60 let state = interpreter.state();
61 assert_eq!(
66 state.stack().len(),
67 1,
68 "stack must only have 1 value but found {:?}",
69 state.stack()
70 );
71 let value = state.stack().last().unwrap().clone();
72 match value {
73 stack::Value::Absent => Err(SpannedError {
74 error: error::Error::XPDY0002,
75 span: Some(self.program.span().into()),
76 }),
77 _ => Ok(value),
78 }
79 }
80
81 pub fn many(&self, xot: &'a mut Xot) -> error::SpannedResult<sequence::Sequence> {
83 Ok(self.run_value(xot)?.try_into()?)
84 }
85
86 pub fn one(&self, xot: &'a mut Xot) -> error::SpannedResult<sequence::Item> {
88 let sequence = self.many(xot)?;
89 sequence.one().map_err(|error| SpannedError {
90 error,
91 span: Some(self.program.span().into()),
92 })
93 }
94
95 pub fn option(&self, xot: &'a mut Xot) -> error::SpannedResult<Option<sequence::Item>> {
97 let sequence = self.many(xot)?;
98 let items = sequence.iter();
99 sequence::option(items).map_err(|error| SpannedError {
100 error,
101 span: Some(self.program.span().into()),
102 })
103 }
104
105 pub(crate) fn program(&self) -> &'a Program {
106 self.program
107 }
108
109 pub fn dynamic_context(&self) -> &'a DynamicContext {
110 self.dynamic_context
111 }
112
113 pub fn documents(&self) -> DocumentsRef {
114 self.dynamic_context.documents()
115 }
116
117 pub fn static_context(&self) -> &StaticContext {
118 self.program.static_context()
119 }
120
121 pub fn default_collation_uri(&self) -> &IriReferenceStr {
122 self.dynamic_context
123 .static_context()
124 .default_collation_uri()
125 }
126
127 pub fn default_collation(&self) -> error::Result<Rc<string::Collation>> {
128 self.dynamic_context.static_context().default_collation()
129 }
130
131 pub fn implicit_timezone(&self) -> chrono::FixedOffset {
132 self.dynamic_context.implicit_timezone()
133 }
134
135 pub fn function_info<'b>(&self, function: &'b Function) -> FunctionInfo<'a, 'b> {
136 self.program.function_info(function)
137 }
138}