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