@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
72 lines • 2.79 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VisitingQueue = void 0;
const fingerprint_1 = require("./fingerprint");
class VisitingQueue {
threshold;
timesHitThreshold = 0;
seen = new Map();
seenByCache = new Set();
idThreshold = new Map();
queue = [];
cache = new Map();
// the set of potential additions holds nodes which may be added if a second edge deems them relevant (e.g., found with the `defined-by-on-call` edge)
// additionally it holds which node id added the addition so we can separate their inclusion on the structure
potentialAdditions = new Map();
cachedCallTargets = new Map();
constructor(threshold, cache) {
this.threshold = threshold;
this.cache = cache;
}
/**
* Adds a node to the queue if it has not been seen before.
* @param target - the node to add
* @param env - the environment the node is traversed in
* @param envFingerprint - the fingerprint of the environment
* @param onlyForSideEffects - whether the node is only used for its side effects
*/
add(target, env, envFingerprint, onlyForSideEffects) {
const idCounter = this.idThreshold.get(target) ?? 0;
if (idCounter > this.threshold) {
this.timesHitThreshold++;
return;
}
/* we do not include the in call part in the fingerprint as it is 'deterministic' from the source position */
const print = (0, fingerprint_1.fingerprint)(target, envFingerprint, onlyForSideEffects);
if (!this.seen.has(print)) {
const cached = this.cache?.get(print);
if (cached) {
this.seenByCache.add(target);
for (const id of cached) {
this.queue.push({ id, baseEnvironment: env, envFingerprint, onlyForSideEffects });
}
}
this.idThreshold.set(target, idCounter + 1);
this.seen.set(print, target);
this.queue.push({ id: target, baseEnvironment: env, envFingerprint, onlyForSideEffects });
}
}
next() {
return this.queue.pop();
}
nonEmpty() {
return this.queue.length > 0;
}
hasId(id) {
return this.idThreshold.has(id);
}
memoizeCallTargets(id, targets) {
if (!this.cachedCallTargets.has(id)) {
this.cachedCallTargets.set(id, targets());
}
return this.cachedCallTargets.get(id);
}
status() {
return {
timesHitThreshold: this.timesHitThreshold,
result: new Set([...this.seen.values(), ...this.seenByCache])
};
}
}
exports.VisitingQueue = VisitingQueue;
//# sourceMappingURL=visiting-queue.js.map