You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.4 KiB
JavaScript

'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)];
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];
};