@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
93 lines • 4.15 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.processRegisterHook = processRegisterHook;
const known_call_handling_1 = require("../known-call-handling");
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
const linker_1 = require("../../../../linker");
const common_1 = require("../common");
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
const general_1 = require("../../../../../eval/values/general");
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
const range_1 = require("../../../../../../util/range");
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
/**
* Process a hook such as `on.exit`
*/
function processRegisterHook(name, args, rootId, data, config) {
const params = {
[config.args.expr.name]: 'expr',
};
if (config.args.add) {
params[config.args.add.name] = 'add';
}
if (config.args.after) {
params[config.args.after.name] = 'after';
}
params['...'] = '...';
const argMaps = (0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params);
const exprIds = new Set(argMaps.get('expr'));
const addIds = config.args.add ? new Set(argMaps.get('add')) : new Set();
const afterIds = config.args.after ? new Set(argMaps.get('after')) : new Set();
const wrappedFunctions = new Set();
// we automatically transform the expr to a function definition that takes no arguments
const transformed = args.map(arg => {
if (arg === r_function_call_1.EmptyArgument) {
return r_function_call_1.EmptyArgument;
}
else if (exprIds.has(arg.info.id) && arg.value) {
const val = arg.value;
const wrapId = `${val.info.id}-hook-fn`;
wrappedFunctions.add(wrapId);
const wrapped = {
type: type_1.RType.FunctionDefinition,
location: val.location ?? name.location ?? range_1.SourceRange.invalid(),
parameters: [],
body: val,
lexeme: 'function',
info: {
...val.info,
id: wrapId,
}
};
data.completeAst.idMap.set(wrapId, wrapped);
return {
...arg,
value: wrapped
};
}
else {
return arg;
}
});
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: transformed, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.RegisterHook });
const resolveArgs = {
graph: res.information.graph,
environment: res.information.environment,
resolve: data.ctx.config.solver.variables,
ctx: data.ctx,
idMap: data.completeAst.idMap,
full: true
};
const shouldAdd = addIds.size === 0 ? config.args.add?.default :
Array.from(addIds).flatMap(id => (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(id, resolveArgs))?.elements ?? [])
.some(v => v.type === 'logical' && v.value !== false);
const shouldBeAfter = afterIds.size === 0 ? config.args.after?.default :
Array.from(afterIds).flatMap(id => (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(id, resolveArgs))?.elements ?? [])
.some(v => v.type === 'logical' && v.value !== false);
const info = res.information;
const hooks = Array.from(wrappedFunctions, id => ({
type: config.hook,
id,
cds: data.cds,
add: shouldAdd,
after: shouldBeAfter
}));
info.hooks.push(...hooks);
if (data.environment.level <= 1) {
// if we are at the root level, we need to assume that the hook can cause unknown side-effects
(0, unknown_side_effect_1.handleUnknownSideEffect)(info.graph, info.environment, rootId);
}
return info;
}
//# sourceMappingURL=built-in-register-hook.js.map