Skip to content

Instantly share code, notes, and snippets.

@janus
Last active May 24, 2018 08:38
Show Gist options
  • Save janus/c1a147f306be9f73f1036baaf1a06a76 to your computer and use it in GitHub Desktop.
Save janus/c1a147f306be9f73f1036baaf1a06a76 to your computer and use it in GitHub Desktop.
Helping kids to play with Math
// 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());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment