const fs = require("fs") const kWantMaxSupportedElements = 100 const kMaxPairedElements = 10 const kMacroParamLimit = 127 function forN(n, cb) { for (var i = 0; i < n; i++) { cb(i) } } function genArray(n) { return [...Array(n).keys()] } function formatNJoin(n, start, join) { return start + genArray(n).join(join) } function formatNJoinReverseSuffix(n, start, join, suffix) { return start + genArray(n).reverse().join(suffix + join) + suffix } function formatNParamPattern(n, join) { return formatNJoin(n, join, ", " + join) } function formatNParamPatternReverseSuffix(n, join, suffix) { return formatNJoinReverseSuffix(n, join, ", " + join, suffix) } var textBuffer = "" textBuffer += `/** * X-Macro alternative. Defines AU_FOR_EACH_N(expandable, ...args*N) * Autogenerated by forEach.js; do not modify" */ #define AU_FE_EXPAND(exp) exp #define AU_FE_ERROR(exp) ERROR. CHECK PARAMETER COUNT. DID YOU FORGET A COMMA? ` forN(kMaxPairedElements, function(nElements) { if (!nElements) return var suffix = nElements != 1 ? "_" + (nElements): "" var nElementsMulNCapped = Math.min(kMacroParamLimit - 3, kWantMaxSupportedElements * nElements) var ignoreList = {} forN(nElementsMulNCapped, function(i) { if (i == 0) { textBuffer += `#define AU_FE_0${suffix}(expandable) \n` ignoreList[`AU_FE_0_FIRST${suffix}`] = true ignoreList[`AU_FE_0_THAT${suffix}`] = true return } var X = formatNParamPattern(nElements, "X") var iM1 = i - 1 var iM1Translated = i - nElements if (i == nElements - 1) { // Edge case: the trailing macro does not do anything // We could hack in an _LAST callback here, should a need for it arise textBuffer += `#define AU_FE_${i}${suffix}(expandable)\n` } else if ((i == 1) && (nElements != 1)) { // Edge case: FOR_EACH_N(EXPANDABLE, ), where N has to be defined/has an element count of > 1, this is always illegal // However, we just ignore empty element expansions textBuffer += `#define AU_FE_${i}${suffix}(expandable, empty)\n` } else if (i % nElements == 0) { if (i == nElements) { // Edge case: the last element does not accept any parameters textBuffer += `#define AU_FE_${i}${suffix}(expandable, ${X}) expandable(${X})\n` } else { textBuffer += `#define AU_FE_${i}${suffix}(expandable, ${X}, ...) expandable(${X}) AU_FE_EXPAND(AU_FE_${iM1Translated}${suffix}(expandable, __VA_ARGS__))\n` } } else { ignoreList[`AU_FE_${i}${suffix}`] = true } var I2 = i + 1 // Similar to above if (i < nElements) { ignoreList[`AU_FE_${i}_THAT${suffix}`] = true } else if (i % nElements == 0) { var offByOne = iM1Translated + 1 if (i == nElements) { // Edge case: the last element does not accept any parameters ignoreList[`AU_FE_${I2}_THAT${suffix}`] = true // ? dont question it textBuffer += `#define AU_FE_${I2}_THAT${suffix}(expandable, ctx, ${X}) expandable(ctx, ${X})\n` } else { textBuffer += `#define AU_FE_${I2}_THAT${suffix}(expandable, ctx, ${X}, ...) expandable(ctx, ${X}) AU_FE_EXPAND(AU_FE_${offByOne}_THAT${suffix}(expandable, ctx, __VA_ARGS__))\n` } } else { ignoreList[`AU_FE_${I2}_THAT${suffix}`] = true } if (i == 1) { textBuffer += `#define AU_FE_${i}_FIRST${suffix}(first, second) \n` } else if (i < nElements) { ignoreList[`AU_FE_${i}_FIRST${suffix}`] = true } else if ((i % (nElements) == 0)) { if (i == nElements) { ignoreList[`AU_FE_${i}_FIRST${suffix}`] = true // ? dont question it textBuffer += `#define AU_FE_${I2}_FIRST${suffix}(first, second, ${X}) first(${X}) AU_FE_EXPAND(AU_FE_${iM1Translated}${suffix}(second))\n` } else { textBuffer += `#define AU_FE_${I2}_FIRST${suffix}(first, second, ${X}, ...) first(${X}) AU_FE_EXPAND(AU_FE_${iM1Translated}${suffix}(second, __VA_ARGS__))\n` } } else { ignoreList[`AU_FE_${I2}_FIRST${suffix}`] = true } }) // Defines a macro that effectively choses a macro given an array of macros based on the number of input arguments var getMacroParams = formatNParamPattern(nElementsMulNCapped, "_") textBuffer += `#define AU_GET_MACRO${suffix}(${getMacroParams}, NAME,...) NAME\n` // Stringify the parameter portion of the prototype var params = formatNParamPatternReverseSuffix(nElementsMulNCapped, "AU_FE_", suffix) var params2 = formatNParamPatternReverseSuffix(nElementsMulNCapped, "AU_FE_", "_FIRST" + suffix) var params3 = formatNParamPatternReverseSuffix(nElementsMulNCapped, "AU_FE_", "_THAT" + suffix) // Replace missing macro paramaters with the AU_FE_ERROR macro params = params .split(", ").map((str) => { return ignoreList[str] ? "AU_FE_ERROR" : str}).join(", ") params2 = params2.split(", ").map((str) => { return ignoreList[str] ? "AU_FE_ERROR" : str}).join(", ") params3 = params3.split(", ").map((str) => { return ignoreList[str] ? "AU_FE_ERROR" : str}).join(", ") textBuffer += `#define AU_FOR_EACH${suffix}(action, ...) AU_FE_EXPAND(AU_GET_MACRO${suffix}(_whydoweneedthis, __VA_ARGS__, ${params})(action,__VA_ARGS__))\n` textBuffer += `#define AU_FOR_EACH_FIRST${suffix}(action, ...) AU_FE_EXPAND(AU_GET_MACRO${suffix}(_whydoweneedthis, __VA_ARGS__, ${params2})(action,__VA_ARGS__))\n` textBuffer += `#define AU_FOR_EACH_THAT${suffix}(action, ...) AU_FE_EXPAND(AU_GET_MACRO${suffix}(_whydoweneedthis, __VA_ARGS__, ${params3})(action,__VA_ARGS__))\n` textBuffer += "\n\n" }) fs.writeFileSync("./Include/AuroraForEach.hpp", textBuffer)