UNPKG

@informalsystems/quint

Version:

Core tool for the Quint specification language

164 lines 6.34 kB
"use strict"; /* ---------------------------------------------------------------------------------- * Copyright 2022-2024 Informal Systems * Licensed under the Apache License, Version 2.0. * See LICENSE in the project root for license information. * --------------------------------------------------------------------------------- */ Object.defineProperty(exports, "__esModule", { value: true }); exports.VarStorage = exports.initialRegisterValue = void 0; /** * A storage to keep track of Quint state variables in the current and next state. * * @author Gabriela Moreira * * @module */ const either_1 = require("@sweet-monads/either"); const runtimeValue_1 = require("./runtimeValue"); const immutable_1 = require("immutable"); const itf_1 = require("../../itf"); /** * Initializes the register value for a given variable name. * * @param name - The name of the variable to initialize, to be used in error messages * @returns a QuintError indicating the variable is not set */ function initialRegisterValue(name) { return (0, either_1.left)({ code: 'QNT502', message: `Variable ${name} not set` }); } exports.initialRegisterValue = initialRegisterValue; /** * A storage to keep track of Quint state variables in the current and next state. */ class VarStorage { /** * Constructs a new VarStorage instance. * * @param storeMetadata - Indicates whether to store metadata. * @param nondetPicks - Non-deterministic picks and their values for the current step. Should be the one constructed in the builder. */ constructor(storeMetadata, nondetPicks) { /** * An immutable map with registers for the current state variables. */ this.vars = (0, immutable_1.Map)(); /** * An immutable map with registers for the next state variables. */ this.nextVars = (0, immutable_1.Map)(); /** * Non-deterministic picks and their values for the current step. */ this.nondetPicks = new Map(); /** * Cached values that need to be cleared when shifting. */ this.cachesToClear = []; this.storeMetadata = storeMetadata; this.nondetPicks = nondetPicks; } /** * Shifts the current state variables to the next state variables. * This method updates the current state variable registers with the values * from the next state variable registers, initializes the next state variable * registers, and clears cached values. */ shiftVars() { this.vars.forEach((reg, key) => { reg.value = this.nextVars.get(key)?.value ?? initialRegisterValue(reg.name); }); this.nextVars.forEach(reg => (reg.value = initialRegisterValue(reg.name))); this.clearCaches(); } /** * Converts the current state variables and metadata into a RuntimeValue record. * * @returns A RuntimeValue representing the current state variables and metadata. */ asRecord() { const map = this.vars .valueSeq() .toArray() .filter(r => r.value.isRight()) .map(r => [r.name, r.value.unwrap()]); if (this.storeMetadata) { const nondetPicksRecord = runtimeValue_1.rv.mkRecord([...this.nondetPicks.entries()].map(([name, value]) => { const valueVariant = value ? runtimeValue_1.rv.mkVariant('Some', value) : runtimeValue_1.rv.mkVariant('None', runtimeValue_1.rv.mkTuple([])); return [name, valueVariant]; })); map.push([itf_1.NONDET_PICKS, nondetPicksRecord]); map.push([itf_1.ACTION_TAKEN, runtimeValue_1.rv.mkStr(this.actionTaken ?? '')]); } return runtimeValue_1.rv.mkRecord(map); } fromRecord(record) { this.reset(); record.toOrderedMap().forEach((value, key) => { const regToSet = this.vars .valueSeq() .toArray() .find(r => r.name === key); if (regToSet != undefined) { regToSet.value = (0, either_1.right)(value); } else if (key === itf_1.NONDET_PICKS && this.storeMetadata) { value.toOrderedMap().forEach((v, k) => { this.nondetPicks.set(k, v.toVariant()[0] == 'None' ? undefined : v); }); } else if (key === itf_1.ACTION_TAKEN && this.storeMetadata) { this.actionTaken = value.toStr(); } }); this.clearCaches(); } /** * Resets the current and next state variable registers to their initial values. * This method sets the value of each register in both the current and next state * variable maps to an undefined (error) value. */ reset() { this.vars.forEach(reg => (reg.value = initialRegisterValue(reg.name))); this.nextVars.forEach(reg => (reg.value = initialRegisterValue(reg.name))); if (this.storeMetadata) { this.actionTaken = undefined; this.nondetPicks.forEach((_, key) => { this.nondetPicks.set(key, undefined); }); } } /** * Creates a snapshot of the current state of the VarStorage, with the relevant information to backtrack. * @returns A snapshot of the current state of the VarStorage. */ snapshot() { return { nextVars: this.nextVars.map(reg => ({ ...reg })), nondetPicks: new Map(this.nondetPicks), actionTaken: this.actionTaken, }; } /** * Recovers the state of the VarStorage from a snapshot. * * @param snapshot - the snapshot to recover the state from */ recoverSnapshot(snapshot) { this.nextVars.forEach((reg, key) => { const snapshotReg = snapshot.nextVars.get(key); if (snapshotReg) { reg.value = snapshotReg.value; } }); this.nondetPicks = snapshot.nondetPicks; this.actionTaken = snapshot.actionTaken; } clearCaches() { this.cachesToClear.forEach(cachedValue => { cachedValue.value = undefined; }); } } exports.VarStorage = VarStorage; //# sourceMappingURL=VarStorage.js.map