1use std::collections::BTreeMap;
9use std::rc::Rc;
10use std::sync::Arc;
11
12use super::executor::Executor;
13use super::program::Expr;
14use super::results::{Res, content_start};
15use super::text::column_of;
16
17const SAFE_INTEGER: i64 = (1 << 53) - 1;
19
20#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
22pub enum OperationValue {
23 Integer(i64),
25 Text(String),
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub(super) enum Abort {
32 StepLimit,
33 NestingTooDeep,
34 MemoryBudget,
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub(super) enum OpError {
40 Failed,
42 Abort(Abort),
44}
45
46impl From<Abort> for OpError {
47 fn from(abort: Abort) -> Self {
48 Self::Abort(abort)
49 }
50}
51
52pub(super) type OpResult<T> = Result<T, OpError>;
53
54#[derive(Debug, PartialEq, Eq, Hash)]
57pub(super) struct StateData {
58 pub(super) modes: Vec<Arc<str>>,
59 pub(super) stacks: BTreeMap<Arc<str>, Vec<OperationValue>>,
60 pub(super) variables: BTreeMap<Arc<str>, OperationValue>,
61}
62
63#[derive(Clone, Debug, PartialEq, Eq, Hash)]
65pub(super) struct State(pub(super) Rc<StateData>);
66
67impl State {
68 pub(super) fn initial() -> Self {
70 Self(Rc::new(StateData {
71 modes: vec![Arc::from("default")],
72 stacks: BTreeMap::new(),
73 variables: BTreeMap::new(),
74 }))
75 }
76
77 pub(super) fn mode(&self) -> &str {
79 self.0.modes.last().map_or("default", |mode| mode)
80 }
81
82 pub(super) fn working(&self) -> Working {
84 Working {
85 modes: self.0.modes.clone(),
86 stacks: self.0.stacks.clone(),
87 variables: self.0.variables.clone(),
88 }
89 }
90}
91
92#[derive(Clone, Debug)]
94pub(super) struct Working {
95 pub(super) modes: Vec<Arc<str>>,
96 pub(super) stacks: BTreeMap<Arc<str>, Vec<OperationValue>>,
97 pub(super) variables: BTreeMap<Arc<str>, OperationValue>,
98}
99
100impl Working {
101 pub(super) fn settle(self) -> State {
103 let mut stacks = self.stacks;
104 stacks.retain(|_, values| !values.is_empty());
105 State(Rc::new(StateData {
106 modes: self.modes,
107 stacks,
108 variables: self.variables,
109 }))
110 }
111}
112
113#[derive(Debug)]
115pub(super) enum ValueOp {
116 Integer(i64),
117 Text(String),
118 Variable(Arc<str>),
119 Top(Arc<str>),
120 Depth(Arc<str>),
121 Column,
122 Matched,
123 Mode,
124 Attribute(String, String),
125 SumOf(String, String),
126 FieldText(String),
127 Length(Box<Self>),
128 Number(Box<Self>),
129 Add(Box<Self>, Box<Self>),
130 Subtract(Box<Self>, Box<Self>),
131 Multiply(Box<Self>, Box<Self>),
132}
133
134#[derive(Debug)]
136pub(super) enum Condition {
137 Valid(Arc<str>),
138 Expected(usize),
141 Next(Expr),
142 AtEnd,
143 Equal(ValueOp, ValueOp),
144 Less(ValueOp, ValueOp),
145 Greater(ValueOp, ValueOp),
146 All(Vec<Self>),
147 Some(Vec<Self>),
148 Not(Box<Self>),
149}
150
151#[derive(Debug)]
153pub(super) enum Statement {
154 Advance,
155 Consume(Expr),
156 Skip(Expr),
157 Mark,
158 Emit(Arc<str>),
159 Fail,
160 If(Condition, Vec<Self>, Option<Vec<Self>>),
161 While(Condition, Vec<Self>),
162 Push(Arc<str>, ValueOp),
163 Pop(Arc<str>),
164 Set(Arc<str>, ValueOp),
165 PushMode(Arc<str>),
166 PopMode,
167 SetMode(Arc<str>),
168 SetAttribute(String, ValueOp),
169 BuildNode(Arc<str>),
170}
171
172pub(super) trait Machine {
176 fn state(&mut self) -> &mut Working;
177 fn step(&mut self) -> Result<(), Abort>;
178 fn requested(&self) -> Option<&str> {
179 None
180 }
181 fn expected(&mut self, _id: usize) -> bool {
182 false
183 }
184 fn column(&mut self) -> usize;
185 fn at_end(&mut self) -> bool;
186 fn matched(&mut self) -> OpResult<String> {
187 Err(OpError::Failed)
188 }
189 fn lookahead(&mut self, _item: &Expr) -> OpResult<bool> {
190 Ok(false)
191 }
192 fn attribute(&mut self, _field: &str, _name: &str) -> OpResult<OperationValue> {
193 Err(OpError::Failed)
194 }
195 fn attributes(&mut self, _field: &str, _name: &str) -> OpResult<Vec<OperationValue>> {
196 Err(OpError::Failed)
197 }
198 fn field_text(&mut self, _field: &str) -> OpResult<String> {
199 Err(OpError::Failed)
200 }
201 fn advance(&mut self) -> OpResult<()> {
202 Err(OpError::Failed)
203 }
204 fn consume(&mut self, _item: &Expr) -> OpResult<()> {
205 Err(OpError::Failed)
206 }
207 fn skip(&mut self, _item: &Expr) -> OpResult<()> {
208 Err(OpError::Failed)
209 }
210 fn mark(&mut self) {}
211 fn set_attribute(&mut self, _name: &str, _value: OperationValue) {}
212 fn build_node(&mut self, _kind: &Arc<str>) {}
213}
214
215const fn integer(value: &OperationValue) -> OpResult<i64> {
216 match value {
217 OperationValue::Integer(value) => Ok(*value),
218 OperationValue::Text(_) => Err(OpError::Failed),
219 }
220}
221
222fn checked(value: Option<i64>) -> OpResult<OperationValue> {
223 match value {
224 Some(value) if (-SAFE_INTEGER..=SAFE_INTEGER).contains(&value) => {
225 Ok(OperationValue::Integer(value))
226 }
227 _ => Err(OpError::Failed),
228 }
229}
230
231fn to_integer(value: usize) -> OperationValue {
232 OperationValue::Integer(i64::try_from(value).unwrap_or(i64::MAX))
233}
234
235fn arithmetic(
236 left: &ValueOp,
237 right: &ValueOp,
238 machine: &mut dyn Machine,
239 combine: fn(i64, i64) -> Option<i64>,
240) -> OpResult<OperationValue> {
241 let left = integer(&evaluate_value(left, machine)?)?;
242 let right = integer(&evaluate_value(right, machine)?)?;
243 checked(combine(left, right))
244}
245
246fn is_number_text(text: &str) -> bool {
247 let digits = text.strip_prefix('-').unwrap_or(text);
248 (1..=15).contains(&digits.len()) && digits.bytes().all(|byte| byte.is_ascii_digit())
249}
250
251pub(super) fn evaluate_value(
253 value: &ValueOp,
254 machine: &mut dyn Machine,
255) -> OpResult<OperationValue> {
256 machine.step()?;
257 Ok(match value {
258 ValueOp::Integer(value) => OperationValue::Integer(*value),
259 ValueOp::Text(value) => OperationValue::Text(value.clone()),
260 ValueOp::Variable(name) => machine
261 .state()
262 .variables
263 .get(name)
264 .cloned()
265 .unwrap_or(OperationValue::Integer(0)),
266 ValueOp::Top(stack) => machine
267 .state()
268 .stacks
269 .get(stack)
270 .and_then(|values| values.last().cloned())
271 .unwrap_or(OperationValue::Integer(0)),
272 ValueOp::Depth(stack) => to_integer(machine.state().stacks.get(stack).map_or(0, Vec::len)),
273 ValueOp::Column => to_integer(machine.column()),
274 ValueOp::Matched => OperationValue::Text(machine.matched()?),
275 ValueOp::Mode => OperationValue::Text(
276 machine
277 .state()
278 .modes
279 .last()
280 .map_or_else(String::new, std::string::ToString::to_string),
281 ),
282 ValueOp::Attribute(field, name) => machine.attribute(field, name)?,
283 ValueOp::SumOf(field, name) => {
284 let mut sum = OperationValue::Integer(0);
285 for item in machine.attributes(field, name)? {
286 sum = checked(integer(&sum)?.checked_add(integer(&item)?))?;
287 }
288 sum
289 }
290 ValueOp::FieldText(field) => OperationValue::Text(machine.field_text(field)?),
291 ValueOp::Length(inner) => match evaluate_value(inner, machine)? {
292 OperationValue::Text(text) => to_integer(text.chars().count()),
293 OperationValue::Integer(_) => return Err(OpError::Failed),
294 },
295 ValueOp::Number(inner) => match evaluate_value(inner, machine)? {
296 number @ OperationValue::Integer(_) => number,
297 OperationValue::Text(text) => {
298 if !is_number_text(&text) {
299 return Err(OpError::Failed);
300 }
301 OperationValue::Integer(text.parse().map_err(|_| OpError::Failed)?)
302 }
303 },
304 ValueOp::Add(left, right) => arithmetic(left, right, machine, i64::checked_add)?,
305 ValueOp::Subtract(left, right) => arithmetic(left, right, machine, i64::checked_sub)?,
306 ValueOp::Multiply(left, right) => arithmetic(left, right, machine, i64::checked_mul)?,
307 })
308}
309
310pub(super) fn evaluate_condition(
312 condition: &Condition,
313 machine: &mut dyn Machine,
314) -> OpResult<bool> {
315 machine.step()?;
316 Ok(match condition {
317 Condition::Valid(token) => machine.requested() == Some(&**token),
318 Condition::Expected(id) => machine.expected(*id),
319 Condition::Next(item) => machine.lookahead(item)?,
320 Condition::AtEnd => machine.at_end(),
321 Condition::Equal(left, right) => {
322 let left = evaluate_value(left, machine)?;
323 let right = evaluate_value(right, machine)?;
324 left == right
325 }
326 Condition::Less(left, right) => {
327 let left = integer(&evaluate_value(left, machine)?)?;
328 left < integer(&evaluate_value(right, machine)?)?
329 }
330 Condition::Greater(left, right) => {
331 let left = integer(&evaluate_value(left, machine)?)?;
332 left > integer(&evaluate_value(right, machine)?)?
333 }
334 Condition::All(items) => {
335 for item in items {
336 if !evaluate_condition(item, machine)? {
337 return Ok(false);
338 }
339 }
340 true
341 }
342 Condition::Some(items) => {
343 for item in items {
344 if evaluate_condition(item, machine)? {
345 return Ok(true);
346 }
347 }
348 false
349 }
350 Condition::Not(inner) => !evaluate_condition(inner, machine)?,
351 })
352}
353
354pub(super) fn run_statements(
357 statements: &[Statement],
358 machine: &mut dyn Machine,
359) -> OpResult<Option<Arc<str>>> {
360 for statement in statements {
361 machine.step()?;
362 match statement {
363 Statement::Advance => machine.advance()?,
364 Statement::Consume(item) => machine.consume(item)?,
365 Statement::Skip(item) => machine.skip(item)?,
366 Statement::Mark => machine.mark(),
367 Statement::Emit(token) => return Ok(Some(token.clone())),
368 Statement::Fail => return Err(OpError::Failed),
369 Statement::If(condition, consequent, alternative) => {
370 let branch = if evaluate_condition(condition, machine)? {
371 Some(consequent)
372 } else {
373 alternative.as_ref()
374 };
375 if let Some(branch) = branch
376 && let Some(signal) = run_statements(branch, machine)?
377 {
378 return Ok(Some(signal));
379 }
380 }
381 Statement::While(condition, body) => {
382 while evaluate_condition(condition, machine)? {
383 if let Some(signal) = run_statements(body, machine)? {
384 return Ok(Some(signal));
385 }
386 }
387 }
388 Statement::Push(stack, value) => {
389 let value = evaluate_value(value, machine)?;
390 machine
391 .state()
392 .stacks
393 .entry(stack.clone())
394 .or_default()
395 .push(value);
396 }
397 Statement::Pop(stack) => {
398 let popped = machine.state().stacks.get_mut(stack).and_then(Vec::pop);
399 if popped.is_none() {
400 return Err(OpError::Failed);
401 }
402 }
403 Statement::Set(variable, value) => {
404 let value = evaluate_value(value, machine)?;
405 machine.state().variables.insert(variable.clone(), value);
406 }
407 Statement::PushMode(mode) => machine.state().modes.push(mode.clone()),
408 Statement::PopMode => {
409 let modes = &mut machine.state().modes;
410 if modes.len() <= 1 {
411 return Err(OpError::Failed);
412 }
413 modes.pop();
414 }
415 Statement::SetMode(mode) => {
416 if let Some(last) = machine.state().modes.last_mut() {
417 *last = mode.clone();
418 }
419 }
420 Statement::SetAttribute(name, value) => {
421 let value = evaluate_value(value, machine)?;
422 machine.set_attribute(name, value);
423 }
424 Statement::BuildNode(kind) => machine.build_node(kind),
425 }
426 }
427 Ok(None)
428}
429
430pub(super) fn allowed_in(context: &str, operation: &str) -> bool {
432 const COMMON: &[&str] = &[
433 "if", "while", "push", "pop", "set", "pushMode", "popMode", "setMode", "atEnd", "equal",
434 "less", "greater", "all", "some", "not", "integer", "text", "variable", "top", "depth",
435 "column", "mode", "length", "number", "add", "subtract", "multiply",
436 ];
437 const SCANNER: &[&str] = &[
438 "advance", "consume", "skip", "mark", "emit", "fail", "valid", "expected", "next",
439 ];
440 const ACTION: &[&str] = &[
441 "fail",
442 "setAttribute",
443 "buildNode",
444 "matched",
445 "attribute",
446 "sumOf",
447 "fieldText",
448 ];
449 const PREDICATE: &[&str] = &[
450 "atEnd", "equal", "less", "greater", "all", "some", "not", "integer", "text", "variable",
451 "top", "depth", "column", "matched", "mode", "length", "number", "add", "subtract",
452 "multiply",
453 ];
454 match context {
455 "scanner" => COMMON.contains(&operation) || SCANNER.contains(&operation),
456 "action" => COMMON.contains(&operation) || ACTION.contains(&operation),
457 _ => PREDICATE.contains(&operation),
458 }
459}
460
461pub(super) struct ValueMachine<'e, 'c> {
463 executor: &'e mut Executor<'c>,
464 working: Working,
465 start: usize,
466 end: usize,
467}
468
469impl<'e, 'c> ValueMachine<'e, 'c> {
470 pub(super) fn new(executor: &'e mut Executor<'c>, result: &Res, from: usize) -> Self {
471 Self {
472 start: content_start(&result.children, from),
473 end: result.end,
474 working: result.state.working(),
475 executor,
476 }
477 }
478}
479
480impl Machine for ValueMachine<'_, '_> {
481 fn state(&mut self) -> &mut Working {
482 &mut self.working
483 }
484
485 fn step(&mut self) -> Result<(), Abort> {
486 self.executor.step()
487 }
488
489 fn column(&mut self) -> usize {
490 column_of(self.executor.bytes, self.start, self.executor.begin)
491 }
492
493 fn at_end(&mut self) -> bool {
494 self.end == self.executor.end
495 }
496
497 fn matched(&mut self) -> OpResult<String> {
498 Ok(self.executor.text(self.start, self.end))
499 }
500}