Last active
December 17, 2024 10:45
-
-
Save joepie91/c5949279cd52ce5cb646d7bd03c3ea36 to your computer and use it in GitHub Desktop.
Revisions
-
joepie91 revised this gist
Jul 14, 2016 . No changes.There are no files selected for viewing
-
joepie91 created this gist
Jul 14, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,35 @@ 'use strict'; const parseExpression = require("./parse-expression"); function findAll(regex, target) { let results = [], match; while (match = regex.exec(target)) { results.push(match); } return results; } module.exports = function(testcase) { let result; let [_, parent, child, initialExpression] = /var s,t,o,p,b,r,e,a,k,i,n,g,f,\s*([a-zA-Z]+)={"([a-zA-Z]+)":([^}]+)};/.exec(testcase); let modifyingExpressions = findAll(new RegExp(`${parent}\.${child}\s*([*+-])=\s*([^;]+)`, "g"), testcase).map((match) => { return { operation: match[1], expression: match[2] } }).map(({operation, expression}) => { return { operation, expression: parseExpression(expression) } }); initialExpression = parseExpression(initialExpression); return {parent, child, initialExpression, modifyingExpressions}; } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,128 @@ 'use strict'; const arrayEqual = require("array-equal"); module.exports = function(string) { return evaluate(parse(string)); } function evaluateBranch(tree, modifiers) { let result = tree.map((expression) => { if (expression.type === "group") { return evaluateBranch(expression.values, expression.modifiers); } else if (expression.modifiers.length === 0) { return ""; // This is a trigger to stringify the previous values } else if (arrayEqual(["plus"], expression.modifiers)) { return 0; } else if (arrayEqual(["negate", "negate"], expression.modifiers)) { return true; } else if (arrayEqual(["negate", "plus"], expression.modifiers)) { return true; } else if (arrayEqual(["plus", "plus", "negate"], expression.modifiers)) { return true; } else if (arrayEqual(["plus", "negate", "negate"], expression.modifiers)) { return 1; } else { throw new Error(`Found unrecognized modifier pattern: ${expression.modifiers}`) } }).reduce((combined, value) => { if (value === "") { return combined.toString(); } else { if (value === true) { value = 1; } if (typeof combined === "string") { return combined + value.toString(); } else { return combined + value; } } }, 0); if (modifiers == null) { return result; } else { if (arrayEqual(["plus"], modifiers)) { return parseInt(result); } else { return result; } } } function evaluate(tree) { return evaluateBranch(tree); } function parse(string) { let length = string.length; let byte; let stateFinishedItem = false; let modifierStack = [[]]; let itemStack = [[]]; let currentStack = itemStack[0]; let currentModifiers = modifierStack[0]; let stackLevel = 0; for (let pos = 0; pos < length; pos++) { byte = string[pos]; switch (byte) { case "+": if (pos === 0 || stateFinishedItem === false) { // Modifier / number-cast currentModifiers.push("plus"); stateFinishedItem = false; } else { // Addition, we don't need to do anything here } break; case "!": stateFinishedItem = false; currentModifiers.push("negate"); break; case "(": stateFinishedItem = false; stackLevel++; itemStack[stackLevel] = currentStack = []; modifierStack[stackLevel] = currentModifiers = []; break; case ")": if (stackLevel === 0) { throw new Error(`Encountered ) without matching (`); } stackLevel--; stateFinishedItem = true; currentStack = itemStack[stackLevel]; currentStack.push({ type: "group", values: itemStack[stackLevel + 1], modifiers: modifierStack[stackLevel] }); currentModifiers = modifierStack[stackLevel] = []; break; case "[": if (string[pos + 1] === "]") { // Reached the brackets; end of the modifier sequence currentStack.push({ type: "brackets", modifiers: currentModifiers }); currentModifiers = []; pos += 1; // Skip over the closing bracket stateFinishedItem = true; } else { throw new Error(`Invalid byte found; expected ] but got ${string[pos + 1]}`); } } } return itemStack[0]; }