'use strict'; const util = require("util"); const generateOperatorMap = require("./generate-operator-map"); const findOperatorSequences = require("./find-operator-sequences"); const addPrecedences = require("./add-precedences"); module.exports = function reorderOperatorExpressions(tree, operators) { let operatorsWithPrecedence = addPrecedences(operators); let operatorMap = generateOperatorMap(operatorsWithPrecedence); let sequenceResults = findOperatorSequences(tree, operatorMap); let modifiedOperands = sequenceResults.operands.slice(); let relocatedOperands = new Array(modifiedOperands.length); function lookupOperandIndex(i) { if (relocatedOperands[i] != null) { // FIXME: This shouldn't be recursive; instead, relocation pointers should be updated after a cascading relocation. return lookupOperandIndex(relocatedOperands[i]); } else { return i; } } function getOperand(i) { let index = lookupOperandIndex(i); let operand = modifiedOperands[lookupOperandIndex(i)]; //console.log(`OPERAND AT INDEX ${index}: ${util.inspect(operand)}`) return modifiedOperands[lookupOperandIndex(i)]; } operatorsWithPrecedence.forEach((operator) => { let currentPrecedence = operator.precedence; let sequences = sequenceResults.operatorSequenceMap[currentPrecedence]; if (sequences != null) { sequences.forEach((sequence, sequenceIndex) => { let untilIndex = sequence.firstIndex + sequence.length; let associativity = sequence.associativity; let root, current; function addOperator(index) { let newNode = { type: "operatorExpression", operator: sequenceResults.operators[index], right: (associativity !== "right") ? getOperand(index + 1) : undefined, left: (associativity !== "left" && !operator.unary) ? getOperand(index) : undefined } if (root == null) { root = newNode; } else { if (associativity === "left") { current.left = newNode; } else if (associativity === "right") { current.right = newNode; } } current = newNode; } if (associativity === "none") { /* Cannot occur more than once... */ if (sequence.length > 1) { // FIXME: This does not yet detect multiple occurrences in different sequences... throw new Error(`Operators in series '${operators[sequence.precedence].join(", ")}' may only occur once in a series of operator expressions, but occurred ${sequence.length} times`); } else { addOperator(sequence.firstIndex); } } else { if (associativity === "left") { for (let i = untilIndex - 1; i >= sequence.firstIndex; i--) { addOperator(i); } current.left = getOperand(sequence.firstIndex); } else if (associativity === "right") { for (let i = sequence.firstIndex; i < untilIndex; i++) { addOperator(i); } current.right = getOperand(untilIndex); } } let newLocation = lookupOperandIndex(sequence.firstIndex); modifiedOperands[newLocation] = root; for (let i = sequence.firstIndex; i < untilIndex; i++) { modifiedOperands[i + 1] = null; relocatedOperands[i + 1] = newLocation; } // console.log(`MODIFIED OPERANDS AFTER PRECEDENCE LEVEL ${currentPrecedence} (pos ${sequence.firstIndex} - ${sequence.firstIndex + sequence.length}):`, modifiedOperands.map((modOp) => { // return (modOp == null) ? "null" : `<${modOp.type} ${modOp.identifier || modOp.value || modOp.operator}>`; // }).join(", ")) }); } }); return modifiedOperands[0]; };