From c8195cef5a55b401a6c56cbb4f92cf0e5770de70 Mon Sep 17 00:00:00 2001 From: ElementG9 Date: Mon, 25 Nov 2019 13:23:51 -0700 Subject: [PATCH] Math operators work now --- src/parser.js | 86 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/src/parser.js b/src/parser.js index c8cb097..4722745 100644 --- a/src/parser.js +++ b/src/parser.js @@ -36,7 +36,20 @@ function parse(tokens) { ast = postfixOperators(ast); // Precedence 12. ast = prefixOperators(ast); - + // Precedence 11. + ast = mathOperators(ast, 0); // Level 0 math operators: **. + // Precedence 10. + ast = mathOperators(ast, 1); // Level 1 math operators: *, /, %. + // Precedence 9. + ast = mathOperators(ast, 2); // Level 2 math operators: +, -. + // Precedence 7. + // ast = comparisonOperators(ast); + // Precedence 6. + // ast = assign(ast); + // Precedence 4. + // ast = logicOperators(ast); + // Precedence 3. + // ast = opAssign(ast); return ast; } @@ -301,7 +314,7 @@ function postfixOperators(ast) { * @private */ function prefixOperators(ast) { - for (let i = 0; i < ast.length; i++) { + for (let i = ast.length - 1; i >= 0; i--) { // Prefix operators are rtl associative, so loop backwards. // Take care of the tokens in the groups. if (ast[i].type == 'group') { if (ast[i].tokens.length > 0) { @@ -325,6 +338,75 @@ function prefixOperators(ast) { return ast; } +/** + * @function mathOperators + * @desc Recursively structures the math operators. + * @param {Token[]} ast The ast. + * @param {Token[]} level The level of math to do. (Order of operations) + * @returns {Token[]} The ast with structured math operators. + * @private + */ +function mathOperators(ast, level) { + if (level == 0) { // Level 0 operators: ** + for (let i = ast.length - 1; i >= 0; i--) { // Exponentiation is rtl associative, so loop backwards. + // Take care of the tokens in the groups. + if (ast[i].type == 'group') { + if (ast[i].tokens.length > 0) { + ast[i].tokens = mathOperators(ast[i].tokens, level); + } + } else if (ast[i].type == 'operator') { + if (typeof ast[i].operands != 'undefined') { + ast[i].operands = mathOperators(ast[i].operands, level); + } + } + if (ast[i].type == 'operator' && ast[i].value == '**') { + if (typeof ast[i - 1] == 'undefined' || typeof ast[i + 1] == 'undefined') + throw new SyntaxError('Dual operator requires two operands.'); + let op = new Operator('dual', ast[i].value, [ast[i - 1], ast[i + 1]]); + op.index = ast[i].index; + op.level = ast[i].level; + ast.splice(i - 1, 3, op); + i--; + } + } + } else { + for (let i = 0; i < ast.length; i++) { // All other math operators are ltr associative. + // Take care of the tokens in the groups. + if (ast[i].type == 'group') { + if (ast[i].tokens.length > 0) { + ast[i].tokens = mathOperators(ast[i].tokens, level); + } + } else if (ast[i].type == 'operator') { + if (typeof ast[i].operands != 'undefined') { + ast[i].operands = mathOperators(ast[i].operands, level); + } + } + if (level == 1) { + if (ast[i].type == 'operator' && (ast[i].value == '*' || ast[i].value == '/' || ast[i].value == '%')) { + if (typeof ast[i - 1] == 'undefined' || typeof ast[i + 1] == 'undefined') + throw new SyntaxError('Dual operator requires two operands.'); + let op = new Operator('dual', ast[i].value, [ast[i - 1], ast[i + 1]]); + op.index = ast[i].index; + op.level = ast[i].level; + ast.splice(i - 1, 3, op); + i--; + } + } else if (level == 2) { + if (ast[i].type == 'operator' && (ast[i].value == '+' || ast[i].value == '-')) { + if (typeof ast[i - 1] == 'undefined' || typeof ast[i + 1] == 'undefined') + throw new SyntaxError('Dual operator requires two operands.'); + let op = new Operator('dual', ast[i].value, [ast[i - 1], ast[i + 1]]); + op.index = ast[i].index; + op.level = ast[i].level; + ast.splice(i - 1, 3, op); + i--; + } + } + } + } + return ast; +} + module.exports = { parse, util: {