@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
145 lines • 6.12 kB
JavaScript
;
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