UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

100 lines 5.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeInputSourcesQuery = executeInputSourcesQuery; const input_sources_query_format_1 = require("./input-sources-query-format"); const log_1 = require("../../../util/log"); const parse_1 = require("../../../slicing/criterion/parse"); const r_function_definition_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-definition"); const model_1 = require("../../../r-bridge/lang-4.x/ast/model/model"); const df_helper_1 = require("../../../dataflow/graph/df-helper"); const simple_input_classifier_1 = require("./simple-input-classifier"); const flowr_search_executor_1 = require("../../../search/flowr-search-executor"); const record_1 = require("../../../util/record"); const identifier_1 = require("../../../dataflow/environments/identifier"); const r_base_packages_1 = require("../../../util/r-base-packages"); const environment_1 = require("../../../dataflow/environments/environment"); /** * Execute an input sources query */ async function executeInputSourcesQuery({ analyzer }, queries) { const start = Date.now(); const results = {}; const nast = await analyzer.normalize(); const df = await analyzer.dataflow(); // flowR's defaults, extended by whatever the (possibly project-kind specialized) configuration adds const defaultConfig = addAll(await resolveSearches(analyzer, input_sources_query_format_1.DefaultInputClassifierConfig), await resolveSearches(analyzer, analyzer.inspectContext().config.inputSources ?? {})); const packages = attachedPackages(analyzer, df.environment); for (const query of queries) { const criteria = Array.isArray(query.criterion) ? query.criterion : [query.criterion]; const config = { ...defaultConfig, ...(await resolveSearches(analyzer, query.config ?? {})) }; for (const criterion of criteria) { if (results[criterion]) { log_1.log.warn(`Duplicate key for input-sources query: ${criterion}, skipping...`); continue; } const criterionId = parse_1.SlicingCriterion.tryParse(criterion, nast.idMap) ?? criterion; const provenanceNode = nast.idMap.get(criterionId); const fdef = r_function_definition_1.RFunctionDefinition.rootFunctionDefinition(provenanceNode, nast.idMap); const provenance = df_helper_1.Dataflow.provenanceGraph(criterionId, df.graph, fdef ? model_1.RNode.collectAllIds(fdef) : undefined); results[criterion] = (0, simple_input_classifier_1.classifyInput)(criterionId, provenance, config, df.graph, packages); } } return { '.meta': { timing: Date.now() - start }, results }; } /** * The packages whose exports are usable without a namespace: those R has on its search path at the end of the * program, the ones the project declares, and the base packages R attaches on startup. */ function attachedPackages(analyzer, environment) { return new Set([ ...environment_1.REnvironment.attachedPackages(environment.current), ...analyzer.inspectContext().deps.getDependencies().map(d => d.name), ...r_base_packages_1.AttachedBasePackages ]); } /** every entry of `extra` appended to the matching list of `base`, so configured entries extend the defaults instead of replacing them */ function addAll(base, extra) { const result = { ...base }; for (const [key, value] of record_1.Record.entries(extra)) { if (value !== undefined) { result[key] = [...(base[key] ?? []), ...value]; } } return result; } /** Config fields that hold structured values (not function searches) and are carried over verbatim. */ const StructuredConfigKeys = ['linkedObjects', 'linkedEntryPoints', 'narrowing']; function isStructuredConfigKey(key) { return StructuredConfigKeys.includes(key); } async function resolveSearches(analyzer, config) { /* structured (non-search) fields are carried over as-is; everything else is a resolvable function search */ const result = {}; for (const key of StructuredConfigKeys) { if (config[key] !== undefined) { result[key] = config[key]; } } for (const [key, value] of record_1.Record.entries(config)) { if (isStructuredConfigKey(key)) { continue; } else if (value === undefined || Array.isArray(value)) { // entries may be written as `pkg::fn` strings in the configuration, which only mean the namespaced function once parsed result[key] = value?.map(e => typeof e === 'string' ? identifier_1.Identifier.parse(e) : e); } else { const searchResult = await (0, flowr_search_executor_1.runSearch)(value, analyzer); result[key] = searchResult.getElements().map(element => element.node.info.id); } } return result; } //# sourceMappingURL=input-sources-query-executor.js.map