@specs-feup/lara
Version:
A js port of the popular framework for building source-to-source compilers
109 lines • 3.62 kB
JavaScript
/**
* Counts occurrences of tuples.
*/
export default class Accumulator {
value = 0;
accs = {};
seenKeys = new Set();
/**
* Adds the tuple to the accumulator. Each time a tuple is added, the corresponding value increments by 1.
*
* Alternatively, can also receive an array with the chain of values
*
* @returns the previous count of the added element
*/
add(...args) {
let currentAcc = this;
const argsParsed = this.parseArguments(args);
// Travel chain of values
for (const chainElement of argsParsed) {
let nextAcc = currentAcc.accs[chainElement];
// If no accumulator, create
if (nextAcc === undefined) {
nextAcc = new Accumulator();
currentAcc.accs[chainElement] = nextAcc;
currentAcc.seenKeys.add(chainElement);
}
// Update acc
currentAcc = nextAcc;
}
// Store previous value
const previousValue = currentAcc.value;
// Increment acc value
currentAcc.value++;
return previousValue;
}
/**
* Adds the value associated to the given tuple. If no value is defined for the given tuple, returns 0.
* <p>
* Alternatively, can also receive an array with the chain of values
*/
get(...args) {
const chainArray = this.parseArguments(arguments);
let currentAcc = this;
// Travel chain of values
for (const chainElement of chainArray) {
const nextAcc = currentAcc.accs[chainElement];
// If no accumulator, return 0
if (nextAcc === undefined) {
return 0;
}
// Update acc
currentAcc = nextAcc;
}
// Return acc value
return currentAcc.value;
}
copy(...args) {
let copy = new Accumulator();
for (const key of this.keys()) {
const value = this.get(key);
// TODO: Not efficient, should have a method to internally set a value ---OLD---
for (let i = 0; i < value; i++) {
copy.add(key);
}
}
return copy;
}
/**
* Returns an array of arrays with keys that have a value set.
*/
keys() {
const chains = [];
const currentChain = [];
this.keysPrivate(currentChain, chains);
return chains;
}
keysPrivate(currentChain, chains) {
// If this accumulator has a value, add current chain
if (this.value > 0) {
chains.push(currentChain);
}
for (const key of this.seenKeys) {
const updatedChain = currentChain.concat(key);
const nextAcc = this.accs[key];
if (nextAcc === undefined) {
continue;
}
nextAcc.keysPrivate(updatedChain, chains);
}
}
/**
* Receives an array with the arguments of the previous function.
*/
parseArguments(...args) {
if (args.length !== 1) {
throw "Accumulator._parseArguments: Expected arguments to have length 1";
}
let functionArguments = args[0];
// If one argument and array, return it
if (functionArguments.length === 1 &&
functionArguments[0].constructor === Array) {
// Retrive the array in the previous arguments
return functionArguments[0];
}
// Transform arguments into array
return Array.from(functionArguments);
}
}
//# sourceMappingURL=Accumulator.js.map