forked from DebaucheryLibrarian/traxxx
Refactored clips into chapters.
This commit is contained in:
153
src/utils/cf.js
Normal file
153
src/utils/cf.js
Normal file
@@ -0,0 +1,153 @@
|
||||
'use strict';
|
||||
|
||||
const arrayEqual = require('array-equal');
|
||||
|
||||
/* eslint-disable */
|
||||
function evaluateBranch(tree, modifiers) {
|
||||
const result = tree.map((expression) => {
|
||||
if (expression.type === 'group') {
|
||||
return evaluateBranch(expression.values, expression.modifiers);
|
||||
} if (expression.modifiers.length === 0) {
|
||||
return ''; // This is a trigger to stringify the previous values
|
||||
} if (arrayEqual(['plus'], expression.modifiers)) {
|
||||
return 0;
|
||||
} if (arrayEqual(['negate', 'negate'], expression.modifiers)) {
|
||||
return true;
|
||||
} if (arrayEqual(['negate', 'plus'], expression.modifiers)) {
|
||||
return true;
|
||||
} if (arrayEqual(['plus', 'plus', 'negate'], expression.modifiers)) {
|
||||
return true;
|
||||
} if (arrayEqual(['plus', 'negate', 'negate'], expression.modifiers)) {
|
||||
return 1;
|
||||
}
|
||||
throw new Error(`Found unrecognized modifier pattern: ${expression.modifiers}`);
|
||||
}).reduce((combined, value) => {
|
||||
if (value === '') {
|
||||
return combined.toString();
|
||||
}
|
||||
if (value === true) {
|
||||
value = 1;
|
||||
}
|
||||
|
||||
if (typeof combined === 'string') {
|
||||
return combined + value.toString();
|
||||
}
|
||||
return combined + value;
|
||||
}, 0);
|
||||
|
||||
if (modifiers == null) {
|
||||
return result;
|
||||
}
|
||||
if (arrayEqual(['plus'], modifiers)) {
|
||||
return parseInt(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function evaluate(tree) {
|
||||
return evaluateBranch(tree);
|
||||
}
|
||||
|
||||
function parse(string) {
|
||||
const length = string.length;
|
||||
let byte;
|
||||
|
||||
let stateFinishedItem = false;
|
||||
const modifierStack = [[]];
|
||||
const 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];
|
||||
}
|
||||
|
||||
function parseExpression(string) {
|
||||
return evaluate(parse(string));
|
||||
}
|
||||
|
||||
function findAll(regex, target) {
|
||||
const results = []; let
|
||||
match;
|
||||
|
||||
while (match = regex.exec(target)) {
|
||||
results.push(match);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function cf(testcase) {
|
||||
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);
|
||||
|
||||
const modifyingExpressions = findAll(new RegExp(`${parent}\.${child}\s*([*+-])=\s*([^;]+)`, 'g'), testcase).map(match => ({
|
||||
operation: match[1],
|
||||
expression: match[2],
|
||||
})).map(({ operation, expression }) => ({
|
||||
operation,
|
||||
expression: parseExpression(expression),
|
||||
}));
|
||||
|
||||
initialExpression = parseExpression(initialExpression);
|
||||
|
||||
return { parent, child, initialExpression, modifyingExpressions };
|
||||
};
|
||||
|
||||
module.exports = cf;
|
||||
Reference in New Issue
Block a user