desmost 0.8.2 → 0.9.1
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 +80 -13
- package/dist/compiler/compile.d.ts +7 -3
- package/dist/compiler/compile.d.ts.map +1 -1
- package/dist/compiler/compile.js +7 -3
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/evaluate.d.ts +5 -5
- package/dist/compiler/evaluate.d.ts.map +1 -1
- package/dist/compiler/evaluate.js +16 -8
- package/dist/compiler/evaluate.js.map +1 -1
- package/dist/compiler/format.d.ts +2 -2
- package/dist/compiler/format.d.ts.map +1 -1
- package/dist/compiler/format.js +14 -1
- package/dist/compiler/format.js.map +1 -1
- package/dist/compiler/index.d.ts +0 -1
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/decompiler/decompile.d.ts +12 -1
- package/dist/decompiler/decompile.d.ts.map +1 -1
- package/dist/decompiler/decompile.js +14 -2
- package/dist/decompiler/decompile.js.map +1 -1
- package/dist/decompiler/emit.d.ts.map +1 -1
- package/dist/decompiler/emit.js +13 -6
- package/dist/decompiler/emit.js.map +1 -1
- package/dist/decompiler/extract.d.ts.map +1 -1
- package/dist/decompiler/extract.js +3 -2
- package/dist/decompiler/extract.js.map +1 -1
- package/dist/decompiler/format.js +1 -1
- package/dist/decompiler/format.js.map +1 -1
- package/dist/desmos.d.ts +4 -0
- package/dist/desmos.d.ts.map +1 -1
- package/dist/desmos.js +6 -0
- package/dist/desmos.js.map +1 -1
- package/dist/errors.d.ts +18 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.internal.d.ts +1 -1
- package/dist/index.internal.d.ts.map +1 -1
- package/dist/index.internal.js +1 -1
- package/dist/index.internal.js.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/magic/expr/latex.d.ts +1 -2
- package/dist/magic/expr/latex.d.ts.map +1 -1
- package/dist/magic/expr/latex.js +1 -4
- package/dist/magic/expr/latex.js.map +1 -1
- package/dist/magic/expr/text.d.ts +1 -1
- package/dist/magic/expr/text.d.ts.map +1 -1
- package/dist/magic/expr/text.js +1 -1
- package/dist/magic/expr/text.js.map +1 -1
- package/dist/magic/global/dark-mode.d.ts.map +1 -1
- package/dist/magic/global/dark-mode.js +1 -3
- package/dist/magic/global/dark-mode.js.map +1 -1
- package/dist/magic/global/desmos.d.ts +4 -1
- package/dist/magic/global/desmos.d.ts.map +1 -1
- package/dist/magic/global/desmos.js +14 -1
- package/dist/magic/global/desmos.js.map +1 -1
- package/dist/magic/global/viewport.d.ts +3 -0
- package/dist/magic/global/viewport.d.ts.map +1 -1
- package/dist/magic/global/viewport.js +23 -0
- package/dist/magic/global/viewport.js.map +1 -1
- package/dist/magic/incantation.d.ts +13 -8
- package/dist/magic/incantation.d.ts.map +1 -1
- package/dist/magic/incantation.js +23 -3
- package/dist/magic/incantation.js.map +1 -1
- package/dist/magic/local/anim.d.ts.map +1 -1
- package/dist/magic/local/anim.js +0 -1
- package/dist/magic/local/anim.js.map +1 -1
- package/dist/magic/local/colour.d.ts +3 -2
- package/dist/magic/local/colour.d.ts.map +1 -1
- package/dist/magic/local/colour.js +3 -3
- package/dist/magic/local/colour.js.map +1 -1
- package/dist/magic/local/label.d.ts +4 -3
- package/dist/magic/local/label.d.ts.map +1 -1
- package/dist/magic/local/label.js +37 -16
- package/dist/magic/local/label.js.map +1 -1
- package/dist/magic/local/line.d.ts +3 -0
- package/dist/magic/local/line.d.ts.map +1 -1
- package/dist/magic/local/line.js +10 -0
- package/dist/magic/local/line.js.map +1 -1
- package/dist/magic/local/slider.d.ts +2 -2
- package/dist/magic/local/slider.d.ts.map +1 -1
- package/dist/magic/local/slider.js +0 -1
- package/dist/magic/local/slider.js.map +1 -1
- package/dist/{compiler/options.d.ts → options.d.ts} +49 -22
- package/dist/options.d.ts.map +1 -0
- package/dist/{compiler/options.js → options.js} +6 -1
- package/dist/options.js.map +1 -0
- package/dist/parser/desmost-parser.d.ts +1 -1
- package/dist/parser/desmost-parser.d.ts.map +1 -1
- package/dist/parser/desmost-parser.js +9 -5
- package/dist/parser/desmost-parser.js.map +1 -1
- package/dist/parser/generic-parser.d.ts +1 -5
- package/dist/parser/generic-parser.d.ts.map +1 -1
- package/dist/parser/generic-parser.js +7 -10
- package/dist/parser/generic-parser.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -0
- package/dist/utils.js.map +1 -1
- package/package.json +9 -6
- package/src/compiler/compile.ts +8 -4
- package/src/compiler/evaluate.ts +22 -13
- package/src/compiler/format.ts +16 -3
- package/src/compiler/index.ts +0 -1
- package/src/decompiler/decompile.ts +18 -2
- package/src/decompiler/emit.ts +15 -6
- package/src/decompiler/extract.ts +3 -2
- package/src/decompiler/format.ts +1 -1
- package/src/decompiler/readme.md +9 -1
- package/src/desmos.ts +9 -0
- package/src/errors.ts +29 -8
- package/src/index.internal.ts +1 -1
- package/src/index.ts +2 -2
- package/src/magic/.template.ts +25 -16
- package/src/magic/expr/latex.ts +2 -7
- package/src/magic/expr/text.ts +2 -2
- package/src/magic/global/dark-mode.ts +1 -3
- package/src/magic/global/desmos.ts +23 -1
- package/src/magic/global/viewport.ts +40 -1
- package/src/magic/incantation.ts +59 -22
- package/src/magic/local/anim.ts +0 -1
- package/src/magic/local/colour.ts +4 -3
- package/src/magic/local/label.ts +52 -22
- package/src/magic/local/line.ts +20 -3
- package/src/magic/local/slider.ts +2 -3
- package/src/{compiler/options.ts → options.ts} +61 -14
- package/src/parser/desmost-parser.ts +12 -6
- package/src/parser/generic-parser.ts +12 -12
- package/src/parser/readme.md +2 -0
- package/src/utils.ts +3 -0
- package/svelte/desmost.svelte +5 -3
- package/dist/compiler/options.d.ts.map +0 -1
- package/dist/compiler/options.js.map +0 -1
package/src/compiler/compile.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type DesmostOptions, fill_defaults } from "./options";
|
|
2
1
|
import { evaluate_global_incantation, evaluate_expr, evaluate_error } from "./evaluate";
|
|
3
2
|
|
|
3
|
+
import { type DesmostOptions, fill_defaults } from "../options";
|
|
4
4
|
import { DesmostParser, Ast } from "../parser";
|
|
5
5
|
|
|
6
6
|
|
|
@@ -37,8 +37,12 @@ export function compile(
|
|
|
37
37
|
/** The Desmost source code to compile. */
|
|
38
38
|
source: string,
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Compilation options.
|
|
42
|
+
*
|
|
43
|
+
* See {@linkcode DesmostOptions} for the options available.
|
|
44
|
+
*/
|
|
45
|
+
options?: Partial<DesmostOptions>,
|
|
42
46
|
): void | DesmostDebug
|
|
43
47
|
{
|
|
44
48
|
if (desmos == undefined) {
|
|
@@ -95,7 +99,7 @@ export function compile(
|
|
|
95
99
|
break;
|
|
96
100
|
|
|
97
101
|
case Ast.Kind.EXPRESSION:
|
|
98
|
-
// @ts-expect-error:
|
|
102
|
+
// @ts-expect-error: check type-narrows
|
|
99
103
|
if (r.data.latex === " ") {
|
|
100
104
|
if (opts.ignore_all_blanks) break;
|
|
101
105
|
if (!seen_non_blank && !opts.keep_leading_blanks) break;
|
package/src/compiler/evaluate.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import dedent from "dedent";
|
|
2
|
+
|
|
1
3
|
import { format_error, normalise_latex, prettify_latex } from "./format";
|
|
2
|
-
import type { DesmostOptions } from "
|
|
4
|
+
import type { DesmostOptions } from "../options";
|
|
3
5
|
|
|
4
6
|
import { Ast } from "../parser";
|
|
5
7
|
import { UnrecoverableError, type Unrecoverable } from "../errors";
|
|
8
|
+
import { is_latex } from "../desmos";
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
/**
|
|
@@ -11,14 +14,14 @@ import { UnrecoverableError, type Unrecoverable } from "../errors";
|
|
|
11
14
|
export function evaluate_global_incantation(
|
|
12
15
|
invocation: Ast.IncantationInvocation,
|
|
13
16
|
desmos: Desmos.Calculator,
|
|
14
|
-
options:
|
|
17
|
+
options: DesmostOptions,
|
|
15
18
|
): Unrecoverable<void | string>
|
|
16
19
|
{
|
|
17
20
|
let data = undefined;
|
|
18
21
|
|
|
19
22
|
if ("arg_raw" in invocation && invocation.arg_raw != undefined) {
|
|
20
23
|
try {
|
|
21
|
-
data = invocation.incantation.evaluate_arg(invocation.arg_raw);
|
|
24
|
+
data = invocation.incantation.evaluate_arg(invocation.arg_raw, options);
|
|
22
25
|
}
|
|
23
26
|
catch (e) {
|
|
24
27
|
let msg = evaluate_error(e as Error, desmos, options);
|
|
@@ -31,12 +34,12 @@ export function evaluate_global_incantation(
|
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
|
-
* Evaluate
|
|
37
|
+
* Evaluate local incantation invocations on `expr`, then add `expr` to `desmos`.
|
|
35
38
|
*/
|
|
36
39
|
export function evaluate_expr(
|
|
37
40
|
expr: Ast.Expression,
|
|
38
41
|
desmos: Desmos.Calculator,
|
|
39
|
-
options:
|
|
42
|
+
options: DesmostOptions,
|
|
40
43
|
): Unrecoverable<void | string>
|
|
41
44
|
{
|
|
42
45
|
let errors: string[] = [];
|
|
@@ -54,31 +57,37 @@ export function evaluate_expr(
|
|
|
54
57
|
|
|
55
58
|
if ("arg_raw" in invocation && invocation.arg_raw != undefined) {
|
|
56
59
|
try {
|
|
57
|
-
data = invocation.incantation.evaluate_arg(invocation.arg_raw);
|
|
60
|
+
data = invocation.incantation.evaluate_arg(invocation.arg_raw, options);
|
|
58
61
|
}
|
|
59
62
|
catch (e) {
|
|
60
63
|
errors.push(format_error(e as Error, options));
|
|
64
|
+
// if it needs the arg, then we can't press on
|
|
61
65
|
if (invocation.incantation.requires_arg) continue;
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
|
|
69
|
+
try {
|
|
70
|
+
invocation.incantation.apply(expr.data, data);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
errors.push(format_error(e as Error, options));
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
if (errors.length > 0) {
|
|
69
78
|
desmos.setExpression({ type: "text", text: errors.join("\n\n") });
|
|
70
79
|
}
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// @ts-expect-error: outdated types
|
|
75
|
-
expr.data.latex = normalise_latex(expr.data.latex);
|
|
81
|
+
if (is_latex(expr.data)) {
|
|
82
|
+
expr.data.latex = normalise_latex(expr.data.latex!);
|
|
76
83
|
|
|
77
84
|
if (options.prettify) {
|
|
78
|
-
// @ts-expect-error: outdated types
|
|
79
85
|
expr.data.latex = prettify_latex(expr.data.latex);
|
|
80
86
|
}
|
|
81
87
|
}
|
|
88
|
+
else if (expr.data.type === "text" && options.dedent_text) {
|
|
89
|
+
expr.data.text = dedent(expr.data.text ?? "");
|
|
90
|
+
}
|
|
82
91
|
|
|
83
92
|
desmos.setExpression(expr.data);
|
|
84
93
|
}
|
|
@@ -92,7 +101,7 @@ export function evaluate_expr(
|
|
|
92
101
|
export function evaluate_error(
|
|
93
102
|
error: UnrecoverableError,
|
|
94
103
|
desmos: Desmos.Calculator,
|
|
95
|
-
options:
|
|
104
|
+
options: DesmostOptions,
|
|
96
105
|
): Unrecoverable<void | string>
|
|
97
106
|
{
|
|
98
107
|
switch (options.errors) {
|
package/src/compiler/format.ts
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
|
-
import type { DesmostOptions } from "
|
|
1
|
+
import type { DesmostOptions } from "../options";
|
|
2
2
|
|
|
3
3
|
import { UnrecoverableError } from "../errors";
|
|
4
|
+
import { LINE } from "../utils";
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
export function format_error(
|
|
7
8
|
e: UnrecoverableError,
|
|
8
|
-
options:
|
|
9
|
+
options: DesmostOptions,
|
|
9
10
|
): string
|
|
10
11
|
{
|
|
11
12
|
let prefix = options.error_prefix;
|
|
12
13
|
let sep = (prefix === "" || prefix.endsWith("\n")) ? "" : " ";
|
|
13
14
|
|
|
14
|
-
return `${prefix}${sep}${e.name}: ${e.message}`;
|
|
15
15
|
// TODO maybe include stack? (configurable?)
|
|
16
|
+
let display = `${prefix}${sep}${e.name}: ${e.message}`;
|
|
17
|
+
|
|
18
|
+
if (e.info != undefined && options.expand_errors) {
|
|
19
|
+
display += `\n${LINE}`;
|
|
20
|
+
|
|
21
|
+
if (e.info.hint != undefined) display += `\nHint: ${e.info.hint}`;
|
|
22
|
+
if (e.info.note != undefined) display += `\n${LINE}\nNote: ${e.info.note}`;
|
|
23
|
+
if (e.info.flagged_by != undefined) display += `\n${LINE}\nFlagged by: \`${e.info.flagged_by}\``;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return display;
|
|
16
27
|
}
|
|
17
28
|
|
|
18
29
|
|
|
@@ -37,7 +48,9 @@ export function normalise_latex(latex: string): string
|
|
|
37
48
|
export function prettify_latex(latex: string): string
|
|
38
49
|
{
|
|
39
50
|
latex = latex.replaceAll(/(?<!\\left)(\(|\[|\\\{)/g, "\\left$1");
|
|
51
|
+
latex = latex.replaceAll(/(?:\\left\s?)+/g, "\\left");
|
|
40
52
|
latex = latex.replaceAll(/(?<!\\right)(\)|\]|\\\})/g, "\\right$1");
|
|
53
|
+
latex = latex.replaceAll(/(?:\\right\s?)+/g, "\\right");
|
|
41
54
|
latex = latex.replaceAll(/(:|,)(?!\\ ) */g, "$1\\ ");
|
|
42
55
|
|
|
43
56
|
latex = latex.replaceAll(
|
package/src/compiler/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { emit_global_incantation, emit_expression } from "./emit";
|
|
|
2
2
|
import { extract_settings, extract_viewport, extract_expression } from "./extract";
|
|
3
3
|
|
|
4
4
|
import { Ast } from "../parser";
|
|
5
|
+
import type { DesmostOptions } from "../compiler";
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
export interface SemiStructuredAst
|
|
@@ -16,9 +17,24 @@ export interface SemiStructuredAst
|
|
|
16
17
|
*
|
|
17
18
|
* The caller must also supply a `blank` calculator instance. This is used as a reference for default field values, so that emitted incantations like `/desmos{}` don't get filled with a huge amount of noise.
|
|
18
19
|
*/
|
|
19
|
-
export function decompile(
|
|
20
|
+
export function decompile(
|
|
21
|
+
/** The Desmos calculator instance to decompile. */
|
|
22
|
+
desmos: Desmos.Calculator,
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The default blank Desmos calculator instance to use as a baseline.
|
|
26
|
+
*
|
|
27
|
+
* It is **highly recommended** to include this, otherwise your decompiled source will have a bunch of unnecessary incantations!
|
|
28
|
+
*
|
|
29
|
+
* This is used in deciding what settings are noise that can be omitted. For instance, most of your calculator settings are probably set to their default values, so there's no need to include *every single one of them* in `/desmos{}`.
|
|
30
|
+
*/
|
|
31
|
+
blank?: Desmos.Calculator,
|
|
32
|
+
|
|
33
|
+
// TODO doc
|
|
34
|
+
options?: Partial<DesmostOptions>,
|
|
35
|
+
): string
|
|
20
36
|
{
|
|
21
|
-
return ast_to_source(desmos_to_ast(desmos, blank));
|
|
37
|
+
return ast_to_source(desmos_to_ast(desmos, blank ?? desmos));
|
|
22
38
|
}
|
|
23
39
|
|
|
24
40
|
/**
|
package/src/decompiler/emit.ts
CHANGED
|
@@ -31,15 +31,24 @@ export function emit_expression(expr?: Ast.Expression): string
|
|
|
31
31
|
|
|
32
32
|
switch (expr.data.type) {
|
|
33
33
|
case "text":
|
|
34
|
-
|
|
34
|
+
expr.data.text ??= "";
|
|
35
|
+
|
|
36
|
+
if (expr.data.text.includes("\n")) {
|
|
37
|
+
content = `/text{\n${expr.data.text}\n}`;
|
|
38
|
+
} else {
|
|
39
|
+
content = `% ${expr.data.text}`;
|
|
40
|
+
}
|
|
35
41
|
break;
|
|
42
|
+
|
|
43
|
+
case "table":
|
|
44
|
+
content = "[tables are currently unsupported]";
|
|
45
|
+
break;
|
|
46
|
+
|
|
36
47
|
default:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
content = "";
|
|
48
|
+
if (expr.data.latex?.trim() !== "") {
|
|
49
|
+
content = expr.data.latex ?? "[unsupported]";
|
|
40
50
|
} else {
|
|
41
|
-
|
|
42
|
-
content = expr.data.latex ?? "?";
|
|
51
|
+
content = "";
|
|
43
52
|
}
|
|
44
53
|
}
|
|
45
54
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { stringify_json5, prettify_source } from "./format";
|
|
2
2
|
|
|
3
3
|
import { Ast } from "../parser";
|
|
4
|
+
import { is_latex } from "../desmos";
|
|
4
5
|
|
|
5
6
|
import { DesmosIncantation, ViewportIncantation } from "../magic/global";
|
|
6
7
|
|
|
@@ -69,7 +70,7 @@ export function extract_expression(expression: Desmos.ExpressionState): Ast.Expr
|
|
|
69
70
|
{
|
|
70
71
|
let data;
|
|
71
72
|
|
|
72
|
-
// @ts-expect-error:
|
|
73
|
+
// @ts-expect-error: check type-narrows
|
|
73
74
|
if (expression.latex?.trim() === "") {
|
|
74
75
|
data = { latex: ` ` };
|
|
75
76
|
} else {
|
|
@@ -79,7 +80,7 @@ export function extract_expression(expression: Desmos.ExpressionState): Ast.Expr
|
|
|
79
80
|
);
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
if (
|
|
83
|
+
if (is_latex(expression)) {
|
|
83
84
|
data.latex = prettify_source(data.latex);
|
|
84
85
|
}
|
|
85
86
|
|
package/src/decompiler/format.ts
CHANGED
package/src/decompiler/readme.md
CHANGED
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
This module implements the Desmos -> Desmost decompiler.
|
|
4
4
|
|
|
5
|
-
This decompiles a `Desmos.Calculator` instance into the *minimal* raw Desmost source code that could *completely* reproduce the calculator state.
|
|
5
|
+
This decompiles a `Desmos.Calculator` instance into the *minimal* raw Desmost source code that could *completely* reproduce the calculator state. In other words, we want this to hold:[^equality]
|
|
6
|
+
|
|
7
|
+
[^equality]: Using value equality of ‘calculator state’.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
compile(decompile(calc)) == calc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Decompilation happens through several lowering stages:
|
|
6
14
|
|
|
7
15
|
```hs
|
|
8
16
|
Desmos.Calculator -> object[] -> Ast[] -> string
|
package/src/desmos.ts
CHANGED
|
@@ -11,3 +11,12 @@ export enum DesmosColour
|
|
|
11
11
|
ORANGE = "#fa7e19",
|
|
12
12
|
BLACK = "#000000",
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Is `expr` a Desmos LaTeX expression (as opposed to a note or table)?
|
|
18
|
+
*/
|
|
19
|
+
export function is_latex(expr: Desmos.ExpressionState): expr is Desmos.Expression
|
|
20
|
+
{
|
|
21
|
+
return (expr.type === undefined || expr.type === "expression");
|
|
22
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -10,28 +10,49 @@ export type NoMatch = typeof NO_MATCH & { readonly __brand?: unique symbol };
|
|
|
10
10
|
*
|
|
11
11
|
* It's not *literally* unrecoverable in the sense that it will crash the compiler completely, but it means there are no further fallbacks to try.
|
|
12
12
|
*/
|
|
13
|
-
export class UnrecoverableError extends Error
|
|
13
|
+
export class UnrecoverableError extends Error
|
|
14
|
+
{
|
|
15
|
+
info?: UnrecoverableError.Info;
|
|
16
|
+
}
|
|
14
17
|
|
|
15
18
|
export namespace UnrecoverableError
|
|
16
19
|
{
|
|
20
|
+
export interface Info
|
|
21
|
+
{
|
|
22
|
+
hint?: string,
|
|
23
|
+
note?: string,
|
|
24
|
+
flagged_by?: string,
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
/** The parser unexpectedly reached the end of its entire input source code. */
|
|
18
|
-
export class UnexpectedEnd extends UnrecoverableError {
|
|
28
|
+
export class UnexpectedEnd extends UnrecoverableError {
|
|
29
|
+
constructor(msg: string, override info?: Info) { super(msg); this.name = "Unexpected End"; }
|
|
30
|
+
}
|
|
19
31
|
|
|
20
32
|
/** The parser did not receive input that it expected. */
|
|
21
|
-
export class MissingInput extends UnrecoverableError {
|
|
33
|
+
export class MissingInput extends UnrecoverableError {
|
|
34
|
+
constructor(msg: string, override info?: Info) { super(msg); this.name = "Missing Input"; }
|
|
35
|
+
}
|
|
22
36
|
|
|
23
37
|
/** The parser received input that did not match what it expected. */
|
|
24
|
-
export class UnexpectedInput extends UnrecoverableError {
|
|
38
|
+
export class UnexpectedInput extends UnrecoverableError {
|
|
39
|
+
constructor(msg: string, override info?: Info) { super(msg); this.name = "Unexpected Input"; }
|
|
40
|
+
}
|
|
25
41
|
|
|
26
42
|
/** The parser received excess input that it did not expect. */
|
|
27
|
-
export class ExcessInput extends UnrecoverableError {
|
|
28
|
-
|
|
43
|
+
export class ExcessInput extends UnrecoverableError {
|
|
44
|
+
constructor(msg: string, override info?: Info) { super(msg); this.name = "Excess Input"; }
|
|
45
|
+
}
|
|
29
46
|
|
|
30
47
|
/** An incantation can't be applied here. */
|
|
31
|
-
export class IllegalIncantation extends UnrecoverableError {
|
|
48
|
+
export class IllegalIncantation extends UnrecoverableError {
|
|
49
|
+
constructor(msg: string, override info?: Info) { super(msg); this.name = "Illegal Incantation"; }
|
|
50
|
+
}
|
|
32
51
|
|
|
33
52
|
/** An incantation's argument couldn't be parsed. */
|
|
34
|
-
export class InvalidArgument extends UnrecoverableError {
|
|
53
|
+
export class InvalidArgument extends UnrecoverableError {
|
|
54
|
+
constructor(msg: string, override info?: Info) { super(msg); this.name = "Invalid Argument"; }
|
|
55
|
+
}
|
|
35
56
|
}
|
|
36
57
|
|
|
37
58
|
|
package/src/index.internal.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { compile
|
|
2
|
-
export {
|
|
1
|
+
export { compile } from "./compiler";
|
|
2
|
+
export type { DesmostOptions } from "./options";
|
package/src/magic/.template.ts
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
// import { Incantation, ArgIncantation, type GLOBAL, type LOCAL, type EXPR } from "../incantation";
|
|
2
2
|
|
|
3
|
+
// import type { DesmostOptions } from "../../options";
|
|
4
|
+
// import { UnrecoverableError, type Unrecoverable } from "../../errors";
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
// export class ?Incantation extends ArgIncantation<?>
|
|
5
8
|
// {
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
|
|
9
|
+
// override readonly description
|
|
10
|
+
// = ""
|
|
11
|
+
|
|
12
|
+
// override readonly identifier = ?
|
|
13
|
+
// override readonly requires_arg = ?
|
|
14
|
+
// override readonly arg_type = Incantation.ArgType.?
|
|
15
|
+
|
|
16
|
+
// override apply(target: ?, data: ?)
|
|
17
|
+
// {
|
|
18
|
+
// // TODO
|
|
19
|
+
// }
|
|
20
|
+
|
|
21
|
+
// override evaluate_arg(raw: ?, options: DesmostOptions): Unrecoverable<?>
|
|
22
|
+
// {
|
|
23
|
+
// let out = super.evaluate_arg(raw, options) as ?;
|
|
24
|
+
|
|
25
|
+
// if (options.check_args) {
|
|
26
|
+
// // TODO
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
// return out;
|
|
30
|
+
// }
|
|
22
31
|
// }
|
package/src/magic/expr/latex.ts
CHANGED
|
@@ -10,15 +10,10 @@ export class LatexIncantation extends ArgIncantation<EXPR>
|
|
|
10
10
|
override readonly requires_arg = true
|
|
11
11
|
override readonly arg_type = Incantation.ArgType.LATEX
|
|
12
12
|
|
|
13
|
-
apply(target: Desmos.ExpressionState, data: string):
|
|
13
|
+
apply(target: Desmos.ExpressionState, data: string): asserts target is Desmos.Expression
|
|
14
14
|
{
|
|
15
15
|
target.type = "expression";
|
|
16
|
-
// @ts-expect-error:
|
|
16
|
+
// @ts-expect-error: previous assignment type-narrows
|
|
17
17
|
target.latex = data === "" ? " " : data;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
override evaluate_arg(data: string): string
|
|
21
|
-
{
|
|
22
|
-
return data;
|
|
23
|
-
}
|
|
24
19
|
}
|
package/src/magic/expr/text.ts
CHANGED
|
@@ -11,10 +11,10 @@ export class TextIncantation extends ArgIncantation<EXPR>
|
|
|
11
11
|
override readonly requires_arg = true
|
|
12
12
|
override readonly arg_type = Incantation.ArgType.STRING
|
|
13
13
|
|
|
14
|
-
override apply(target: Desmos.ExpressionState, data: string)
|
|
14
|
+
override apply(target: Desmos.ExpressionState, data: string): asserts target is Desmos.Note
|
|
15
15
|
{
|
|
16
16
|
target.type = "text";
|
|
17
|
-
// @ts-expect-error:
|
|
17
|
+
// @ts-expect-error: previous assignment type-narrows
|
|
18
18
|
target.text = data;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Incantation, ArgIncantation, type GLOBAL } from "../incantation";
|
|
2
2
|
|
|
3
|
+
import { UnrecoverableError, type Unrecoverable } from "../../errors";
|
|
4
|
+
import type { DesmostOptions } from "../../options";
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
type DesmosSettings = Desmos.GraphConfiguration & Desmos.GraphSettings
|
|
5
8
|
|
|
@@ -7,7 +10,7 @@ type DesmosSettings = Desmos.GraphConfiguration & Desmos.GraphSettings
|
|
|
7
10
|
export class DesmosIncantation extends ArgIncantation<GLOBAL>
|
|
8
11
|
{
|
|
9
12
|
override readonly description
|
|
10
|
-
= "
|
|
13
|
+
= "Tweak calculator settings via `Calculator.updateSettings()`."
|
|
11
14
|
|
|
12
15
|
override readonly identifier = "desmos"
|
|
13
16
|
override readonly requires_arg = false
|
|
@@ -22,4 +25,23 @@ export class DesmosIncantation extends ArgIncantation<GLOBAL>
|
|
|
22
25
|
target.updateSettings(data);
|
|
23
26
|
}
|
|
24
27
|
}
|
|
28
|
+
|
|
29
|
+
override evaluate_arg(raw: string, options: DesmostOptions): Unrecoverable<DesmosSettings>
|
|
30
|
+
{
|
|
31
|
+
let out = super.evaluate_arg(raw, options) as DesmosSettings;
|
|
32
|
+
|
|
33
|
+
if (options.check_args) {
|
|
34
|
+
if (Object.keys(out).length === 0) {
|
|
35
|
+
throw new UnrecoverableError.MissingInput(
|
|
36
|
+
`/${this.identifier} received empty settings`,
|
|
37
|
+
{
|
|
38
|
+
hint: `Provide settings like \`/desmos{expressionsCollapsed: true}\``,
|
|
39
|
+
note: `Use just /desmos (without \`{}\`) if you want it as an indicator`,
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
25
47
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Incantation, ArgIncantation, type GLOBAL } from "../incantation";
|
|
2
2
|
|
|
3
|
+
import { UnrecoverableError, type Unrecoverable } from "../../errors";
|
|
4
|
+
import type { DesmostOptions } from "../../options";
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
interface ViewportBounds
|
|
5
8
|
{
|
|
@@ -7,6 +10,8 @@ interface ViewportBounds
|
|
|
7
10
|
bottom?: number; top?: number;
|
|
8
11
|
}
|
|
9
12
|
|
|
13
|
+
const VALID_KEYS = ["left", "right", "bottom", "top"];
|
|
14
|
+
|
|
10
15
|
|
|
11
16
|
export class ViewportIncantation extends ArgIncantation<GLOBAL>
|
|
12
17
|
{
|
|
@@ -17,7 +22,7 @@ export class ViewportIncantation extends ArgIncantation<GLOBAL>
|
|
|
17
22
|
override readonly requires_arg = true
|
|
18
23
|
override readonly arg_type = Incantation.ArgType.OBJECT
|
|
19
24
|
|
|
20
|
-
apply(target: Desmos.Calculator, data: ViewportBounds)
|
|
25
|
+
override apply(target: Desmos.Calculator, data: ViewportBounds)
|
|
21
26
|
{
|
|
22
27
|
let existing = target.graphpaperBounds.mathCoordinates;
|
|
23
28
|
|
|
@@ -30,4 +35,38 @@ export class ViewportIncantation extends ArgIncantation<GLOBAL>
|
|
|
30
35
|
|
|
31
36
|
target.setMathBounds({ left, right, bottom, top });
|
|
32
37
|
}
|
|
38
|
+
|
|
39
|
+
override evaluate_arg(raw: string, options: DesmostOptions): Unrecoverable<ViewportBounds>
|
|
40
|
+
{
|
|
41
|
+
let out = super.evaluate_arg(raw, options) as ViewportBounds;
|
|
42
|
+
|
|
43
|
+
if (options.check_args) {
|
|
44
|
+
if (Object.keys(out).length === 0) {
|
|
45
|
+
throw new UnrecoverableError.InvalidArgument(
|
|
46
|
+
`/${this.identifier} received empty viewport bounds`,
|
|
47
|
+
{
|
|
48
|
+
hint: `Provide bounds like \`/viewport{left: -8, right: 8}\``,
|
|
49
|
+
note: `Missing bounds are kept as their defaults`,
|
|
50
|
+
flagged_by: "check_args",
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let invalid_keys = Object.keys(out).filter(key => !VALID_KEYS.includes(key));
|
|
56
|
+
|
|
57
|
+
if (invalid_keys.length > 0) {
|
|
58
|
+
let plural = invalid_keys.length > 1 ? "fields" : "field";
|
|
59
|
+
|
|
60
|
+
throw new UnrecoverableError.InvalidArgument(
|
|
61
|
+
`/${this.identifier} received invalid ${plural}: [${invalid_keys.join(", ")}]`,
|
|
62
|
+
{
|
|
63
|
+
hint: `Valid fields are: [${VALID_KEYS.join(", ")}]`,
|
|
64
|
+
flagged_by: "check_args",
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
33
72
|
}
|