UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

131 lines 5.64 kB
"use strict"; 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