1use std::collections::{BTreeMap, BTreeSet};
2
3use tla_syntax::token::Op;
4use tla_syntax::{Bound, Def, ExceptPath, Expr, Param, QuantKind};
5
6use crate::builtin;
7use crate::error::{Error, Result, type_error};
8use crate::spec::Spec;
9use crate::value::{Infinite, Value};
10
11pub const MAX_ELEMENTS: usize = 1 << 20;
15
16const MAX_DEPTH: usize = 512;
17
18pub type State = BTreeMap<String, Value>;
20
21#[derive(Debug)]
22pub struct Evaluator<'m> {
23 pub(crate) spec: &'m Spec,
24 constants: BTreeMap<String, Value>,
25}
26
27#[derive(Clone)]
33pub(crate) enum Local<'m> {
34 Val(Value),
35 Def {
38 def: &'m Def,
39 scope: usize,
40 },
41 Closure {
43 params: &'m [Param],
44 body: &'m Expr,
45 scope: usize,
46 },
47 Symbol(Op),
49 Builtin(String),
51 Subst {
55 expr: &'m Expr,
56 module: usize,
57 scope: usize,
58 },
59}
60
61pub(crate) struct Ctx<'m, 'a> {
62 pub(crate) module: usize,
66 pub(crate) state: &'a State,
67 pub(crate) next: Option<&'a State>,
68 pub(crate) primed: bool,
69 pub(crate) locals: Vec<(String, Local<'m>)>,
70 pub(crate) at: Vec<Value>,
71 pub(crate) depth: usize,
72}
73
74impl<'m> Evaluator<'m> {
75 pub fn new(spec: &'m Spec, constants: BTreeMap<String, Value>) -> Result<Self> {
78 let missing: Vec<&str> = spec
79 .constants()
80 .filter(|c| !constants.contains_key(*c))
81 .collect();
82 if !missing.is_empty() {
83 return Err(Error::Undefined(format!(
84 "constants without a value: {}",
85 missing.join(", ")
86 )));
87 }
88 Ok(Self { spec, constants })
89 }
90
91 pub fn holds_at(&self, name: &str, state: &State) -> Result<bool> {
93 let body = self.body_of(name)?;
94 self.eval_bool(body, &mut self.ctx(state, None))
95 }
96
97 pub fn step_allowed(&self, name: &str, from: &State, to: &State) -> Result<bool> {
99 let body = self.body_of(name)?;
100 self.eval_bool(body, &mut self.ctx(from, Some(to)))
101 }
102
103 pub fn value_of(&self, name: &str, state: &State) -> Result<Value> {
104 let body = self.body_of(name)?;
105 self.eval(body, &mut self.ctx(state, None))
106 }
107
108 pub fn eval_at(&self, expr: &'m Expr, from: &State, to: Option<&State>) -> Result<Value> {
109 self.eval(expr, &mut self.ctx(from, to))
110 }
111
112 pub(crate) fn body_of(&self, name: &str) -> Result<&'m Expr> {
113 let (_, def) = self
114 .spec
115 .definition(self.spec.root(), name)
116 .ok_or_else(|| Error::Undefined(name.to_string()))?;
117 if def.params.is_empty() {
118 Ok(&def.body)
119 } else {
120 Err(Error::Malformed(format!(
121 "`{name}` takes {} argument(s) and is not a predicate",
122 def.params.len()
123 )))
124 }
125 }
126
127 pub(crate) fn ctx<'a>(&self, state: &'a State, next: Option<&'a State>) -> Ctx<'m, 'a> {
128 Ctx {
129 module: self.spec.root(),
130 state,
131 next,
132 primed: false,
133 locals: Vec::new(),
134 at: Vec::new(),
135 depth: 0,
136 }
137 }
138
139 #[expect(
142 clippy::too_many_lines,
143 reason = "one arm per syntactic form; splitting it would only scatter the language"
144 )]
145 pub(crate) fn eval(&self, e: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
146 match e {
147 Expr::Num(n) => Ok(Value::Int(*n)),
148 Expr::Decimal(text) => Err(Error::NotGround(format!(
149 "{text} is a real number, and real arithmetic is not implemented"
150 ))),
151 Expr::Str(s) => Ok(Value::Str(s.clone())),
152 Expr::Bool(b) => Ok(Value::Bool(*b)),
153 Expr::Ident(name) => self.ident(name, ctx),
154 Expr::Prime(inner) => self.primed(inner, ctx),
155 Expr::At => ctx
156 .at
157 .last()
158 .cloned()
159 .ok_or_else(|| Error::Malformed("`@` outside an EXCEPT update".to_string())),
160 Expr::Apply(head, args) => self.apply(head, args, ctx),
161 Expr::FnApply(f, args) => {
162 let func = self.eval(f, ctx)?;
163 let key = self.key(args, ctx)?;
164 func.apply(&key)
165 .ok_or_else(|| Error::Type(format!("{func} is not defined at {key}")))
166 }
167 Expr::Field(inner, name) => {
168 let v = self.eval(inner, ctx)?;
169 v.apply(&Value::Str(name.clone()))
170 .ok_or_else(|| Error::Type(format!("{v} has no field `{name}`")))
171 }
172 Expr::Qualified {
173 instance,
174 name,
175 args,
176 } => self.qualified(instance, name, args, ctx),
177 Expr::Unary(op, inner) => self.unary(*op, inner, ctx),
178 Expr::Binary(op, l, r) => self.binary(*op, l, r, ctx),
179 Expr::Tuple(items) => Ok(Value::Seq(self.eval_all(items, ctx)?)),
180 Expr::SetEnum(items) => Ok(Value::set(self.eval_all(items, ctx)?)),
181 Expr::SetFilter { bound, pred } => self.set_filter(bound, pred, ctx),
182 Expr::SetMap { expr, bounds } => self.set_map(expr, bounds, ctx),
183 Expr::Record(fields) => {
184 let mut out = BTreeMap::new();
185 for (k, v) in fields {
186 out.insert(k.clone(), self.eval(v, ctx)?);
187 }
188 Ok(Value::Record(out))
189 }
190 Expr::RecordSet(fields) => self.record_set(fields, ctx),
191 Expr::FnDef { bounds, body } => self.fn_def(bounds, body, ctx),
192 Expr::FnSet { domain, range } => self.fn_set(domain, range, ctx),
193 Expr::Except { base, updates } => {
194 let mut v = self.eval(base, ctx)?;
195 for (path, rhs) in updates {
196 v = self.update(v, path, rhs, ctx)?;
197 }
198 Ok(v)
199 }
200 Expr::Quant { kind, bounds, body } => self.quantify(*kind, bounds, body, ctx),
201 Expr::Choose { bound, body } => self.choose(bound, body, ctx),
202 Expr::Let { defs, body, .. } => {
203 let base = ctx.locals.len();
204 let scope = base + defs.len();
205 for def in defs {
206 ctx.locals
207 .push((def.name.clone(), Local::Def { def, scope }));
208 }
209 let out = self.eval(body, ctx);
210 ctx.locals.truncate(base);
211 out
212 }
213 Expr::If {
214 cond,
215 then,
216 otherwise,
217 } => {
218 if self.eval_bool(cond, ctx)? {
219 self.eval(then, ctx)
220 } else {
221 self.eval(otherwise, ctx)
222 }
223 }
224 Expr::Case { arms, other } => {
225 for (guard, result) in arms {
226 if self.eval_bool(guard, ctx)? {
227 return self.eval(result, ctx);
228 }
229 }
230 match other {
231 Some(e) => self.eval(e, ctx),
232 None => Err(Error::Malformed("no CASE arm applies".to_string())),
233 }
234 }
235 Expr::ActionBox { action, subscript } => {
237 if self.eval_bool(action, ctx)? {
238 return Ok(Value::Bool(true));
239 }
240 self.unchanged(subscript, ctx)
241 }
242 Expr::Lambda { .. } => Err(Error::Malformed(
243 "a LAMBDA is an operator, and can only be passed to one".to_string(),
244 )),
245 Expr::ActionAngle { .. } | Expr::Fairness { .. } => Err(Error::NotGround(
246 "a fairness or angle-bracket formula is about behaviours, not about one step"
247 .to_string(),
248 )),
249 }
250 }
251
252 pub(crate) fn eval_bool(&self, e: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<bool> {
253 match self.eval(e, ctx)? {
254 Value::Bool(b) => Ok(b),
255 other => type_error(format!("expected a boolean, got {other}")),
256 }
257 }
258
259 fn eval_all(&self, items: &'m [Expr], ctx: &mut Ctx<'m, '_>) -> Result<Vec<Value>> {
260 items.iter().map(|e| self.eval(e, ctx)).collect()
261 }
262
263 fn key(&self, args: &'m [Expr], ctx: &mut Ctx<'m, '_>) -> Result<Value> {
264 let mut values = self.eval_all(args, ctx)?;
265 Ok(if values.len() == 1 {
266 values.remove(0)
267 } else {
268 Value::Seq(values)
269 })
270 }
271
272 fn primed(&self, e: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
273 let saved = ctx.primed;
274 ctx.primed = true;
275 let out = self.eval(e, ctx);
276 ctx.primed = saved;
277 out
278 }
279
280 fn ident(&self, name: &str, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
281 if let Some(local) = lookup(name, ctx) {
282 return match local {
283 Local::Val(v) => Ok(v),
284 Local::Def { def, scope } => self.call(def, scope, &[], ctx),
285 Local::Closure { body, scope, .. } => {
286 self.run(name, body, scope, &[], Vec::new(), ctx)
287 }
288 Local::Subst {
289 expr,
290 module,
291 scope,
292 } => self.substituted(expr, module, scope, ctx),
293 Local::Symbol(_) | Local::Builtin(_) => Err(Error::Malformed(format!(
294 "`{name}` is an operator and must be applied to arguments"
295 ))),
296 };
297 }
298 if self.spec.declares_variable(ctx.module, name) {
299 let source = if ctx.primed {
300 ctx.next.ok_or_else(|| {
301 Error::NoNextState(format!(
302 "`{name}'` needs a successor state, but only one state was given"
303 ))
304 })?
305 } else {
306 ctx.state
307 };
308 return source.get(name).cloned().ok_or_else(|| {
309 Error::Malformed(format!("the state gives no value for variable `{name}`"))
310 });
311 }
312 if let Some(v) = self.constants.get(name) {
313 return Ok(v.clone());
314 }
315 if let Some((module, def)) = self.spec.definition(ctx.module, name) {
316 if !def.params.is_empty() {
317 return Err(Error::Malformed(format!(
318 "`{name}` takes {} argument(s) but was used as a value",
319 def.params.len()
320 )));
321 }
322 return self.in_module(module, ctx, |me, ctx| me.call(def, 0, &[], ctx));
323 }
324 if self.spec.declares_constant(ctx.module, name) {
325 return Err(Error::Undefined(format!("constant `{name}` has no value")));
326 }
327 builtin::constant(name).ok_or_else(|| Error::Undefined(name.to_string()))
328 }
329
330 fn apply(&self, head: &'m Expr, args: &'m [Expr], ctx: &mut Ctx<'m, '_>) -> Result<Value> {
331 let Expr::Ident(name) = head else {
332 return Err(Error::Malformed(
333 "only a named operator can be applied to arguments".to_string(),
334 ));
335 };
336 match lookup(name, ctx) {
337 Some(Local::Def { def, scope }) => return self.invoke(def, scope, args, ctx),
338 Some(Local::Closure {
339 params,
340 body,
341 scope,
342 }) => return self.enter_closure(name, params, body, scope, args, ctx),
343 Some(Local::Symbol(op)) => {
344 let values = self.eval_all(args, ctx)?;
345 return Self::apply_symbol(op, values);
346 }
347 Some(Local::Builtin(builtin)) => {
348 let values = self.eval_all(args, ctx)?;
349 return builtin::call(&builtin, &values);
350 }
351 Some(Local::Subst {
354 expr,
355 module,
356 scope,
357 }) => {
358 let Expr::Ident(replacement) = expr else {
359 return Err(Error::Malformed(format!(
360 "`{name}` stands for {expr}, which cannot be applied"
361 )));
362 };
363 let values = self.eval_all(args, ctx)?;
364 let hidden = ctx.locals.split_off(scope);
365 let out = self.in_module(module, ctx, |me, ctx| {
366 match me.spec.definition(ctx.module, replacement) {
367 Some((defining, def)) => {
368 me.in_module(defining, ctx, |me, ctx| me.call(def, 0, &values, ctx))
369 }
370 None => builtin::call(replacement, &values),
371 }
372 });
373 ctx.locals.truncate(scope);
374 ctx.locals.extend(hidden);
375 return out;
376 }
377 Some(Local::Val(_)) => {
378 return Err(Error::Malformed(format!(
379 "`{name}` is a value, and cannot be applied to arguments"
380 )));
381 }
382 None => {}
383 }
384 if let Some((module, def)) = self.spec.definition(ctx.module, name) {
385 return self.in_module(module, ctx, |me, ctx| me.invoke(def, 0, args, ctx));
386 }
387 let values = self.eval_all(args, ctx)?;
388 builtin::call(name, &values)
389 }
390
391 fn apply_symbol(op: Op, mut values: Vec<Value>) -> Result<Value> {
393 match values.len() {
394 2 => {
395 let right = values.pop().expect("length checked");
396 let left = values.pop().expect("length checked");
397 combine(op, left, right)
398 }
399 _ => Err(Error::Malformed(format!(
400 "`{}` takes two arguments, given {}",
401 op.symbol(),
402 values.len()
403 ))),
404 }
405 }
406
407 fn invoke(
410 &self,
411 def: &'m Def,
412 scope: usize,
413 args: &'m [Expr],
414 ctx: &mut Ctx<'m, '_>,
415 ) -> Result<Value> {
416 if def.params.len() != args.len() {
417 return Err(Error::Malformed(format!(
418 "`{}` takes {} argument(s), given {}",
419 def.name,
420 def.params.len(),
421 args.len()
422 )));
423 }
424 let mut bindings = Vec::with_capacity(args.len());
425 for (param, arg) in def.params.iter().zip(args) {
426 bindings.push(if param.arity == 0 {
427 Local::Val(self.eval(arg, ctx)?)
428 } else {
429 self.operator_argument(arg, ctx)?
430 });
431 }
432 self.run(&def.name, &def.body, scope, &def.params, bindings, ctx)
433 }
434
435 fn enter_closure(
436 &self,
437 name: &str,
438 params: &'m [Param],
439 body: &'m Expr,
440 scope: usize,
441 args: &'m [Expr],
442 ctx: &mut Ctx<'m, '_>,
443 ) -> Result<Value> {
444 if params.len() != args.len() {
445 return Err(Error::Malformed(format!(
446 "`{name}` takes {} argument(s), given {}",
447 params.len(),
448 args.len()
449 )));
450 }
451 let mut bindings = Vec::with_capacity(args.len());
452 for (param, arg) in params.iter().zip(args) {
453 bindings.push(if param.arity == 0 {
454 Local::Val(self.eval(arg, ctx)?)
455 } else {
456 self.operator_argument(arg, ctx)?
457 });
458 }
459 self.run(name, body, scope, params, bindings, ctx)
460 }
461
462 fn operator_argument(&self, arg: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Local<'m>> {
464 match arg {
465 Expr::Lambda { params, body } => Ok(Local::Closure {
466 params,
467 body,
468 scope: ctx.locals.len(),
469 }),
470 Expr::Ident(name) => {
471 if let Some(
472 local @ (Local::Closure { .. } | Local::Symbol(_) | Local::Builtin(_)),
473 ) = lookup(name, ctx)
474 {
475 return Ok(local);
476 }
477 if let Some((_, def)) = self.spec.definition(ctx.module, name) {
478 return Ok(Local::Closure {
479 params: &def.params,
480 body: &def.body,
481 scope: 0,
482 });
483 }
484 if let Some(op) = symbol_operator(name) {
485 return Ok(Local::Symbol(op));
486 }
487 Ok(Local::Builtin(name.clone()))
488 }
489 other => Err(Error::Malformed(format!(
490 "an operator was expected here, but {other} is an expression"
491 ))),
492 }
493 }
494
495 fn in_module<T>(
497 &self,
498 module: usize,
499 ctx: &mut Ctx<'m, '_>,
500 f: impl FnOnce(&Self, &mut Ctx<'m, '_>) -> Result<T>,
501 ) -> Result<T> {
502 let previous = std::mem::replace(&mut ctx.module, module);
503 let out = f(self, ctx);
504 ctx.module = previous;
505 out
506 }
507
508 fn substituted(
512 &self,
513 expr: &'m Expr,
514 module: usize,
515 scope: usize,
516 ctx: &mut Ctx<'m, '_>,
517 ) -> Result<Value> {
518 let hidden = ctx.locals.split_off(scope);
519 let previous = std::mem::replace(&mut ctx.module, module);
520 let out = self.eval(expr, ctx);
521 ctx.module = previous;
522 ctx.locals.truncate(scope);
523 ctx.locals.extend(hidden);
524 out
525 }
526
527 fn qualified(
530 &self,
531 instance: &str,
532 name: &str,
533 args: &'m [Expr],
534 ctx: &mut Ctx<'m, '_>,
535 ) -> Result<Value> {
536 if let Some((head, rest)) = instance.split_once('!') {
538 let outer = self
539 .spec
540 .instance(ctx.module, head)
541 .ok_or_else(|| Error::Undefined(format!("no instance named `{head}`")))?;
542 let scope = Self::bind_substitutions(outer, ctx);
543 let out = self.in_module(outer.target, ctx, |me, ctx| {
544 me.qualified(rest, name, args, ctx)
545 });
546 ctx.locals.truncate(scope);
547 return out;
548 }
549
550 let found = self
551 .spec
552 .instance(ctx.module, instance)
553 .ok_or_else(|| Error::Undefined(format!("no instance named `{instance}`")))?;
554 let (module, def) = self
555 .spec
556 .definition(found.target, name)
557 .ok_or_else(|| Error::Undefined(format!("`{instance}!{name}`")))?;
558
559 let scope = Self::bind_substitutions(found, ctx);
562 let out = self.in_module(module, ctx, |me, ctx| me.invoke(def, scope, args, ctx));
563 ctx.locals.truncate(scope);
564 out
565 }
566
567 fn bind_substitutions(instance: &'m crate::spec::Instance, ctx: &mut Ctx<'m, '_>) -> usize {
568 let outer = ctx.locals.len();
569 let here = ctx.module;
570 for (name, expr) in &instance.subs {
571 ctx.locals.push((
572 name.clone(),
573 Local::Subst {
574 expr,
575 module: here,
576 scope: outer,
577 },
578 ));
579 }
580 ctx.locals.len()
581 }
582
583 fn run(
586 &self,
587 name: &str,
588 body: &'m Expr,
589 scope: usize,
590 params: &[Param],
591 bindings: Vec<Local<'m>>,
592 ctx: &mut Ctx<'m, '_>,
593 ) -> Result<Value> {
594 if ctx.depth >= MAX_DEPTH {
595 return Err(Error::Malformed(format!(
596 "`{name}` recursed more than {MAX_DEPTH} deep"
597 )));
598 }
599 let hidden = ctx.locals.split_off(scope);
600 for (param, binding) in params.iter().zip(bindings) {
601 ctx.locals.push((param.name.clone(), binding));
602 }
603 ctx.depth += 1;
604 let out = self.eval(body, ctx);
605 ctx.depth -= 1;
606 ctx.locals.truncate(scope);
607 ctx.locals.extend(hidden);
608 out
609 }
610
611 fn call(
612 &self,
613 def: &'m Def,
614 scope: usize,
615 args: &[Value],
616 ctx: &mut Ctx<'m, '_>,
617 ) -> Result<Value> {
618 if def.params.len() != args.len() {
619 return Err(Error::Malformed(format!(
620 "`{}` takes {} argument(s), given {}",
621 def.name,
622 def.params.len(),
623 args.len()
624 )));
625 }
626 let bindings = args.iter().cloned().map(Local::Val).collect();
627 self.run(&def.name, &def.body, scope, &def.params, bindings, ctx)
628 }
629
630 fn unary(&self, op: Op, inner: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
633 if let Some((module, def)) = self.spec.definition(ctx.module, op.symbol())
634 && def.params.len() == 1
635 {
636 let values = vec![self.eval(inner, ctx)?];
637 return self.in_module(module, ctx, |me, ctx| me.call(def, 0, &values, ctx));
638 }
639 match op {
640 Op::Not => Ok(Value::Bool(!self.eval_bool(inner, ctx)?)),
641 Op::Minus => match self.eval(inner, ctx)? {
642 Value::Int(n) => Ok(Value::Int(-n)),
643 other => type_error(format!("cannot negate {other}")),
644 },
645 Op::Domain => {
646 let v = self.eval(inner, ctx)?;
647 v.domain()
648 .map(Value::Set)
649 .ok_or_else(|| Error::Type(format!("DOMAIN of {v}, which is not a function")))
650 }
651 Op::Subset => {
652 let v = self.eval(inner, ctx)?;
653 powerset(&elements(&v)?)
654 }
655 Op::BigUnion => {
656 let v = self.eval(inner, ctx)?;
657 let mut out = BTreeSet::new();
658 for member in elements(&v)? {
659 out.extend(elements(&member)?);
660 }
661 Ok(Value::Set(out))
662 }
663 Op::Unchanged => self.unchanged(inner, ctx),
664 Op::Enabled => Err(Error::NotGround(
665 "ENABLED asks whether some successor state exists, which needs a search"
666 .to_string(),
667 )),
668 Op::Always | Op::Eventually => Err(Error::NotGround(
669 "a temporal formula is about behaviours, not about one state".to_string(),
670 )),
671 other => Err(Error::Malformed(format!(
672 "{other:?} is not a prefix operator"
673 ))),
674 }
675 }
676
677 fn unchanged(&self, e: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
678 let before = self.eval(e, ctx)?;
679 let after = self.primed(e, ctx)?;
680 Ok(Value::Bool(before == after))
681 }
682
683 fn binary(&self, op: Op, lhs: &'m Expr, rhs: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
684 match op {
688 Op::And => {
689 return Ok(Value::Bool(
690 self.eval_bool(lhs, ctx)? && self.eval_bool(rhs, ctx)?,
691 ));
692 }
693 Op::Or => {
694 return Ok(Value::Bool(
695 self.eval_bool(lhs, ctx)? || self.eval_bool(rhs, ctx)?,
696 ));
697 }
698 Op::Implies => {
699 return Ok(Value::Bool(
700 !self.eval_bool(lhs, ctx)? || self.eval_bool(rhs, ctx)?,
701 ));
702 }
703 _ => {}
704 }
705 if let Op::User(symbol) = op
708 && let Some((module, def)) = self.spec.definition(ctx.module, symbol)
709 {
710 let values = vec![self.eval(lhs, ctx)?, self.eval(rhs, ctx)?];
711 return self.in_module(module, ctx, |me, ctx| me.call(def, 0, &values, ctx));
712 }
713 let left = self.eval(lhs, ctx)?;
714 let right = self.eval(rhs, ctx)?;
715 combine(op, left, right)
716 }
717}
718
719fn combine(op: Op, a: Value, b: Value) -> Result<Value> {
721 match op {
722 Op::Equiv => Ok(Value::Bool(as_bool(&a)? == as_bool(&b)?)),
723 Op::Eq => Ok(Value::Bool(a == b)),
724 Op::Neq => Ok(Value::Bool(a != b)),
725 Op::Lt => Ok(Value::Bool(as_int(&a)? < as_int(&b)?)),
726 Op::Gt => Ok(Value::Bool(as_int(&a)? > as_int(&b)?)),
727 Op::Le => Ok(Value::Bool(as_int(&a)? <= as_int(&b)?)),
728 Op::Ge => Ok(Value::Bool(as_int(&a)? >= as_int(&b)?)),
729 Op::Plus => arith(&a, &b, i64::checked_add, "+"),
730 Op::Minus => arith(&a, &b, i64::checked_sub, "-"),
731 Op::Times => arith(&a, &b, i64::checked_mul, "*"),
732 Op::Div => arith(&a, &b, i64::checked_div_euclid, "\\div"),
733 Op::Mod => arith(&a, &b, i64::checked_rem_euclid, "%"),
734 Op::Pow => {
735 let exp = u32::try_from(as_int(&b)?)
736 .map_err(|_| Error::Type("exponent out of range".to_string()))?;
737 as_int(&a)?
738 .checked_pow(exp)
739 .map(Value::Int)
740 .ok_or_else(|| Error::Type("^ overflowed".to_string()))
741 }
742 Op::DotDot => Ok(Value::interval(as_int(&a)?, as_int(&b)?)),
743 Op::In => Ok(Value::Bool(member(&a, &b)?)),
744 Op::NotIn => Ok(Value::Bool(!member(&a, &b)?)),
745 Op::Subseteq => {
746 for item in elements(&a)? {
747 if !member(&item, &b)? {
748 return Ok(Value::Bool(false));
749 }
750 }
751 Ok(Value::Bool(true))
752 }
753 Op::Supseteq => {
754 for item in elements(&b)? {
755 if !member(&item, &a)? {
756 return Ok(Value::Bool(false));
757 }
758 }
759 Ok(Value::Bool(true))
760 }
761 Op::Cup => {
762 let mut out = set_of(&a)?.clone();
763 out.extend(set_of(&b)?.iter().cloned());
764 Ok(Value::Set(out))
765 }
766 Op::Cap => Ok(Value::Set(
767 set_of(&a)?.intersection(set_of(&b)?).cloned().collect(),
768 )),
769 Op::SetMinus => Ok(Value::Set(
770 set_of(&a)?.difference(set_of(&b)?).cloned().collect(),
771 )),
772 Op::Cartesian => {
773 let mut out = BTreeSet::new();
774 for x in set_of(&a)? {
775 for y in set_of(&b)? {
776 out.insert(Value::Seq(vec![x.clone(), y.clone()]));
777 }
778 }
779 Ok(Value::Set(out))
780 }
781 Op::Concat => match (&a, &b) {
782 (Value::Seq(x), Value::Seq(y)) => Ok(Value::Seq(x.iter().chain(y).cloned().collect())),
783 _ => type_error(format!("\\o expects two sequences, got {a} and {b}")),
784 },
785 Op::OneTo => Ok(Value::function(BTreeMap::from([(a, b)]))),
786 Op::AtAt => {
787 let mut left = a
788 .entries()
789 .ok_or_else(|| Error::Type(format!("@@ expects functions, got {a}")))?;
790 let right = b
791 .entries()
792 .ok_or_else(|| Error::Type(format!("@@ expects functions, got {b}")))?;
793 for (k, v) in right {
794 left.entry(k).or_insert(v);
795 }
796 Ok(Value::function(left))
797 }
798 other => Err(Error::Malformed(format!(
799 "{other:?} is not an infix operator"
800 ))),
801 }
802}
803
804impl<'m> Evaluator<'m> {
805 fn set_filter(&self, bound: &'m Bound, pred: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
808 let mut out = BTreeSet::new();
809 for binding in self.expand(std::slice::from_ref(bound), ctx)? {
810 let restore = push(ctx, &binding);
811 let keep = self.eval_bool(pred, ctx);
812 ctx.locals.truncate(restore);
813 if keep? {
814 out.insert(element_of(&binding));
815 }
816 }
817 Ok(Value::Set(out))
818 }
819
820 fn set_map(&self, expr: &'m Expr, bounds: &'m [Bound], ctx: &mut Ctx<'m, '_>) -> Result<Value> {
821 let mut out = BTreeSet::new();
822 for binding in self.expand(bounds, ctx)? {
823 let restore = push(ctx, &binding);
824 let v = self.eval(expr, ctx);
825 ctx.locals.truncate(restore);
826 out.insert(v?);
827 }
828 Ok(Value::Set(out))
829 }
830
831 fn record_set(&self, fields: &'m [(String, Expr)], ctx: &mut Ctx<'m, '_>) -> Result<Value> {
832 let mut out: Vec<BTreeMap<String, Value>> = vec![BTreeMap::new()];
833 for (name, domain) in fields {
834 let choices = elements(&self.eval(domain, ctx)?)?;
835 check_size(out.len().saturating_mul(choices.len()), "a record set")?;
836 out = out
837 .into_iter()
838 .flat_map(|partial| {
839 choices.iter().map(move |c| {
840 let mut next = partial.clone();
841 next.insert(name.clone(), c.clone());
842 next
843 })
844 })
845 .collect();
846 }
847 Ok(Value::set(out.into_iter().map(Value::Record)))
848 }
849
850 fn fn_def(&self, bounds: &'m [Bound], body: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
851 let mut entries = BTreeMap::new();
852 for binding in self.expand(bounds, ctx)? {
853 let key = element_of(&binding);
854 let restore = push(ctx, &binding);
855 let v = self.eval(body, ctx);
856 ctx.locals.truncate(restore);
857 entries.insert(key, v?);
858 }
859 Ok(Value::function(entries))
860 }
861
862 fn fn_set(&self, domain: &'m Expr, range: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
863 let keys = elements(&self.eval(domain, ctx)?)?;
864 let range = self.eval(range, ctx)?;
865 let values = elements(&range)?;
866 let count = values
867 .len()
868 .checked_pow(u32::try_from(keys.len()).unwrap_or(u32::MAX))
869 .unwrap_or(usize::MAX);
870 check_size(count, "a function set")?;
871
872 let mut out = BTreeSet::new();
873 for mut index in 0..count {
874 let mut entries = BTreeMap::new();
875 for key in &keys {
876 entries.insert(key.clone(), values[index % values.len()].clone());
877 index /= values.len();
878 }
879 out.insert(Value::function(entries));
880 }
881 if keys.is_empty() {
882 out.insert(Value::Seq(Vec::new()));
883 }
884 Ok(Value::Set(out))
885 }
886
887 fn quantify(
888 &self,
889 kind: QuantKind,
890 bounds: &'m [Bound],
891 body: &'m Expr,
892 ctx: &mut Ctx<'m, '_>,
893 ) -> Result<Value> {
894 let wanted = kind == QuantKind::Exists;
895 for binding in self.expand(bounds, ctx)? {
896 let restore = push(ctx, &binding);
897 let holds = self.eval_bool(body, ctx);
898 ctx.locals.truncate(restore);
899 if holds? == wanted {
900 return Ok(Value::Bool(wanted));
901 }
902 }
903 Ok(Value::Bool(!wanted))
904 }
905
906 fn choose(&self, bound: &'m Bound, body: &'m Expr, ctx: &mut Ctx<'m, '_>) -> Result<Value> {
910 for binding in self.expand(std::slice::from_ref(bound), ctx)? {
911 let restore = push(ctx, &binding);
912 let holds = self.eval_bool(body, ctx);
913 ctx.locals.truncate(restore);
914 if holds? {
915 return Ok(element_of(&binding));
916 }
917 }
918 Err(Error::Malformed(
919 "CHOOSE found no value satisfying its predicate".to_string(),
920 ))
921 }
922
923 pub(crate) fn expand(
927 &self,
928 bounds: &'m [Bound],
929 ctx: &mut Ctx<'m, '_>,
930 ) -> Result<Vec<Vec<(String, Value)>>> {
931 let mut out = Vec::new();
932 let mut current = Vec::new();
933 self.expand_into(bounds, ctx, &mut current, &mut out)?;
934 Ok(out)
935 }
936
937 fn expand_into(
938 &self,
939 bounds: &'m [Bound],
940 ctx: &mut Ctx<'m, '_>,
941 current: &mut Vec<(String, Value)>,
942 out: &mut Vec<Vec<(String, Value)>>,
943 ) -> Result<()> {
944 let Some((first, rest)) = bounds.split_first() else {
945 check_size(out.len() + 1, "a quantifier")?;
946 out.push(current.clone());
947 return Ok(());
948 };
949 let Some(domain) = &first.domain else {
950 return Err(Error::Unbounded(format!(
951 "`{}` is quantified over no set, so it cannot be enumerated",
952 first.names.join(", ")
953 )));
954 };
955 let items = elements(&self.eval(domain, ctx)?)?;
956
957 if first.destructure {
958 for item in items {
959 let Value::Seq(parts) = &item else {
960 return type_error(format!("cannot destructure {item}, which is not a tuple"));
961 };
962 if parts.len() != first.names.len() {
963 return type_error(format!(
964 "cannot destructure {item} into {} names",
965 first.names.len()
966 ));
967 }
968 let restore = ctx.locals.len();
969 for (name, part) in first.names.iter().zip(parts) {
970 current.push((name.clone(), part.clone()));
971 ctx.locals.push((name.clone(), Local::Val(part.clone())));
972 }
973 self.expand_into(rest, ctx, current, out)?;
974 current.truncate(current.len() - first.names.len());
975 ctx.locals.truncate(restore);
976 }
977 return Ok(());
978 }
979 self.product(&first.names, &items, rest, ctx, current, out)
980 }
981
982 fn product(
983 &self,
984 names: &[String],
985 items: &[Value],
986 rest: &'m [Bound],
987 ctx: &mut Ctx<'m, '_>,
988 current: &mut Vec<(String, Value)>,
989 out: &mut Vec<Vec<(String, Value)>>,
990 ) -> Result<()> {
991 let Some((name, more)) = names.split_first() else {
992 return self.expand_into(rest, ctx, current, out);
993 };
994 for item in items {
995 let restore = ctx.locals.len();
996 current.push((name.clone(), item.clone()));
997 ctx.locals.push((name.clone(), Local::Val(item.clone())));
998 self.product(more, items, rest, ctx, current, out)?;
999 current.pop();
1000 ctx.locals.truncate(restore);
1001 }
1002 Ok(())
1003 }
1004
1005 fn update(
1007 &self,
1008 base: Value,
1009 path: &'m [ExceptPath],
1010 rhs: &'m Expr,
1011 ctx: &mut Ctx<'m, '_>,
1012 ) -> Result<Value> {
1013 let Some((step, rest)) = path.split_first() else {
1014 ctx.at.push(base);
1015 let out = self.eval(rhs, ctx);
1016 ctx.at.pop();
1017 return out;
1018 };
1019 let key = match step {
1020 ExceptPath::Index(e) => self.eval(e, ctx)?,
1021 ExceptPath::Field(name) => Value::Str(name.clone()),
1022 };
1023 let old = base
1024 .apply(&key)
1025 .ok_or_else(|| Error::Type(format!("EXCEPT: {base} is not defined at {key}")))?;
1026 let replacement = self.update(old, rest, rhs, ctx)?;
1027 let mut entries = base
1028 .entries()
1029 .ok_or_else(|| Error::Type(format!("EXCEPT: {base} is not a function")))?;
1030 entries.insert(key, replacement);
1031 Ok(Value::function(entries))
1032 }
1033}
1034
1035fn symbol_operator(name: &str) -> Option<Op> {
1037 const CANDIDATES: &[Op] = &[
1038 Op::Plus,
1039 Op::Minus,
1040 Op::Times,
1041 Op::Div,
1042 Op::Mod,
1043 Op::Pow,
1044 Op::Cup,
1045 Op::Cap,
1046 Op::SetMinus,
1047 Op::Concat,
1048 Op::AtAt,
1049 Op::And,
1050 Op::Or,
1051 Op::Eq,
1052 Op::DotDot,
1053 ];
1054 CANDIDATES.iter().copied().find(|op| op.symbol() == name)
1055}
1056
1057fn lookup<'m>(name: &str, ctx: &Ctx<'m, '_>) -> Option<Local<'m>> {
1058 ctx.locals
1059 .iter()
1060 .rev()
1061 .find(|(n, _)| n == name)
1062 .map(|(_, local)| local.clone())
1063}
1064
1065pub(crate) fn push(ctx: &mut Ctx<'_, '_>, binding: &[(String, Value)]) -> usize {
1066 let restore = ctx.locals.len();
1067 for (name, value) in binding {
1068 ctx.locals.push((name.clone(), Local::Val(value.clone())));
1069 }
1070 restore
1071}
1072
1073fn element_of(binding: &[(String, Value)]) -> Value {
1076 if let [(_, only)] = binding {
1077 only.clone()
1078 } else {
1079 Value::Seq(binding.iter().map(|(_, v)| v.clone()).collect())
1080 }
1081}
1082
1083fn powerset(items: &[Value]) -> Result<Value> {
1084 let bits = u32::try_from(items.len()).unwrap_or(u32::MAX);
1085 let count = 1usize.checked_shl(bits).unwrap_or(usize::MAX);
1086 check_size(count, "SUBSET")?;
1087 let mut out = BTreeSet::new();
1088 for mask in 0..count {
1089 out.insert(Value::set(
1090 items
1091 .iter()
1092 .enumerate()
1093 .filter(|(i, _)| mask >> i & 1 == 1)
1094 .map(|(_, v)| v.clone()),
1095 ));
1096 }
1097 Ok(Value::Set(out))
1098}
1099
1100fn check_size(count: usize, what: &str) -> Result<()> {
1101 if count > MAX_ELEMENTS {
1102 return Err(Error::Unbounded(format!(
1103 "{what} would have {count} elements, over the {MAX_ELEMENTS} limit"
1104 )));
1105 }
1106 Ok(())
1107}
1108
1109fn elements(v: &Value) -> Result<Vec<Value>> {
1113 if matches!(v, Value::Infinite(_)) {
1114 return Err(Error::Unbounded(format!("{v} cannot be enumerated")));
1115 }
1116 Ok(set_of(v)?.iter().cloned().collect())
1117}
1118
1119fn member(elem: &Value, set: &Value) -> Result<bool> {
1120 match set {
1121 Value::Set(s) => Ok(s.contains(elem)),
1122 Value::Infinite(Infinite::Nat) => Ok(matches!(elem, Value::Int(n) if *n >= 0)),
1123 Value::Infinite(Infinite::Int) => Ok(matches!(elem, Value::Int(_))),
1124 Value::Infinite(Infinite::Strings) => Ok(matches!(elem, Value::Str(_))),
1125 Value::Infinite(Infinite::Sequences(of)) => {
1126 let Value::Seq(items) = elem else {
1127 return Ok(false);
1128 };
1129 for item in items {
1130 if !member(item, of)? {
1131 return Ok(false);
1132 }
1133 }
1134 Ok(true)
1135 }
1136 other => type_error(format!("\\in expects a set on the right, got {other}")),
1137 }
1138}
1139
1140fn set_of(v: &Value) -> Result<&BTreeSet<Value>> {
1141 match v {
1142 Value::Set(s) => Ok(s),
1143 Value::Infinite(_) => Err(Error::Unbounded(format!(
1144 "{v} cannot take part in a set operation"
1145 ))),
1146 other => type_error(format!(
1147 "expected a set, got {} ({other})",
1148 other.type_name()
1149 )),
1150 }
1151}
1152
1153fn as_int(v: &Value) -> Result<i64> {
1154 match v {
1155 Value::Int(n) => Ok(*n),
1156 other => type_error(format!("expected an integer, got {other}")),
1157 }
1158}
1159
1160fn as_bool(v: &Value) -> Result<bool> {
1161 match v {
1162 Value::Bool(b) => Ok(*b),
1163 other => type_error(format!("expected a boolean, got {other}")),
1164 }
1165}
1166
1167fn arith(a: &Value, b: &Value, f: fn(i64, i64) -> Option<i64>, name: &str) -> Result<Value> {
1168 f(as_int(a)?, as_int(b)?)
1169 .map(Value::Int)
1170 .ok_or_else(|| Error::Type(format!("{a} {name} {b} is undefined or overflows")))
1171}