xee_interpreter/interpreter/
state.rs1use std::cell::RefCell;
2use std::rc::Rc;
3
4use ahash::HashMap;
5use ahash::HashMapExt;
6use arrayvec::ArrayVec;
7use xot::Xot;
8
9use crate::error;
10use crate::function;
11use crate::sequence;
12use crate::stack;
13
14const FRAMES_MAX: usize = 64;
15
16#[derive(Debug, Clone)]
17pub(crate) struct Frame {
18 function: function::InlineFunctionId,
19 base: usize,
20 pub(crate) ip: usize,
21}
22
23impl Frame {
24 pub(crate) fn function(&self) -> function::InlineFunctionId {
25 self.function
26 }
27 pub(crate) fn base(&self) -> usize {
28 self.base
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33struct RegexKey {
34 pattern: String,
35 flags: String,
36}
37
38#[derive(Debug)]
39pub struct State<'a> {
40 stack: Vec<stack::Value>,
41 build_stack: Vec<BuildStackEntry>,
42 frames: ArrayVec<Frame, FRAMES_MAX>,
43 regex_cache: RefCell<HashMap<RegexKey, Rc<regexml::Regex>>>,
44 pub(crate) xot: &'a mut Xot,
45}
46
47#[derive(Debug)]
48struct ItemBuildStackEntry {
49 build_stack: Vec<sequence::Item>,
50}
51
52#[derive(Debug)]
53struct BuildStackEntry {
54 item: ItemBuildStackEntry,
55}
56
57impl BuildStackEntry {
58 fn new() -> Self {
59 Self {
60 item: ItemBuildStackEntry {
61 build_stack: Vec::new(),
62 },
63 }
64 }
65
66 fn push(&mut self, item: sequence::Item) {
67 self.item.build_stack.push(item);
68 }
69
70 fn extend<I: Iterator<Item = sequence::Item>>(
71 &mut self,
72 items: impl IntoIterator<Item = sequence::Item, IntoIter = I>,
73 ) {
74 self.item.build_stack.extend(items);
75 }
76}
77
78impl From<BuildStackEntry> for sequence::Sequence {
79 fn from(build: BuildStackEntry) -> Self {
80 sequence::Sequence::new(build.item.build_stack)
81 }
82}
83
84impl<'a> State<'a> {
85 pub(crate) fn new(xot: &'a mut Xot) -> Self {
86 Self {
87 stack: vec![],
88 build_stack: vec![],
89 frames: ArrayVec::new(),
90 regex_cache: RefCell::new(HashMap::new()),
91 xot,
92 }
93 }
94
95 pub(crate) fn push<T>(&mut self, sequence: T)
96 where
97 T: Into<sequence::Sequence>,
98 {
99 let sequence: sequence::Sequence = sequence.into();
100 self.stack.push(sequence.into());
101 }
102
103 pub(crate) fn push_value<T>(&mut self, value: T)
104 where
105 T: Into<stack::Value>,
106 {
107 self.stack.push(value.into());
108 }
109
110 pub(crate) fn build_new(&mut self) {
111 self.build_stack.push(BuildStackEntry::new());
112 }
113
114 pub(crate) fn build_push(&mut self) -> error::Result<()> {
115 let value = self.pop()?;
116 let build = self.build_stack.last_mut().unwrap();
117 match value {
118 sequence::Sequence::Empty(_) => {}
119 sequence::Sequence::One(item) => build.push(item.into_item()),
120 sequence => build.extend(sequence.iter()),
122 }
123 Ok(())
124 }
125
126 pub(crate) fn build_complete(&mut self) {
127 let build = self.build_stack.pop().unwrap();
128 self.stack.push(build.into());
129 }
130
131 pub(crate) fn push_var(&mut self, index: usize) {
132 self.stack
133 .push(self.stack[self.frame().base + index].clone());
134 }
135
136 pub(crate) fn push_closure_var(&mut self, index: usize) -> error::Result<()> {
137 let function = self.function()?;
138 let closure_vars = function.closure_vars();
139 self.stack.push(closure_vars[index].clone());
140 Ok(())
141 }
142
143 pub(crate) fn set_var(&mut self, index: usize) {
144 let base = self.frame().base;
145 self.stack[base + index] = self.stack.pop().unwrap();
146 }
147
148 #[inline]
149 pub(crate) fn pop(&mut self) -> error::Result<sequence::Sequence> {
150 self.pop_value().try_into()
151 }
152
153 #[inline]
154 pub(crate) fn pop_value(&mut self) -> stack::Value {
155 self.stack.pop().unwrap()
156 }
157
158 pub(crate) fn function(&self) -> error::Result<function::Function> {
159 let value = &self.stack[self.frame().base - 1];
161 match value {
162 stack::Value::Sequence(sequence) => sequence.clone().try_into(),
163 stack::Value::Absent => Err(error::Error::XPDY0002),
164 }
165 }
166
167 pub(crate) fn push_start_frame(&mut self, function_id: function::InlineFunctionId) {
168 self.frames.push(Frame {
169 function: function_id,
170 ip: 0,
171 base: 0,
172 });
173 }
174
175 pub(crate) fn push_frame(
176 &mut self,
177 function_id: function::InlineFunctionId,
178 arity: usize,
179 ) -> error::Result<()> {
180 if self.frames.len() >= self.frames.capacity() {
181 return Err(error::Error::StackOverflow);
182 }
183 self.frames.push(Frame {
184 function: function_id,
185 ip: 0,
186 base: self.stack.len() - arity,
187 });
188 Ok(())
189 }
190
191 pub(crate) fn frame(&self) -> &Frame {
192 self.frames.last().unwrap()
193 }
194
195 pub(crate) fn frame_mut(&mut self) -> &mut Frame {
196 self.frames.last_mut().unwrap()
197 }
198
199 pub(crate) fn jump(&mut self, displacement: i32) {
200 self.frame_mut().ip = (self.frame().ip as i32 + displacement) as usize;
201 }
202
203 pub(crate) fn callable(&self, arity: usize) -> error::Result<function::Function> {
204 let value = &self.stack[self.stack.len() - (arity + 1)];
205 match value {
206 stack::Value::Sequence(sequence) => sequence.clone().try_into(),
207 stack::Value::Absent => Err(error::Error::XPDY0002),
208 }
209 }
210
211 pub(crate) fn arguments(&self, arity: usize) -> &[stack::Value] {
212 &self.stack[self.stack.len() - arity..]
213 }
214
215 pub(crate) fn truncate_arguments(&mut self, arity: usize) {
216 self.stack.truncate(self.stack.len() - arity);
217 }
218
219 pub(crate) fn inline_return(&mut self, start_base: usize) -> bool {
220 let return_value = self.stack.pop().unwrap();
221
222 let base = self.frame().base;
224 self.stack.truncate(base);
225
226 if !self.stack.is_empty() {
229 self.stack.pop();
230 }
231
232 self.stack.push(return_value);
234
235 self.frames.pop();
237
238 base == start_base
241 }
242
243 pub(crate) fn top(&self) -> error::Result<sequence::Sequence> {
244 self.stack.last().unwrap().try_into()
245 }
246
247 pub fn stack(&self) -> &[stack::Value] {
248 &self.stack
249 }
250
251 pub fn regex(&self, pattern: &str, flags: &str) -> error::Result<Rc<regexml::Regex>> {
252 let key = RegexKey {
256 pattern: pattern.to_string(),
257 flags: flags.to_string(),
258 };
259 let mut cache = self.regex_cache.borrow_mut();
260 let entry = cache.entry(key);
261 match entry {
262 std::collections::hash_map::Entry::Occupied(entry) => Ok(entry.get().clone()),
263 std::collections::hash_map::Entry::Vacant(entry) => {
264 let v = entry.insert(Rc::new(regexml::Regex::xpath(pattern, flags)?));
265 Ok(v.clone())
266 }
267 }
268 }
269
270 pub fn xot(&self) -> &Xot {
271 self.xot
272 }
273
274 pub fn xot_mut(&mut self) -> &mut Xot {
275 self.xot
276 }
277}