@informalsystems/quint
Version:
Core tool for the Quint specification language
132 lines • 8.06 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const mocha_1 = require("mocha");
const flattener_1 = require("../../src/flattening/flattener");
const IRprinting_1 = require("../../src/ir/IRprinting");
const idGenerator_1 = require("../../src/idGenerator");
const quintParserFrontend_1 = require("../../src/parsing/quintParserFrontend");
(0, mocha_1.describe)('flattenModule', () => {
function getFlatennedDecls(baseDecls, decls, thirdModuleDecls, moduleToCheck = 'B') {
const idGenerator = (0, idGenerator_1.newIdGenerator)();
const fake_path = { normalizedPath: 'fake_path', toSourceName: () => 'fake_path' };
const quintModules = `module A { ${baseDecls.join('\n')} } module B { ${decls.join('\n')} } module C { ${thirdModuleDecls.join('\n')} }`;
const { modules, table, errors } = (0, quintParserFrontend_1.parse)(idGenerator, 'fake_location', fake_path, quintModules);
chai_1.assert.isEmpty(errors, 'Failed to parse mocked up module');
const modulesByName = new Map(modules.map(m => [m.name, m]));
modules.forEach(m => {
const flattenedModule = (0, flattener_1.flattenModule)(m, modulesByName, table);
modulesByName.set(m.name, flattenedModule);
});
const flattenedModule = modulesByName.get(moduleToCheck);
return flattenedModule.declarations.map(decl => (0, IRprinting_1.declarationToString)(decl));
}
(0, mocha_1.it)('flattens simple import', () => {
const baseDecls = ['def f(x) = x + 1'];
const decls = ['import A.*', 'def g(x) = f(x)'];
const expectedDecls = ['def f = ((x) => iadd(x, 1))', 'def g = ((x) => f(x))'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, []);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('flattens import with qualifier', () => {
const baseDecls = ['def f(x) = x + 1'];
const decls = ['import A as MyA', 'val a = MyA::f(1)'];
const expectedDecls = ['def MyA::f = ((MyA::x) => iadd(MyA::x, 1))', 'val a = MyA::f(1)'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, []);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('flattens import with self-qualifier', () => {
const baseDecls = ['def f(x) = x + 1'];
const decls = ['import A', 'val a = A::f(1)'];
const expectedDecls = ['def A::f = ((A::x) => iadd(A::x, 1))', 'val a = A::f(1)'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, []);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('flattens export with previous import without definitions being used', () => {
const baseDecls = ['def f(x) = x + 1'];
// No definition from A is used here
const decls = ['import A.*', 'export A.*'];
const thirdModuleDecls = ['import B.*', 'val a = f(1)'];
const expectedDecls = ['def f = ((x) => iadd(x, 1))'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, thirdModuleDecls);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('flattens export with previous import with used definition', () => {
const baseDecls = ['def f(x) = x + 1'];
const decls = ['import A.*', 'val a = f(2)', 'export A.*'];
const thirdModuleDecls = ['import B.*', 'val b = f(1)'];
const expectedDecls = ['def f = ((x) => iadd(x, 1))', 'val a = f(2)'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, thirdModuleDecls);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('flattens export without previous import', () => {
const baseDecls = ['def f(x) = x + 1'];
const decls = ['export A.*'];
const thirdModuleDecls = ['import B.*', 'val a = f(1)'];
const expectedDecls = ['def f = ((x) => iadd(x, 1))'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, thirdModuleDecls);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('does not flatten definitions that come from instance', () => {
const baseDecls = ['const N: int', 'def f(x) = x + 1'];
const decls = ['import A(N = 1) as A1', 'val a = A1::f(1)'];
const expectedDecls = decls;
const flattenedDecls = getFlatennedDecls(baseDecls, decls, []);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('flattens export qualified module with no qualifier', () => {
const baseDecls = ['def f(x) = x + 1'];
const decls = ['import A as MyA', 'export MyA.*'];
const thirdModuleDecls = ['import B.*', 'val a = f(1)'];
const expectedDecls = ['def f = ((x) => iadd(x, 1))'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, thirdModuleDecls);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('flattens export instance with no qualifier', () => {
// I was not able to make this scenario work in the PoC, not with interactions with the instance flattener.
// In #1102, we should make sure a proper error is raised in the export + import combinatinos we do not support.
// Alternatively (and at some point), we could support this scenario.
const baseDecls = ['const N: int', 'def f(x) = x + 1'];
const decls = ['import A(N = 1) as A1', 'export A1.*'];
const thirdModuleDecls = ['import B.*', 'val a = f(1)'];
const expectedDecls = ['import A(N = 1) as A1', 'def f = ((x) => iadd(x, 1))', 'const N: int'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, thirdModuleDecls);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('imports definitions recursively when there are dependencies', () => {
const baseDecls = ['val z = 3', 'def f(x) = x + z'];
const decls = ['import A as MyA', 'val a = MyA::f(1)'];
const expectedDecls = ['val MyA::z = 3', 'def MyA::f = ((MyA::x) => iadd(MyA::x, MyA::z))', 'val a = MyA::f(1)'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, []);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('imports definitions recursively when there are dependencies in single def import', () => {
const baseDecls = ['val z = 3', 'def f(x) = x + z'];
const decls = ['import A.f', 'val a = f(1)'];
const expectedDecls = ['val z = 3', 'def f = ((x) => iadd(x, z))', 'val a = f(1)'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, []);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('does not create conflicts', () => {
const baseDecls = ['val z = val x = 3 { x }', 'def f(x) = x + z', 'val y = 1'];
const decls = ['import A.f', 'val a = def g = f { g(1) }', 'export A.*'];
const thirdModuleDecls = ['import B.*', 'val b = z + y'];
const expectedDecls = [
'val z = val x = 3 { x }',
'def f = ((x) => iadd(x, z))',
'val y = 1',
'val a = def g = f { g(1) }',
];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, thirdModuleDecls);
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
(0, mocha_1.it)('can have definitions with same id but different name (#1141)', () => {
const baseDecls = ['val a = 1'];
const decls = ['import A.*', 'val b = a'];
const thirdModuleDecls = ['import A.*', 'import B', 'val c = a + B::b'];
const expectedDecls = ['val a = 1', 'val B::a = 1', 'val B::b = B::a', 'val c = iadd(a, B::b)'];
const flattenedDecls = getFlatennedDecls(baseDecls, decls, thirdModuleDecls, 'C');
chai_1.assert.deepEqual(flattenedDecls, expectedDecls);
});
});
//# sourceMappingURL=flattener.test.js.map