@informalsystems/quint
Version:
Core tool for the Quint specification language
727 lines • 29.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const mocha_1 = require("mocha");
const chai_1 = require("chai");
const ir_1 = require("../builders/ir");
const IRVisitor_1 = require("../../src/ir/IRVisitor");
const IRprinting_1 = require("../../src/ir/IRprinting");
(0, mocha_1.describe)('walkModule', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)([
'var a: int',
'const B: int',
'type MY_TYPE = int',
'assume _ = N > 1',
'import M.*',
'import A(x = "rainbow") as A1',
'val f = S.filter(x => x + 1)',
'def l = val x = false { x }',
]);
(0, mocha_1.it)('finds expressions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterExpr(expr) {
this.entered.push(expr);
}
exitExpr(expr) {
this.exited.push(expr);
}
}
const enteredExpressions = [
'igt(N, 1)',
'N',
'1',
'"rainbow"',
'filter(S, ((x) => iadd(x, 1)))',
'S',
'((x) => iadd(x, 1))',
'iadd(x, 1)',
'x',
'1',
'val x = false { x }',
'false',
'x',
];
const exitedExpressions = [
'N',
'1',
'igt(N, 1)',
'"rainbow"',
'S',
'x',
'1',
'iadd(x, 1)',
'((x) => iadd(x, 1))',
'filter(S, ((x) => iadd(x, 1)))',
'false',
'x',
'val x = false { x }',
];
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.expressionToString), enteredExpressions);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.expressionToString), exitedExpressions);
});
(0, mocha_1.it)('finds declarations', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterDecl(decl) {
this.entered.push(decl);
}
exitDecl(decl) {
this.exited.push(decl);
}
}
const enteredDeclarations = [
'var a: int',
'const B: int',
'type MY_TYPE = int',
'assume _ = igt(N, 1)',
'import M.*',
'import A(x = "rainbow") as A1',
'val f = filter(S, ((x) => iadd(x, 1)))',
'def l = val x = false { x }',
];
const exitedDeclarations = [
'var a: int',
'const B: int',
'type MY_TYPE = int',
'assume _ = igt(N, 1)',
'import M.*',
'import A(x = "rainbow") as A1',
'val f = filter(S, ((x) => iadd(x, 1)))',
'def l = val x = false { x }',
];
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDeclarations);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDeclarations);
});
(0, mocha_1.it)('finds definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterDef(def) {
this.entered.push(def);
}
exitDef(def) {
this.exited.push(def);
}
}
const enteredDefinitions = [
'var a: int',
'const B: int',
'type MY_TYPE = int',
'assume _ = igt(N, 1)',
'val f = filter(S, ((x) => iadd(x, 1)))',
'def l = val x = false { x }',
'val x = false', // From the let definition
];
const exitedDefinitions = [
'var a: int',
'const B: int',
'type MY_TYPE = int',
'assume _ = igt(N, 1)',
'val f = filter(S, ((x) => iadd(x, 1)))',
'val x = false',
'def l = val x = false { x }',
];
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.definitionToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.definitionToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterType(type) {
this.entered.push(type);
}
exitType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'int',
'int',
'int', // type MY_TYPE = int
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
// assert.deepEqual(visitor.entered.map(typeToString), enteredTypes)
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.describe)('visiting specific definitions', () => {
(0, mocha_1.it)('finds operator definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterOpDef(def) {
this.entered.push(def);
}
exitOpDef(def) {
this.exited.push(def);
}
}
const enteredDefinitions = [
'val f = filter(S, ((x) => iadd(x, 1)))',
'def l = val x = false { x }',
'val x = false', // From the let definition
];
const exitedDefinitions = [
'val f = filter(S, ((x) => iadd(x, 1)))',
'val x = false',
'def l = val x = false { x }',
];
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds constant definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterConst(def) {
this.entered.push(def);
}
exitConst(def) {
this.exited.push(def);
}
}
const enteredDefinitions = ['const B: int'];
const exitedDefinitions = enteredDefinitions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds variable definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterVar(def) {
this.entered.push(def);
}
exitVar(def) {
this.exited.push(def);
}
}
const enteredDefinitions = ['var a: int'];
const exitedDefinitions = enteredDefinitions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds assume definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterAssume(def) {
this.entered.push(def);
}
exitAssume(def) {
this.exited.push(def);
}
}
const enteredDefinitions = ['assume _ = igt(N, 1)'];
const exitedDefinitions = enteredDefinitions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds typedef definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterTypeDef(def) {
this.entered.push(def);
}
exitTypeDef(def) {
this.exited.push(def);
}
}
const enteredDefinitions = ['type MY_TYPE = int'];
const exitedDefinitions = enteredDefinitions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds import definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterImport(def) {
this.entered.push(def);
}
exitImport(def) {
this.exited.push(def);
}
}
const enteredDefinitions = ['import M.*'];
const exitedDefinitions = enteredDefinitions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds instance definitions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterInstance(def) {
this.entered.push(def);
}
exitInstance(def) {
this.exited.push(def);
}
}
const enteredDefinitions = ['import A(x = "rainbow") as A1'];
const exitedDefinitions = enteredDefinitions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(d => (0, IRprinting_1.declarationToString)(d)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(d => (0, IRprinting_1.declarationToString)(d)), exitedDefinitions);
});
(0, mocha_1.it)('finds the module itself', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterModule(module) {
this.entered.push(module);
}
exitModule(module) {
this.exited.push(module);
}
}
const enteredDefinitions = [
`module wrapper {
var a: int
const B: int
type MY_TYPE = int
assume _ = igt(N, 1)
import M.*
import A(x = "rainbow") as A1
val f = filter(S, ((x) => iadd(x, 1)))
def l = val x = false { x }
}`,
];
const exitedDefinitions = enteredDefinitions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(m => (0, IRprinting_1.moduleToString)(m)), enteredDefinitions);
chai_1.assert.deepEqual(visitor.exited.map(m => (0, IRprinting_1.moduleToString)(m)), exitedDefinitions);
});
});
(0, mocha_1.describe)('visiting specific expressions', () => {
(0, mocha_1.it)('finds name expressions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterName(expr) {
this.entered.push(expr);
}
exitName(expr) {
this.exited.push(expr);
}
}
const enteredExpressions = ['N', 'S', 'x', 'x'];
const exitedExpressions = enteredExpressions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.expressionToString), enteredExpressions);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.expressionToString), exitedExpressions);
});
(0, mocha_1.it)('finds literal expressions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterLiteral(expr) {
this.entered.push(expr);
}
exitLiteral(expr) {
this.exited.push(expr);
}
}
const enteredExpressions = ['1', '"rainbow"', '1', 'false'];
const exitedExpressions = enteredExpressions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.expressionToString), enteredExpressions);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.expressionToString), exitedExpressions);
});
(0, mocha_1.it)('finds application expressions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterApp(expr) {
this.entered.push(expr);
}
exitApp(expr) {
this.exited.push(expr);
}
}
const enteredExpressions = ['igt(N, 1)', 'filter(S, ((x) => iadd(x, 1)))', 'iadd(x, 1)'];
const exitedExpressions = ['igt(N, 1)', 'iadd(x, 1)', 'filter(S, ((x) => iadd(x, 1)))'];
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.expressionToString), enteredExpressions);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.expressionToString), exitedExpressions);
});
(0, mocha_1.it)('finds lambda expressions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterLambda(expr) {
this.entered.push(expr);
}
exitLambda(expr) {
this.exited.push(expr);
}
}
const enteredExpressions = ['((x) => iadd(x, 1))'];
const exitedExpressions = enteredExpressions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.expressionToString), enteredExpressions);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.expressionToString), exitedExpressions);
});
(0, mocha_1.it)('finds let expressions', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterLet(expr) {
this.entered.push(expr);
}
exitLet(expr) {
this.exited.push(expr);
}
}
const enteredExpressions = ['val x = false { x }'];
const exitedExpressions = enteredExpressions;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.expressionToString), enteredExpressions);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.expressionToString), exitedExpressions);
});
});
(0, mocha_1.describe)('visiting specific types', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)([
'var a: bool',
'const b: int',
'val c: str = "rainbow"',
'var d: MY_CONST_TYPE',
'var e: a -> Set[a]',
'var f: Set[int]',
'var g: List[Set[str]]',
'var h: (int -> str) -> List[bool]',
'def i: (int, a) => bool = false',
'var j: (int, List[bool], MY_CONST_TYPE)',
'var k: { name: str, age: int }',
]);
(0, mocha_1.it)('finds literal types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterLiteralType(type) {
this.entered.push(type);
}
exitLiteralType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'bool',
'int',
'str',
'int',
'str',
'int',
'str',
'bool',
'int',
'bool',
'int',
'bool',
'str',
'int', // var k: { name: str, age: int }
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds const types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterConstType(type) {
this.entered.push(type);
}
exitConstType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'MY_CONST_TYPE',
'MY_CONST_TYPE', // var j: (int, list(bool), MY_CONST_TYPE)
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds var types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterVarType(type) {
this.entered.push(type);
}
exitVarType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'a',
'a',
'a', // def i: (int, a) => bool = false
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds set types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterSetType(type) {
this.entered.push(type);
}
exitSetType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'Set[a]',
'Set[int]',
'Set[str]', // var g: List[Set[str]]
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds list types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterSeqType(type) {
this.entered.push(type);
}
exitSeqType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'List[Set[str]]',
'List[bool]',
'List[bool]', // var j: (int, List[bool], MY_CONST_TYPE)
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds function types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterFunType(type) {
this.entered.push(type);
}
exitFunType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'(a -> Set[a])',
'((int -> str) -> List[bool])',
'(int -> str)', // var h: (int -> str) -> List[bool]
];
const exitedTypes = [
'(a -> Set[a])',
'(int -> str)',
'((int -> str) -> List[bool])', // var h: (int -> str) -> List[bool]
];
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds operator types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterOperType(type) {
this.entered.push(type);
}
exitOperType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'(int, a) => bool', // def i: (int, a) => bool = false
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds tuple types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterTupleType(type) {
this.entered.push(type);
}
exitTupleType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'(int, List[bool], MY_CONST_TYPE)', // var j: (int, list(bool), MY_CONST_TYPE)
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds record types', () => {
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterRecordType(type) {
this.entered.push(type);
}
exitRecordType(type) {
this.exited.push(type);
}
}
const enteredTypes = [
'{ name: str, age: int }', // var k: { name: str, age: int }
];
const exitedTypes = enteredTypes;
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), enteredTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), exitedTypes);
});
(0, mocha_1.it)('finds type applications', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['val strMap: StrMap[int] = Map("a" -> 1, "b" -> 2)']);
class TestVisitor {
constructor() {
this.entered = [];
this.exited = [];
}
enterAppType(type) {
this.entered.push(type);
}
exitAppType(type) {
this.exited.push(type);
}
}
const expectedTypes = ['StrMap[int]'];
const visitor = new TestVisitor();
(0, IRVisitor_1.walkModule)(visitor, quintModule);
chai_1.assert.deepEqual(visitor.entered.map(IRprinting_1.typeToString), expectedTypes);
chai_1.assert.deepEqual(visitor.exited.map(IRprinting_1.typeToString), expectedTypes);
});
(0, mocha_1.it)('finds parameter type annotations', () => {
class TestVisitor {
constructor() {
this.typesVisited = [];
}
exitType(t) {
this.typesVisited.push(t);
}
}
const visitor = new TestVisitor();
const m = (0, ir_1.buildModuleWithDecls)(['def foo(x: int, b: str): bool = true']);
(0, IRVisitor_1.walkModule)(visitor, m);
const actualTypes = visitor.typesVisited.map(IRprinting_1.typeToString);
// `int` and `str` should each show up TWICE:
// - once from of the lambda type annotations
// - once from of the parameter type annotation
const expectedTypes = ['int', 'str', 'bool', '(int, str) => bool', 'int', 'str'];
chai_1.assert.deepEqual(actualTypes, expectedTypes);
});
});
});
//# sourceMappingURL=IRVisitor.test.js.map