exprify 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +49 -0
- package/README.md +109 -182
- package/SECURITY.md +18 -0
- package/bin/cli.mjs +234 -0
- package/dist/exprify.cjs.cjs +3558 -1220
- package/dist/exprify.cjs.cjs.map +1 -1
- package/dist/exprify.esm.js +3558 -1220
- package/dist/exprify.esm.js.map +1 -1
- package/dist/exprify.js +3560 -1222
- package/dist/exprify.js.map +1 -1
- package/dist/exprify.min.js +2 -2
- package/dist/exprify.min.js.map +1 -1
- package/package.json +44 -17
- package/src/core/context.js +35 -27
- package/src/core/exprify.js +880 -0
- package/src/function/executor.js +29 -20
- package/src/function/internal.js +1150 -153
- package/src/function/registry.js +23 -16
- package/src/index.js +1 -1
- package/src/math/bignumber.js +31 -0
- package/src/math/fraction.js +112 -0
- package/src/math/operations.js +38 -24
- package/src/parser/astBuild.js +276 -214
- package/src/parser/evaluator.js +431 -171
- package/src/parser/tokenizer.js +179 -146
- package/src/utils/decimal.js +264 -0
- package/src/utils/globalUnits.js +43 -35
- package/src/utils/matrix.js +14 -14
- package/src/utils/store.js +69 -47
- package/src/variables/store.js +18 -15
- package/src/core/Exprify.js +0 -369
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
import { stdin, stdout, stderr, exit, argv, version } from 'node:process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { dirname, resolve } from 'node:path';
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
|
|
11
|
+
let pkg;
|
|
12
|
+
try {
|
|
13
|
+
pkg = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf-8'));
|
|
14
|
+
} catch {
|
|
15
|
+
pkg = { version: 'unknown' };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let Exprify;
|
|
19
|
+
try {
|
|
20
|
+
const mod = await import('../src/core/exprify.js');
|
|
21
|
+
Exprify = mod.default || mod.Exprify;
|
|
22
|
+
} catch {
|
|
23
|
+
stderr.write('Error: Could not load Exprify module\n');
|
|
24
|
+
exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const expr = new Exprify();
|
|
28
|
+
|
|
29
|
+
const USAGE = `Usage: exprify [options] [expression...]
|
|
30
|
+
|
|
31
|
+
Options:
|
|
32
|
+
--help Show this help message
|
|
33
|
+
--version Show version number
|
|
34
|
+
--parse <expr> Parse expression and show token/AST structure
|
|
35
|
+
--tokens <expr> Tokenize expression and show tokens
|
|
36
|
+
|
|
37
|
+
If no expression is provided and stdin is a TTY, starts interactive REPL.
|
|
38
|
+
If stdin is piped, reads expression from stdin.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
exprify "2 + 2"
|
|
42
|
+
exprify "sqrt(16)" "5 * 3"
|
|
43
|
+
exprify --parse "x ^ 2 + 2 * x + 1"
|
|
44
|
+
echo "2 + 2" | exprify
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
const COLORS = {
|
|
48
|
+
reset: '\x1b[0m',
|
|
49
|
+
red: '\x1b[31m',
|
|
50
|
+
green: '\x1b[32m',
|
|
51
|
+
yellow: '\x1b[33m',
|
|
52
|
+
cyan: '\x1b[36m',
|
|
53
|
+
bold: '\x1b[1m',
|
|
54
|
+
dim: '\x1b[2m',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function formatResult(value) {
|
|
58
|
+
if (value === null) return 'null';
|
|
59
|
+
if (value === undefined) return 'undefined';
|
|
60
|
+
if (typeof value === 'object' || Array.isArray(value)) {
|
|
61
|
+
return JSON.stringify(value, null, 2);
|
|
62
|
+
}
|
|
63
|
+
return String(value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function printError(msg) {
|
|
67
|
+
stderr.write(COLORS.red + 'Error: ' + COLORS.reset + msg + '\n');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function evaluateAndPrint(expression, mode) {
|
|
71
|
+
try {
|
|
72
|
+
if (mode === 'parse') {
|
|
73
|
+
const result = expr.parse(expression);
|
|
74
|
+
console.log(JSON.stringify(result, null, 2));
|
|
75
|
+
} else if (mode === 'tokens') {
|
|
76
|
+
const result = expr.tokenize(expression);
|
|
77
|
+
console.log(JSON.stringify(result, null, 2));
|
|
78
|
+
} else {
|
|
79
|
+
const result = expr.evaluate(expression);
|
|
80
|
+
console.log(formatResult(result));
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
printError(err.message);
|
|
84
|
+
exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const args = argv.slice(2);
|
|
89
|
+
|
|
90
|
+
if (args.length === 0) {
|
|
91
|
+
if (stdin.isTTY) {
|
|
92
|
+
startREPL();
|
|
93
|
+
} else {
|
|
94
|
+
let input = '';
|
|
95
|
+
stdin.setEncoding('utf-8');
|
|
96
|
+
stdin.on('data', (chunk) => {
|
|
97
|
+
input += chunk;
|
|
98
|
+
});
|
|
99
|
+
stdin.on('end', () => {
|
|
100
|
+
const exprStr = input.trim();
|
|
101
|
+
if (exprStr) evaluateAndPrint(exprStr);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
exit(0);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const flag = args[0];
|
|
108
|
+
|
|
109
|
+
if (flag === '--help' || flag === '-h') {
|
|
110
|
+
console.log(USAGE);
|
|
111
|
+
exit(0);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (flag === '--version' || flag === '-v') {
|
|
115
|
+
console.log(pkg.version);
|
|
116
|
+
exit(0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (flag === '--parse' || flag === '--tokens') {
|
|
120
|
+
if (args.length < 2) {
|
|
121
|
+
printError('Missing expression argument');
|
|
122
|
+
console.log(USAGE);
|
|
123
|
+
exit(2);
|
|
124
|
+
}
|
|
125
|
+
const mode = flag.slice(2);
|
|
126
|
+
for (let i = 1; i < args.length; i++) {
|
|
127
|
+
evaluateAndPrint(args[i], mode);
|
|
128
|
+
}
|
|
129
|
+
exit(0);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const arg of args) {
|
|
133
|
+
evaluateAndPrint(arg);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function startREPL() {
|
|
137
|
+
console.log(`Exprify v${pkg.version} - interactive REPL`);
|
|
138
|
+
console.log('Type an expression or .help for commands\n');
|
|
139
|
+
|
|
140
|
+
const rl = createInterface({
|
|
141
|
+
input: stdin,
|
|
142
|
+
output: stdout,
|
|
143
|
+
prompt: COLORS.cyan + '» ' + COLORS.reset,
|
|
144
|
+
completer: (line) => {
|
|
145
|
+
const completions = [
|
|
146
|
+
'help',
|
|
147
|
+
'.help',
|
|
148
|
+
'.exit',
|
|
149
|
+
'pi',
|
|
150
|
+
'e',
|
|
151
|
+
'i',
|
|
152
|
+
'PHI',
|
|
153
|
+
'TAU',
|
|
154
|
+
'INFINITY',
|
|
155
|
+
'NaN',
|
|
156
|
+
'sin',
|
|
157
|
+
'cos',
|
|
158
|
+
'tan',
|
|
159
|
+
'sqrt',
|
|
160
|
+
'abs',
|
|
161
|
+
'log',
|
|
162
|
+
'exp',
|
|
163
|
+
'map',
|
|
164
|
+
'filter',
|
|
165
|
+
'sum',
|
|
166
|
+
'prod',
|
|
167
|
+
'mean',
|
|
168
|
+
'max',
|
|
169
|
+
'min',
|
|
170
|
+
'if',
|
|
171
|
+
'parse',
|
|
172
|
+
'leafCount',
|
|
173
|
+
'random',
|
|
174
|
+
'simplify',
|
|
175
|
+
'expand',
|
|
176
|
+
'factor',
|
|
177
|
+
'solve',
|
|
178
|
+
'derivative',
|
|
179
|
+
'integral',
|
|
180
|
+
'sigma',
|
|
181
|
+
'limit',
|
|
182
|
+
'substitute',
|
|
183
|
+
'det',
|
|
184
|
+
'transpose',
|
|
185
|
+
'inverse',
|
|
186
|
+
'trace',
|
|
187
|
+
'rank',
|
|
188
|
+
];
|
|
189
|
+
const hits = completions.filter((c) => c.startsWith(line));
|
|
190
|
+
return [hits.length ? hits : completions, line];
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
rl.on('line', (line) => {
|
|
195
|
+
const input = line.trim();
|
|
196
|
+
|
|
197
|
+
if (!input) {
|
|
198
|
+
rl.prompt();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (input === '.exit' || input === 'exit' || input === 'quit') {
|
|
203
|
+
rl.close();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (input === '.help' || input === 'help') {
|
|
208
|
+
console.log(`\n ${COLORS.bold}Commands:${COLORS.reset}`);
|
|
209
|
+
console.log(' .exit Exit the REPL');
|
|
210
|
+
console.log(' .help Show this message');
|
|
211
|
+
console.log(' <expr> Evaluate an expression');
|
|
212
|
+
console.log(' Ctrl+C Cancel / exit');
|
|
213
|
+
console.log('');
|
|
214
|
+
rl.prompt();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const result = expr.evaluate(input);
|
|
220
|
+
console.log(COLORS.green + formatResult(result) + COLORS.reset);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
console.log(COLORS.red + 'Error: ' + COLORS.reset + err.message);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
rl.prompt();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
rl.on('close', () => {
|
|
229
|
+
console.log('');
|
|
230
|
+
exit(0);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
rl.prompt();
|
|
234
|
+
}
|