Skip to main content

tla_eval/
eval.rs

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
11/// Nothing enumerable is materialized beyond this many elements. The bound
12/// exists so a `SUBSET` or `[S -> T]` over an unexpectedly large set reports a
13/// limit instead of exhausting memory.
14pub const MAX_ELEMENTS: usize = 1 << 20;
15
16const MAX_DEPTH: usize = 512;
17
18/// A binding of every variable the specification declares.
19pub 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/// What a name in scope stands for.
28///
29/// A parameter declared `f(_)` is an operator, not a value, so what it binds to
30/// has to be something that can be *applied* — and TLA+ lets that be any of
31/// four things.
32#[derive(Clone)]
33pub(crate) enum Local<'m> {
34    Val(Value),
35    /// A `LET` definition, together with how much of the local stack it may
36    /// see — everything pushed after that is the caller's, not its own.
37    Def {
38        def: &'m Def,
39        scope: usize,
40    },
41    /// A `LAMBDA`, or a definition passed by name.
42    Closure {
43        params: &'m [Param],
44        body: &'m Expr,
45        scope: usize,
46    },
47    /// An operator symbol passed by itself, as in `FoldSet(+, 0, S)`.
48    Symbol(Op),
49    /// An operator of a standard module passed by name, as in `FoldSet(Len, ...)`.
50    Builtin(String),
51    /// What an instantiated module's declared name stands for. Held as an
52    /// expression rather than a value because priming has to reach through it:
53    /// under `x <- y`, an `x'` inside the instance means `y'`.
54    Subst {
55        expr: &'m Expr,
56        module: usize,
57        scope: usize,
58    },
59}
60
61pub(crate) struct Ctx<'m, 'a> {
62    /// The module whose scope names are read in. Evaluating an instantiated
63    /// definition moves it, which is what makes `S!Op` mean `Op` as written in
64    /// the instantiated module rather than here.
65    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    /// Every declared constant must be given a value; a specification with a
76    /// free constant has no determinate meaning at a state.
77    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    /// Does the named state predicate hold at `state`?
92    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    /// Is `from -> to` a step the named action permits?
98    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    // ------------------------------------------------------------ evaluation
140
141    #[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            // `[A]_v` is `A \/ UNCHANGED v`, which one step decides.
236            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            // An instance's declared name can itself be an operator, so an
352            // application of it applies whatever it stands for.
353            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    /// An operator symbol used as a value: `+` in `FoldSet(+, 0, S)`.
392    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    /// Call a definition with argument *expressions*, so that an argument for
408    /// an operator parameter is bound rather than evaluated.
409    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    /// What an argument means when the parameter it fills is an operator.
463    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    /// Read the rest of this expression in another module's scope.
496    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    /// A declared name of an instantiated module, which stands for whatever
509    /// the `WITH` clause put in its place — read back where the instance was
510    /// written, and under the prime in force here.
511    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    /// `S!Op(args)`: `Op` as written in the module `S` instantiates, with that
528    /// module's declared names standing for what `S` substituted for them.
529    fn qualified(
530        &self,
531        instance: &str,
532        name: &str,
533        args: &'m [Expr],
534        ctx: &mut Ctx<'m, '_>,
535    ) -> Result<Value> {
536        // `A!B!C` names a chain of instances; each step moves into the next.
537        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        // The substituting expressions belong to the scope the instance was
560        // written in, so they are bound before the arguments are read.
561        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    /// Evaluate a body with its parameters bound and the caller's locals
584    /// hidden, which is the one rule operator application has to follow.
585    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    // -------------------------------------------------------------- operators
631
632    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        // The propositional connectives must not evaluate their right operand
685        // when the left already decides the answer: a guard like
686        // `Len(buf) > 0 /\ Head(buf) = x` relies on it.
687        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        // `\prec`, `\oplus`, `&` and the rest have a symbol and a precedence
706        // but no meaning until a specification gives them one.
707        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
719/// The operators whose meaning depends only on their operands' values.
720fn 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    // ----------------------------------------------------------------- sets
806
807    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    /// `CHOOSE` must be deterministic: the same set and predicate always give
907    /// the same answer. Taking the least satisfying element in the value order
908    /// is one such rule, and sets are already held in that order.
909    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    /// All the ways the bound variables can be assigned. A later bound's
924    /// domain may mention an earlier bound's variable, so they are evaluated
925    /// with the bindings so far in scope.
926    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    /// One `![a][b] = e` update. `@` inside `e` is the value being replaced.
1006    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
1035/// The operator a bare symbol names, for `FoldSet(+, 0, S)`.
1036fn 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
1073/// The value a binding contributes to a set or a function's domain: the single
1074/// bound variable, or the tuple of them.
1075fn 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
1109/// Every member of a set, for the operations that have to visit them all.
1110/// Membership of an infinite set is decidable where enumeration is not, so the
1111/// two failures are reported differently.
1112fn 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}