UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

135 lines 6.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveNode = resolveNode; exports.resolveAsVector = resolveAsVector; exports.resolveAsSeq = resolveAsSeq; const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call"); const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type"); const r_value_1 = require("../../../util/r-value"); const interval_constants_1 = require("../values/intervals/interval-constants"); const logical_constants_1 = require("../values/logical/logical-constants"); const r_value_2 = require("../values/r-value"); const string_constants_1 = require("../values/string/string-constants"); const vector_constants_1 = require("../values/vectors/vector-constants"); const scalar_constants_1 = require("../values/scalar/scalar-constants"); const identifier_1 = require("../../environments/identifier"); const df_helper_1 = require("../../graph/df-helper"); const node_id_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/node-id"); const resolve_helper_1 = require("../../environments/resolve-helper"); /** * The {@link BuiltInEvalHandler} the given name resolves to in the current environment, just like the * {@link BuiltInIdentifierDefinition#processor} a call resolves to; `undefined` if the name is shadowed * by a user definition or its built-in declares no handler. */ function evalHandlerOf(name, environment, ctx) { const defs = environment ? resolve_helper_1.Resolve.byNameAndType(name, environment, identifier_1.ReferenceType.BuiltInFunction) : ctx.env.builtInEnvironment.memory.get(identifier_1.Identifier.getName(name)); const def = defs?.length === 1 ? defs[0] : undefined; return def?.type === identifier_1.ReferenceType.BuiltInFunction ? def.evalHandler : undefined; } /** the node types that may fold through a built-in: calls, operators, and the `(`/`{` groupings */ const EvalNodeTypes = [type_1.RType.FunctionCall, type_1.RType.BinaryOp, type_1.RType.UnaryOp, type_1.RType.ExpressionList]; /** * The name of the built-in the given node folds through, `undefined` if it is no call to one or if it may just * as well resolve to something else (a user redefinition, a conditional one, ...), which must not be folded. */ function evalNameOf({ node, graph }) { if (graph === undefined || !EvalNodeTypes.includes(node.type)) { return undefined; } let name; for (const origin of df_helper_1.Dataflow.origin(graph, node.info.id) ?? []) { if (origin.type === 2 /* OriginType.FunctionCallOrigin */ || origin.type === 1 /* OriginType.WriteVariableOrigin */) { /* the call may go to a definition of the program instead, so we know too little to fold it */ return undefined; } else if (origin.type !== 3 /* OriginType.BuiltInFunctionOrigin */) { continue; } /* an alias like `f <- c` keeps the built-in it stands for in `proc`, a direct call names itself */ const pkgFn = node_id_1.NodeId.toPkgFn(origin.proc); const named = pkgFn !== undefined ? identifier_1.Identifier.make(pkgFn[1], pkgFn[0]) : node_id_1.NodeId.isBuiltIn(origin.proc) ? node_id_1.NodeId.fromBuiltIn(origin.proc) : origin.fn.name; if (name !== undefined && identifier_1.Identifier.getName(name) !== identifier_1.Identifier.getName(named)) { return undefined; } name = named; } return name; } /** * Helper function used by {@link Resolve.toValue}, please use that instead, if * you want to resolve the value of an identifier / node * * This function converts an RNode to its Value, either directly for a constant or by handing the node * to the {@link BuiltInEvalHandler} its built-in declares, which may resolve further nodes recursively. * @returns resolved value or top/bottom */ function resolveNode(args) { const { node, environment, ctx } = args; const nt = node.type; if (nt === type_1.RType.String) { return (0, string_constants_1.stringFrom)(node.content.str); } else if (nt === type_1.RType.Number) { return (0, interval_constants_1.intervalFrom)(node.content.num, node.content.num); } else if (nt === type_1.RType.Logical) { return node.content.valueOf() ? logical_constants_1.ValueLogicalTrue : logical_constants_1.ValueLogicalFalse; } else if (nt === type_1.RType.FunctionDefinition) { return { type: 'function-definition' }; } const name = evalNameOf(args); const handler = name === undefined ? undefined : evalHandlerOf(name, environment, ctx); return handler?.(args) ?? r_value_2.Top; } /** * Helper function used by {@link Resolve.toValue}, please use that instead, if * you want to resolve the value of an identifier / node * * This function resolves a vector function call `c` to a {@link ValueVector} * by recursively resolving the values of the arguments by calling {@link Resolve.toValue} * @returns ValueVector or Top */ function resolveAsVector(args) { const node = args.node; if (node.type !== type_1.RType.FunctionCall) { return r_value_2.Top; } return (0, vector_constants_1.vectorFrom)((0, vector_constants_1.flattenVectorElements)(node.arguments.map(arg => arg !== r_function_call_1.EmptyArgument ? resolve_helper_1.Resolve.toValue(arg.value, args) : r_value_2.Top))); } /** * Helper function used by {@link Resolve.toValue}, please use that instead, if * you want to resolve the value of an identifier / node * * This function resolves a binary sequence operator `:` to a {@link ValueVector} of {@link ValueNumber}s * by recursively resolving the values of the arguments by calling {@link Resolve.toValue} * @returns ValueVector of ValueNumbers or Top */ function resolveAsSeq(args) { const operator = args.node; if (operator.type !== type_1.RType.BinaryOp) { return r_value_2.Top; } const leftValue = (0, r_value_1.unliftRValue)(resolve_helper_1.Resolve.toValue(operator.lhs, args)); const rightValue = (0, r_value_1.unliftRValue)(resolve_helper_1.Resolve.toValue(operator.rhs, args)); if ((0, r_value_1.isRNumberValue)(leftValue) && (0, r_value_1.isRNumberValue)(rightValue)) { return (0, vector_constants_1.vectorFrom)(createNumberSequence(leftValue, rightValue).map(scalar_constants_1.liftScalar)); } return r_value_2.Top; } function createNumberSequence(start, end) { const sequence = []; const min = Math.min(start.num, end.num); const max = Math.max(start.num, end.num); for (let i = min; i <= max; i++) { sequence.push({ ...start, num: i }); } if (start > end) { sequence.reverse(); } return sequence; } //# sourceMappingURL=resolve.js.map