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