//! 宿主与集成测试使用的源码编译门面:输出不依赖 VM 堆的模板,显式加载后才得到代码对象。 //! Minimal source-to-wordcode compiler. Analysis and emission do not allocate //! VM objects; a compiled unit can be loaded into independent VMs explicitly. // 名称分析决定局部槽与全局名字表,供下一个字节码生成阶段使用。 mod analysis; // 生成可跨 VM 复用的代码模板;仅显式 load 时才分配目标 VM 的对象。 mod codegen; // 对宿主和测试公开名称解析结果,便于检查绑定与源码位置。 pub use analysis::{NameBinding, NameUse, Scope, ScopeKind, SymbolTable, analyze}; // 宿主取得模板后负责选择 VM 并调用 CompiledCode::load。 pub use codegen::CompiledCode; use frontend::ast::{AstDocument, AstRoot}; use frontend::{Diagnostic, DiagnosticKind, ParseMode, SourceDiagnostic, SourceUnit, Span}; /// 宿主通过 compile_source/compile_ast 提供的编译选项;名称分析据此允许访问宿主全局或内置名。 /// 这里只声明名称,宿主仍需在执行前向 VM 的环境字典提供实际值。 /// Names supplied by the host's globals or builtins dictionary. These are /// compile-time declarations only; loading code never injects their values. #[derive(Debug, Clone, Default)] pub struct CompileOptions { // 编译期已知名称列表;analyze 与源码声明共同解析可用的全局名,不在此持有 VM 值。 pub globals: Vec, } /// 宿主及 compiler 集成测试的源码编译入口:按指定模式解析,再校验 AST、解析名称并生成模板。 /// source 提供文件身份与原始文本;mode 决定模块、表达式或交互根;options 声明额外宿主名称。 /// 解析错误已有源码诊断;后续编译错误在这里附加同一源码的来源和行列位置,成功不执行任何 VM 指令。 pub fn compile_source( source: &SourceUnit, mode: ParseMode, options: &CompileOptions, ) -> Result { // 前端根据模式返回对应 AstRoot,解析失败立即把带源码信息的错误传给宿主。 let root = frontend::parse_source_ast(source, mode)?; // AST 入口返回不含源码快照的 Diagnostic;在此统一补上 SourceUnit 上下文。 compile_ast(&root, source, options).map_err(|error| source.annotate(error)) } /// compile_source 及已有 AST 的宿主/测试调用;先验证结构与跨度,再分析名称,最后输出代码模板。 /// 传入 source 必须是期望匹配的位置快照;跨度有效只说明位置在范围内,不能证明 AST 与文本语义相同。 /// Compile an AST against its original source snapshot. Span validation does /// not prove the AST's semantic equivalence to the supplied text. pub fn compile_ast( root: &AstRoot, source: &SourceUnit, options: &CompileOptions, ) -> Result { // 包装并校验 AST 文档结构,再检查节点跨度对当前 source 文本是否有效;不修改调用方的树。 AstDocument::new(root.clone()) .and_then(|document| document.validate_source(source.text())) // 文档结构/跨度验证错误归入编译错误,尚无可靠单一节点位置,使用默认跨度。 .map_err(|error| { diagnostic( DiagnosticKind::Compilation, Span::default(), error.to_string(), ) })?; // 收集并解析所有作用域的绑定及代码布局;错误会阻止生成阶段继续。 let symbols = analyze(root, options)?; // 生成器按解析后的槽/名字索引编码,不在此加载模板或分配 VM 堆对象。 codegen::generate(root, source, &symbols) } /// 本模块的 AST 验证及 analysis/codegen 的错误辅助函数共用,统一构造不带源码快照的诊断。 /// kind 区分语义/编译错误,span 标记位置,message 接受可转 String 的说明;语法期望项留空。 fn diagnostic(kind: DiagnosticKind, span: Span, message: impl Into) -> Diagnostic { // 编译器错误没有解析器的“期望 token”列表,源码上下文由上层 compile_source 统一附加。 Diagnostic { kind, span, message: message.into(), expected: Vec::new(), } }