87 lines
3.6 KiB
Rust
87 lines
3.6 KiB
Rust
//! # Compiler Orchestration
|
|
//!
|
|
//! This module provides the high-level API for triggering the compilation process.
|
|
//! It handles the transition between different compiler phases: Frontend -> IR -> Backend.
|
|
|
|
use crate::backend;
|
|
use crate::common::files::FileManager;
|
|
use crate::common::symbols::Symbol;
|
|
use crate::frontends::ts::TypescriptFrontend;
|
|
use crate::frontends::Frontend;
|
|
use crate::ir;
|
|
use anyhow::Result;
|
|
use std::path::Path;
|
|
|
|
/// The result of a successful compilation process.
|
|
/// It contains the final binary and the metadata needed for debugging.
|
|
pub struct CompilationUnit {
|
|
/// The raw binary data formatted as Prometeu ByteCode (PBC).
|
|
/// This is what gets written to a `.pbc` file.
|
|
pub rom: Vec<u8>,
|
|
|
|
/// The list of debug symbols discovered during compilation.
|
|
/// These are used to map bytecode offsets back to source code locations.
|
|
pub symbols: Vec<Symbol>,
|
|
}
|
|
|
|
impl CompilationUnit {
|
|
/// Writes the compilation results (PBC binary, disassembly, and symbols) to the disk.
|
|
///
|
|
/// # Arguments
|
|
/// * `out` - The base path for the output `.pbc` file.
|
|
/// * `emit_disasm` - If true, a `.disasm` file will be created next to the output.
|
|
/// * `emit_symbols` - If true, a `.json` symbols file will be created next to the output.
|
|
pub fn export(&self, out: &Path, emit_disasm: bool, emit_symbols: bool) -> Result<()> {
|
|
let artifacts = backend::artifacts::Artifacts::new(self.rom.clone(), self.symbols.clone());
|
|
artifacts.export(out, emit_disasm, emit_symbols)
|
|
}
|
|
}
|
|
|
|
/// Orchestrates the compilation of a Prometeu project starting from an entry file.
|
|
///
|
|
/// This function executes the full compiler pipeline:
|
|
/// 1. **Frontend**: Loads and parses the entry file (and its dependencies).
|
|
/// Currently, it uses the `TypescriptFrontend`.
|
|
/// 2. **IR Generation**: The frontend produces a high-level Intermediate Representation (IR).
|
|
/// 3. **Validation**: Checks the IR for consistency and VM compatibility.
|
|
/// 4. **Backend**: Lowers the IR into final Prometeu ByteCode.
|
|
///
|
|
/// # Errors
|
|
/// Returns an error if parsing fails, validation finds issues, or code generation fails.
|
|
///
|
|
/// # Example
|
|
/// ```no_run
|
|
/// use std::path::Path;
|
|
/// let entry = Path::new("src/main.ts");
|
|
/// let unit = prometeu_compiler::compiler::compile(entry).expect("Failed to compile");
|
|
/// unit.export(Path::new("build/program.pbc"), true, true).unwrap();
|
|
/// ```
|
|
pub fn compile(entry: &Path) -> Result<CompilationUnit> {
|
|
let mut file_manager = FileManager::new();
|
|
|
|
// 1. Select Frontend (Currently only TS is supported)
|
|
// The frontend is responsible for parsing source code and producing the IR.
|
|
let frontend = TypescriptFrontend;
|
|
|
|
// 2. Compile to IR (Intermediate Representation)
|
|
// This step abstracts away source-specific syntax (like TypeScript) into a
|
|
// generic set of instructions that the backend can understand.
|
|
let ir_module = frontend.compile_to_ir(entry, &mut file_manager)
|
|
.map_err(|bundle| anyhow::anyhow!("Compilation failed with {} errors", bundle.diagnostics.len()))?;
|
|
|
|
// 3. IR Validation
|
|
// Ensures the generated IR is sound and doesn't violate any VM constraints
|
|
// before we spend time generating bytecode.
|
|
ir::validate::validate_module(&ir_module)
|
|
.map_err(|bundle| anyhow::anyhow!("IR Validation failed: {:?}", bundle))?;
|
|
|
|
// 4. Emit Bytecode
|
|
// The backend takes the validated IR and produces the final binary executable.
|
|
let result = backend::emit_module(&ir_module, &file_manager)?;
|
|
|
|
Ok(CompilationUnit {
|
|
rom: result.rom,
|
|
symbols: result.symbols,
|
|
})
|
|
}
|