1. 错误模型
好的编译器要把 compile-time errors 和 运行时错误 分开。Diagnostic 记录源码 span,formatDiagnostic() 负责展示;RuntimeError 则描述 VM 执行期问题,比如除零或空调用。
type Diagnostic = { message: string; line: number; column: number; length: number };
function formatDiagnostic(source: string, diagnostic: Diagnostic): string {
return `${diagnostic.line}:${diagnostic.column} ${diagnostic.message}`;
}
class RuntimeError extends Error {
constructor(message: string, public frame?: CallFrame) {
super(message);
}
}
2. 测试与扩展
测试编译器 可以采用 snapshot-style compiler tests:源码输入、诊断输出、IR 输出和字节码输出都能固定下来。后续可以把后端替换为 WebAssembly,或加入模块系统、泛型和更完整的运行时。
function compileSnapshot(source: string): string {
const result = compile(source);
return JSON.stringify({ diagnostics: result.diagnostics, bytecode: result.bytecode }, null, 2);
}
// MiniLang example:
// print(missingName);