UNPKG

@informalsystems/quint

Version:

Core tool for the Quint specification language

141 lines 4.91 kB
"use strict"; /* ---------------------------------------------------------------------------------- * Copyright 2025 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.convertInit = void 0; /** * Convert init definitions to predicates to be compatible with TLA+. * Returns errors if some action is re-used between init and step, as that would require generating new actions. * We ask for user intervention in such edge cases. * * @author Gabriela Moreira * * @module */ const either_1 = require("@sweet-monads/either"); const IRTransformer_1 = require("./IRTransformer"); const IRVisitor_1 = require("./IRVisitor"); /** * Converts the action named as "q::init" and all its dependencies to * predicates (transforming assignments into equalities). If one of the * converted dependencies is also used outside of init, this produces an error * as that case would be more complicated to handle. * * @param module: the module with the init definition and its dependencies * @param lookupTable: the lookup table for the module * @param modes: the result of mode checking the module * * @returns The converted module, or errors instructing manual fix. */ function convertInit(module, lookupTable, modes) { const defsFinder = new InitDefsFinder(lookupTable); (0, IRVisitor_1.walkModule)(defsFinder, module); const converter = new InitConverter(defsFinder.insideInitDefs, lookupTable, modes); const convertedModule = (0, IRTransformer_1.transformModule)(converter, module); if (converter.errors.length > 0) { return (0, either_1.left)(converter.errors); } else { return (0, either_1.right)(convertedModule); } } exports.convertInit = convertInit; class InitDefsFinder { constructor(lookupTable) { this.insideInitDefs = ['q::init']; this.insideInit = 0; this.lookupTable = lookupTable; } enterDef(def) { if (this.insideInitDefs.includes(def.name)) { this.insideInit++; } } exitDef(def) { if (this.insideInitDefs.includes(def.name)) { this.insideInit--; } } enterName(expr) { if (this.insideInit > 0) { const def = this.lookupTable.get(expr.id); if (!def || def.kind != 'def') { return; } this.insideInitDefs.push(expr.name); (0, IRVisitor_1.walkDefinition)(this, def); } } enterApp(app) { if (this.insideInit > 0) { const def = this.lookupTable.get(app.id); if (!def || def.kind != 'def') { return; } this.insideInitDefs.push(app.opcode); (0, IRVisitor_1.walkDefinition)(this, def); } } } class InitConverter { constructor(insideInitDefs, lookupTable, modes) { this.errors = []; this.insideInit = 0; this.insideInitDefs = insideInitDefs; this.lookupTable = lookupTable; this.modes = modes; } enterDef(def) { if (this.insideInitDefs.includes(def.name)) { this.insideInit++; } return def; } exitDef(def) { if (this.insideInitDefs.includes(def.name)) { this.insideInit--; } return def; } enterApp(app) { this.checkMixedUsage(app.id, app.opcode); if (this.insideInit && app.opcode == 'assign') { return { ...app, opcode: 'eq' }; } return app; } enterName(expr) { this.checkMixedUsage(expr.id, expr.name); return expr; } checkMixedUsage(id, name) { if (this.insideInit == 0 && this.insideInitDefs.includes(name) && this.hasAssignment(id)) { this.errors.push({ code: 'QNT409', message: `Action ${name} is used both for init and for step, and therefore can't be converted into TLA+. You can duplicate this with a different name to use on init. Sorry Quint can't do it for you yet.`, reference: id, }); } } hasAssignment(id) { const def = this.lookupTable.get(id); if (!def) { return false; } const mode = this.modes.get(def.id); if (mode == 'action') { // The mode checker says the mode should be action return true; } if (mode == undefined) { // The mode checker doesn't have suggestions, so the annotation is correct return def.kind == 'def' && def.qualifier == 'action'; } // Mode is not action return false; } } //# sourceMappingURL=initToPredicate.js.map