UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

76 lines 3.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isFunctionHigherOrder = isFunctionHigherOrder; const vertex_1 = require("../graph/vertex"); const assert_1 = require("../../util/assert"); const edge_1 = require("../graph/edge"); const alias_tracking_1 = require("../eval/resolve/alias-tracking"); const config_1 = require("../../config"); const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call"); const general_1 = require("../eval/values/general"); function isAnyReturnAFunction(def, graph) { const workingQueue = def.exitPoints.map(d => graph.getVertex(d.nodeId)).filter(assert_1.isNotUndefined); const seen = new Set(); while (workingQueue.length > 0) { const current = workingQueue.pop(); if (seen.has(current.id)) { continue; } seen.add(current.id); if ((0, vertex_1.isFunctionDefinitionVertex)(current)) { return true; } const next = graph.outgoingEdges(current.id) ?? []; for (const [t, e] of next) { if (edge_1.DfEdge.includesType(e, edge_1.EdgeType.Returns)) { const v = graph.getVertex(t); if (v) { workingQueue.push(v); } } } } return false; } function inspectCallSitesArgumentsFns(def, graph, ctx, invertedGraph) { const callSites = invertedGraph?.outgoingEdges(def.id) ?? graph.ingoingEdges(def.id); for (const [callerId, e] of callSites ?? []) { if (!edge_1.DfEdge.includesType(e, edge_1.EdgeType.Calls)) { continue; } const caller = graph.getVertex(callerId); if (!caller || !(0, vertex_1.isFunctionCallVertex)(caller)) { continue; } for (const arg of caller.args) { if (arg === r_function_call_1.EmptyArgument) { continue; } const value = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(arg.nodeId, { graph, idMap: graph.idMap, resolve: config_1.VariableResolve.Alias, full: true, ctx })); if (value?.elements.some(e => e.type === 'function-definition')) { return true; } } } return false; } /** * Determines whether the function with the given id is a higher-order function, i.e., * either takes a function as an argument or (may) returns a function. * If the return is an identity, e.g., `function(x) x`, this is not considered higher-order, * if no function is passed as an argument. * Please note that inspecting higher order functions can be sped up (if queries multiple times) by providing an inverted graph as well! */ function isFunctionHigherOrder(id, graph, ctx, invertedGraph) { const vert = graph.getVertex(id); if (!vert || !(0, vertex_1.isFunctionDefinitionVertex)(vert)) { return false; } // 1. check whether any of the exit types is a function if (isAnyReturnAFunction(vert, graph)) { return true; } // 2. check whether any of the callsites passes a function return inspectCallSitesArgumentsFns(vert, graph, ctx, invertedGraph); } //# sourceMappingURL=higher-order-function.js.map