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.
107 lines
3.5 KiB
JavaScript
107 lines
3.5 KiB
JavaScript
7 years ago
|
'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];
|
||
|
};
|