| 695 | #[cfg(not(target_arch = "wasm32"))] |
| 696 | fn write_bytes_artifact(&self, subdir: &str, stem: &str, extension: &str, bytes: &[u8]) { |
| 697 | if !self.write_artifacts { |
| 698 | return; |
| 699 | } |
| 700 | let path = self |
| 701 | .artifact_root |
| 702 | .join(subdir) |
| 703 | .join(format!("{stem}{extension}")); |
| 704 | if let Some(parent) = path.parent() |
| 705 | && let Err(err) = fs::create_dir_all(parent) |
| 706 | { |
| 707 | log::warn!( |
| 708 | "failed to create artifact directory `{}`: {err}", |
| 709 | parent.display() |
| 710 | ); |
| 711 | return; |
| 712 | } |
| 713 | if let Err(err) = fs::write(&path, bytes) { |
| 714 | log::warn!("failed to write artifact `{}`: {err}", path.display()); |
| 715 | } |
| 716 | } |
| 717 | |
| 718 | #[cfg(target_arch = "wasm32")] |
| 719 | fn write_text_artifact(&self, _subdir: &str, _stem: &str, _extension: &str, _content: &str) {} |
| 720 | |
| 721 | #[cfg(target_arch = "wasm32")] |
| 722 | fn write_bytes_artifact(&self, _subdir: &str, _stem: &str, _extension: &str, _bytes: &[u8]) {} |
| 723 | |
| 724 | /// Source -> tokens -> AST -> IR, with mode-specific validation. |
| 725 | #[track_caller] |
| 726 | pub fn compile(&self, source: &str) -> Result<CompilationResult, CompilationError> { |
| 727 | log::info!("Starting compilation pipeline"); |
| 728 | |
| 729 | let resolved = self |
| 730 | .resolve_modules(source) |
| 731 | .map_err(CompilationError::DiagnosticErrors)?; |
| 732 | let compiler = HllCompiler::new(CompileConfig { |
| 733 | target: self.target_mode, |
| 734 | strict: self.run_semantic_analysis, |
| 735 | string_prefix: self.string_prefix.clone(), |
| 736 | type_prelude: self.type_prelude.clone(), |
| 737 | source_prelude: resolved.prelude, |
| 738 | module_aliases: resolved.aliases, |
| 739 | module_mangle_prefix: self |
| 740 | .mangle_modules |
| 741 | .then(|| self.current_module_prefix.clone()) |
| 742 | .flatten(), |
| 743 | source_file: self.config_source_file(), |
| 744 | }); |
| 745 | |
| 746 | let mut out = compiler |
| 747 | .compile(source) |
| 748 | .map_err(CompilationError::DiagnosticErrors)?; |
| 749 | optimize_ir(&mut out.ir, self.optimize); |
| 750 | |
| 751 | // Entry-point presence check for freestanding builds. |
| 752 | // Kernel mode skips this: `_kernel_start` is provided by the kernel stdlib, not user code. |
| 753 | if self.target_mode == TargetMode::Freestanding { |
| 754 | let entry = self.effective_entry_point(); |