desmost 0.9.0 → 0.10.0
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/README.md +87 -11
- package/dist/compiler/compile.d.ts +1 -7
- package/dist/compiler/compile.d.ts.map +1 -1
- package/dist/compiler/compile.js +3 -94
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/compiler.d.ts +56 -0
- package/dist/compiler/compiler.d.ts.map +1 -0
- package/dist/compiler/compiler.js +209 -0
- package/dist/compiler/compiler.js.map +1 -0
- package/dist/compiler/format.d.ts +2 -2
- package/dist/compiler/format.d.ts.map +1 -1
- package/dist/compiler/format.js +18 -9
- package/dist/compiler/format.js.map +1 -1
- package/dist/decompiler/decompile.d.ts +1 -1
- package/dist/decompiler/decompile.d.ts.map +1 -1
- package/dist/decompiler/decompile.js +1 -3
- package/dist/decompiler/decompile.js.map +1 -1
- package/dist/decompiler/extract.d.ts.map +1 -1
- package/dist/decompiler/extract.js +7 -3
- package/dist/decompiler/extract.js.map +1 -1
- package/dist/decompiler/format.d.ts.map +1 -1
- package/dist/decompiler/format.js +0 -1
- package/dist/decompiler/format.js.map +1 -1
- package/dist/errors.d.ts +35 -27
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +46 -48
- package/dist/errors.js.map +1 -1
- package/dist/index.internal.d.ts +1 -1
- package/dist/index.internal.d.ts.map +1 -1
- package/dist/magic/global/desmos.d.ts +2 -2
- package/dist/magic/global/desmos.d.ts.map +1 -1
- package/dist/magic/global/desmos.js +3 -2
- package/dist/magic/global/desmos.js.map +1 -1
- package/dist/magic/global/viewport.d.ts +2 -2
- package/dist/magic/global/viewport.d.ts.map +1 -1
- package/dist/magic/global/viewport.js +5 -5
- package/dist/magic/global/viewport.js.map +1 -1
- package/dist/magic/incantation.d.ts +4 -4
- package/dist/magic/incantation.d.ts.map +1 -1
- package/dist/magic/incantation.js +15 -8
- package/dist/magic/incantation.js.map +1 -1
- package/dist/magic/local/colour.d.ts +3 -1
- package/dist/magic/local/colour.d.ts.map +1 -1
- package/dist/magic/local/colour.js +15 -11
- package/dist/magic/local/colour.js.map +1 -1
- package/dist/magic/local/label.d.ts +2 -2
- package/dist/magic/local/label.d.ts.map +1 -1
- package/dist/magic/local/label.js +8 -7
- package/dist/magic/local/label.js.map +1 -1
- package/dist/magic/local/line.d.ts +2 -2
- package/dist/magic/local/line.d.ts.map +1 -1
- package/dist/magic/local/line.js +0 -1
- package/dist/magic/local/line.js.map +1 -1
- package/dist/options.d.ts +59 -27
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +2 -1
- package/dist/options.js.map +1 -1
- package/dist/parser/ast.d.ts +3 -17
- package/dist/parser/ast.d.ts.map +1 -1
- package/dist/parser/ast.js +0 -2
- package/dist/parser/ast.js.map +1 -1
- package/dist/parser/desmost-parser.d.ts +33 -22
- package/dist/parser/desmost-parser.d.ts.map +1 -1
- package/dist/parser/desmost-parser.js +106 -92
- package/dist/parser/desmost-parser.js.map +1 -1
- package/dist/parser/generic-parser.d.ts +19 -10
- package/dist/parser/generic-parser.d.ts.map +1 -1
- package/dist/parser/generic-parser.js +56 -16
- package/dist/parser/generic-parser.js.map +1 -1
- package/dist/utils.d.ts +9 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +13 -2
- package/dist/utils.js.map +1 -1
- package/package.json +4 -3
- package/src/compiler/compile.ts +7 -120
- package/src/compiler/compiler.ts +275 -0
- package/src/compiler/format.ts +19 -7
- package/src/decompiler/decompile.ts +1 -7
- package/src/decompiler/extract.ts +3 -1
- package/src/decompiler/format.ts +0 -1
- package/src/errors.ts +40 -24
- package/src/index.internal.ts +1 -1
- package/src/magic/.template.ts +2 -2
- package/src/magic/global/desmos.ts +7 -9
- package/src/magic/global/viewport.ts +11 -17
- package/src/magic/incantation.ts +21 -22
- package/src/magic/local/colour.ts +23 -13
- package/src/magic/local/label.ts +14 -19
- package/src/magic/local/line.ts +2 -2
- package/src/options.ts +83 -51
- package/src/parser/ast.ts +1 -21
- package/src/parser/desmost-parser.ts +131 -135
- package/src/parser/generic-parser.ts +71 -29
- package/src/utils.ts +25 -3
- package/dist/compiler/evaluate.d.ts +0 -18
- package/dist/compiler/evaluate.d.ts.map +0 -1
- package/dist/compiler/evaluate.js +0 -93
- package/dist/compiler/evaluate.js.map +0 -1
- package/dist/desmos.d.ts +0 -16
- package/dist/desmos.d.ts.map +0 -1
- package/dist/desmos.js +0 -19
- package/dist/desmos.js.map +0 -1
- package/src/compiler/evaluate.ts +0 -128
- package/src/desmos.ts +0 -22
package/src/index.internal.ts
CHANGED
package/src/magic/.template.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// import { Incantation, ArgIncantation, type GLOBAL, type LOCAL, type EXPR } from "../incantation";
|
|
2
2
|
|
|
3
3
|
// import type { DesmostOptions } from "../../options";
|
|
4
|
-
// import {
|
|
4
|
+
// import { DesmostError, type Fallible } from "../../errors";
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
// export class ?Incantation extends ArgIncantation<?>
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// // TODO
|
|
19
19
|
// }
|
|
20
20
|
|
|
21
|
-
// override evaluate_arg(raw: ?, options: DesmostOptions):
|
|
21
|
+
// override evaluate_arg(raw: ?, options: DesmostOptions): Fallible<?>
|
|
22
22
|
// {
|
|
23
23
|
// let out = super.evaluate_arg(raw, options) as ?;
|
|
24
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Incantation, ArgIncantation, type GLOBAL } from "../incantation";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { DesmostError, type Fallible } from "../../errors";
|
|
4
4
|
import type { DesmostOptions } from "../../options";
|
|
5
5
|
|
|
6
6
|
|
|
@@ -26,19 +26,17 @@ export class DesmosIncantation extends ArgIncantation<GLOBAL>
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
override evaluate_arg(raw: string, options: DesmostOptions):
|
|
29
|
+
override evaluate_arg(raw: string, options: DesmostOptions): Fallible<DesmosSettings>
|
|
30
30
|
{
|
|
31
31
|
let out = super.evaluate_arg(raw, options) as DesmosSettings;
|
|
32
32
|
|
|
33
33
|
if (options.check_args) {
|
|
34
34
|
if (Object.keys(out).length === 0) {
|
|
35
|
-
throw new
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
);
|
|
35
|
+
throw new DesmostError.MissingInput({
|
|
36
|
+
msg: `/desmos received empty settings`,
|
|
37
|
+
hint: `Provide settings like \`/desmos{expressionsCollapsed: true}\``,
|
|
38
|
+
note: `Use just /desmos (without \`{}\`) if you want it as an indicator`,
|
|
39
|
+
});
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Incantation, ArgIncantation, type GLOBAL } from "../incantation";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { DesmostError, type Fallible } from "../../errors";
|
|
4
4
|
import type { DesmostOptions } from "../../options";
|
|
5
5
|
|
|
6
6
|
|
|
@@ -36,20 +36,17 @@ export class ViewportIncantation extends ArgIncantation<GLOBAL>
|
|
|
36
36
|
target.setMathBounds({ left, right, bottom, top });
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
override evaluate_arg(raw: string, options: DesmostOptions):
|
|
39
|
+
override evaluate_arg(raw: string, options: DesmostOptions): Fallible<ViewportBounds>
|
|
40
40
|
{
|
|
41
41
|
let out = super.evaluate_arg(raw, options) as ViewportBounds;
|
|
42
42
|
|
|
43
43
|
if (options.check_args) {
|
|
44
44
|
if (Object.keys(out).length === 0) {
|
|
45
|
-
throw new
|
|
46
|
-
`/${this.identifier} received empty viewport bounds`,
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
flagged_by: "check_args",
|
|
51
|
-
}
|
|
52
|
-
);
|
|
45
|
+
throw new DesmostError.InvalidArgument({
|
|
46
|
+
msg: `/${this.identifier} received empty viewport bounds`,
|
|
47
|
+
hint: `Provide bounds like \`/viewport{left: -8, right: 8}\``,
|
|
48
|
+
note: `Missing bounds are kept as their defaults`,
|
|
49
|
+
});
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
let invalid_keys = Object.keys(out).filter(key => !VALID_KEYS.includes(key));
|
|
@@ -57,13 +54,10 @@ export class ViewportIncantation extends ArgIncantation<GLOBAL>
|
|
|
57
54
|
if (invalid_keys.length > 0) {
|
|
58
55
|
let plural = invalid_keys.length > 1 ? "fields" : "field";
|
|
59
56
|
|
|
60
|
-
throw new
|
|
61
|
-
`/${this.identifier} received invalid ${plural}: [${invalid_keys.join(", ")}]`,
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
flagged_by: "check_args",
|
|
65
|
-
}
|
|
66
|
-
);
|
|
57
|
+
throw new DesmostError.InvalidArgument({
|
|
58
|
+
msg: `/${this.identifier} received invalid ${plural}: [${invalid_keys.join(", ")}]`,
|
|
59
|
+
hint: `Valid fields are: [${VALID_KEYS.join(", ")}]`,
|
|
60
|
+
});
|
|
67
61
|
}
|
|
68
62
|
}
|
|
69
63
|
|
package/src/magic/incantation.ts
CHANGED
|
@@ -2,7 +2,7 @@ import Json5 from "json5";
|
|
|
2
2
|
import dedent from "dedent";
|
|
3
3
|
|
|
4
4
|
import type { DesmostOptions } from "../options";
|
|
5
|
-
import {
|
|
5
|
+
import { DesmostError, type Fallible } from "../errors";
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -46,9 +46,11 @@ export abstract class Incantation<
|
|
|
46
46
|
{
|
|
47
47
|
if ((actual ?? "expression") !== required)
|
|
48
48
|
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
let req = required === "expression" ? "latex" : required;
|
|
50
|
+
|
|
51
|
+
throw new DesmostError.IllegalIncantation({
|
|
52
|
+
msg: `/${this.identifier} can only applied to ${req} blocks, but target block has type: ${actual}`,
|
|
53
|
+
});
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
}
|
|
@@ -80,7 +82,7 @@ export abstract class ArgIncantation<
|
|
|
80
82
|
*
|
|
81
83
|
* Validity checks for missing or invalid values, incorrect types, and unknown fields should be performed here, so that `.apply()` can assume the data it receives is guaranteed to be valid.
|
|
82
84
|
*/
|
|
83
|
-
evaluate_arg(raw: string, options: DesmostOptions):
|
|
85
|
+
evaluate_arg(raw: string, options: DesmostOptions): Fallible<unknown>
|
|
84
86
|
{
|
|
85
87
|
switch (this.arg_type) {
|
|
86
88
|
case Incantation.ArgType.LATEX: return raw;
|
|
@@ -95,7 +97,7 @@ export abstract class ArgIncantation<
|
|
|
95
97
|
}
|
|
96
98
|
catch (e) {
|
|
97
99
|
// @ts-expect-error: fine
|
|
98
|
-
throw new
|
|
100
|
+
throw new DesmostError.InvalidArgument({ msg: e.message });
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
}
|
|
@@ -103,34 +105,31 @@ export abstract class ArgIncantation<
|
|
|
103
105
|
|
|
104
106
|
protected require_nonempty(
|
|
105
107
|
arg: object,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
): Unrecoverable<void>
|
|
108
|
+
error_data?: DesmostError.Data,
|
|
109
|
+
): Fallible<void>
|
|
109
110
|
{
|
|
110
111
|
if (Object.entries(arg).length === 0) {
|
|
111
|
-
throw new
|
|
112
|
-
msg
|
|
113
|
-
|
|
114
|
-
);
|
|
112
|
+
throw new DesmostError.MissingInput({
|
|
113
|
+
msg: `/${this.identifier} received an empty argument {}`,
|
|
114
|
+
...error_data
|
|
115
|
+
});
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
protected require_known(
|
|
119
120
|
arg: object,
|
|
120
121
|
valid_fields: string[],
|
|
121
|
-
|
|
122
|
-
):
|
|
122
|
+
error_data?: DesmostError.Data,
|
|
123
|
+
): Fallible<void>
|
|
123
124
|
{
|
|
124
125
|
// TODO accumulate
|
|
125
126
|
for (let field of Object.keys(arg)) {
|
|
126
127
|
if (!valid_fields.includes(field)) {
|
|
127
|
-
throw new
|
|
128
|
-
`/${this.identifier} received invalid field: ${field}`,
|
|
129
|
-
{
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
);
|
|
128
|
+
throw new DesmostError.InvalidArgument({
|
|
129
|
+
msg: `/${this.identifier} received invalid field: ${field}`,
|
|
130
|
+
hint: `Valid fields are [${valid_fields.join(", ")}]`,
|
|
131
|
+
...error_data,
|
|
132
|
+
});
|
|
134
133
|
}
|
|
135
134
|
}
|
|
136
135
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { Incantation, ArgIncantation, type LOCAL } from "../incantation";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { UnrecoverableError } from "../../errors";
|
|
3
|
+
import { DesmostError } from "../../errors";
|
|
5
4
|
import type { DesmostOptions } from "../../options";
|
|
6
5
|
|
|
7
6
|
|
|
7
|
+
type DesmosColourName = keyof typeof Desmos.Colors;
|
|
8
|
+
type DesmosColour = (typeof Desmos.Colors)[DesmosColourName];
|
|
9
|
+
|
|
10
|
+
const VALID_COLOURS = ["RED", "BLUE", "GREEN", "PURPLE", "ORANGE", "BLACK"];
|
|
11
|
+
|
|
12
|
+
|
|
8
13
|
export class ColourIncantation extends ArgIncantation<LOCAL>
|
|
9
14
|
{
|
|
10
15
|
override readonly description
|
|
@@ -23,17 +28,22 @@ export class ColourIncantation extends ArgIncantation<LOCAL>
|
|
|
23
28
|
|
|
24
29
|
override evaluate_arg(data: string, options: DesmostOptions): DesmosColour
|
|
25
30
|
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
let colour = data.trim().toUpperCase();
|
|
32
|
+
|
|
33
|
+
if (VALID_COLOURS.includes(colour)) {
|
|
34
|
+
return Desmos.Colors[colour as DesmosColourName];
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
let internal = Desmos.Colors[colour as DesmosColourName];
|
|
38
|
+
|
|
39
|
+
if (options.check_args && internal == undefined) {
|
|
40
|
+
throw new DesmostError.InvalidArgument({
|
|
41
|
+
msg: `/colour received invalid colour: \`${data}\``,
|
|
42
|
+
hint: `Valid colours are ${VALID_COLOURS.join(", ")}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return internal;
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
}
|
package/src/magic/local/label.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Incantation, ArgIncantation, type LOCAL } from "../incantation";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { DesmostError } from "../../errors";
|
|
4
4
|
import type { DesmostOptions } from "../../options";
|
|
5
5
|
|
|
6
6
|
|
|
@@ -8,8 +8,8 @@ interface LabelOptions
|
|
|
8
8
|
{
|
|
9
9
|
text: string;
|
|
10
10
|
show?: boolean;
|
|
11
|
-
size?: number
|
|
12
|
-
pos?:
|
|
11
|
+
size?: number;
|
|
12
|
+
pos?: "ABOVE" | "BELOW" | "LEFT" | "RIGHT" | "ABOVE_LEFT" | "ABOVE_RIGHT" | "BELOW_LEFT" | "BELOW_RIGHT";
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const VALID_FIELDS = ["text", "show", "size", "pos"];
|
|
@@ -36,6 +36,7 @@ export class LabelIncantation extends ArgIncantation<LOCAL>
|
|
|
36
36
|
target.showLabel = data.show ?? true;
|
|
37
37
|
// @ts-expect-error: outdated types
|
|
38
38
|
if (data.size != undefined) target.labelSize = data.size;
|
|
39
|
+
// @ts-expect-error: outdated types
|
|
39
40
|
if (data.pos != undefined) target.labelOrientation = data.pos;
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -44,19 +45,16 @@ export class LabelIncantation extends ArgIncantation<LOCAL>
|
|
|
44
45
|
let out = super.evaluate_arg(raw, options) as LabelOptions;
|
|
45
46
|
|
|
46
47
|
if (options.check_args) {
|
|
47
|
-
super.require_nonempty(out,
|
|
48
|
+
super.require_nonempty(out, {
|
|
49
|
+
msg: `/label received empty argument`,
|
|
48
50
|
hint: `You can provide [${VALID_FIELDS.join(", ")}]`,
|
|
49
|
-
flagged_by: "check_args",
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
if (!("text" in out)) {
|
|
53
|
-
throw new
|
|
54
|
-
`/label is missing label text`,
|
|
55
|
-
{
|
|
56
|
-
|
|
57
|
-
flagged_by: "check_args",
|
|
58
|
-
}
|
|
59
|
-
);
|
|
54
|
+
throw new DesmostError.MissingInput({
|
|
55
|
+
msg: `/label is missing label text`,
|
|
56
|
+
hint: `Provide text for the label: \`/label{text: "sup world!"}\``,
|
|
57
|
+
});
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
super.require_known(out, VALID_FIELDS);
|
|
@@ -74,13 +72,10 @@ export class LabelIncantation extends ArgIncantation<LOCAL>
|
|
|
74
72
|
let orientation = Desmos.LabelOrientations[pos];
|
|
75
73
|
|
|
76
74
|
if (options.check_args && orientation == undefined) {
|
|
77
|
-
throw new
|
|
78
|
-
`/label received invalid label position: ${pos}`,
|
|
79
|
-
{
|
|
80
|
-
|
|
81
|
-
flagged_by: "check_args"
|
|
82
|
-
}
|
|
83
|
-
);
|
|
75
|
+
throw new DesmostError.InvalidArgument({
|
|
76
|
+
msg: `/label received invalid label position: ${pos}`,
|
|
77
|
+
hint: `Valid label positions are ${VALID_POSITIONS.join(", ")}`,
|
|
78
|
+
});
|
|
84
79
|
}
|
|
85
80
|
|
|
86
81
|
out.pos = orientation;
|
package/src/magic/local/line.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Incantation, ArgIncantation, type LOCAL } from "../incantation";
|
|
2
2
|
|
|
3
3
|
import type { DesmostOptions } from "../../options";
|
|
4
|
-
import {
|
|
4
|
+
import type { Fallible } from "../../errors";
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
interface LineOptions
|
|
@@ -32,7 +32,7 @@ export class LineIncantation extends ArgIncantation<LOCAL>
|
|
|
32
32
|
if (data.opacity != undefined) target.lineOpacity = data.opacity;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
override evaluate_arg(raw: string, options: DesmostOptions):
|
|
35
|
+
override evaluate_arg(raw: string, options: DesmostOptions): Fallible<LineOptions>
|
|
36
36
|
{
|
|
37
37
|
let out = super.evaluate_arg(raw, options) as LineOptions;
|
|
38
38
|
|
package/src/options.ts
CHANGED
|
@@ -2,6 +2,36 @@ import { LINE } from "./utils";
|
|
|
2
2
|
import { compile } from "./compiler/compile";
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
/** Default options that Desmost uses for `compile()` and `decompile()`. */
|
|
6
|
+
export const DEFAULT_OPTIONS: DesmostOptions =
|
|
7
|
+
{
|
|
8
|
+
errors: "surface",
|
|
9
|
+
place_errors: "inline",
|
|
10
|
+
error_prefix: `[DESMOST ERROR]\n${LINE}\n`,
|
|
11
|
+
expand_errors: true,
|
|
12
|
+
check_args: true,
|
|
13
|
+
prettify: true,
|
|
14
|
+
dedent_text: true,
|
|
15
|
+
ignore_comments: false,
|
|
16
|
+
ignore_all_blanks: false,
|
|
17
|
+
keep_leading_blanks: false,
|
|
18
|
+
keep_trailing_blanks: false,
|
|
19
|
+
debug: false,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Fill in `options` with Desmost's defaults to produce a complete `DesmostOptions` config.
|
|
25
|
+
*/
|
|
26
|
+
export function fill_defaults(options: Partial<DesmostOptions> | undefined): DesmostOptions
|
|
27
|
+
{
|
|
28
|
+
return {
|
|
29
|
+
...DEFAULT_OPTIONS,
|
|
30
|
+
...options,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
5
35
|
/**
|
|
6
36
|
* Options to customise Desmost compilation.
|
|
7
37
|
*
|
|
@@ -29,14 +59,15 @@ import { compile } from "./compiler/compile";
|
|
|
29
59
|
export interface DesmostOptions
|
|
30
60
|
{
|
|
31
61
|
/**
|
|
32
|
-
* How should errors be
|
|
62
|
+
* How should errors be displayed?
|
|
33
63
|
*
|
|
34
|
-
* - `surface` (default): Blocks that result in errors will become Desmos text
|
|
64
|
+
* - `surface` (default): Blocks that result in errors will become Desmos text blocks containing the error message, leaving other expressions unaffected.
|
|
35
65
|
*
|
|
36
|
-
* - `crash`: The entire compilation to Desmos will terminate with a single error message
|
|
37
|
-
*
|
|
66
|
+
* - `crash`: The entire compilation to Desmos will terminate with a single error message in a text block.
|
|
67
|
+
* - This means you don't get any Desmos rendering at all, but errors are also immediately obvious.
|
|
68
|
+
* - Note that this will *clear all expressions* in the calculator instance. If you pass in a non-blank `Desmos.Calculator` to `compile()`, it could get cleared.
|
|
38
69
|
*
|
|
39
|
-
* - `suppress`: Silently fail on the frontend (if you wish to give the illusion that everything is fine).
|
|
70
|
+
* - `suppress`: Silently fail on the frontend (if you wish to give the illusion that everything is fine!).
|
|
40
71
|
*/
|
|
41
72
|
errors: "surface" | "crash" | "suppress"
|
|
42
73
|
|
|
@@ -52,7 +83,7 @@ export interface DesmostOptions
|
|
|
52
83
|
/**
|
|
53
84
|
* The prefix to prepend to error blocks.
|
|
54
85
|
*
|
|
55
|
-
* Defaults to `[DESMOST ERROR]
|
|
86
|
+
* Defaults to `"[DESMOST ERROR]"`.
|
|
56
87
|
*
|
|
57
88
|
* Provide a `""` blank string if you wish for no prefix to be added.
|
|
58
89
|
*/
|
|
@@ -61,100 +92,101 @@ export interface DesmostOptions
|
|
|
61
92
|
/**
|
|
62
93
|
* Show all the available diagnostics for errors, including hints and debug information?
|
|
63
94
|
*
|
|
64
|
-
* Defaults to `true
|
|
95
|
+
* Defaults to `true` – all output is shown.
|
|
65
96
|
*/
|
|
66
97
|
expand_errors: boolean
|
|
67
98
|
|
|
68
99
|
/**
|
|
69
|
-
* Error if an incantation receives a `{}` object argument with unknown fields?
|
|
100
|
+
* Error if an incantation receives a `{}` object argument with unknown fields, or no fields at all?
|
|
70
101
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* For instance, `/label{position: LEFT}` is invalid; it should be `/label{pos: LEFT}`. With `check_args: false`, this silently no-ops; with `check_args: true`, it flags an error.
|
|
102
|
+
* For instance, `/label{position: LEFT}` is invalid; it should be `/label{pos: LEFT}`. With `check_args: false`, this silently no-ops.
|
|
74
103
|
*
|
|
75
104
|
* Desmost doesn’t remove unknown fields, it just passes them directly to the Desmos API. If you know what you’re doing and a field you know exists isn’t supported by Desmos, you can disable this to avoid erroring.
|
|
76
105
|
*
|
|
77
|
-
* Defaults to `true
|
|
106
|
+
* Defaults to `true` – arguments are checked. The Desmos API happily accepts and ignores invalid fields, so Desmost provides a safety net for you ;)
|
|
78
107
|
*/
|
|
79
108
|
check_args: boolean
|
|
80
109
|
|
|
81
110
|
/**
|
|
82
111
|
* Prettify LaTeX output so it renders nicely in the Desmos editor?
|
|
83
112
|
*
|
|
84
|
-
*
|
|
113
|
+
* This means you can keep your source code much neater. It handles stuff like converting `()` –> `\left(\right)`, `x, y` –> `x,\ y`, `min(x, y)` –> `\operatorname{min}\left(x,\ y\right)`, and more!
|
|
114
|
+
*
|
|
115
|
+
* Defaults to `true` – LaTeX is prettified.
|
|
85
116
|
*/
|
|
86
117
|
prettify: boolean
|
|
87
118
|
|
|
88
119
|
/**
|
|
89
120
|
* Strip common indentation from `/text{}` blocks?
|
|
90
121
|
*
|
|
91
|
-
*
|
|
122
|
+
* This allows you to indent content for readability:
|
|
123
|
+
*
|
|
124
|
+
* ```hs
|
|
125
|
+
* /text{
|
|
126
|
+
* Now I have
|
|
127
|
+
* a lovely indent
|
|
128
|
+
* }
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* Defaults to `true` – text is dedented.
|
|
92
132
|
*/
|
|
93
133
|
dedent_text: boolean
|
|
94
134
|
|
|
95
135
|
/**
|
|
96
|
-
* Should `%` LaTeX comments be ignored, instead of turned into text
|
|
136
|
+
* Should `%` LaTeX comments be ignored, instead of turned into text blocks (notes)?
|
|
97
137
|
*
|
|
98
|
-
*
|
|
138
|
+
* ```hs
|
|
139
|
+
* % Do I become a text expression?
|
|
140
|
+
* y = x
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* Defaults to `false` – comments are kept.
|
|
99
144
|
*/
|
|
100
145
|
ignore_comments: boolean
|
|
101
146
|
|
|
102
147
|
/**
|
|
103
148
|
* Should all line breaks be ignored, instead of kept as blank expressions?
|
|
104
149
|
*
|
|
105
|
-
*
|
|
150
|
+
* ```hs
|
|
151
|
+
* % Should there be a blank block after this?
|
|
152
|
+
*
|
|
153
|
+
* % Should there be a blank block before this?
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* This takes precedence over `keep_leading_blanks` and `keep_trailing_blanks`.
|
|
157
|
+
*
|
|
158
|
+
* Defaults to `false` – blank lines are recognised.
|
|
106
159
|
*/
|
|
107
160
|
ignore_all_blanks: boolean
|
|
108
161
|
|
|
109
162
|
/**
|
|
110
163
|
* Should trailing blank lines at the start of the source be kept as blank expressions?
|
|
111
164
|
*
|
|
112
|
-
*
|
|
165
|
+
* This is disabled by default so line breaks after global incantations don’t mess things up:
|
|
166
|
+
*
|
|
167
|
+
* ```hs
|
|
168
|
+
* /viewport{left: -8, right: 8}
|
|
169
|
+
*
|
|
170
|
+
* % I don’t have a blank block above me, yay
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* Defaults to `false` – leading blank lines are ignored.
|
|
113
174
|
*/
|
|
114
175
|
keep_leading_blanks: boolean
|
|
115
176
|
|
|
116
177
|
/**
|
|
117
178
|
* Should trailing blank lines at the end of the source be kept as blank expressions?
|
|
118
179
|
*
|
|
119
|
-
* Defaults to `false
|
|
180
|
+
* Defaults to `false` – trailing blank lines are ignored.
|
|
120
181
|
*/
|
|
121
182
|
keep_trailing_blanks: boolean
|
|
122
183
|
|
|
123
184
|
/**
|
|
124
|
-
* Return debug diagnostics
|
|
185
|
+
* Return debug diagnostics from `compile()`?
|
|
125
186
|
*
|
|
126
|
-
* This includes the unevaluated AST and performance diagnostics.
|
|
187
|
+
* This includes the unevaluated AST and performance diagnostics. Relevant types are exposed from `desmost/internal`, but beware that these are implementation details and unstable.
|
|
127
188
|
*
|
|
128
|
-
* Defaults to `false
|
|
189
|
+
* Defaults to `false` – `compile()` returns `void`.
|
|
129
190
|
*/
|
|
130
191
|
debug: boolean
|
|
131
192
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
export const DEFAULT_OPTIONS: DesmostOptions =
|
|
135
|
-
{
|
|
136
|
-
errors: "surface",
|
|
137
|
-
place_errors: "inline",
|
|
138
|
-
error_prefix: `[DESMOST ERROR]\n${LINE}\n`,
|
|
139
|
-
expand_errors: true,
|
|
140
|
-
prettify: true,
|
|
141
|
-
dedent_text: true,
|
|
142
|
-
check_args: false,
|
|
143
|
-
ignore_comments: false,
|
|
144
|
-
ignore_all_blanks: false,
|
|
145
|
-
keep_leading_blanks: false,
|
|
146
|
-
keep_trailing_blanks: false,
|
|
147
|
-
debug: false,
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Fill in `options` with Desmost's defaults to produce a complete `DesmostOptions` config.
|
|
153
|
-
*/
|
|
154
|
-
export function fill_defaults(options: Partial<DesmostOptions> | undefined): DesmostOptions
|
|
155
|
-
{
|
|
156
|
-
return {
|
|
157
|
-
...DEFAULT_OPTIONS,
|
|
158
|
-
...options,
|
|
159
|
-
};
|
|
160
|
-
}
|
package/src/parser/ast.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { UnrecoverableError } from "../errors";
|
|
2
1
|
import { Incantation, ArgIncantation } from "../magic";
|
|
3
2
|
|
|
4
3
|
|
|
@@ -9,7 +8,6 @@ export namespace Ast
|
|
|
9
8
|
{
|
|
10
9
|
EXPRESSION = "Expression",
|
|
11
10
|
INCANTATION_INVOCATION = "Incantation-Invocation",
|
|
12
|
-
INVALID_INCANTATION = "Invalid-Incantation",
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
|
|
@@ -18,10 +16,7 @@ export namespace Ast
|
|
|
18
16
|
{
|
|
19
17
|
kind: Kind.EXPRESSION
|
|
20
18
|
data: Desmos.ExpressionState
|
|
21
|
-
incantations:
|
|
22
|
-
| IncantationInvocation<Incantation.Effect.LOCAL>
|
|
23
|
-
| InvalidInvocation
|
|
24
|
-
>
|
|
19
|
+
incantations: IncantationInvocation<Incantation.Effect.LOCAL>[]
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
|
|
@@ -30,31 +25,16 @@ export namespace Ast
|
|
|
30
25
|
| {
|
|
31
26
|
kind: Kind.INCANTATION_INVOCATION
|
|
32
27
|
incantation: Incantation<Effect>
|
|
33
|
-
arg_raw: undefined
|
|
34
28
|
}
|
|
35
29
|
| {
|
|
36
30
|
kind: Kind.INCANTATION_INVOCATION
|
|
37
31
|
incantation: ArgIncantation<Effect>
|
|
38
32
|
arg_raw: string | undefined
|
|
39
33
|
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* An invalid invantation invocation that raised an error when parsed.
|
|
43
|
-
*
|
|
44
|
-
* This will be propogated to the user as an extra Desmos text expression (unless they have `errors: "suppress"` configured).
|
|
45
|
-
*/
|
|
46
|
-
export interface InvalidInvocation
|
|
47
|
-
{
|
|
48
|
-
kind: Kind.INVALID_INCANTATION
|
|
49
|
-
incantation: Incantation
|
|
50
|
-
arg_raw?: string
|
|
51
|
-
error: UnrecoverableError
|
|
52
|
-
}
|
|
53
34
|
}
|
|
54
35
|
|
|
55
36
|
/** An abstract object produced by the parser. */
|
|
56
37
|
export type Ast =
|
|
57
38
|
| Ast.Expression
|
|
58
39
|
| Ast.IncantationInvocation
|
|
59
|
-
| Ast.InvalidInvocation
|
|
60
40
|
;
|