@informalsystems/quint
Version:
Core tool for the Quint specification language
178 lines • 7.55 kB
JavaScript
;
/* ----------------------------------------------------------------------------------
* Copyright 2022 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.getSignatures = void 0;
/**
* Type signatures for built-in operators
*
* @author Gabriela Moreira
*
* @module
*/
const parser_1 = require("./parser");
const quintTypes_1 = require("../ir/quintTypes");
const lodash_1 = require("lodash");
function getSignatures() {
return new Map(fixedAritySignatures.concat(multipleAritySignatures));
}
exports.getSignatures = getSignatures;
// NOTE: Signatures operations over products (records and tuples) and sums
// (enums/disjoint unions/variants) cannot be precisely defined with this
// syntax, because they are "exotic", in the sense that they represent basic
// language constructions that cannot be represented in the type system of the
// language itself.
//
// Their types are handled directly with constraints in specialConstraints.ts.
const literals = [
{ name: 'Nat', type: 'Set[int]' },
{ name: 'Int', type: 'Set[int]' },
{ name: 'Bool', type: 'Set[bool]' },
];
const booleanOperators = [
{ name: 'eq', type: '(a, a) => bool' },
{ name: 'neq', type: '(a, a) => bool' },
{ name: 'iff', type: '(bool, bool) => bool' },
{ name: 'implies', type: '(bool, bool) => bool' },
{ name: 'not', type: '(bool) => bool' },
];
const setOperators = [
{ name: 'exists', type: '(Set[a], (a) => bool) => bool' },
{ name: 'forall', type: '(Set[a], (a) => bool) => bool' },
{ name: 'in', type: '(a, Set[a]) => bool' },
{ name: 'contains', type: '(Set[a], a) => bool' },
{ name: 'union', type: '(Set[a], Set[a]) => Set[a]' },
{ name: 'intersect', type: '(Set[a], Set[a]) => Set[a]' },
{ name: 'exclude', type: '(Set[a], Set[a]) => Set[a]' },
{ name: 'subseteq', type: '(Set[a], Set[a]) => bool' },
{ name: 'filter', type: '(Set[a], (a) => bool) => Set[a]' },
{ name: 'map', type: '(Set[a], (a) => b) => Set[b]' },
{ name: 'fold', type: '(Set[a], b, (b, a) => b) => b' },
{ name: 'powerset', type: '(Set[a]) => Set[Set[a]]' },
{ name: 'flatten', type: '(Set[Set[a]]) => Set[a]' },
{ name: 'allLists', type: '(Set[a]) => Set[List[a]]' },
{ name: 'allListsUpTo', type: '(Set[a], int) => Set[List[a]]' },
{ name: 'getOnlyElement', type: '(Set[a]) => a' },
{ name: 'chooseSome', type: '(Set[a]) => a' },
{ name: 'oneOf', type: '(Set[a]) => a' },
{ name: 'isFinite', type: '(Set[a]) => bool' },
{ name: 'size', type: '(Set[a]) => int' },
];
const mapOperators = [
{ name: 'get', type: '(a -> b, a) => b' },
{ name: 'keys', type: '(a -> b) => Set[a]' },
{ name: 'mapBy', type: '(Set[a], (a) => b) => a -> b' },
{ name: 'setToMap', type: '(Set[(a, b)]) => (a -> b)' },
{ name: 'setOfMaps', type: '(Set[a], Set[b]) => Set[a -> b]' },
{ name: 'set', type: '(a -> b, a, b) => a -> b' },
{ name: 'setBy', type: '(a -> b, a, (b) => b) => a -> b' },
{ name: 'put', type: '(a -> b, a, b) => a -> b' },
];
const listOperators = [
{ name: 'append', type: '(List[a], a) => List[a]' },
{ name: 'concat', type: '(List[a], List[a]) => List[a]' },
{ name: 'head', type: '(List[a]) => a' },
{ name: 'tail', type: '(List[a]) => List[a]' },
{ name: 'length', type: '(List[a]) => int' },
{ name: 'nth', type: '(List[a], int) => a' },
{ name: 'indices', type: '(List[a]) => Set[int]' },
{ name: 'replaceAt', type: '(List[a], int, a) => List[a]' },
{ name: 'slice', type: '(List[a], int, int) => List[a]' },
{ name: 'range', type: '(int, int) => List[int]' },
{ name: 'select', type: '(List[a], (a) => bool) => List[a]' },
{ name: 'foldl', type: '(List[a], b, (b, a) => b) => b' },
{ name: 'foldr', type: '(List[a], b, (a, b) => b) => b' },
];
const integerOperators = [
{ name: 'iadd', type: '(int, int) => int' },
{ name: 'isub', type: '(int, int) => int' },
{ name: 'imul', type: '(int, int) => int' },
{ name: 'idiv', type: '(int, int) => int' },
{ name: 'imod', type: '(int, int) => int' },
{ name: 'ipow', type: '(int, int) => int' },
{ name: 'ilt', type: '(int, int) => bool' },
{ name: 'igt', type: '(int, int) => bool' },
{ name: 'ilte', type: '(int, int) => bool' },
{ name: 'igte', type: '(int, int) => bool' },
{ name: 'to', type: '(int, int) => Set[int]' },
{ name: 'iuminus', type: '(int) => int' },
];
const temporalOperators = [
{ name: 'always', type: '(bool) => bool' },
{ name: 'eventually', type: '(bool) => bool' },
{ name: 'next', type: '(a) => a' },
{ name: 'orKeep', type: '(bool, a) => bool' },
{ name: 'mustChange', type: '(bool, a) => bool' },
// Should we do this? https://github.com/informalsystems/quint/discussions/109
{ name: 'enabled', type: '(bool) => bool' },
{ name: 'weakFair', type: '(bool, a) => bool' },
{ name: 'strongFair', type: '(bool, a) => bool' },
];
const otherOperators = [
{ name: 'assign', type: '(a, a) => bool' },
{ name: 'ite', type: '(bool, a, a) => a' },
{ name: 'then', type: '(bool, bool) => bool' },
{ name: 'expect', type: '(bool, bool) => bool' },
{ name: 'reps', type: '(int, int => bool) => bool' },
{ name: 'fail', type: '(bool) => bool' },
{ name: 'assert', type: '(bool) => bool' },
{ name: 'q::debug', type: '(str, a) => a' },
{ name: 'q::lastTrace', type: 'List[a]' },
{ name: 'q::test', type: '(int, int, int, bool, bool, bool) => bool' },
{ name: 'q::testOnce', type: '(int, int, bool, bool, bool) => bool' },
{ name: 'apalache::generate', type: '(int) => a' },
];
function uniformArgsWithResult(argsType, resultType) {
return (arity) => {
const args = (0, lodash_1.times)(arity, () => argsType);
return parseAndQuantify(`(${args.join(', ')}) => ${resultType}`);
};
}
const multipleAritySignatures = [
['List', uniformArgsWithResult('a', 'List[a]')],
['Set', uniformArgsWithResult('a', 'Set[a]')],
['Map', uniformArgsWithResult('(a, b)', 'a -> b')],
['and', uniformArgsWithResult('bool', 'bool')],
['actionAll', uniformArgsWithResult('bool', 'bool')],
['or', uniformArgsWithResult('bool', 'bool')],
['actionAny', uniformArgsWithResult('bool', 'bool')],
[
'matchVariant',
(arity) => {
const args = (0, lodash_1.times)((arity - 1) / 2, () => 'str, (a) => b');
return parseAndQuantify(`(a, ${args.join(', ')}) => b`);
},
],
[
'tuples',
(arity) => {
const ts = (0, lodash_1.times)(arity, i => `t${i}`);
const args = ts.map(t => `Set[${t}]`);
const tupleType = `(${ts.join(', ')})`;
return parseAndQuantify(`(${args.join(', ')}) => Set[${tupleType}]`);
},
],
];
const fixedAritySignatures = [
literals,
booleanOperators,
setOperators,
mapOperators,
listOperators,
integerOperators,
temporalOperators,
otherOperators,
]
.flat()
.map(sig => [sig.name, (_) => parseAndQuantify(sig.type)]);
function parseAndQuantify(typeString) {
const t = (0, parser_1.parseTypeOrThrow)(typeString);
return {
type: t,
...(0, quintTypes_1.typeNames)(t),
};
}
//# sourceMappingURL=builtinSignatures.js.map