// This is just a sample script. Paste your real code (javascript or HTML) here. /* * Copy right holder Ikjo * You are free to enjoy, however give credit to Ikjo * examples * mathProxy.twofourMultiplyonePlusfivefiveDividethree() * mathProxy.two_four_Multiply_one_Plus_five_five_Divide_three() * conditions * math operators are titlized * number are lower case * it accepts '_' as separation * mathProxy is already instantiated */ 'use strict' const BINARY_OPS = ["Plus", "Minus", "Divide", "Multiply"]; const OPS_WEIGHT = { Plus: 1, Minus: 1, Divide: 2, Multiply: 2 }; const FUNCTIONS = { Plus: (left, right) => left + right, Minus: (left, right) => left - right, Multiply: (left, right) => left * right, Divide: (left, right) => { if (right === 0) { throw new Error("Division by zero is not allowed"); } return left / right; } }; var mathProxy = new Proxy({}, { get(target, property) { return computeMath(property); } }); function computeMath(query) { let parsed = parser(query); return () => interpret(parsed.tokens); } function isUpperCase(str) { return str === str.toUpperCase(); } function mapStringToNum(str) { let strNumMap = { 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5', 'six': '6', 'seven': '7', 'eight': '8', 'nine': '9', 'zero': '0' }; return strNumMap[str]; } function parser(nstream) { let stream = nstream.replace(/_/g, ''); let len = stream.length, storeStringNum = [], tokens = [], val; let unknown = 1, operand = 2, operator = 3; let state = unknown, string_acc = '', i = 0; while (i < len) { switch (state) { case unknown: state = isUpperCase(stream[i]) ? operator : operand; string_acc = stream[i]; i++; break; case operand: if (i < len) { string_acc += stream[i]; i++; while (i < len) { if (!mapStringToNum(string_acc)) { string_acc += stream[i]; i++; continue; } else { storeStringNum.push(mapStringToNum(string_acc)); string_acc = ''; state = unknown; break; } } } if (mapStringToNum(string_acc)) { storeStringNum.push(mapStringToNum(string_acc)); } else if (string_acc) { throw new Error(`Unknown token operand <${string_acc}>`); } break; case operator: if (storeStringNum.length === 0) { throw new Error("Operator must be binary operator"); } else { val = storeStringNum.join(''); tokens.push(Number(val)); storeStringNum = []; } if (i < len) { string_acc += stream[i]; i++; while (i < len) { if (BINARY_OPS.includes(string_acc)) { tokens.push(string_acc); string_acc = ''; state = unknown; break; } string_acc += stream[i]; i++; } } break; default: throw new Error(`Unknown token <${string_acc}>`); } } if (storeStringNum.length === 0) { throw new Error('Only Binary operators are expected'); } else { val = storeStringNum.join(''); tokens.push(Number(val)); } return { tokens }; } function interpret(tokens) { let vals = [], ops = [], right, left, val, vop; let len = tokens.length, i = 0; while (i < len) { if (typeof tokens[i] === 'number') { vals.push(tokens[i]); i++; continue; } if (ops.length === 0) { ops.push(tokens[i]); i++ continue; } else { vop = ops.pop(); if (OPS_WEIGHT[vop] > OPS_WEIGHT[tokens[i]]) { right = vals.pop(); left = vals.pop(); vals.push(FUNCTIONS[vop](left, right)); while (ops.length > 0) { vop = ops.pop(); if (OPS_WEIGHT[vop] > OPS_WEIGHT[tokens[i]]) { right = vals.pop(); left = vals.pop(); vals.push(FUNCTIONS[vop](left, right)); continue; } ops.push(vop); ops.push(tokens[i]); break; } if (ops.length === 0) { ops.push(tokens[i]); } } else { ops.push(vop); ops.push(tokens[i]); } i++; } } while (ops.length > 0) { right = vals.pop(); left = vals.pop(); vals.push(FUNCTIONS[ops.pop()](left, right)); } if (vals.length === 1) { return vals.pop(); } else { throw new Error("Interpretation failed, wrong grammar"); } } //console.log(parser("twotwoPluseightfive")); //console.log(interpret(parser("twotwoPluseightfiveMultiplyfour").tokens)); console.log(mathProxy.twofourMultiplyonePlusfivefiveDividethree()); console.log(mathProxy.two_four_Multiply_one_Plus_five_five_Divide_three());