@khanacademy/kas 0.2.3

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.
@@ -0,0 +1,480 @@
1
+ import _ from "underscore";
2
+
3
+ import * as KAS from "../index.js";
4
+
5
+ expect.extend({
6
+ toParseAs(input: string, expected: string, options: $FlowFixMe) {
7
+ const actual = KAS.parse(input, options).expr.print();
8
+
9
+ if (actual !== expected) {
10
+ return {
11
+ pass: false,
12
+ message: () => `${input} parses as ${expected}`,
13
+ };
14
+ }
15
+
16
+ return {pass: !this.isNot};
17
+ },
18
+ toParseWithStructure(input: string, expected: string, options: $FlowFixMe) {
19
+ const actual = KAS.parse(input, options).expr.repr();
20
+
21
+ if (actual !== expected) {
22
+ return {
23
+ pass: false,
24
+ message: () => `${input} parses as ${expected}`,
25
+ };
26
+ }
27
+
28
+ return {pass: !this.isNot};
29
+ },
30
+ });
31
+
32
+ describe("parsing", () => {
33
+ test("empty", () => {
34
+ expect("").toParseAs("");
35
+ });
36
+
37
+ test("positive and negative primitives", () => {
38
+ expect("0").toParseAs("0");
39
+ expect("1.").toParseAs("1");
40
+ expect("3.14").toParseAs("3.14");
41
+ expect(".14").toParseAs("0.14");
42
+ expect("pi").toParseAs("pi");
43
+ expect("e").toParseAs("e");
44
+ expect("x").toParseAs("x");
45
+ expect("theta").toParseAs("theta");
46
+
47
+ expect("-0").toParseAs("-1*0");
48
+ expect("-1.").toParseAs("-1");
49
+ expect("-3.14").toParseAs("-3.14");
50
+ expect("-.14").toParseAs("-0.14");
51
+ expect("-pi").toParseAs("-1*pi");
52
+ expect("-e").toParseAs("-1*e");
53
+ expect("-theta").toParseAs("-1*theta");
54
+ });
55
+
56
+ test("LaTeX constants", () => {
57
+ expect("\\theta").toParseAs("theta");
58
+ expect("\\pi").toParseAs("pi");
59
+ expect("\\phi").toParseAs("phi");
60
+ });
61
+
62
+ test("ignore TeX spaces", () => {
63
+ expect("a\\space b").toParseAs("a*b");
64
+ expect("a\\ b").toParseAs("a*b");
65
+ });
66
+
67
+ test("positive and negative rationals", () => {
68
+ expect("1/2").toParseAs("1/2");
69
+ expect("-1/2").toParseAs("-1/2");
70
+ expect("1/-2").toParseAs("-1/2");
71
+ expect("-1/-2").toParseAs("-1*-1/2");
72
+ expect("42/42").toParseAs("42/42");
73
+ expect("42/1").toParseAs("42/1");
74
+ expect("0/42").toParseAs("0/42");
75
+
76
+ expect("2 (1/2)").toParseAs("2*1/2");
77
+ expect("1/2 1/2").toParseAs("1/2*1/2");
78
+ expect("-1/2").toParseAs("-1/2");
79
+ expect("1/2 2").toParseAs("1/2*2");
80
+ });
81
+
82
+ test("rationals using \\frac", () => {
83
+ expect("\\frac{1}{2}").toParseAs("1/2");
84
+ expect("\\frac{-1}{2}").toParseAs("-1/2");
85
+ expect("\\frac{1}{-2}").toParseAs("-1/2");
86
+ expect("\\frac{-1}{-2}").toParseAs("-1*-1/2");
87
+ expect("\\frac{42}{42}").toParseAs("42/42");
88
+ expect("\\frac{42}{1}").toParseAs("42/1");
89
+ expect("\\frac{0}{42}").toParseAs("0/42");
90
+
91
+ expect("2\\frac{1}{2}").toParseAs("2*1/2");
92
+ expect("\\frac{1}{2}\\frac{1}{2}").toParseAs("1/2*1/2");
93
+ expect("-\\frac{1}{2}").toParseAs("-1/2");
94
+ expect("\\frac{1}{2}2").toParseAs("1/2*2");
95
+ });
96
+
97
+ test("rationals using \\dfrac", () => {
98
+ expect("\\dfrac{1}{2}").toParseAs("1/2");
99
+ expect("\\dfrac{-1}{2}").toParseAs("-1/2");
100
+ expect("\\dfrac{1}{-2}").toParseAs("-1/2");
101
+ expect("\\dfrac{-1}{-2}").toParseAs("-1*-1/2");
102
+ expect("\\dfrac{42}{42}").toParseAs("42/42");
103
+ expect("\\dfrac{42}{1}").toParseAs("42/1");
104
+ expect("\\dfrac{0}{42}").toParseAs("0/42");
105
+
106
+ expect("2\\dfrac{1}{2}").toParseAs("2*1/2");
107
+ expect("\\dfrac{1}{2}\\dfrac{1}{2}").toParseAs("1/2*1/2");
108
+ expect("-\\dfrac{1}{2}").toParseAs("-1/2");
109
+ expect("\\dfrac{1}{2}2").toParseAs("1/2*2");
110
+ });
111
+
112
+ test("parens", () => {
113
+ expect("(0)").toParseAs("0");
114
+ expect("(ab)").toParseAs("a*b");
115
+ expect("(a/b)").toParseAs("a*b^(-1)");
116
+ expect("(a^b)").toParseAs("a^(b)");
117
+ expect("(ab)c").toParseAs("a*b*c");
118
+ expect("a(bc)").toParseAs("a*b*c");
119
+ expect("a+(b+c)").toParseAs("a+b+c");
120
+ expect("(a+b)+c").toParseAs("a+b+c");
121
+ expect("a(b+c)").toParseAs("a*(b+c)");
122
+ expect("(a+b)^c").toParseAs("(a+b)^(c)");
123
+ expect("(ab)^c").toParseAs("(a*b)^(c)");
124
+ });
125
+
126
+ test("subscripts", () => {
127
+ expect("a").toParseAs("a");
128
+ expect("a_0").toParseAs("a_(0)");
129
+ expect("a_i").toParseAs("a_(i)");
130
+ expect("a_n").toParseAs("a_(n)");
131
+ expect("a_n+1").toParseAs("a_(n)+1");
132
+ expect("a_(n+1)").toParseAs("a_(n+1)");
133
+ expect("a_{n+1}").toParseAs("a_(n+1)");
134
+ });
135
+
136
+ test("negation", () => {
137
+ expect("-x").toParseAs("-1*x");
138
+ expect("--x").toParseAs("-1*-1*x");
139
+ expect("---x").toParseAs("-1*-1*-1*x");
140
+ expect("-1").toParseAs("-1");
141
+ expect("--1").toParseAs("-1*-1");
142
+ expect("---1").toParseAs("-1*-1*-1");
143
+ expect("-3x").toParseAs("-3*x");
144
+ expect("--3x").toParseAs("-1*-3*x");
145
+ expect("-x*3").toParseAs("x*-3");
146
+ expect("--x*3").toParseAs("-1*x*-3");
147
+ expect("\u2212x").toParseAs("-1*x");
148
+ });
149
+
150
+ test("addition and subtraction", () => {
151
+ expect("a+b").toParseAs("a+b");
152
+ expect("a-b").toParseAs("a+-1*b");
153
+ expect("a--b").toParseAs("a+-1*-1*b");
154
+ expect("a---b").toParseAs("a+-1*-1*-1*b");
155
+ expect("2-4").toParseAs("2+-4");
156
+ expect("2--4").toParseAs("2+-1*-4");
157
+ expect("2---4").toParseAs("2+-1*-1*-4");
158
+ expect("2-x*4").toParseAs("2+x*-4");
159
+ expect("1-2+a-b+pi-e").toParseAs("1+-2+a+-1*b+pi+-1*e");
160
+ expect("x+1").toParseAs("x+1");
161
+ expect("x-1").toParseAs("x+-1");
162
+ expect("(x-1)").toParseAs("x+-1");
163
+ expect("a(x-1)").toParseAs("a*(x+-1)");
164
+ expect("a\u2212b").toParseAs("a+-1*b");
165
+ });
166
+
167
+ test("multiplication", () => {
168
+ expect("a*b").toParseAs("a*b");
169
+ expect("-a*b").toParseAs("-1*a*b");
170
+ expect("a*-b").toParseAs("a*-1*b");
171
+ expect("-ab").toParseAs("-1*a*b");
172
+ expect("-a*b").toParseAs("-1*a*b");
173
+ expect("-(ab)").toParseAs("-1*a*b");
174
+ expect("a\u00b7b").toParseAs("a*b");
175
+ expect("a\u00d7b").toParseAs("a*b");
176
+ expect("a\\cdotb").toParseAs("a*b");
177
+ expect("a\\timesb").toParseAs("a*b");
178
+ expect("a\\astb").toParseAs("a*b");
179
+ });
180
+
181
+ test("division", () => {
182
+ expect("a/b").toParseAs("a*b^(-1)");
183
+ expect("a/bc").toParseAs("a*b^(-1)*c");
184
+ expect("(ab)/c").toParseAs("a*b*c^(-1)");
185
+ expect("ab/c").toParseAs("a*b*c^(-1)");
186
+ expect("ab/cd").toParseAs("a*b*c^(-1)*d");
187
+ expect("a\\divb").toParseAs("a*b^(-1)");
188
+ expect("a\u00F7b").toParseAs("a*b^(-1)");
189
+ });
190
+
191
+ test("exponentiation", () => {
192
+ expect("x^y").toParseAs("x^(y)");
193
+ expect("x^y^z").toParseAs("x^(y^(z))");
194
+ expect("x^yz").toParseAs("x^(y)*z");
195
+ expect("-x^2").toParseAs("-1*x^(2)");
196
+ expect("-(x^2)").toParseAs("-1*x^(2)");
197
+ expect("0-x^2").toParseAs("0+-1*x^(2)");
198
+ expect("x^-y").toParseAs("x^(-1*y)");
199
+ expect("x^(-y)").toParseAs("x^(-1*y)");
200
+ expect("x^-(y)").toParseAs("x^(-1*y)");
201
+ expect("x^-(-y)").toParseAs("x^(-1*-1*y)");
202
+ expect("x^--y").toParseAs("x^(-1*-1*y)");
203
+ expect("x^-yz").toParseAs("x^(-1*y)*z");
204
+ expect("x^-y^z").toParseAs("x^(-1*y^(z))");
205
+ expect("x**y").toParseAs("x^(y)");
206
+
207
+ expect("x^{a}").toParseAs("x^(a)");
208
+ expect("x^{ab}").toParseAs("x^(a*b)");
209
+ });
210
+
211
+ test("square root", () => {
212
+ expect("sqrt(x)").toParseAs("x^(1/2)");
213
+ expect("sqrt(x)y").toParseAs("x^(1/2)*y");
214
+ expect("1/sqrt(x)").toParseAs("x^(-1/2)");
215
+ expect("1/sqrt(x)y").toParseAs("x^(-1/2)*y");
216
+
217
+ expect("sqrt(2)/2").toParseAs("2^(1/2)*1/2");
218
+ expect("sqrt(2)^2").toParseAs("(2^(1/2))^(2)");
219
+
220
+ expect("\\sqrt(x)").toParseAs("x^(1/2)");
221
+ expect("\\sqrt(x)y").toParseAs("x^(1/2)*y");
222
+ expect("1/\\sqrt(x)").toParseAs("x^(-1/2)");
223
+ expect("1/\\sqrt(x)y").toParseAs("x^(-1/2)*y");
224
+
225
+ expect("\\sqrt(2)/2").toParseAs("2^(1/2)*1/2");
226
+ expect("\\sqrt(2)^2").toParseAs("(2^(1/2))^(2)");
227
+
228
+ expect("\\sqrt{2}").toParseAs("2^(1/2)");
229
+ expect("\\sqrt{2+2}").toParseAs("(2+2)^(1/2)");
230
+ });
231
+
232
+ test("nth root", () => {
233
+ expect("sqrt[3]{x}").toParseAs("x^(1/3)");
234
+ expect("sqrt[4]{x}y").toParseAs("x^(1/4)*y");
235
+ expect("1/sqrt[5]{x}").toParseAs("x^(-1/5)");
236
+ expect("1/sqrt[7]{x}y").toParseAs("x^(-1/7)*y");
237
+
238
+ expect("sqrt[3]{2}/2").toParseAs("2^(1/3)*1/2");
239
+ expect("sqrt[3]{2}^2").toParseAs("(2^(1/3))^(2)");
240
+
241
+ expect("\\sqrt[4]{x}").toParseAs("x^(1/4)");
242
+ expect("\\sqrt[4]{x}y").toParseAs("x^(1/4)*y");
243
+ expect("1/\\sqrt[4]{x}").toParseAs("x^(-1/4)");
244
+ expect("1/\\sqrt[4]{x}y").toParseAs("x^(-1/4)*y");
245
+
246
+ expect("\\sqrt[5]{2}/2").toParseAs("2^(1/5)*1/2");
247
+ expect("\\sqrt[5]{2}^2").toParseAs("(2^(1/5))^(2)");
248
+
249
+ expect("\\sqrt[6]{2}").toParseAs("2^(1/6)");
250
+ expect("\\sqrt[6]{2+2}").toParseAs("(2+2)^(1/6)");
251
+
252
+ expect("\\sqrt[2]{2}").toParseAs("2^(1/2)");
253
+ expect("\\sqrt[2]{2+2}").toParseAs("(2+2)^(1/2)");
254
+ });
255
+
256
+ test("absolute value", () => {
257
+ expect("abs(x)").toParseAs("abs(x)");
258
+ expect("abs(abs(x))").toParseAs("abs(abs(x))");
259
+ expect("abs(x)abs(y)").toParseAs("abs(x)*abs(y)");
260
+
261
+ expect("|x|").toParseAs("abs(x)");
262
+ expect("||x||").toParseAs("abs(abs(x))");
263
+ // TODO(alex): fix the below so it doesn't require an *
264
+ // may require own lexer/preprocessor
265
+ expect("|x|*|y|").toParseAs("abs(x)*abs(y)");
266
+
267
+ expect("\\abs(x)").toParseAs("abs(x)");
268
+ expect("\\abs(\\abs(x))").toParseAs("abs(abs(x))");
269
+ expect("\\abs(x)\\abs(y)").toParseAs("abs(x)*abs(y)");
270
+
271
+ expect("\\left|x\\right|").toParseAs("abs(x)");
272
+ expect("\\left|\\left|x\\right|\\right|").toParseAs("abs(abs(x))");
273
+ expect("\\left|x\\right|\\left|y\\right|").toParseAs("abs(x)*abs(y)");
274
+ });
275
+
276
+ test("logarithms", () => {
277
+ expect("lnx").toParseAs("ln(x)");
278
+ expect("ln x").toParseAs("ln(x)");
279
+ expect("ln x^y").toParseAs("ln(x^(y))");
280
+ expect("ln xy").toParseAs("ln(x*y)");
281
+ expect("ln x/y").toParseAs("ln(x*y^(-1))");
282
+ expect("ln x+y").toParseAs("ln(x)+y");
283
+ expect("ln x-y").toParseAs("ln(x)+-1*y");
284
+
285
+ expect("ln xyz").toParseAs("ln(x*y*z)");
286
+ expect("ln xy/z").toParseAs("ln(x*y*z^(-1))");
287
+ expect("ln xy/z+1").toParseAs("ln(x*y*z^(-1))+1");
288
+
289
+ expect("ln x(y)").toParseAs("ln(x)*y");
290
+
291
+ expect("logx").toParseAs("log_(10) (x)");
292
+ expect("log x").toParseAs("log_(10) (x)");
293
+ expect("log_2x").toParseAs("log_(2) (x)");
294
+ expect("log _ 2 x").toParseAs("log_(2) (x)");
295
+ expect("log_bx_0").toParseAs("log_(b) (x_(0))");
296
+ expect("log_x_0b").toParseAs("log_(x_(0)) (b)");
297
+
298
+ expect("log_2.5x").toParseAs("log_(2.5) (x)");
299
+
300
+ expect("ln ln x").toParseAs("ln(ln(x))");
301
+ expect("ln x ln y").toParseAs("ln(x)*ln(y)");
302
+ expect("ln x/ln y").toParseAs("ln(x)*ln(y)^(-1)");
303
+
304
+ expect("\\lnx").toParseAs("ln(x)");
305
+ expect("\\ln x").toParseAs("ln(x)");
306
+ expect("\\ln x^y").toParseAs("ln(x^(y))");
307
+ expect("\\ln xy").toParseAs("ln(x*y)");
308
+ expect("\\ln x/y").toParseAs("ln(x*y^(-1))");
309
+ expect("\\ln x+y").toParseAs("ln(x)+y");
310
+ expect("\\ln x-y").toParseAs("ln(x)+-1*y");
311
+
312
+ expect("\\logx").toParseAs("log_(10) (x)");
313
+ expect("\\log x").toParseAs("log_(10) (x)");
314
+ expect("\\log_2x").toParseAs("log_(2) (x)");
315
+ expect("\\log _ 2 x").toParseAs("log_(2) (x)");
316
+ expect("\\log_bx_0").toParseAs("log_(b) (x_(0))");
317
+ expect("\\log_x_0b").toParseAs("log_(x_(0)) (b)");
318
+
319
+ expect("\\log_2.5x").toParseAs("log_(2.5) (x)");
320
+
321
+ expect("\\frac{\\logx}{y}").toParseAs("log_(10) (x)*y^(-1)");
322
+ expect("\\frac{\\log x}{y}").toParseAs("log_(10) (x)*y^(-1)");
323
+ });
324
+
325
+ test("trig functions", () => {
326
+ var functions = ["sin", "cos", "tan", "csc", "sec", "cot"];
327
+
328
+ var inverses = _.map(functions, function (func) {
329
+ return "arc" + func;
330
+ });
331
+
332
+ _.each(functions.concat(inverses), function (func) {
333
+ expect(func + "x").toParseAs(func + "(x)");
334
+ expect("\\" + func + "x").toParseAs(func + "(x)");
335
+ });
336
+
337
+ expect("sin^-1 x").toParseAs("arcsin(x)");
338
+ expect("\\sin^-1 x").toParseAs("arcsin(x)");
339
+
340
+ expect("(sinx)^2").toParseAs("sin(x)^(2)");
341
+ expect("sin^2x").toParseAs("sin(x)^(2)");
342
+ expect("sin^2(x)").toParseAs("sin(x)^(2)");
343
+ expect("sin^2 x").toParseAs("sin(x)^(2)");
344
+ expect("(sin^2x)").toParseAs("sin(x)^(2)");
345
+
346
+ expect("sin xy").toParseAs("sin(x*y)");
347
+ expect("sin x(y)").toParseAs("sin(x)*y");
348
+ expect("sin x/y").toParseAs("sin(x*y^(-1))");
349
+ expect("(sin x)/y").toParseAs("sin(x)*y^(-1)");
350
+
351
+ expect("sin sin x").toParseAs("sin(sin(x))");
352
+ expect("sin x sin y").toParseAs("sin(x)*sin(y)");
353
+ expect("sin x/sin y").toParseAs("sin(x)*sin(y)^(-1)");
354
+
355
+ expect("1/(sinx)^2").toParseAs("sin(x)^(-2)");
356
+ expect("1/sin^2x").toParseAs("sin(x)^(-2)");
357
+ expect("1/sin^2(x)").toParseAs("sin(x)^(-2)");
358
+ expect("1/(sin^2x)").toParseAs("sin(x)^(-2)");
359
+
360
+ expect("sin(theta)").toParseAs("sin(theta)");
361
+ expect("\\sin(\\theta)").toParseAs("sin(theta)");
362
+ });
363
+
364
+ test("hyperbolic functions", () => {
365
+ expect("sinh xy").toParseAs("sinh(x*y)");
366
+ expect("1/(sinhx)^2").toParseAs("sinh(x)^(-2)");
367
+ expect("\\sinh(\\theta)").toParseAs("sinh(theta)");
368
+ });
369
+
370
+ test("formulas", () => {
371
+ expect("mx+b").toParseAs("m*x+b");
372
+ expect("v^2/r").toParseAs("v^(2)*r^(-1)");
373
+ expect("4/3pir^3").toParseAs("4/3*pi*r^(3)");
374
+ expect("4/3\u03C0r^3").toParseAs("4/3*pi*r^(3)");
375
+ expect("sin^2 x + cos^2 x = 1").toParseAs("sin(x)^(2)+cos(x)^(2)=1");
376
+ });
377
+
378
+ test("factors", () => {
379
+ expect("(6x+1)(x-1)").toParseAs("(6*x+1)*(x+-1)");
380
+ });
381
+
382
+ test("whitespace", () => {
383
+ expect("12/3").toParseAs("12/3");
384
+ expect("12 /3").toParseAs("12/3");
385
+ expect("12/ 3").toParseAs("12/3");
386
+ expect("xy").toParseAs("x*y");
387
+ expect("x y").toParseAs("x*y");
388
+ });
389
+
390
+ test("equations", () => {
391
+ expect("y=x").toParseAs("y=x");
392
+ expect("y=x^2").toParseAs("y=x^(2)");
393
+ expect("1<2").toParseAs("1<2");
394
+ expect("1<=2").toParseAs("1<=2");
395
+ expect("1\\le2").toParseAs("1<=2");
396
+ expect("2>1").toParseAs("2>1");
397
+ expect("2>=1").toParseAs("2>=1");
398
+ expect("2\\ge1").toParseAs("2>=1");
399
+ expect("1<>2").toParseAs("1<>2");
400
+ expect("1=/=2").toParseAs("1<>2");
401
+ expect("1\\ne2").toParseAs("1<>2");
402
+ expect("1\\neq2").toParseAs("1<>2");
403
+ expect("a\u2260b").toParseAs("a<>b");
404
+ expect("a\u2264b").toParseAs("a<=b");
405
+ expect("a\u2265b").toParseAs("a>=b");
406
+
407
+ expect("y \\le x").toParseAs("y<=x");
408
+ expect("y \\leq x").toParseAs("y<=x");
409
+ expect("y \\ge x").toParseAs("y>=x");
410
+ expect("y \\geq x").toParseAs("y>=x");
411
+ });
412
+
413
+ test("function variables", () => {
414
+ expect("f(x)").toParseAs("f*x");
415
+ expect("f(x)").toParseAs("f(x)", {functions: ["f"]});
416
+ expect("f(x+y)").toParseAs("f(x+y)", {functions: ["f"]});
417
+ expect("f(x)g(x)").toParseAs("f(x)*g(x)", {functions: ["f", "g"]});
418
+ expect("f(g(h(x)))").toParseAs("f(g(h(x)))", {
419
+ functions: ["f", "g", "h"],
420
+ });
421
+
422
+ expect("f\\left(x\\right)").toParseAs("f*x");
423
+ expect("f\\left(x\\right)").toParseAs("f(x)", {functions: ["f"]});
424
+ expect("f\\left(x+y\\right)").toParseAs("f(x+y)", {
425
+ functions: ["f"],
426
+ });
427
+ expect("f\\left(x\\right)g\\left(x\\right)").toParseAs("f(x)*g(x)", {
428
+ functions: ["f", "g"],
429
+ });
430
+ expect("f\\left(g\\left(h\\left(x\\right)\\right)\\right)").toParseAs(
431
+ "f(g(h(x)))",
432
+ {functions: ["f", "g", "h"]},
433
+ );
434
+ });
435
+
436
+ test("structure", () => {
437
+ expect("").toParseWithStructure("Add()");
438
+ expect("1.").toParseWithStructure("1");
439
+ expect("1/2").toParseWithStructure("1/2");
440
+ expect("1/-2").toParseWithStructure("-1/2");
441
+ expect("x/-2").toParseWithStructure("Mul(Var(x),-1/2)");
442
+ expect("a+b").toParseWithStructure("Add(Var(a),Var(b))");
443
+ expect("a+b+c").toParseWithStructure("Add(Var(a),Var(b),Var(c))");
444
+ expect("a-b").toParseWithStructure("Add(Var(a),Mul(-1,Var(b)))");
445
+ expect("a-b+c").toParseWithStructure(
446
+ "Add(Var(a),Mul(-1,Var(b)),Var(c))",
447
+ );
448
+ expect("abc").toParseWithStructure("Mul(Var(a),Var(b),Var(c))");
449
+ expect("a/bc").toParseWithStructure(
450
+ "Mul(Var(a),Pow(Var(b),-1),Var(c))",
451
+ );
452
+ expect("a*(b+c)").toParseWithStructure(
453
+ "Mul(Var(a),Add(Var(b),Var(c)))",
454
+ );
455
+ expect("x--y").toParseWithStructure("Add(Var(x),Mul(-1,-1,Var(y)))");
456
+ expect("--y").toParseWithStructure("Mul(-1,-1,Var(y))");
457
+ expect("e").toParseWithStructure("Const(e)");
458
+ expect("2e").toParseWithStructure("Mul(2,Const(e))");
459
+ expect("2e^x").toParseWithStructure("Mul(2,Pow(Const(e),Var(x)))");
460
+ expect("cdef").toParseWithStructure(
461
+ "Mul(Var(c),Var(d),Const(e),Var(f))",
462
+ );
463
+ expect("pi").toParseWithStructure("Const(pi)");
464
+ expect("pi^2").toParseWithStructure("Pow(Const(pi),2)");
465
+ expect("pir").toParseWithStructure("Mul(Const(pi),Var(r))");
466
+ expect("pir^2").toParseWithStructure("Mul(Const(pi),Pow(Var(r),2))");
467
+ expect("y=x^2").toParseWithStructure("Eq(Var(y),=,Pow(Var(x),2))");
468
+ expect("log_2x").toParseWithStructure("Log(2,Var(x))");
469
+ expect("f(x+y)").toParseWithStructure("Mul(Var(f),Add(Var(x),Var(y)))");
470
+ expect("f(x+y)").toParseWithStructure("Func(f,Add(Var(x),Var(y)))", {
471
+ functions: ["f"],
472
+ });
473
+ expect("sin(theta)").toParseWithStructure("Trig(sin,Var(theta))");
474
+ expect("tanh(theta)").toParseWithStructure("Trig(tanh,Var(theta))");
475
+
476
+ // verify that negative signs get folded into numbers
477
+ expect("-x*3").toParseWithStructure("Mul(Var(x),-3)");
478
+ expect("sin -x*3").toParseWithStructure("Trig(sin,Mul(Var(x),-3))");
479
+ });
480
+ });