57 lines
1.8 KiB
Rust
57 lines
1.8 KiB
Rust
//! 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;
|
|
mod codegen;
|
|
|
|
pub use analysis::{NameBinding, NameUse, Scope, ScopeKind, SymbolTable, analyze};
|
|
pub use codegen::CompiledCode;
|
|
|
|
use frontend::ast::{AstDocument, AstRoot};
|
|
use frontend::{Diagnostic, DiagnosticKind, ParseMode, SourceDiagnostic, SourceUnit, Span};
|
|
|
|
/// 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 {
|
|
pub globals: Vec<String>,
|
|
}
|
|
|
|
pub fn compile_source(
|
|
source: &SourceUnit,
|
|
mode: ParseMode,
|
|
options: &CompileOptions,
|
|
) -> Result<CompiledCode, SourceDiagnostic> {
|
|
let root = frontend::parse_source_ast(source, mode)?;
|
|
compile_ast(&root, source, options).map_err(|error| source.annotate(error))
|
|
}
|
|
|
|
/// 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<CompiledCode, Diagnostic> {
|
|
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)?;
|
|
codegen::generate(root, source, &symbols)
|
|
}
|
|
|
|
fn diagnostic(kind: DiagnosticKind, span: Span, message: impl Into<String>) -> Diagnostic {
|
|
Diagnostic {
|
|
kind,
|
|
span,
|
|
message: message.into(),
|
|
expected: Vec::new(),
|
|
}
|
|
}
|