@informalsystems/quint
Version:
Core tool for the Quint specification language
100 lines • 5.19 kB
JavaScript
;
/* ----------------------------------------------------------------------------------
* Copyright 2023 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.analyzeInc = exports.analyzeModules = void 0;
const inferrer_1 = require("./types/inferrer");
const inferrer_2 = require("./effects/inferrer");
const modeChecker_1 = require("./effects/modeChecker");
const errorTree_1 = require("./errorTree");
const MultipleUpdatesChecker_1 = require("./effects/MultipleUpdatesChecker");
const typeApplicationResolution_1 = require("./types/typeApplicationResolution");
const NondetChecker_1 = require("./effects/NondetChecker");
/**
* Analyzes multiple Quint modules and returns the analysis result.
*
* NOTE: This is modifies the `lookupTable` and the `quintModules`!
* See XXX for the mutation sites.
*
* @param lookupTable - The lookup tables for the modules.
* @param quintModules - The Quint modules to be analyzed.
* @returns A tuple with a list of errors and the analysis output.
*/
function analyzeModules(lookupTable, quintModules) {
const analyzer = new QuintAnalyzer(lookupTable);
// XXX: the modules are mutated here.
quintModules.forEach(m => (m.declarations = analyzer.analyzeDeclarations(m.declarations)));
return analyzer.getResult();
}
exports.analyzeModules = analyzeModules;
/**
* Analyzes declarations incrementally and returns the analysis result.
*
* NOTE: This is modifies the `lookupTable`!
* See XXX for the mutation sites.
*
* @param analysisOutput - The previous analysis output to be used as a starting point.
* @param lookupTable - The lookup tables for the modules.
* @param declarations - The Quint declarations to be analyzed.
* @returns A tuple with a list of errors and the analysis output.
*/
function analyzeInc(analysisOutput, lookupTable, declarations) {
const analyzer = new QuintAnalyzer(lookupTable, analysisOutput);
analyzer.analyzeDeclarations(declarations);
return analyzer.getResult();
}
exports.analyzeInc = analyzeInc;
/**
* Statically analyzes a Quint specification.
*
* This class is stateful and accumulates analyzed data for multiple modules.
* Use it by calling the analyze method for each module and then calling the
* getResult method to get the analysis result.
*
* @param lookupTable - The lookup tables for the modules.
* @param previousOutput - The previous analysis output to be used as a starting point.
*/
class QuintAnalyzer {
constructor(lookupTable, previousOutput) {
this.errors = [];
this.output = { types: new Map(), effects: new Map(), modes: new Map() };
// XXX: the lookUp table is mutated when TypeApplicationResolver is instantiated
this.typeApplicationResolver = new typeApplicationResolution_1.TypeApplicationResolver(lookupTable);
this.typeInferrer = new inferrer_1.TypeInferrer(lookupTable, previousOutput?.types);
// FIXES: https://github.com/informalsystems/quint/issues/428
this.effectInferrer = new inferrer_2.EffectInferrer(lookupTable, new Map([...(previousOutput?.effects.entries() ?? [])]));
this.multipleUpdatesChecker = new MultipleUpdatesChecker_1.MultipleUpdatesChecker();
this.modeChecker = new modeChecker_1.ModeChecker(previousOutput?.modes);
this.nondetChecker = new NondetChecker_1.NondetChecker(lookupTable);
}
analyzeDeclarations(decls) {
const [typAppErrMap, resolvedDecls] = this.typeApplicationResolver.resolveTypeApplications(decls);
// XXX: the lookUp table is mutated during type inference
const [typeErrMap, types] = this.typeInferrer.inferTypes(resolvedDecls);
const [effectErrMap, effects] = this.effectInferrer.inferEffects(resolvedDecls);
const updatesErrMap = this.multipleUpdatesChecker.checkEffects([...effects.values()]);
const nondetErrors = this.nondetChecker.checkNondets(types, resolvedDecls);
const [modeErrMap, modes] = this.modeChecker.checkModes(resolvedDecls, effects);
const errorTrees = [...typeErrMap, ...effectErrMap, ...typAppErrMap];
// TODO: Type and effect checking should return QuintErrors instead of error trees
this.errors.push(...errorTrees.map(([id, err]) => {
return { code: 'QNT000', message: (0, errorTree_1.errorTreeToString)(err), reference: id, data: { trace: err } };
}));
this.errors.push(...modeErrMap.values(), ...updatesErrMap.values(), ...nondetErrors);
// We assume that ids are unique across modules, and map merging can be done
// without collision checks
this.output = {
types: new Map([...this.output.types, ...types]),
effects: new Map([...this.output.effects, ...effects]),
modes: new Map([...this.output.modes, ...modes]),
};
return resolvedDecls;
}
getResult() {
return [this.errors, this.output];
}
}
//# sourceMappingURL=quintAnalyzer.js.map