UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

145 lines 6.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAccessOperands = getAccessOperands; exports.resolveIndicesByName = resolveIndicesByName; exports.resolveSingleIndex = resolveSingleIndex; exports.filterIndices = filterIndices; exports.constructNestedAccess = constructNestedAccess; exports.addSubIndicesToLeafIndices = addSubIndicesToLeafIndices; const resolve_by_name_1 = require("../dataflow/environments/resolve-by-name"); const vertex_1 = require("../dataflow/graph/vertex"); 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"); /** * Returns the accessed and access argument of an access operation by filtering the operation arguments. */ function getAccessOperands(args) { const nonEmptyArgs = args.filter(arg => arg !== r_function_call_1.EmptyArgument); const accessedArg = nonEmptyArgs.find(arg => arg.info.role === "accessed" /* RoleInParent.Accessed */); const accessArg = nonEmptyArgs.find(arg => arg.info.role === "index-access" /* RoleInParent.IndexAccess */); return { accessedArg, accessArg }; } /** * Resolves the passed name in the passed environment and returns the indicesCollection of the resolved definitions. * * @param name - Name to resolve * @param environment - Environment in which name is resolved * @returns The indicesCollection of the resolved definitions */ function resolveIndicesByName(name, environment) { const definitions = (0, resolve_by_name_1.resolveByName)(name, environment); return definitions?.flatMap(def => def?.indicesCollection ?? []); } /** * Resolves {@link accessedArg} in the {@link environment} and filters its indices according to {@link accessArg}. * * If no indices could be found that match the `accessArg`, the original indices are returned as overapproximation. * * @param accessedArg - The argument to resolve * @param accessArg - The argument which is used to filter the indices * @param environment - The environment in which {@link accessedArg} is resolved * @returns The filtered {@link ContainerIndicesCollection} of the resolved {@link accessedArg} */ function resolveSingleIndex(accessedArg, accessArg, environment, isIndexBasedAccess) { const indicesCollection = resolveIndicesByName(accessedArg.lexeme, environment); const accessedIndicesCollection = filterIndices(indicesCollection, accessArg, isIndexBasedAccess); // If the accessed indices couldn't be resolved, overapproximate by returning the original indices. // This could also be the case, when nothing is acccessed, but we better be safe. if (accessedIndicesCollection === undefined) { return indicesCollection; } else { return accessedIndicesCollection; } } /** * Filters the single indices of the {@link indicesCollection} according to the lexeme of the {@link accessArg}. * * @param indicesCollection - The {@link ContainerIndicesCollection} to filter * @param accessArg - The argument which is used to filter {@link indicesCollection} * @returns The filtered copy of {@link indicesCollection} */ function filterIndices(indicesCollection, accessArg, isIndexBasedAccess) { let accessedIndicesCollection = undefined; for (const indices of indicesCollection ?? []) { const filteredIndices = indices.indices.filter(index => (0, vertex_1.isAccessed)(index, accessArg.lexeme, isIndexBasedAccess)); if (filteredIndices.length === 0) { continue; } accessedIndicesCollection ??= []; accessedIndicesCollection.push({ indices: filteredIndices, isContainer: indices.isContainer }); } return accessedIndicesCollection; } /** * Constructs the definition of a nested access. * * Example: * ```r * person$credentials$username * ``` * would result in a list with the index `credentials`, which has the subIndex `username`. * * @param accessedArg - The top level argument that is accessed * @param leafIndices - The index at the end of the nested access i.e. `c` in `a$b$c`. * @returns The constructed nested access */ function constructNestedAccess(accessedArg, leafIndices, constructIdentifier) { const accessed = accessedArg.accessed; const accesses = accessedArg.access.filter(arg => arg !== r_function_call_1.EmptyArgument).map(arg => arg); const indices = []; for (const access of accesses) { const newIndices = { indices: [ { identifier: constructIdentifier(access), nodeId: access.info.id, subIndices: [leafIndices], } ], isContainer: false, }; if (accessed.type === type_1.RType.Access) { const nestedIndices = constructNestedAccess(accessed, newIndices, constructIdentifier); indices.push(...nestedIndices); } else { indices.push(newIndices); } } return indices; } /** * Adds the passed list of {@link leafSubIndices} to the leaf (sub-)indices of {@link indicesCollection}. * * @param indicesCollection - Indices where to add the sub indices. * @param leafSubIndices - Indices that are added to the leaf indices. */ function addSubIndicesToLeafIndices(indicesCollection, leafSubIndices) { const result = []; for (const indices of indicesCollection) { const newIndices = []; for (const index of indices.indices) { let newSubIndices = []; if ((0, vertex_1.isParentContainerIndex)(index)) { newSubIndices = addSubIndicesToLeafIndices(index.subIndices, leafSubIndices); } else { newSubIndices = leafSubIndices; } newIndices.push({ ...index, subIndices: newSubIndices, }); } result.push({ ...indices, indices: newIndices, }); } return result; } //# sourceMappingURL=containers.js.map