UNPKG

@specs-feup/lara

Version:

A js port of the popular framework for building source-to-source compilers

143 lines (113 loc) 3.48 kB
/** * Counts occurrences of tuples. */ export default class Accumulator { value = 0; accs: { [key: string]: Accumulator } = {}; seenKeys = new Set<string>(); /** * 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: any[]): number { let currentAcc: Accumulator = this; const argsParsed = this.parseArguments(args); // Travel chain of values for (const chainElement of argsParsed) { let nextAcc: Accumulator | undefined = 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: number = 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: any) { const chainArray: string[] = this.parseArguments(arguments); let currentAcc: Accumulator = this; // Travel chain of values for (const chainElement of chainArray) { const nextAcc: Accumulator = 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: any) { let copy: Accumulator = new Accumulator(); for (const key of this.keys()) { const value: number = 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: Array<Array<string>> = []; const currentChain: Array<string> = []; this.keysPrivate(currentChain, chains); return chains; } private keysPrivate( currentChain: Array<string>, chains: Array<Array<string>> ) { // 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. */ private parseArguments(...args: any[]) { 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); } }