woving
Version:
Parses woving patterns. Woving is a domain specific language for generating patterns and instructions for weaving drafts.
153 lines (129 loc) • 4.21 kB
JavaScript
function evaluate(ast) {
if (!ast) {
return '';
}
if (Number.isInteger(ast)) {
return ast.toString();
}
if (typeof ast === 'string' || ast instanceof String) {
return ast;
} switch (ast.type) {
case "binary":
return repeat(evaluate(ast.left), parseHexToNumber(evaluate(ast.right)));
case "join":
return join(evaluate(ast.left), evaluate(ast.right));
case "step_array":
return stepArray(evaluate(ast.left));
case "postfix":
switch (ast.op) {
case ("|"):
return sym(evaluate(ast.left));
case ("!"):
return pointSym(evaluate(ast.left));
case ("?"):
return randomKeep(evaluate(ast.left));
}
break;
case "number": {
return ast.left.toString();
}
default:
throw ("Error with: " + JSON.stringify(ast));
}
}
// :
function repeat(value, repeat) {
if (repeat > 100) {
repeat = 1;
console.warn('repeat value greater than 100, setting back to 1 since, well, yeah.');
}
return (Array(repeat + 1).join(value));
}
// /.../
function stepArray(value) {
if (!value || value === '') {
return '';
}
const valueStr = value.toString();
if (valueStr.length === 1) {
return valueStr;
}
const stepArr = [];
// Helper function to convert hex digit to numeric value for comparison
const getHexValue = (char) => {
if (char >= '1' && char <= '9') return parseInt(char);
if (char >= 'a' && char <= 'f') return char.charCodeAt(0) - 'a'.charCodeAt(0) + 10;
return 0; // fallback
};
// Helper function to get next/previous hex digit
const getHexChar = (value) => {
if (value >= 1 && value <= 9) return value.toString();
if (value >= 10 && value <= 15) return String.fromCharCode('a'.charCodeAt(0) + value - 10);
return '';
};
for (let i = 1; i < valueStr.length; i++) {
const start = valueStr[i - 1];
const end = valueStr[i];
const startVal = getHexValue(start);
const endVal = getHexValue(end);
if (startVal < endVal) {
for (let j = startVal; j < endVal; j++) {
stepArr.push(getHexChar(j));
}
} else if (startVal > endVal) {
for (let j = startVal; j > endVal; j--) {
stepArr.push(getHexChar(j));
}
} else {
stepArr.push(start);
}
}
stepArr.push(valueStr[valueStr.length - 1]);
return arrToStr(stepArr);
}
// |
function sym(value) {
return arrToStr([value, Array.from(value.toString()).reverse().join("")]);
}
// !
function pointSym(value) {
const valueArr = Array.from(value.toString());
const valueLen = valueArr.length;
if (valueLen === 1) {
return value;
}
const result = valueArr.slice(0, valueLen - 1);
const mirroredPart = result.slice().reverse();
result.push(valueArr[valueLen - 1]);
return arrToStr(result.concat(mirroredPart));
}
// ?
function randomKeep(value) {
return Math.random() < 0.5 ? value.toString() : '';
}
// Helper function to parse hex string to number
function parseHexToNumber(hexStr) {
if (!hexStr || hexStr === '') return 0;
// Convert hex string to number
let result = 0;
for (let i = 0; i < hexStr.length; i++) {
const char = hexStr[i];
let digitValue;
if (char >= '1' && char <= '9') {
digitValue = parseInt(char);
} else if (char >= 'a' && char <= 'f') {
digitValue = char.charCodeAt(0) - 'a'.charCodeAt(0) + 10;
} else {
continue; // skip invalid characters
}
result = result * 16 + digitValue;
}
return result;
}
function join(a, b) {
return arrToStr([a, b]);
}
function arrToStr(arr) {
return (arr.join(""));
}
module.exports = evaluate;