UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

88 lines 4.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataFrameShapeInferenceVisitor = void 0; const absint_visitor_1 = require("../absint-visitor"); const dataframe_domain_1 = require("./dataframe-domain"); const access_mapper_1 = require("./mappers/access-mapper"); const function_mapper_1 = require("./mappers/function-mapper"); const replacement_mapper_1 = require("./mappers/replacement-mapper"); const semantics_1 = require("./semantics"); /** * The control flow graph visitor to infer the shape of data frames using abstract interpretation */ class DataFrameShapeInferenceVisitor extends absint_visitor_1.AbstractInterpretationVisitor { /** * The abstract data frame operations the function call nodes are mapped to. */ operations; constructor({ trackOperations = true, ...config }) { super(config); if (trackOperations) { this.operations = new Map(); } } /** * Gets the mapped abstract data frame operations for an AST node (this only includes direct function calls, replacement calls, or access operations). * This requires that the abstract interpretation visitor has been completed, or at least started. * @param id - The ID of the node to get the mapped abstract operations for * @returns The mapped abstract data frame operations for the node, or `undefined` if no abstract operation was mapped for the node or storing mapped abstract operations is disabled via the visitor config. */ getAbstractOperations(id) { return id !== undefined ? this.operations?.get(id) : undefined; } onFunctionCall({ call }) { super.onFunctionCall({ call }); const node = this.getNormalizedAst(call.id); if (node === undefined) { return; } const operations = (0, function_mapper_1.mapDataFrameFunctionCall)(node, this, this.config.dfg, this.config.ctx); this.applyDataFrameExpression(node, operations); } onReplacementCall({ call, target, source }) { super.onReplacementCall({ call, target, source }); const node = this.getNormalizedAst(call.id); const targetNode = this.getNormalizedAst(target); const sourceNode = this.getNormalizedAst(source); if (node === undefined || targetNode === undefined || sourceNode === undefined) { return; } const operations = (0, replacement_mapper_1.mapDataFrameReplacementFunction)(node, sourceNode, this, this.config.dfg, this.config.ctx); this.applyDataFrameExpression(node, operations); } onAccessCall({ call }) { super.onAccessCall({ call }); const node = this.getNormalizedAst(call.id); if (node === undefined) { return; } const operations = (0, access_mapper_1.mapDataFrameAccess)(node, this, this.config.dfg, this.config.ctx); this.applyDataFrameExpression(node, operations); } applyDataFrameExpression(node, operations) { if (operations === undefined) { return; } else if (this.operations !== undefined) { this.operations.set(node.info.id, operations); } const maxColNames = this.config.ctx.config.abstractInterpretation.dataFrame.maxColNames; let value = dataframe_domain_1.DataFrameDomain.top(maxColNames); for (const { operation, operand, type, options, ...args } of operations) { const operandValue = operand !== undefined ? this.getAbstractValue(operand, this.currentState) : value; value = (0, semantics_1.applyDataFrameSemantics)(operation, operandValue ?? dataframe_domain_1.DataFrameDomain.top(maxColNames), args, options); const constraintType = type ?? (0, semantics_1.getConstraintType)(operation); if (operand !== undefined && constraintType === semantics_1.ConstraintType.OperandModification) { this.updateState(operand, value); for (const origin of this.getVariableOrigins(operand)) { this.updateState(origin, value); } } else if (constraintType === semantics_1.ConstraintType.ResultPostcondition) { this.updateState(node.info.id, value); } } } } exports.DataFrameShapeInferenceVisitor = DataFrameShapeInferenceVisitor; //# sourceMappingURL=shape-inference.js.map