@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
131 lines • 5.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DfEdge = exports.EdgeType = void 0;
exports.shouldTraverseEdge = shouldTraverseEdge;
/**
* Represents the relationship between the source and the target vertex in the dataflow graph.
* The actual value is represented as a bitmask, so please refer to {@link DfEdge} for helpful functions.
*/
var EdgeType;
(function (EdgeType) {
/** The edge determines that source reads target */
EdgeType[EdgeType["Reads"] = 1] = "Reads";
/** The edge determines that source is defined by target */
EdgeType[EdgeType["DefinedBy"] = 2] = "DefinedBy";
/** The edge determines that the source calls the target */
EdgeType[EdgeType["Calls"] = 4] = "Calls";
/** The source returns target on call */
EdgeType[EdgeType["Returns"] = 8] = "Returns";
/**
* The edge determines that source (probably argument) defines the target (probably parameter).
* This may also link a function call to definitions it causes to be active (as part of the closure) of the called function definition.
*/
EdgeType[EdgeType["DefinesOnCall"] = 16] = "DefinesOnCall";
/**
* Usually the inverse of `defines-on-call` (in the context of arguments and parameters).
* This may also link an open read (within a function) to the definition that is active at the call site.
*/
EdgeType[EdgeType["DefinedByOnCall"] = 32] = "DefinedByOnCall";
/** Formal used as argument to a function call */
EdgeType[EdgeType["Argument"] = 64] = "Argument";
/** The edge determines that the source is a side effect that happens when the target is called */
EdgeType[EdgeType["SideEffectOnCall"] = 128] = "SideEffectOnCall";
/** The Edge determines that the reference is affected by a non-standard evaluation (e.g., a for-loop body or a quotation) */
EdgeType[EdgeType["NonStandardEvaluation"] = 256] = "NonStandardEvaluation";
})(EdgeType || (exports.EdgeType = EdgeType = {}));
const edgeTypeToHumanReadableName = new Map([
[EdgeType.Reads, "reads" /* EdgeTypeName.Reads */],
[EdgeType.DefinedBy, "defined-by" /* EdgeTypeName.DefinedBy */],
[EdgeType.Calls, "calls" /* EdgeTypeName.Calls */],
[EdgeType.Returns, "returns" /* EdgeTypeName.Returns */],
[EdgeType.DefinesOnCall, "defines-on-call" /* EdgeTypeName.DefinesOnCall */],
[EdgeType.DefinedByOnCall, "defined-by-on-call" /* EdgeTypeName.DefinedByOnCall */],
[EdgeType.Argument, "argument" /* EdgeTypeName.Argument */],
[EdgeType.SideEffectOnCall, "side-effect-on-call" /* EdgeTypeName.SideEffectOnCall */],
[EdgeType.NonStandardEvaluation, "non-standard-evaluation" /* EdgeTypeName.NonStandardEvaluation */]
]);
/**
* Helper Functions to work with {@link DfEdge} and {@link EdgeType}.
*/
exports.DfEdge = {
name: 'DfEdge',
/**
* Takes joint edge types and returns their human-readable names.
*/
typesToNames({ types }) {
const rTypes = new Set();
for (const [bit, name] of edgeTypeToHumanReadableName.entries()) {
if ((types & bit) !== 0) {
rTypes.add(name);
}
}
return rTypes;
},
/**
* Takes joint edge types and splits them into their individual components.
* @example
* ```ts
* DfEdge.splitTypes({ types: EdgeType.Reads | EdgeType.DefinedBy });
* // returns [EdgeType.Reads, EdgeType.DefinedBy]
* ```
*/
splitTypes({ types }) {
const split = [];
for (const bit of edgeTypeToHumanReadableName.keys()) {
if ((types & bit) !== 0) {
split.push(bit);
}
}
return split;
},
/**
* Only use this function to retrieve a human-readable name if you know that it is a single bitmask.
* Otherwise, use {@link DfEdge#typesToNames} which handles these cases.
*/
typeToName(type) {
return edgeTypeToHumanReadableName.get(type);
},
/**
* Check if the given-edge type has any of the given types.
* As types are bitmasks, you can combine multiple types with a bitwise OR (`|`).
* @example
*
* ```ts
* edgeIncludesType({ types: EdgeType.Reads }, EdgeType.Reads | EdgeType.DefinedBy) // true
*```
*
* Counterpart of {@link DfEdge#doesNotIncludeType}.
*/
includesType({ types }, typesToInclude) {
return (typesToInclude & types) !== 0;
},
/**
* Check if the given-edge type does not include the given type.
* As types are bitmasks, you can combine multiple types with a bitwise OR (`|`).
* Counterpart of {@link DfEdge#includesType}.
*/
doesNotIncludeType({ types }, any) {
return (any & types) === 0;
},
};
const alwaysTraverseEdgeTypes = EdgeType.Reads | EdgeType.DefinedBy | EdgeType.Argument | EdgeType.Calls;
const definedByOnCallTypes = EdgeType.DefinesOnCall | EdgeType.DefinedByOnCall;
/**
* Determines whether an edge should be traversed during dataflow analysis.
*/
function shouldTraverseEdge(e) {
if (exports.DfEdge.includesType(e, EdgeType.NonStandardEvaluation)) {
return 0 /* TraverseEdge.Never */;
}
else if (exports.DfEdge.includesType(e, alwaysTraverseEdgeTypes)) {
return 3 /* TraverseEdge.Always */;
}
else if (exports.DfEdge.includesType(e, definedByOnCallTypes)) {
return 2 /* TraverseEdge.OnlyIfBoth */;
}
else if (exports.DfEdge.includesType(e, EdgeType.SideEffectOnCall)) {
return 1 /* TraverseEdge.SideEffect */;
}
return 0 /* TraverseEdge.Never */;
}
//# sourceMappingURL=edge.js.map