1 | #!/usr/bin/env node
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | var scope = {};
|
49 | var fs = require('fs');
|
50 |
|
51 | var PRECISION = 14;
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | function getMath () {
|
60 | return require('../index');
|
61 | }
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 | function format(value) {
|
69 | var math = getMath();
|
70 |
|
71 | return math.format(value, {
|
72 | fn: function (value) {
|
73 | if (typeof value === 'number') {
|
74 |
|
75 | return math.format(value, PRECISION);
|
76 | }
|
77 | else {
|
78 | return math.format(value);
|
79 | }
|
80 | }
|
81 | });
|
82 | }
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 | function completer (text) {
|
90 | var math = getMath();
|
91 | var name;
|
92 | var matches = [];
|
93 | var m = /[a-zA-Z_0-9]+$/.exec(text);
|
94 | if (m) {
|
95 | var keyword = m[0];
|
96 |
|
97 |
|
98 | for (var def in scope) {
|
99 | if (scope.hasOwnProperty(def)) {
|
100 | if (def.indexOf(keyword) == 0) {
|
101 | matches.push(def);
|
102 | }
|
103 | }
|
104 | }
|
105 |
|
106 |
|
107 | ['exit', 'quit', 'clear'].forEach(function (cmd) {
|
108 | if (cmd.indexOf(keyword) == 0) {
|
109 | matches.push(cmd);
|
110 | }
|
111 | });
|
112 |
|
113 |
|
114 | var ignore = ['expr', 'type'];
|
115 | for (var func in math) {
|
116 | if (math.hasOwnProperty(func)) {
|
117 | if (func.indexOf(keyword) == 0 && ignore.indexOf(func) == -1) {
|
118 | matches.push(func);
|
119 | }
|
120 | }
|
121 | }
|
122 |
|
123 |
|
124 | var Unit = math.type.Unit;
|
125 | for (name in Unit.UNITS) {
|
126 | if (Unit.UNITS.hasOwnProperty(name)) {
|
127 | if (name.indexOf(keyword) == 0) {
|
128 | matches.push(name);
|
129 | }
|
130 | }
|
131 | }
|
132 | for (name in Unit.PREFIXES) {
|
133 | if (Unit.PREFIXES.hasOwnProperty(name)) {
|
134 | var prefixes = Unit.PREFIXES[name];
|
135 | for (var prefix in prefixes) {
|
136 | if (prefixes.hasOwnProperty(prefix)) {
|
137 | if (prefix.indexOf(keyword) == 0) {
|
138 | matches.push(prefix);
|
139 | }
|
140 | else if (keyword.indexOf(prefix) == 0) {
|
141 | var unitKeyword = keyword.substring(prefix.length);
|
142 | for (var n in Unit.UNITS) {
|
143 | if (Unit.UNITS.hasOwnProperty(n)) {
|
144 | if (n.indexOf(unitKeyword) == 0 &&
|
145 | Unit.isValuelessUnit(prefix + n)) {
|
146 | matches.push(prefix + n);
|
147 | }
|
148 | }
|
149 | }
|
150 | }
|
151 | }
|
152 | }
|
153 | }
|
154 | }
|
155 |
|
156 |
|
157 | matches = matches.filter(function(elem, pos, arr) {
|
158 | return arr.indexOf(elem) == pos;
|
159 | });
|
160 | }
|
161 |
|
162 | return [matches, keyword];
|
163 | }
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 | function runStream (input, output, mode, parenthesis) {
|
175 | var readline = require('readline'),
|
176 | rl = readline.createInterface({
|
177 | input: input || process.stdin,
|
178 | output: output || process.stdout,
|
179 | completer: completer
|
180 | });
|
181 |
|
182 | if (rl.output.isTTY) {
|
183 | rl.setPrompt('> ');
|
184 | rl.prompt();
|
185 | }
|
186 |
|
187 |
|
188 | var math = getMath();
|
189 |
|
190 |
|
191 |
|
192 | rl.on('line', function(line) {
|
193 | var expr = line.trim();
|
194 |
|
195 | switch (expr.toLowerCase()) {
|
196 | case 'quit':
|
197 | case 'exit':
|
198 |
|
199 | rl.close();
|
200 | break;
|
201 | case 'clear':
|
202 |
|
203 | scope = {};
|
204 | console.log('memory cleared');
|
205 |
|
206 |
|
207 | if (rl.output.isTTY) {
|
208 | rl.prompt();
|
209 | }
|
210 | break;
|
211 | default:
|
212 | if (!expr) {
|
213 | break;
|
214 | }
|
215 | switch (mode) {
|
216 | case 'eval':
|
217 |
|
218 | try {
|
219 | var node = math.parse(expr);
|
220 | var res = node.eval(scope);
|
221 |
|
222 | if (math.type.isResultSet(res)) {
|
223 |
|
224 |
|
225 | res = res.entries[0];
|
226 | node = node.blocks
|
227 | .filter(function (entry) { return entry.visible; })
|
228 | .map(function (entry) { return entry.node })[0];
|
229 | }
|
230 |
|
231 | if (node) {
|
232 | if (math.type.isAssignmentNode(node)) {
|
233 | var name = findSymbolName(node);
|
234 | if (name != null) {
|
235 | scope.ans = scope[name];
|
236 | console.log(name + ' = ' + format(scope[name]));
|
237 | }
|
238 | else {
|
239 | scope.ans = res;
|
240 | console.log(format(res));
|
241 | }
|
242 | }
|
243 | else if (math.type.isHelp(res)) {
|
244 | console.log(res.toString());
|
245 | }
|
246 | else {
|
247 | scope.ans = res;
|
248 | console.log(format(res));
|
249 | }
|
250 | }
|
251 | }
|
252 | catch (err) {
|
253 | console.log(err.toString());
|
254 | }
|
255 | break;
|
256 |
|
257 | case 'string':
|
258 | try {
|
259 | var string = math.parse(expr).toString({parenthesis: parenthesis});
|
260 | console.log(string);
|
261 | }
|
262 | catch (err) {
|
263 | console.log(err.toString());
|
264 | }
|
265 | break;
|
266 |
|
267 | case 'tex':
|
268 | try {
|
269 | var tex = math.parse(expr).toTex({parenthesis: parenthesis});
|
270 | console.log(tex);
|
271 | }
|
272 | catch (err) {
|
273 | console.log(err.toString());
|
274 | }
|
275 | break;
|
276 | }
|
277 | }
|
278 |
|
279 |
|
280 | if (rl.output.isTTY) {
|
281 | rl.prompt();
|
282 | }
|
283 | });
|
284 |
|
285 | rl.on('close', function() {
|
286 | console.log();
|
287 | process.exit(0);
|
288 | });
|
289 | }
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 | function findSymbolName (node) {
|
298 | var math = getMath();
|
299 | var n = node;
|
300 |
|
301 | while (n) {
|
302 | if (math.type.isSymbolNode(n)) {
|
303 | return n.name;
|
304 | }
|
305 | n = n.object;
|
306 | }
|
307 |
|
308 | return null;
|
309 | }
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 | function outputVersion () {
|
316 | fs.readFile(__dirname + '/../package.json', function (err, data) {
|
317 | if (err) {
|
318 | console.log(err.toString());
|
319 | }
|
320 | else {
|
321 | var pkg = JSON.parse(data);
|
322 | var version = pkg && pkg.version ? pkg.version : 'unknown';
|
323 | console.log(version);
|
324 | }
|
325 | process.exit(0);
|
326 | });
|
327 | }
|
328 |
|
329 |
|
330 |
|
331 |
|
332 | function outputHelp() {
|
333 | console.log('math.js');
|
334 | console.log('http://mathjs.org');
|
335 | console.log();
|
336 | console.log('Math.js is an extensive math library for JavaScript and Node.js. It features ');
|
337 | console.log('real and complex numbers, units, matrices, a large set of mathematical');
|
338 | console.log('functions, and a flexible expression parser.');
|
339 | console.log();
|
340 | console.log('Usage:');
|
341 | console.log(' mathjs [scriptfile(s)|expression] {OPTIONS}');
|
342 | console.log();
|
343 | console.log('Options:');
|
344 | console.log(' --version, -v Show application version');
|
345 | console.log(' --help, -h Show this message');
|
346 | console.log(' --tex Generate LaTeX instead of evaluating');
|
347 | console.log(' --string Generate string instead of evaluating');
|
348 | console.log(' --parenthesis= Set the parenthesis option to');
|
349 | console.log(' either of "keep", "auto" and "all"');
|
350 | console.log();
|
351 | console.log('Example usage:');
|
352 | console.log(' mathjs Open a command prompt');
|
353 | console.log(' mathjs 1+2 Evaluate expression');
|
354 | console.log(' mathjs script.txt Run a script file');
|
355 | console.log(' mathjs script.txt script2.txt Run two script files');
|
356 | console.log(' mathjs script.txt > results.txt Run a script file, output to file');
|
357 | console.log(' cat script.txt | mathjs Run input stream');
|
358 | console.log(' cat script.txt | mathjs > results.txt Run input stream, output to file');
|
359 | console.log();
|
360 | process.exit(0);
|
361 | }
|
362 |
|
363 |
|
364 |
|
365 |
|
366 | var scripts = [];
|
367 | var mode = 'eval';
|
368 | var parenthesis = 'keep';
|
369 | var version = false;
|
370 | var help = false;
|
371 |
|
372 | process.argv.forEach(function (arg, index) {
|
373 | if (index < 2) {
|
374 | return;
|
375 | }
|
376 |
|
377 | switch (arg) {
|
378 | case '-v':
|
379 | case '--version':
|
380 | version = true;
|
381 | break;
|
382 |
|
383 | case '-h':
|
384 | case '--help':
|
385 | help = true;
|
386 | break;
|
387 |
|
388 | case '--tex':
|
389 | mode = 'tex';
|
390 | break;
|
391 |
|
392 | case '--string':
|
393 | mode = 'string';
|
394 | break;
|
395 |
|
396 | case '--parenthesis=keep':
|
397 | parenthesis = 'keep';
|
398 | break;
|
399 |
|
400 | case '--parenthesis=auto':
|
401 | parenthesis = 'auto';
|
402 | break;
|
403 |
|
404 | case '--parenthesis=all':
|
405 | parenthesis = 'all';
|
406 | break;
|
407 |
|
408 |
|
409 |
|
410 | default:
|
411 | scripts.push(arg);
|
412 | }
|
413 | });
|
414 |
|
415 | if (version) {
|
416 | outputVersion();
|
417 | }
|
418 | else if (help) {
|
419 | outputHelp();
|
420 | }
|
421 | else if (scripts.length === 0) {
|
422 |
|
423 | runStream(process.stdin, process.stdout, mode, parenthesis);
|
424 | }
|
425 | else {
|
426 | fs.stat(scripts[0], function(e, f) {
|
427 | if (e) {
|
428 | console.log(getMath().eval(scripts.join(' ')).toString())
|
429 | } else {
|
430 |
|
431 | scripts.forEach(function (arg) {
|
432 |
|
433 | runStream(fs.createReadStream(arg), process.stdout, mode, parenthesis);
|
434 | });
|
435 | }
|
436 | })
|
437 | }
|