@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
233 lines • 11.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BuiltIns = exports.BuiltInEvalHandlerMapper = exports.BuiltInProcessorMapper = void 0;
exports.builtInId = builtInId;
exports.isBuiltIn = isBuiltIn;
const known_call_handling_1 = require("../internal/process/functions/call/known-call-handling");
const built_in_access_1 = require("../internal/process/functions/call/built-in/built-in-access");
const built_in_if_then_else_1 = require("../internal/process/functions/call/built-in/built-in-if-then-else");
const built_in_assignment_1 = require("../internal/process/functions/call/built-in/built-in-assignment");
const built_in_special_bin_op_1 = require("../internal/process/functions/call/built-in/built-in-special-bin-op");
const built_in_pipe_1 = require("../internal/process/functions/call/built-in/built-in-pipe");
const built_in_for_loop_1 = require("../internal/process/functions/call/built-in/built-in-for-loop");
const built_in_repeat_loop_1 = require("../internal/process/functions/call/built-in/built-in-repeat-loop");
const built_in_while_loop_1 = require("../internal/process/functions/call/built-in/built-in-while-loop");
const identifier_1 = require("./identifier");
const assert_1 = require("../../util/assert");
const built_in_replacement_1 = require("../internal/process/functions/call/built-in/built-in-replacement");
const built_in_quote_1 = require("../internal/process/functions/call/built-in/built-in-quote");
const built_in_function_definition_1 = require("../internal/process/functions/call/built-in/built-in-function-definition");
const built_in_expression_list_1 = require("../internal/process/functions/call/built-in/built-in-expression-list");
const built_in_get_1 = require("../internal/process/functions/call/built-in/built-in-get");
const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
const edge_1 = require("../graph/edge");
const built_in_library_1 = require("../internal/process/functions/call/built-in/built-in-library");
const built_in_source_1 = require("../internal/process/functions/call/built-in/built-in-source");
const built_in_apply_1 = require("../internal/process/functions/call/built-in/built-in-apply");
const built_in_list_1 = require("../internal/process/functions/call/built-in/built-in-list");
const built_in_vector_1 = require("../internal/process/functions/call/built-in/built-in-vector");
const built_in_rm_1 = require("../internal/process/functions/call/built-in/built-in-rm");
const built_in_eval_1 = require("../internal/process/functions/call/built-in/built-in-eval");
const vertex_1 = require("../graph/vertex");
const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
const unknown_side_effect_1 = require("../graph/unknown-side-effect");
const resolve_1 = require("../eval/resolve/resolve");
function builtInId(name) {
return `built-in:${name}`;
}
function isBuiltIn(name) {
return String(name).startsWith('built-in:');
}
function defaultBuiltInProcessor(name, args, rootId, data, { returnsNthArgument, useAsProcessor, forceArgs, readAllArguments, cfg, hasUnknownSideEffects, treatAsFnCall }) {
const activeProcessor = useAsProcessor ?? 'builtin:default';
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs, origin: activeProcessor });
if (returnsNthArgument !== undefined) {
const arg = returnsNthArgument === 'last' ? processedArguments[args.length - 1] : processedArguments[returnsNthArgument];
if (arg !== undefined) {
res.graph.addEdge(rootId, arg.entryPoint, edge_1.EdgeType.Returns);
}
}
if (readAllArguments) {
for (const arg of processedArguments) {
if (arg) {
res.graph.addEdge(rootId, arg.entryPoint, edge_1.EdgeType.Reads);
}
}
}
if (hasUnknownSideEffects) {
if (typeof hasUnknownSideEffects !== 'boolean') {
(0, unknown_side_effect_1.handleUnknownSideEffect)(res.graph, res.environment, rootId, hasUnknownSideEffects);
}
else {
(0, unknown_side_effect_1.handleUnknownSideEffect)(res.graph, res.environment, rootId);
}
}
const fnCallNames = treatAsFnCall?.[name.content];
if (fnCallNames) {
for (const arg of args) {
if (arg !== r_function_call_1.EmptyArgument && arg.value && fnCallNames.includes(arg.name?.content)) {
const rhs = arg.value;
let fnName;
let fnId;
if (rhs.type === type_1.RType.String) {
fnName = rhs.content.str;
fnId = rhs.info.id;
}
else if (rhs.type === type_1.RType.Symbol) {
fnName = rhs.content;
fnId = rhs.info.id;
}
else {
continue;
}
res.graph.updateToFunctionCall({
tag: vertex_1.VertexType.FunctionCall,
id: fnId,
name: fnName,
args: [],
environment: data.environment,
onlyBuiltin: false,
cds: data.controlDependencies,
origin: [activeProcessor]
});
}
}
}
if (cfg !== undefined) {
res.exitPoints.push({ type: cfg, nodeId: rootId, controlDependencies: data.controlDependencies });
}
return res;
}
exports.BuiltInProcessorMapper = {
'builtin:default': defaultBuiltInProcessor,
'builtin:eval': built_in_eval_1.processEvalCall,
'builtin:apply': built_in_apply_1.processApply,
'builtin:expression-list': built_in_expression_list_1.processExpressionList,
'builtin:source': built_in_source_1.processSourceCall,
'builtin:access': built_in_access_1.processAccess,
'builtin:if-then-else': built_in_if_then_else_1.processIfThenElse,
'builtin:get': built_in_get_1.processGet,
'builtin:rm': built_in_rm_1.processRm,
'builtin:library': built_in_library_1.processLibrary,
'builtin:assignment': built_in_assignment_1.processAssignment,
'builtin:special-bin-op': built_in_special_bin_op_1.processSpecialBinOp,
'builtin:pipe': built_in_pipe_1.processPipe,
'builtin:function-definition': built_in_function_definition_1.processFunctionDefinition,
'builtin:quote': built_in_quote_1.processQuote,
'builtin:for-loop': built_in_for_loop_1.processForLoop,
'builtin:repeat-loop': built_in_repeat_loop_1.processRepeatLoop,
'builtin:while-loop': built_in_while_loop_1.processWhileLoop,
'builtin:replacement': built_in_replacement_1.processReplacementFunction,
'builtin:list': built_in_list_1.processList,
'builtin:vector': built_in_vector_1.processVector,
};
exports.BuiltInEvalHandlerMapper = {
'built-in:c': resolve_1.resolveAsVector,
'built-in::': resolve_1.resolveAsSeq,
'built-in:+': resolve_1.resolveAsPlus,
'built-in:-': resolve_1.resolveAsMinus
};
class BuiltIns {
/**
* Register a built-in constant (like `NULL` or `TRUE`) to the given {@link builtIns}
*/
registerBuiltInConstant({ names, value, assumePrimitive }) {
for (const name of names) {
const id = builtInId(name);
const d = [{
type: identifier_1.ReferenceType.BuiltInConstant,
definedAt: id,
controlDependencies: undefined,
value,
name,
nodeId: id
}];
this.set(name, d, assumePrimitive);
}
}
/**
* Register a built-in function (like `print` or `c`) to the given {@link builtIns}
*/
registerBuiltInFunctions({ names, processor, config, assumePrimitive }) {
const mappedProcessor = exports.BuiltInProcessorMapper[processor];
(0, assert_1.guard)(mappedProcessor !== undefined, () => `Processor for ${processor} is undefined! Please pass a valid builtin name ${JSON.stringify(Object.keys(exports.BuiltInProcessorMapper))}!`);
for (const name of names) {
(0, assert_1.guard)(processor !== undefined, `Processor for ${name} is undefined, maybe you have an import loop? You may run 'npm run detect-circular-deps' - although by far not all are bad`);
const id = builtInId(name);
const d = [{
type: identifier_1.ReferenceType.BuiltInFunction,
definedAt: id,
controlDependencies: undefined,
/* eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument */
processor: (name, args, rootId, data) => mappedProcessor(name, args, rootId, data, config),
config,
name,
nodeId: id
}];
this.set(name, d, assumePrimitive);
}
}
/**
* Registers all combinations of replacements
*/
registerReplacementFunctions({ names, suffixes, assumePrimitive, config }) {
const replacer = exports.BuiltInProcessorMapper['builtin:replacement'];
(0, assert_1.guard)(replacer !== undefined, () => 'Processor for builtin:replacement is undefined!');
for (const assignment of names) {
for (const suffix of suffixes) {
const effectiveName = `${assignment}${suffix}`;
const id = builtInId(effectiveName);
const d = [{
type: identifier_1.ReferenceType.BuiltInFunction,
definedAt: id,
processor: (name, args, rootId, data) => replacer(name, args, rootId, data, { makeMaybe: true, assignmentOperator: suffix, readIndices: config.readIndices }),
config: {
...config,
assignmentOperator: suffix,
makeMaybe: true
},
name: effectiveName,
controlDependencies: undefined,
nodeId: id
}];
this.set(effectiveName, d, assumePrimitive);
}
}
}
/**
* Register a single {@link BuiltInDefinition} to the given memories in {@link builtIns}
*/
registerBuiltInDefinition(definition) {
switch (definition.type) {
case 'constant':
return this.registerBuiltInConstant(definition);
case 'function':
return this.registerBuiltInFunctions(definition);
case 'replacement':
return this.registerReplacementFunctions(definition);
}
}
/**
* The built-in {@link REnvironmentInformation|environment} is the root of all environments.
*
* For its default content (when not overwritten by a flowR config),
* see the {@link DefaultBuiltinConfig}.
*/
builtInMemory = new Map();
/**
* The twin of the {@link builtInMemory} but with less built ins defined for
* cases in which we want some commonly overwritten variables to remain open.
* If you do not know if you need the empty environment, you do not need the empty environment (right now).
*
* @see {@link builtInMemory}
*/
emptyBuiltInMemory = new Map();
set(identifier, definition, includeInEmptyMemory) {
this.builtInMemory.set(identifier, definition);
if (includeInEmptyMemory) {
this.emptyBuiltInMemory.set(identifier, definition);
}
}
}
exports.BuiltIns = BuiltIns;
//# sourceMappingURL=built-in.js.map