@informalsystems/quint
Version:
Core tool for the Quint specification language
433 lines • 13.9 kB
JavaScript
;
/* ----------------------------------------------------------------------------------
* Copyright 2022 Informal Systems
* Licensed under the Apache License, Version 2.0.
* See LICENSE in the project root for license information.
* --------------------------------------------------------------------------------- */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.walkExpression = exports.walkDefinition = exports.walkDeclaration = exports.walkType = exports.walkModule = void 0;
/**
* Visitor pattern implementation for Quint IR components. Use this to navigate the IR instead
* of implementing a recursion over it yourself.
*
* @author Gabriela Moreira
*
* @module
*/
const ir = __importStar(require("./quintIr"));
const util_1 = require("../util");
/**
* Navigates a Quint module with a visitor, invoking the correspondent function for each
* found IR component.
*
* @param visitor: the IRVisitor instance with the functions to be invoked
* @param quintModule: the Quint module to be navigated
*
* @returns nothing, any collected information has to be a state inside the IRVisitor instance.
*/
function walkModule(visitor, quintModule) {
if (visitor.enterModule) {
visitor.enterModule(quintModule);
}
quintModule.declarations.forEach(decl => walkDeclaration(visitor, decl));
if (visitor.exitModule) {
visitor.exitModule(quintModule);
}
}
exports.walkModule = walkModule;
/**
* Navigates a Quint type with a visitor, invoking the correspondent function for each
* inner type.
*
* @param visitor: the IRVisitor instance with the functions to be invoked
* @param type: the Quint type to be navigated
*
* @returns nothing, any collected information has to be a state inside the IRVisitor instance.
*/
function walkType(visitor, type) {
if (visitor.enterType) {
visitor.enterType(type);
}
switch (type.kind) {
case 'bool':
case 'int':
case 'str':
if (visitor.enterLiteralType) {
visitor.enterLiteralType(type);
}
if (visitor.exitLiteralType) {
visitor.exitLiteralType(type);
}
break;
case 'const':
if (visitor.enterConstType) {
visitor.enterConstType(type);
}
if (visitor.exitConstType) {
visitor.exitConstType(type);
}
break;
case 'var':
if (visitor.enterVarType) {
visitor.enterVarType(type);
}
if (visitor.exitVarType) {
visitor.exitVarType(type);
}
break;
case 'set':
if (visitor.enterSetType) {
visitor.enterSetType(type);
}
walkType(visitor, type.elem);
if (visitor.exitSetType) {
visitor.exitSetType(type);
}
break;
case 'list':
if (visitor.enterSeqType) {
visitor.enterSeqType(type);
}
walkType(visitor, type.elem);
if (visitor.exitSeqType) {
visitor.exitSeqType(type);
}
break;
case 'fun':
if (visitor.enterFunType) {
visitor.enterFunType(type);
}
// Functions, walk both argument and result
walkType(visitor, type.arg);
walkType(visitor, type.res);
if (visitor.exitFunType) {
visitor.exitFunType(type);
}
break;
case 'oper':
if (visitor.enterOperType) {
visitor.enterOperType(type);
}
// Operators, walk all arguments and result
type.args.forEach(arg => walkType(visitor, arg));
walkType(visitor, type.res);
if (visitor.exitOperType) {
visitor.exitOperType(type);
}
break;
case 'tup':
if (visitor.enterTupleType) {
visitor.enterTupleType(type);
}
// Tuples, walk all elements
walkRow(visitor, type.fields);
if (visitor.exitTupleType) {
visitor.exitTupleType(type);
}
break;
case 'rec':
if (visitor.enterRecordType) {
visitor.enterRecordType(type);
}
// Records, walk all fields
walkRow(visitor, type.fields);
if (visitor.exitRecordType) {
visitor.exitRecordType(type);
}
break;
case 'sum':
visitor.enterSumType?.(type);
walkRow(visitor, type.fields);
visitor.exitSumType?.(type);
break;
case 'app':
visitor.enterAppType?.(type);
walkType(visitor, type.ctor);
type.args.map(t => walkType(visitor, t));
visitor.exitAppType?.(type);
break;
default:
(0, util_1.unreachable)(type);
}
if (visitor.exitType) {
visitor.exitType(type);
}
}
exports.walkType = walkType;
/**
* Navigates a Quint declaration with a visitor, invoking the correspondent function for each
* inner component.
*
* @param visitor: the IRVisitor instance with the functions to be invoked
* @param decl: the Quint declaration to be navigated
*
* @returns nothing, any collected information has to be a state inside the IRVisitor instance.
*/
function walkDeclaration(visitor, decl) {
if (visitor.enterDecl) {
visitor.enterDecl(decl);
}
// The standard depth starts at 0, so definitions inside delclarations (i.e.
// assume and instance overrides) are not considered top-level
visitor.definitionDepth = 0;
switch (decl.kind) {
case 'const':
case 'var':
case 'typedef':
case 'assume':
walkDefinition(visitor, decl);
break;
case 'def':
// depth will be increased inside `walkDefinition`, so we set it to -1 in
// order for it to be 0 there
visitor.definitionDepth = -1;
walkDefinition(visitor, decl);
break;
case 'instance':
if (visitor.enterInstance) {
visitor.enterInstance(decl);
}
decl.overrides.forEach(([_, e]) => walkExpression(visitor, e));
if (visitor.exitInstance) {
visitor.exitInstance(decl);
}
break;
case 'import':
if (visitor.enterImport) {
visitor.enterImport(decl);
}
if (visitor.exitImport) {
visitor.exitImport(decl);
}
break;
case 'export':
if (visitor.enterExport) {
visitor.enterExport(decl);
}
if (visitor.exitExport) {
visitor.exitExport(decl);
}
break;
default:
(0, util_1.unreachable)(decl);
}
if (visitor.exitDecl) {
visitor.exitDecl(decl);
}
}
exports.walkDeclaration = walkDeclaration;
/**
* Navigates a Quint definition with a visitor, invoking the correspondent function for each
* inner component.
*
* @param visitor: the IRVisitor instance with the functions to be invoked
* @param def: the Quint definition to be navigated
*
* @returns nothing, any collected information has to be a state inside the IRVisitor instance.
*/
function walkDefinition(visitor, def) {
if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth++;
}
if (visitor.enterDef) {
visitor.enterDef(def);
}
if (ir.isAnnotatedDef(def)) {
walkType(visitor, def.typeAnnotation);
}
else if (ir.isTypeAlias(def)) {
walkType(visitor, def.type);
}
switch (def.kind) {
case 'const':
if (visitor.enterConst) {
visitor.enterConst(def);
}
if (visitor.exitConst) {
visitor.exitConst(def);
}
break;
case 'var':
if (visitor.enterVar) {
visitor.enterVar(def);
}
if (visitor.exitVar) {
visitor.exitVar(def);
}
break;
case 'def':
if (visitor.enterOpDef) {
visitor.enterOpDef(def);
}
walkExpression(visitor, def.expr);
if (visitor.exitOpDef) {
visitor.exitOpDef(def);
}
break;
case 'typedef':
if (visitor.enterTypeDef) {
visitor.enterTypeDef(def);
}
if (visitor.exitTypeDef) {
visitor.exitTypeDef(def);
}
break;
case 'assume':
if (visitor.enterAssume) {
visitor.enterAssume(def);
}
walkExpression(visitor, def.assumption);
if (visitor.exitAssume) {
visitor.exitAssume(def);
}
break;
default:
(0, util_1.unreachable)(def);
}
if (visitor.exitDef) {
visitor.exitDef(def);
}
if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth--;
}
}
exports.walkDefinition = walkDefinition;
function walkExpression(visitor, expr) {
if (visitor.enterExpr) {
visitor.enterExpr(expr);
}
switch (expr.kind) {
case 'name':
if (visitor.enterName) {
visitor.enterName(expr);
}
if (visitor.exitName) {
visitor.exitName(expr);
}
break;
case 'bool':
case 'int':
case 'str':
if (visitor.enterLiteral) {
visitor.enterLiteral(expr);
}
if (visitor.exitLiteral) {
visitor.exitLiteral(expr);
}
break;
case 'app': {
if (visitor.enterApp) {
visitor.enterApp(expr);
}
expr.args.forEach(arg => walkExpression(visitor, arg));
if (visitor.exitApp) {
visitor.exitApp(expr);
}
break;
}
case 'lambda':
if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth++;
}
if (visitor.enterLambda) {
visitor.enterLambda(expr);
}
expr.params.forEach(p => {
if (p.typeAnnotation) {
walkType(visitor, p.typeAnnotation);
}
});
walkExpression(visitor, expr.expr);
if (visitor.exitLambda) {
visitor.exitLambda(expr);
}
if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth--;
}
break;
case 'let':
if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth++;
}
if (visitor.enterLet) {
visitor.enterLet(expr);
}
walkDefinition(visitor, expr.opdef);
walkExpression(visitor, expr.expr);
if (visitor.exitLet) {
visitor.exitLet(expr);
}
if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth--;
}
break;
default:
(0, util_1.unreachable)(expr);
}
if (visitor.exitExpr) {
visitor.exitExpr(expr);
}
}
exports.walkExpression = walkExpression;
function walkRow(visitor, r) {
if (visitor.enterRow) {
visitor.enterRow(r);
}
switch (r.kind) {
case 'row':
if (visitor.enterConcreteRow) {
visitor.enterConcreteRow(r);
}
r.fields.forEach(field => walkType(visitor, field.fieldType));
walkRow(visitor, r.other);
if (visitor.exitConcreteRow) {
visitor.exitConcreteRow(r);
}
break;
case 'var':
if (visitor.enterVarRow) {
visitor.enterVarRow(r);
}
if (visitor.exitVarRow) {
visitor.exitVarRow(r);
}
break;
case 'empty':
if (visitor.enterEmptyRow) {
visitor.enterEmptyRow(r);
}
if (visitor.exitEmptyRow) {
visitor.exitEmptyRow(r);
}
break;
default:
(0, util_1.unreachable)(r);
}
if (visitor.exitRow) {
visitor.exitRow(r);
}
}
//# sourceMappingURL=IRVisitor.js.map