UNPKG

@informalsystems/quint

Version:

Core tool for the Quint specification language

727 lines 29.5 kB
"use strict"; 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