Skip to content

Instantly share code, notes, and snippets.

@mjnaderi
Created September 26, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjnaderi/3bb3be3d244495d7e559 to your computer and use it in GitHub Desktop.
Save mjnaderi/3bb3be3d244495d7e559 to your computer and use it in GitHub Desktop.
Simple math expression evaluator based on jsep
var jsep = require('jsep');
(function (root) {
var COMPOUND = 'Compound',
IDENTIFIER = 'Identifier',
MEMBER_EXP = 'MemberExpression',
LITERAL = 'Literal',
THIS_EXP = 'ThisExpression',
CALL_EXP = 'CallExpression',
UNARY_EXP = 'UnaryExpression',
BINARY_EXP = 'BinaryExpression',
LOGICAL_EXP = 'LogicalExpression',
CONDITIONAL_EXP = 'ConditionalExpression',
ARRAY_EXP = 'ArrayExpression';
var functions = {
'abs': Math.abs,
'floor': Math.floor,
'ceil': Math.ceil,
'exp': Math.exp,
'sqrt': Math.sqrt,
'log': Math.log,
'log10': Math.log10
};
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
var evalTree = function (tree, context) {
if (tree === false || typeof tree === 'undefined')
throw 'خطایی در عبارت ریاضی داده شده وجود دارد.';
if (tree.type === LITERAL) {
if (!(isNumeric(tree.value)))
throw 'تنها مقادیر عددی قابل قبول هستند.';
return tree.value;
}
if (tree.type == IDENTIFIER) {
if (typeof context === 'undefined')
throw 'ورودی context داده نشده است';
if (tree.name in context)
return context[tree.name];
throw 'مقدار ' + tree.name + ' تعریف نشده است.';
}
if (tree.type === UNARY_EXP) {
if (tree.operator === '+')
return evalTree(tree.argument, context);
if (tree.operator === '-')
return -evalTree(tree.argument, context);
throw 'عملگر یگانی ' + tree.operator + ' پشتیبانی نمی‌شود.';
}
if (tree.type === BINARY_EXP) {
if (tree.operator === '+')
return evalTree(tree.left, context) + evalTree(tree.right, context);
if (tree.operator === '-')
return evalTree(tree.left, context) - evalTree(tree.right, context);
if (tree.operator === '*')
return evalTree(tree.left, context) * evalTree(tree.right, context);
if (tree.operator === '/')
return evalTree(tree.left, context) / evalTree(tree.right, context);
if (tree.operator === '%')
return evalTree(tree.left, context) % evalTree(tree.right, context);
if (tree.operator === '^')
return Math.pow(evalTree(tree.left, context), evalTree(tree.right, context));
throw 'عملگر دوگانی ' + tree.operator + ' پشتیبانی نمی‌شود.';
}
if (tree.type === CALL_EXP) {
if (tree.callee.type !== IDENTIFIER)
throw 'عمل ریاضی وارد شده پشتیبانی نمی‌شود.';
if (tree.arguments.length > 1)
throw 'امکان استفاده از توابع با بیش از یک ورودی وجود ندارد.';
if (!(tree.callee.name in functions))
throw 'تابع ' + tree.callee.name + ' پشتیبانی نمی‌شود.';
return functions[tree.callee.name](evalTree(tree.arguments[0], context));
}
throw 'عبارت ریاضی داده‌شده پشتیبانی نمی‌شود و یا عبارت داده‌شده خطا دارد.';
};
queval = function (expression, context) {
var tree = jsep(expression);
return evalTree(tree, context);
};
// In desktop environments, have a way to restore the old value for `queval`
if (typeof exports === 'undefined') {
var old_queval = root.queval;
// The star of the show! It's a function!
root.queval = queval;
// And a courteous function willing to move out of the way for other similarly-named objects!
queval.noConflict = function () {
if (root.queval === queval) {
root.queval = old_queval;
}
return queval;
};
} else {
// In Node.JS environments
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = queval;
} else {
exports.parse = queval;
}
}
}(this));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment