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