UNPKG

5.7 kBJavaScriptView Raw
1import { factory } from '../utils/factory'
2import { extend, hasOwnProperty } from '../utils/object'
3import { getSafeProperty, setSafeProperty } from '../utils/customs'
4import { warnOnce } from '../utils/log'
5
6const name = 'Parser'
7const dependencies = ['parse']
8
9export const createParserClass = /* #__PURE__ */ factory(name, dependencies, ({ parse }) => {
10 /**
11 * @constructor Parser
12 * Parser contains methods to evaluate or parse expressions, and has a number
13 * of convenience methods to get, set, and remove variables from memory. Parser
14 * keeps a scope containing variables in memory, which is used for all
15 * evaluations.
16 *
17 * Methods:
18 * const result = parser.evaluate(expr) // evaluate an expression
19 * const value = parser.get(name) // retrieve a variable from the parser
20 * const values = parser.getAll() // retrieve all defined variables
21 * parser.set(name, value) // set a variable in the parser
22 * parser.remove(name) // clear a variable from the
23 * // parsers scope
24 * parser.clear() // clear the parsers scope
25 *
26 * Example usage:
27 * const parser = new Parser()
28 * // Note: there is a convenience method which can be used instead:
29 * // const parser = new math.parser()
30 *
31 * // evaluate expressions
32 * parser.evaluate('sqrt(3^2 + 4^2)') // 5
33 * parser.evaluate('sqrt(-4)') // 2i
34 * parser.evaluate('2 inch in cm') // 5.08 cm
35 * parser.evaluate('cos(45 deg)') // 0.7071067811865476
36 *
37 * // define variables and functions
38 * parser.evaluate('x = 7 / 2') // 3.5
39 * parser.evaluate('x + 3') // 6.5
40 * parser.evaluate('function f(x, y) = x^y') // f(x, y)
41 * parser.evaluate('f(2, 3)') // 8
42 *
43 * // get and set variables and functions
44 * const x = parser.get('x') // 7
45 * const f = parser.get('f') // function
46 * const g = f(3, 2) // 9
47 * parser.set('h', 500)
48 * const i = parser.evaluate('h / 2') // 250
49 * parser.set('hello', function (name) {
50 * return 'hello, ' + name + '!'
51 * })
52 * parser.evaluate('hello("user")') // "hello, user!"
53 *
54 * // clear defined functions and variables
55 * parser.clear()
56 *
57 */
58 function Parser () {
59 if (!(this instanceof Parser)) {
60 throw new SyntaxError(
61 'Constructor must be called with the new operator')
62 }
63 this.scope = {}
64 }
65
66 /**
67 * Attach type information
68 */
69 Parser.prototype.type = 'Parser'
70 Parser.prototype.isParser = true
71
72 /**
73 * Parse an expression and return the parsed function node.
74 * The node tree can be compiled via `code = node.compile(math)`,
75 * and the compiled code can be executed as `code.evaluate([scope])`
76 * @param {string} expr
77 * @return {Node} node
78 * @throws {Error}
79 */
80 Parser.prototype.parse = function (expr) {
81 throw new Error('Parser.parse is deprecated. Use math.parse instead.')
82 }
83
84 /**
85 * Parse and compile an expression, return the compiled javascript code.
86 * The node can be evaluated via code.evaluate([scope])
87 * @param {string} expr
88 * @return {{evaluate: function}} code
89 * @throws {Error}
90 */
91 Parser.prototype.compile = function (expr) {
92 throw new Error('Parser.compile is deprecated. Use math.compile instead.')
93 }
94
95 /**
96 * Parse and evaluate the given expression
97 * @param {string} expr A string containing an expression, for example "2+3"
98 * @return {*} result The result, or undefined when the expression was empty
99 * @throws {Error}
100 */
101 Parser.prototype.evaluate = function (expr) {
102 // TODO: validate arguments
103 return parse(expr)
104 .compile()
105 .evaluate(this.scope)
106 }
107
108 /**
109 * Parse and evaluate the given expression
110 * @param {string} expr A string containing an expression, for example "2+3"
111 * @return {*} result The result, or undefined when the expression was empty
112 * @throws {Error}
113 */
114 // TODO: Deprecated since v6.0.0. Clean up some day
115 Parser.prototype.eval = function (expr) {
116 warnOnce('Method Parser.eval is renamed to Parser.evaluate. Please use the new method name.')
117
118 return this.evaluate(expr)
119 }
120
121 /**
122 * Get a variable (a function or variable) by name from the parsers scope.
123 * Returns undefined when not found
124 * @param {string} name
125 * @return {* | undefined} value
126 */
127 Parser.prototype.get = function (name) {
128 // TODO: validate arguments
129 return name in this.scope
130 ? getSafeProperty(this.scope, name)
131 : undefined
132 }
133
134 /**
135 * Get a map with all defined variables
136 * @return {Object} values
137 */
138 Parser.prototype.getAll = function () {
139 return extend({}, this.scope)
140 }
141
142 /**
143 * Set a symbol (a function or variable) by name from the parsers scope.
144 * @param {string} name
145 * @param {* | undefined} value
146 */
147 Parser.prototype.set = function (name, value) {
148 // TODO: validate arguments
149 return setSafeProperty(this.scope, name, value)
150 }
151
152 /**
153 * Remove a variable from the parsers scope
154 * @param {string} name
155 */
156 Parser.prototype.remove = function (name) {
157 // TODO: validate arguments
158 delete this.scope[name]
159 }
160
161 /**
162 * Clear the scope with variables and functions
163 */
164 Parser.prototype.clear = function () {
165 for (const name in this.scope) {
166 if (hasOwnProperty(this.scope, name)) {
167 delete this.scope[name]
168 }
169 }
170 }
171
172 return Parser
173}, { isClass: true })