UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

120 lines 7.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processors = void 0; exports.produceDataFlowGraph = produceDataFlowGraph; const processor_1 = require("./processor"); const process_uninteresting_leaf_1 = require("./internal/process/process-uninteresting-leaf"); const process_symbol_1 = require("./internal/process/process-symbol"); const default_call_handling_1 = require("./internal/process/functions/call/default-call-handling"); const process_parameter_1 = require("./internal/process/functions/process-parameter"); const process_argument_1 = require("./internal/process/functions/process-argument"); const process_named_call_1 = require("./internal/process/process-named-call"); const process_value_1 = require("./internal/process/process-value"); const named_call_handling_1 = require("./internal/process/functions/call/named-call-handling"); const make_argument_1 = require("./internal/process/functions/call/argument/make-argument"); const range_1 = require("../util/range"); const type_1 = require("../r-bridge/lang-4.x/ast/model/type"); const environment_1 = require("./environments/environment"); const built_in_source_1 = require("./internal/process/functions/call/built-in/built-in-source"); const extract_cfg_1 = require("../control-flow/extract-cfg"); const edge_1 = require("./graph/edge"); const identify_link_to_last_call_relation_1 = require("../queries/catalog/call-context-query/identify-link-to-last-call-relation"); const built_in_function_definition_1 = require("./internal/process/functions/call/built-in/built-in-function-definition"); const built_in_config_1 = require("./environments/built-in-config"); /** * The best friend of {@link produceDataFlowGraph} and {@link processDataflowFor}. * Maps every {@link RType} in the normalized AST to a processor. */ exports.processors = { [type_1.RType.Number]: process_value_1.processValue, [type_1.RType.String]: process_value_1.processValue, [type_1.RType.Logical]: process_value_1.processValue, [type_1.RType.Comment]: process_uninteresting_leaf_1.processUninterestingLeaf, [type_1.RType.LineDirective]: process_uninteresting_leaf_1.processUninterestingLeaf, [type_1.RType.Symbol]: process_symbol_1.processSymbol, [type_1.RType.Access]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.operator, [n.accessed, ...n.access]), [type_1.RType.BinaryOp]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.operator, [n.lhs, n.rhs]), [type_1.RType.Pipe]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, [n.lhs, n.rhs]), [type_1.RType.UnaryOp]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.operator, [n.operand]), [type_1.RType.ForLoop]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, [n.variable, n.vector, n.body]), [type_1.RType.WhileLoop]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, [n.condition, n.body]), [type_1.RType.RepeatLoop]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, [n.body]), [type_1.RType.IfThenElse]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, [n.condition, n.then, n.otherwise]), [type_1.RType.Break]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, []), [type_1.RType.Next]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, []), [type_1.RType.FunctionCall]: default_call_handling_1.processFunctionCall, [type_1.RType.FunctionDefinition]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, [...n.parameters, n.body]), [type_1.RType.Parameter]: process_parameter_1.processFunctionParameter, [type_1.RType.Argument]: process_argument_1.processFunctionArgument, [type_1.RType.ExpressionList]: ({ grouping, info, children, location }, d) => { const groupStart = grouping?.[0]; return (0, named_call_handling_1.processNamedCall)({ type: type_1.RType.Symbol, info: info, content: groupStart?.content ?? '{', lexeme: groupStart?.lexeme ?? '{', location: location ?? (0, range_1.rangeFrom)(-1, -1, -1, -1), namespace: groupStart?.content ? undefined : 'base' }, (0, make_argument_1.wrapArgumentsUnnamed)(children, d.completeAst.idMap), info.id, d); } }; function resolveLinkToSideEffects(ast, graph) { let cfg = undefined; for (const s of graph.unknownSideEffects) { if (typeof s !== 'object') { continue; } cfg ??= (0, extract_cfg_1.extractCfgQuick)(ast).graph; /* this has to change whenever we add a new link to relations because we currently offer no abstraction for the type */ const potentials = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(s.id, cfg, graph, s.linkTo); for (const pot of potentials) { graph.addEdge(s.id, pot, edge_1.EdgeType.Reads); } if (potentials.length > 0) { graph.unknownSideEffects.delete(s); } } } /** * This is the main function to produce the dataflow graph from a given request and normalized AST. * Note, that this requires knowledge of the active parser in case the dataflow analysis uncovers other files that have to be parsed and integrated into the analysis * (e.g., in the event of a `source` call). * For the actual, canonical fold entry point, see {@link processDataflowFor}. */ function produceDataFlowGraph(parser, request, completeAst, config) { let firstRequest; const multifile = Array.isArray(request); if (multifile) { firstRequest = request[0]; } else { firstRequest = request; } const builtInsConfig = config.semantics.environment.overwriteBuiltIns; const builtIns = (0, built_in_config_1.getBuiltInDefinitions)(builtInsConfig.definitions, builtInsConfig.loadDefaults); const env = (0, environment_1.initializeCleanEnvironments)(builtIns.builtInMemory); const dfData = { parser, completeAst, environment: env, builtInEnvironment: env.current.parent, processors: exports.processors, currentRequest: firstRequest, controlDependencies: undefined, referenceChain: [firstRequest], flowrConfig: config }; let df = (0, processor_1.processDataflowFor)(completeAst.ast, dfData); df.graph.sourced.unshift(firstRequest.request === 'file' ? firstRequest.content : '<inline>'); if (multifile) { for (let i = 1; i < request.length; i++) { /* source requests register automatically */ df = (0, built_in_source_1.standaloneSourceFile)(request[i], dfData, `root-${i}`, df); } } // finally, resolve linkages (0, built_in_function_definition_1.updateNestedFunctionCalls)(df.graph, df.environment); resolveLinkToSideEffects(completeAst, df.graph); return df; } //# sourceMappingURL=extractor.js.map