UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

93 lines 4.15 kB
"use strict"; 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