UNPKG

6.13 kBJavaScriptView Raw
1import { escape } from '../../utils/string';
2import { getSafeProperty } from '../../utils/customs';
3import { factory } from '../../utils/factory';
4import { toSymbol } from '../../utils/latex';
5var name = 'SymbolNode';
6var dependencies = ['math', '?Unit', 'Node'];
7export var createSymbolNode = /* #__PURE__ */factory(name, dependencies, function (_ref) {
8 var math = _ref.math,
9 Unit = _ref.Unit,
10 Node = _ref.Node;
11
12 /**
13 * Check whether some name is a valueless unit like "inch".
14 * @param {string} name
15 * @return {boolean}
16 */
17 function isValuelessUnit(name) {
18 return Unit ? Unit.isValuelessUnit(name) : false;
19 }
20 /**
21 * @constructor SymbolNode
22 * @extends {Node}
23 * A symbol node can hold and resolve a symbol
24 * @param {string} name
25 * @extends {Node}
26 */
27
28
29 function SymbolNode(name) {
30 if (!(this instanceof SymbolNode)) {
31 throw new SyntaxError('Constructor must be called with the new operator');
32 } // validate input
33
34
35 if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"');
36 this.name = name;
37 }
38
39 SymbolNode.prototype = new Node();
40 SymbolNode.prototype.type = 'SymbolNode';
41 SymbolNode.prototype.isSymbolNode = true;
42 /**
43 * Compile a node into a JavaScript function.
44 * This basically pre-calculates as much as possible and only leaves open
45 * calculations which depend on a dynamic scope with variables.
46 * @param {Object} math Math.js namespace with functions and constants.
47 * @param {Object} argNames An object with argument names as key and `true`
48 * as value. Used in the SymbolNode to optimize
49 * for arguments from user assigned functions
50 * (see FunctionAssignmentNode) or special symbols
51 * like `end` (see IndexNode).
52 * @return {function} Returns a function which can be called like:
53 * evalNode(scope: Object, args: Object, context: *)
54 */
55
56 SymbolNode.prototype._compile = function (math, argNames) {
57 var name = this.name;
58
59 if (argNames[name] === true) {
60 // this is a FunctionAssignment argument
61 // (like an x when inside the expression of a function assignment `f(x) = ...`)
62 return function (scope, args, context) {
63 return args[name];
64 };
65 } else if (name in math) {
66 return function (scope, args, context) {
67 return name in scope ? getSafeProperty(scope, name) : getSafeProperty(math, name);
68 };
69 } else {
70 var isUnit = isValuelessUnit(name);
71 return function (scope, args, context) {
72 return name in scope ? getSafeProperty(scope, name) : isUnit ? new Unit(null, name) : undef(name);
73 };
74 }
75 };
76 /**
77 * Execute a callback for each of the child nodes of this node
78 * @param {function(child: Node, path: string, parent: Node)} callback
79 */
80
81
82 SymbolNode.prototype.forEach = function (callback) {// nothing to do, we don't have childs
83 };
84 /**
85 * Create a new SymbolNode having it's childs be the results of calling
86 * the provided callback function for each of the childs of the original node.
87 * @param {function(child: Node, path: string, parent: Node) : Node} callback
88 * @returns {SymbolNode} Returns a clone of the node
89 */
90
91
92 SymbolNode.prototype.map = function (callback) {
93 return this.clone();
94 };
95 /**
96 * Throws an error 'Undefined symbol {name}'
97 * @param {string} name
98 */
99
100
101 function undef(name) {
102 throw new Error('Undefined symbol ' + name);
103 }
104 /**
105 * Create a clone of this node, a shallow copy
106 * @return {SymbolNode}
107 */
108
109
110 SymbolNode.prototype.clone = function () {
111 return new SymbolNode(this.name);
112 };
113 /**
114 * Get string representation
115 * @param {Object} options
116 * @return {string} str
117 * @override
118 */
119
120
121 SymbolNode.prototype._toString = function (options) {
122 return this.name;
123 };
124 /**
125 * Get HTML representation
126 * @param {Object} options
127 * @return {string} str
128 * @override
129 */
130
131
132 SymbolNode.prototype.toHTML = function (options) {
133 var name = escape(this.name);
134
135 if (name === 'true' || name === 'false') {
136 return '<span class="math-symbol math-boolean">' + name + '</span>';
137 } else if (name === 'i') {
138 return '<span class="math-symbol math-imaginary-symbol">' + name + '</span>';
139 } else if (name === 'Infinity') {
140 return '<span class="math-symbol math-infinity-symbol">' + name + '</span>';
141 } else if (name === 'NaN') {
142 return '<span class="math-symbol math-nan-symbol">' + name + '</span>';
143 } else if (name === 'null') {
144 return '<span class="math-symbol math-null-symbol">' + name + '</span>';
145 } else if (name === 'undefined') {
146 return '<span class="math-symbol math-undefined-symbol">' + name + '</span>';
147 }
148
149 return '<span class="math-symbol">' + name + '</span>';
150 };
151 /**
152 * Get a JSON representation of the node
153 * @returns {Object}
154 */
155
156
157 SymbolNode.prototype.toJSON = function () {
158 return {
159 mathjs: 'SymbolNode',
160 name: this.name
161 };
162 };
163 /**
164 * Instantiate a SymbolNode from its JSON representation
165 * @param {Object} json An object structured like
166 * `{"mathjs": "SymbolNode", name: "x"}`,
167 * where mathjs is optional
168 * @returns {SymbolNode}
169 */
170
171
172 SymbolNode.fromJSON = function (json) {
173 return new SymbolNode(json.name);
174 };
175 /**
176 * Get LaTeX representation
177 * @param {Object} options
178 * @return {string} str
179 * @override
180 */
181
182
183 SymbolNode.prototype._toTex = function (options) {
184 var isUnit = false;
185
186 if (typeof math[this.name] === 'undefined' && isValuelessUnit(this.name)) {
187 isUnit = true;
188 }
189
190 var symbol = toSymbol(this.name, isUnit);
191
192 if (symbol[0] === '\\') {
193 // no space needed if the symbol starts with '\'
194 return symbol;
195 } // the space prevents symbols from breaking stuff like '\cdot' if it's written right before the symbol
196
197
198 return ' ' + symbol;
199 };
200
201 return SymbolNode;
202}, {
203 isClass: true,
204 isNode: true
205});
\No newline at end of file