UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

154 lines 6.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.mergeDefinitions = mergeDefinitions; exports.define = define; const assert_1 = require("../../util/assert"); const environment_1 = require("./environment"); const clone_1 = require("./clone"); const vertex_1 = require("../graph/vertex"); const config_1 = require("../../config"); function defInEnv(newEnvironments, name, definition) { const existing = newEnvironments.memory.get(name); // When there are defined indices, merge the definitions const inGraphDefinition = definition; if ((0, config_1.getConfig)().solver.pointerTracking && existing !== undefined && inGraphDefinition.controlDependencies === undefined) { if (inGraphDefinition.indicesCollection !== undefined) { newEnvironments.memory.set(name, mergeDefinitions(existing, inGraphDefinition)); return; } else if (existing?.flatMap(i => i.indicesCollection ?? []).length > 0) { // When indices couldn't be resolved, but indices where defined before, just add the definition existing.push(definition); return; } } // check if it is maybe or not if (existing === undefined || definition.controlDependencies === undefined) { newEnvironments.memory.set(name, [definition]); } else { existing.push(definition); } } /** * assumes: existing is not undefined, the overwrite has indices */ function mergeDefinitions(existing, definition) { // When new definition is not a single index, e.g., a list redefinition, then reset existing definition if (definition.indicesCollection?.some(indices => indices.isContainer)) { return [definition]; } const existingDefs = existing.filter(assert_1.isNotUndefined); const overwriteIndices = definition.indicesCollection?.flatMap(indices => indices.indices) ?? []; // Compare existing and new definitions, // add new definitions and remove existing definitions that are overwritten by new definition const newExistingDefs = []; const hasCache = new Set(); for (const overwriteIndex of overwriteIndices) { for (const existingDef of existingDefs) { // empty or missing if (existingDef.indicesCollection === undefined || existingDef.indicesCollection.length === 0) { const existingDefPrint = JSON.stringify(existingDef); if (!hasCache.has(existingDefPrint)) { newExistingDefs.push(existingDef); hasCache.add(existingDefPrint); } continue; } const newIndicesCollection = overwriteContainerIndices(existingDef.indicesCollection, overwriteIndex); // if indices are now empty list, don't keep empty definition if (newIndicesCollection.length > 0) { const obj = { ...existingDef, indicesCollection: newIndicesCollection, }; const objHash = JSON.stringify(obj); if (!hasCache.has(objHash)) { newExistingDefs.push(obj); hasCache.add(objHash); } } } } // store changed existing definitions and add new one return [...newExistingDefs, definition]; } function overwriteContainerIndices(existingIndices, overwriteIndex) { const newIndicesCollection = []; for (const indices of existingIndices) { let newIndices; // When overwrite index is container itself, then only overwrite sub-index if ((0, vertex_1.isParentContainerIndex)(overwriteIndex)) { newIndices = []; for (const index of indices.indices) { if ((0, vertex_1.isSameIndex)(index, overwriteIndex) && (0, vertex_1.isParentContainerIndex)(index)) { const overwriteSubIndices = overwriteIndex.subIndices.flatMap(a => a.indices); let newSubIndices = index.subIndices; for (const overwriteSubIndex of overwriteSubIndices) { newSubIndices = overwriteContainerIndices(newSubIndices, overwriteSubIndex); } if (newSubIndices.length > 0) { newIndices.push({ ...index, subIndices: newSubIndices, }); } } if (!(0, vertex_1.isSameIndex)(index, overwriteIndex) || !(0, vertex_1.isParentContainerIndex)(index)) { newIndices.push(index); } } } else if (indices.isContainer) { // If indices are not a single, e.g., a list, take the whole definition newIndices = indices.indices; } else { // Filter existing indices with the same name newIndices = indices.indices.filter(def => !(0, vertex_1.isSameIndex)(def, overwriteIndex)); } if (indices.isContainer || newIndices.length > 0) { newIndicesCollection.push({ ...indices, indices: newIndices, }); } } return newIndicesCollection; } /** * Insert the given `definition` --- defined within the given scope --- into the passed along `environments` will take care of propagation. * Does not modify the passed along `environments` in-place! It returns the new reference. */ function define(definition, superAssign, environment) { const name = definition.name; (0, assert_1.guard)(name !== undefined, () => `Name must be defined, but isn't for ${JSON.stringify(definition)}`); let newEnvironment; if (superAssign) { newEnvironment = (0, clone_1.cloneEnvironmentInformation)(environment, true); let current = newEnvironment.current; let last = undefined; let found = false; do { if (current.memory.has(name)) { current.memory.set(name, [definition]); found = true; break; } last = current; current = current.parent; } while (current.id !== environment_1.BuiltInEnvironment.id); if (!found) { (0, assert_1.guard)(last !== undefined, () => `Could not find global scope for ${name}`); last.memory.set(name, [definition]); } } else { newEnvironment = (0, clone_1.cloneEnvironmentInformation)(environment, false); defInEnv(newEnvironment.current, name, definition); } return newEnvironment; } //# sourceMappingURL=define.js.map