1. 作用域链
每个块都可以创建 Scope,define() 在当前作用域记录 SymbolInfo,resolve() 沿父链查找名称。重复声明应该在 define 阶段报错,未定义变量应该在 resolve 失败时形成诊断。
type SymbolInfo = { name: string; type: ValueType; declaredAt: Position };
class Scope {
private symbols = new Map<string, SymbolInfo>();
constructor(private parent?: Scope) {}
define(symbol: SymbolInfo): void {
if (this.symbols.has(symbol.name)) throw new Error("重复声明");
this.symbols.set(symbol.name, symbol);
}
resolve(name: string): SymbolInfo | undefined {
return this.symbols.get(name) ?? this.parent?.resolve(name);
}
}
2. 块级名称
MiniLang 的块级作用域让局部变量只在花括号内可见。示例 { let local: number = 1; print(local); } 中 local 可以解析成功,但离开块以后再次访问就会触发未定义变量。
{ let local: number = 1; print(local); }