Repository navigation
Expand file tree
/
Copy pathCompileController.ts
More file actions
165 lines (147 loc) · 5.94 KB
/
Copy pathCompileController.ts
File metadata and controls
165 lines (147 loc) · 5.94 KB
1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
* CompileController -- 源码到 SceneIR 的编译编排器.
*
* DslApp 不再直接处理 AST/runSequence 和显隐状态,而是通过这个控制器
* 完成三件事:
* 1. `run(source)`:解析新源码并生成一份完整 SceneIR;
* 2. `refresh(paramOverrides)`:复用当前 AST,只按新参数重新编译;
* 3. `toggleAnalysis/toggleIntegral/toggleIntersection/toggleSolve/toggleAntiderivative/toggleOde`:切换求值对象显隐后重新编译.
*
* 实体显隐不经过这里:它只改 Plotter 可见性,不需要重新编译
* (见 RenderController.toggleObject).
*
* 真正的编译细节仍由 compiler/dsl 下的 DslCompiler 和静态场景缓存负责.
*/
import { compileScene } from '@/compiler/dsl/DslCompiler';
import { parseMiko } from '@/compiler/parser';
import { createWasmMatrixOps } from '@/wasm/matrixOps';
import type { SceneIR } from '@/contract/ir';
import { CompileError, formatLocatedError } from '@/compiler/errors';
import { SceneStore } from './SceneStore';
export class CompileController {
private runSequence = 0;
private disposed = false;
constructor(private readonly store: SceneStore) {}
/**
* 解析并编译一份新源码.
*
* 返回 null 表示请求已经过期或控制器已销毁,调用方必须直接丢弃结果.
* 这样异步 parseMiko 返回后不会覆盖用户随后发起的新运行.
*/
async run(source: string): Promise<SceneIR | null> {
const runId = ++this.runSequence;
const ast = await parseMiko(source);
if (this.disposed || runId !== this.runSequence) return null;
this.store.commitSource(source, ast, createWasmMatrixOps());
return this.compile({});
}
/**
* 基于当前 AST 重新编译.
*
* 参数刷新不会重新解析 DSL,只把当前参数覆盖到静态场景上.这样可以
* 命中 DslCompiler 内部的静态场景缓存,避免重复做声明级建模.
*/
refresh(paramOverrides: Record<string, number>): SceneIR | null {
if (!this.store.ast) return null;
return this.compile(paramOverrides);
}
toggleAnalysis(
name: string,
paramOverrides: Record<string, number>,
): SceneIR | null {
this.store.toggleAnalysisHidden(name);
return this.recompileForVisibilityChange(paramOverrides);
}
toggleIntegral(
name: string,
paramOverrides: Record<string, number>,
): SceneIR | null {
this.store.toggleIntegralHidden(name);
return this.recompileForVisibilityChange(paramOverrides);
}
toggleIntersection(
name: string,
paramOverrides: Record<string, number>,
): SceneIR | null {
this.store.toggleIntersectionHidden(name);
return this.recompileForVisibilityChange(paramOverrides);
}
toggleSolve(
name: string,
paramOverrides: Record<string, number>,
): SceneIR | null {
this.store.toggleSolveHidden(name);
return this.recompileForVisibilityChange(paramOverrides);
}
/**
* 切换原函数条目显隐:隐藏会同时跳过积分内核与实体对象下发,所以必须重编译
* (与求解同一条路径).
*/
toggleAntiderivative(
name: string,
paramOverrides: Record<string, number>,
): SceneIR | null {
this.store.toggleAntiderivativeHidden(name);
return this.recompileForVisibilityChange(paramOverrides);
}
/**
* 切换微分方程条目显隐:隐藏会同时跳过实体下发(斜率场与解曲线),所以必须
* 重编译(与不定积分同一条路径).
*/
toggleOde(
name: string,
paramOverrides: Record<string, number>,
): SceneIR | null {
this.store.toggleOdeHidden(name);
return this.recompileForVisibilityChange(paramOverrides);
}
dispose(): void {
this.disposed = true;
this.runSequence += 1;
}
private recompileForVisibilityChange(
paramOverrides: Record<string, number>,
): SceneIR | null {
const scene = this.refresh(paramOverrides);
if (!scene) return null;
// 实体显隐不需要重新触发数值采样,但 SceneIR 中的 enabled 必须
// 与 SceneStore 保持同步,后续对象列表和渲染层都依赖它.
for (const object of scene.objects) {
object.enabled = !this.store.isEntityHidden(object.id);
}
return scene;
}
private compile(paramOverrides: Record<string, number>): SceneIR {
const ast = this.store.ast;
if (!ast) {
throw new Error('CompileController 没有可用的 AST,请先调用 run()');
}
const matrixOps = this.store.matrixOps;
if (!matrixOps) {
throw new Error('矩阵运算后端尚未初始化,请先调用 run()');
}
try {
return compileScene(ast, paramOverrides, matrixOps, {
hiddenAnalysisNames: this.store.hiddenAnalysisNames,
hiddenIntegralNames: this.store.hiddenIntegralNames,
hiddenIntersectionNames: this.store.hiddenIntersectionNames,
hiddenSolveNames: this.store.hiddenSolveNames,
hiddenAntiderivativeNames: this.store.hiddenAntiderivativeNames,
hiddenOdeNames: this.store.hiddenOdeNames,
});
} catch (error) {
throw this.locate(error);
}
}
/**
* 语句级编译错误(CompileError)由各 dsl 模块按语句 span 抛出;这里用
* store 里的原始源码把 span 换算成"第几行第几列"拼进文案,实现错误定位.
* 解析错误(Rust pest 文案自带行列)与运行期错误与具体语句无关,原样抛出.
*/
private locate(error: unknown): Error {
if (!(error instanceof CompileError)) {
return error instanceof Error ? error : new Error(String(error));
}
return new Error(formatLocatedError(error.message, error.span, this.store.source));
}
}