mirror of
https://github.com/josdejong/mathjs.git
synced 2026-02-01 16:07:46 +00:00
Implemented math.eval and a readonly option for the Parser and Scope.
This commit is contained in:
parent
f6ae1d70e7
commit
b851f418e5
@ -2,6 +2,12 @@
|
||||
https://github.com/josdejong/mathjs
|
||||
|
||||
|
||||
## not yet released, version 0.7.0
|
||||
|
||||
- Implemented method math.eval, which uses a readonly parser to evaluate
|
||||
expressions.
|
||||
|
||||
|
||||
## 2013-04-13, version 0.6.0
|
||||
|
||||
- Implemented chained operations via method math.select(). For example
|
||||
|
||||
@ -44,7 +44,6 @@ task('concat', function () {
|
||||
'./src/type/**/*.js',
|
||||
'./src/constants.js',
|
||||
'./src/functions.js',
|
||||
'./src/function/**/*.js',
|
||||
'./src/expr/node/Node.js',
|
||||
'./src/expr/node/Symbol.js',
|
||||
'./src/expr/node/Constant.js',
|
||||
@ -56,6 +55,7 @@ task('concat', function () {
|
||||
'./src/expr/Scope.js',
|
||||
'./src/expr/Parser.js',
|
||||
'./src/expr/Workspace.js',
|
||||
'./src/function/**/*.js',
|
||||
'./src/compatibility.js',
|
||||
'./src/init.js'
|
||||
],
|
||||
|
||||
@ -455,6 +455,7 @@ types (Number, Complex, Unit, String, and Array) where applicable.
|
||||
### Utils
|
||||
|
||||
- math.clone(x)
|
||||
- math.eval(expr)
|
||||
- math.format([template, ] values)
|
||||
- math.import(filename | object, override)
|
||||
- math.select([x])
|
||||
|
||||
6
math.min.js
vendored
6
math.min.js
vendored
File diff suppressed because one or more lines are too long
@ -3,6 +3,9 @@
|
||||
* @constructor math.expr.Parser
|
||||
* Parser parses math expressions and evaluates them or returns a node tree.
|
||||
*
|
||||
* @param {Object} [options] Available options:
|
||||
* {boolean} readonly (false by default).
|
||||
*
|
||||
* Methods:
|
||||
* var result = parser.eval(expr); // evaluate an expression
|
||||
* var value = parser.get(name); // retrieve a variable from the parser
|
||||
@ -43,13 +46,13 @@
|
||||
* // clear defined functions and variables
|
||||
* parser.clear();
|
||||
*/
|
||||
math.expr.Parser = function Parser() {
|
||||
math.expr.Parser = function Parser(options) {
|
||||
if (this.constructor != Parser) {
|
||||
throw new SyntaxError(
|
||||
'Parser constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
this.scope = new math.expr.Scope();
|
||||
this.scope = new math.expr.Scope(null, options);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -430,16 +433,18 @@
|
||||
function parse_ans (scope) {
|
||||
var expression = parse_function_assignment(scope);
|
||||
|
||||
// TODO: not so nice having to specify some special types here...
|
||||
if (!(expression instanceof Assignment)
|
||||
// !(expression instanceof FunctionAssignment) && // TODO
|
||||
// !(expression instanceof plot) // TODO
|
||||
) {
|
||||
// create a variable definition for ans
|
||||
var name = 'ans';
|
||||
var params = undefined;
|
||||
var link = scope.createDef(name);
|
||||
return new Assignment(name, params, expression, link);
|
||||
if (!scope.readonly) {
|
||||
// TODO: not so nice having to specify some special types here...
|
||||
if (!(expression instanceof Assignment)
|
||||
// !(expression instanceof FunctionAssignment) && // TODO
|
||||
// !(expression instanceof plot) // TODO
|
||||
) {
|
||||
// create a variable definition for ans
|
||||
var name = 'ans';
|
||||
var params = undefined;
|
||||
var link = scope.createDef(name);
|
||||
return new Assignment(name, params, expression, link);
|
||||
}
|
||||
}
|
||||
|
||||
return expression;
|
||||
|
||||
@ -5,8 +5,15 @@
|
||||
*
|
||||
* @constructor mathnotepad.Scope
|
||||
* @param {Scope} [parentScope]
|
||||
* @param {Object} [options] Available options:
|
||||
* {boolean} readonly (false by default).
|
||||
*/
|
||||
math.expr.Scope = function Scope(parentScope) {
|
||||
math.expr.Scope = function Scope(parentScope, options) {
|
||||
this.readonly = false;
|
||||
if (options && options.readonly != undefined) {
|
||||
this.readonly = options.readonly;
|
||||
}
|
||||
|
||||
this.parentScope = parentScope;
|
||||
this.nestedScopes = undefined;
|
||||
|
||||
@ -27,6 +34,10 @@ math.expr.Scope.prototype = {
|
||||
* @return {math.expr.Scope} nestedScope
|
||||
*/
|
||||
createNestedScope: function () {
|
||||
if (this.readonly) {
|
||||
throw new Error('Cannot create nested scope: Scope is read-only');
|
||||
}
|
||||
|
||||
var nestedScope = new math.expr.Scope(this);
|
||||
if (!this.nestedScopes) {
|
||||
this.nestedScopes = [];
|
||||
@ -40,6 +51,10 @@ math.expr.Scope.prototype = {
|
||||
* (parent scope will not be cleared)
|
||||
*/
|
||||
clear: function () {
|
||||
if (this.readonly) {
|
||||
throw new Error('Cannot clear scope: Scope is read-only');
|
||||
}
|
||||
|
||||
this.symbols = {};
|
||||
this.defs = {};
|
||||
this.links = {};
|
||||
@ -146,6 +161,10 @@ math.expr.Scope.prototype = {
|
||||
* @return {function} symbol
|
||||
*/
|
||||
createDef: function (name, value) {
|
||||
if (this.readonly) {
|
||||
throw new Error('Cannot create variable: Scope is read-only');
|
||||
}
|
||||
|
||||
var symbol = this.defs[name];
|
||||
if (!symbol) {
|
||||
symbol = this.createSymbol(name);
|
||||
@ -164,6 +183,10 @@ math.expr.Scope.prototype = {
|
||||
* @return {function} symbol
|
||||
*/
|
||||
createUpdate: function (name) {
|
||||
if (this.readonly) {
|
||||
throw new Error('Cannot update variable: Scope is read-only');
|
||||
}
|
||||
|
||||
var symbol = this.updates[name];
|
||||
if (!symbol) {
|
||||
symbol = this.createLink(name);
|
||||
|
||||
22
src/function/utils/eval.js
Normal file
22
src/function/utils/eval.js
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Evaluate an expression. The expression will be evaluated using a read-only
|
||||
* instance of a Parser (i.e. variable definitions are not supported).
|
||||
* @param {String} expr
|
||||
* @return {*} res
|
||||
*/
|
||||
math.eval = function eval(expr) {
|
||||
if (arguments.length != 1) {
|
||||
throw newArgumentsError('eval', arguments.length, 1);
|
||||
}
|
||||
|
||||
if (!isString(expr)) {
|
||||
throw new TypeError('String expected');
|
||||
}
|
||||
|
||||
return _readonlyParser.eval(expr);
|
||||
};
|
||||
|
||||
/** @private */
|
||||
var _readonlyParser = new math.expr.Parser({
|
||||
readonly: true
|
||||
});
|
||||
@ -122,5 +122,12 @@ assert.throws(function () {
|
||||
assert.equal(parser.eval('q = 4/2'), 2);
|
||||
assert.equal(parser.eval('g(3)'), 9);
|
||||
|
||||
// test read-only parser
|
||||
var readonlyParser = new math.expr.Parser({readonly: true});
|
||||
assert.equal(readonlyParser.get('pi'), Math.PI);
|
||||
assert.throws(function () {readonlyParser.eval('b = 43');});
|
||||
assert.throws(function () {readonlyParser.eval('function f(x) = a * x');});
|
||||
assert.throws(function () {readonlyParser.eval('a([1,1])= [4]');});
|
||||
assert.throws(function () {readonlyParser.set('a', 3)});
|
||||
|
||||
// TODO: extensively test the Parser
|
||||
|
||||
@ -55,6 +55,16 @@ a.valueOf()[2].re = 5;
|
||||
assert.equal(b.valueOf()[2].re, 2);
|
||||
|
||||
|
||||
// test eval
|
||||
assert.equal(math.eval('pi'), Math.PI);
|
||||
assert.equal(math.eval('(2+3)/4'), 1.25);
|
||||
assert.equal(math.eval('sqrt(-4)').toString(), '2i');
|
||||
assert.throws(function () {math.eval('b = 43');});
|
||||
assert.throws(function () {math.eval('function f(x) = a * x');});
|
||||
assert.throws(function () {math.eval('a([1,1])= [4]');});
|
||||
assert.throws(function () {math.set('a', 3)});
|
||||
|
||||
|
||||
// test format
|
||||
assert.equal(math.format(2/7), '0.2857142857');
|
||||
assert.equal(math.format([[1,2],[3,4]]), '[[1, 2], [3, 4]]');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user