UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

206 lines 8.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.mapDataFrameReplacementFunction = mapDataFrameReplacementFunction; const config_1 = require("../../../config"); const vertex_1 = require("../../../dataflow/graph/vertex"); const make_argument_1 = require("../../../dataflow/internal/process/functions/call/argument/make-argument"); const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call"); const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type"); const resolve_args_1 = require("../resolve-args"); const semantics_1 = require("../semantics"); const access_mapper_1 = require("./access-mapper"); const arguments_1 = require("./arguments"); /** Mapper for mapping the supported data frame replacement functions to mapper functions */ const DataFrameReplacementFunctionMapper = { 'colnames': mapDataFrameColNamesAssignment, 'names': mapDataFrameColNamesAssignment, 'rownames': mapDataFrameRowNamesAssignment, 'dimnames': mapDataFrameDimNamesAssignment }; /** * Maps a concrete data frame replacement function to abstract data frame operations. * * @param node - The R node of the replacement function * @param dfg - The data flow graph for resolving the arguments * @returns Data frame expression info containing the mapped abstract data frame operations, or `undefined` if the node does not represent a data frame replacement function */ function mapDataFrameReplacementFunction(node, expression, dfg) { const parent = hasParentReplacement(node, dfg) ? dfg.idMap?.get(node.info.parent) : undefined; const resolveInfo = { graph: dfg, idMap: dfg.idMap, full: true, resolve: config_1.VariableResolve.Alias }; let operations; if (node.type === type_1.RType.Access) { if (node.access.every(arg => arg === r_function_call_1.EmptyArgument)) { operations = mapDataFrameContentAssignment(node, expression, resolveInfo); } else if ((0, access_mapper_1.isStringBasedAccess)(node)) { operations = mapDataFrameNamedColumnAssignment(node, expression, resolveInfo); } else { operations = mapDataFrameIndexColRowAssignment(node, expression, resolveInfo); } } else if (node.type === type_1.RType.FunctionCall && node.named && node.arguments.length === 1 && node.arguments[0] !== r_function_call_1.EmptyArgument) { if (isDataFrameReplacement(node.functionName.content)) { const functionName = node.functionName.content; const functionMapping = DataFrameReplacementFunctionMapper[functionName]; operations = functionMapping(node.arguments[0], expression, resolveInfo, parent); } else { operations = mapDataFrameUnknownAssignment(node.arguments[0], expression, resolveInfo); } } if (operations !== undefined) { return { type: 'expression', operations: operations }; } } function isDataFrameReplacement(functionName) { // a check with `functionName in DataFrameReplacementFunctionMapper` would return true for "toString" return Object.prototype.hasOwnProperty.call(DataFrameReplacementFunctionMapper, functionName); } function hasParentReplacement(node, dfg) { const parentVertex = node.info.parent ? dfg.getVertex(node.info.parent) : undefined; return (0, vertex_1.isFunctionCallVertex)(parentVertex) && parentVertex.origin.includes('builtin:replacement'); } function mapDataFrameContentAssignment(access, expression, info) { const dataFrame = access.accessed; if (!(0, arguments_1.isDataFrameArgument)(dataFrame, info)) { return; } if ((0, arguments_1.isRNull)(expression)) { return [{ operation: 'subsetCols', operand: dataFrame.info.id, colnames: [], type: semantics_1.ConstraintType.OperandModification }]; } else { return [{ operation: 'identity', operand: dataFrame.info.id, type: semantics_1.ConstraintType.OperandModification }]; } } function mapDataFrameNamedColumnAssignment(access, expression, info) { const dataFrame = access.accessed; if (!(0, arguments_1.isDataFrameArgument)(dataFrame, info)) { return; } const colname = (0, resolve_args_1.resolveIdToArgValueSymbolName)(access.access[0], info); if ((0, arguments_1.isRNull)(expression)) { return [{ operation: 'removeCols', operand: dataFrame.info.id, colnames: colname ? [colname] : undefined, type: semantics_1.ConstraintType.OperandModification, options: { maybe: true } }]; } else { return [{ operation: 'assignCols', operand: dataFrame.info.id, columns: colname ? [colname] : undefined }]; } } function mapDataFrameIndexColRowAssignment(access, expression, info) { const dataFrame = access.accessed; const args = access.access; if (!(0, arguments_1.isDataFrameArgument)(dataFrame, info) || args.every(arg => arg === r_function_call_1.EmptyArgument)) { return; } const result = []; const rowArg = args.length < 2 ? undefined : args[0]; const colArg = args.length < 2 ? args[0] : args[1]; if (rowArg !== undefined && rowArg !== r_function_call_1.EmptyArgument) { const rowValue = (0, resolve_args_1.resolveIdToArgValue)(rowArg, info); let rows = undefined; if (typeof rowValue === 'number') { rows = [rowValue]; } else if (Array.isArray(rowValue) && rowValue.every(row => typeof row === 'number')) { rows = rowValue; } result.push({ operation: 'assignRows', operand: dataFrame.info.id, rows }); } if (colArg !== undefined && colArg !== r_function_call_1.EmptyArgument) { const colValue = (0, resolve_args_1.resolveIdToArgValue)(colArg, info); let columns = undefined; if (typeof colValue === 'string') { columns = [colValue]; } else if (typeof colValue === 'number') { columns = [colValue]; } else if (Array.isArray(colValue) && (colValue.every(col => typeof col === 'string') || colValue.every(col => typeof col === 'number'))) { columns = colValue; } if ((0, arguments_1.isRNull)(expression)) { result.push({ operation: 'removeCols', operand: dataFrame.info.id, colnames: columns?.map(col => typeof col === 'string' ? col : undefined), type: semantics_1.ConstraintType.OperandModification, options: { maybe: true } }); } else { result.push({ operation: 'assignCols', operand: dataFrame.info.id, columns }); } } return result; } function mapDataFrameColNamesAssignment(operand, expression, info, parent) { if (!(0, arguments_1.isDataFrameArgument)(operand, info)) { return; } const argument = info.idMap !== undefined ? (0, make_argument_1.toUnnamedArgument)(expression, info.idMap) : r_function_call_1.EmptyArgument; const assignedNames = (0, resolve_args_1.resolveIdToArgStringVector)(argument, info); return [{ operation: 'setColNames', operand: operand.value?.info.id, colnames: assignedNames, ...(parent !== undefined ? { options: { partial: true } } : {}) }]; } function mapDataFrameRowNamesAssignment(operand, expression, info) { if (!(0, arguments_1.isDataFrameArgument)(operand, info)) { return; } return [{ operation: 'identity', operand: operand.value?.info.id, type: semantics_1.ConstraintType.OperandModification }]; } function mapDataFrameDimNamesAssignment(operand, expression, info) { if (!(0, arguments_1.isDataFrameArgument)(operand, info)) { return; } return [{ operation: 'setColNames', operand: operand.value?.info.id, colnames: undefined }]; } function mapDataFrameUnknownAssignment(operand, expression, info) { if (!(0, arguments_1.isDataFrameArgument)(operand, info)) { return; } return [{ operation: 'unknown', operand: operand.value?.info.id, type: semantics_1.ConstraintType.OperandModification }]; } //# sourceMappingURL=replacement-mapper.js.map