Compile HLL source -> assembly text, stripping inline comments so the assembly can be passed safely through a shell heredoc. Uses two-stage compilation: compile stdlib and user code independently, then assemble them into objects and link the objects before generating ELF.
(source: &str)
| 30 | { |
| 31 | let mut p = CompilationPipeline::new(); |
| 32 | p.set_string_prefix(Some(format!("std{i}_str_"))); |
| 33 | p.set_type_prelude(get_stdlib_type_prelude()); |
| 34 | let r = p |
| 35 | .compile(src) |
| 36 | .unwrap_or_else(|e| panic!("stdlib compilation failed: {e}")); |
| 37 | let (asm, _) = p.compile_ir_to_assembly_with_tokens(&r.ir_program); |
| 38 | stdlib_asm.push_str(&asm); |
| 39 | stdlib_asm.push('\n'); |
| 40 | } |
| 41 | |
| 42 | // Stage 2: Compile user code |
| 43 | let user_pipeline = CompilationPipeline::new(); |
| 44 | let user_result = user_pipeline |
| 45 | .compile(source) |
| 46 | .unwrap_or_else(|e| panic!("HLL compilation failed: {e}")); |
| 47 | let (user_asm, _) = user_pipeline.compile_ir_to_assembly_with_tokens(&user_result.ir_program); |
| 48 | |
| 49 | let combined = format!("{}\n{}", stdlib_asm, user_asm); |
| 50 | strip_comments(&combined) |
| 51 | } |
| 52 | |
| 53 | fn strip_comments(asm: &str) -> String { |
| 54 | asm.lines() |
| 55 | .map(|line| line.split(';').next().unwrap_or("").trim_end()) |
| 56 | .filter(|line| !line.is_empty()) |
| 57 | .collect::<Vec<_>>() |
| 58 | .join("\n") |
| 59 | } |
| 60 | |
| 61 | struct QemuResult { |
| 62 | exit_code: i32, |
| 63 | /// Everything the program wrote to stdout (after stripping our sentinel). |