onion_frontend/
compile.rs1use std::collections::HashMap;
23use std::fs;
24use std::path::PathBuf;
25use std::sync::Arc;
26use std::sync::RwLock;
27
28use crate::diagnostics::Diagnostic;
29use crate::diagnostics::collector::DiagnosticCollector;
30use crate::ir_generator::ir_generator;
31use crate::parser::Source;
32use crate::parser::analyzer::analyze_ast;
33use crate::parser::analyzer::auto_capture_and_rebuild;
34use crate::parser::ast::ast_token_stream;
35use crate::parser::ast::build_ast;
36use crate::parser::comptime::solver::ComptimeSolver;
37use crate::parser::lexer::tokenizer;
38use crate::utils::cycle_detector::CycleDetector;
39use onion_vm::types::lambda::vm_instructions::instruction_set::VMInstructionPackage;
40use onion_vm::types::lambda::vm_instructions::ir::DebugInfo;
41use onion_vm::types::lambda::vm_instructions::ir::Functions;
42use onion_vm::types::lambda::vm_instructions::ir::IR;
43use onion_vm::types::lambda::vm_instructions::ir::IRPackage;
44use onion_vm::types::lambda::vm_instructions::ir_translator::IRTranslator;
45
46#[derive(Debug, Clone)]
50pub enum CompileDiagnostic {
51 IOError(String),
53 BorrowError(String),
55}
56
57impl Diagnostic for CompileDiagnostic {
58 fn severity(&self) -> crate::diagnostics::ReportSeverity {
59 match self {
60 CompileDiagnostic::IOError(_) => crate::diagnostics::ReportSeverity::Error,
61 CompileDiagnostic::BorrowError(_) => crate::diagnostics::ReportSeverity::Error,
62 }
63 }
64
65 fn title(&self) -> String {
66 "Compile Error".to_string()
67 }
68
69 fn message(&self) -> String {
70 match self {
71 CompileDiagnostic::IOError(msg) => format!("I/O Error: {}", msg),
72 CompileDiagnostic::BorrowError(msg) => format!("Borrow Error: {}", msg),
73 }
74 }
75
76 fn location(&self) -> Option<crate::diagnostics::SourceLocation> {
77 None
78 }
79
80 fn help(&self) -> Option<String> {
81 None
82 }
83
84 fn copy(&self) -> Box<dyn Diagnostic> {
85 Box::new(self.clone())
86 }
87}
88
89pub fn build_code(collector: &mut DiagnosticCollector, source: &Source) -> Result<IRPackage, ()> {
112 let tokens = tokenizer::tokenize(&source);
113 let tokens = tokenizer::reject_comment(&tokens);
114 let gathered = ast_token_stream::from_stream(&tokens);
115 let ast = build_ast(collector, gathered)?;
116
117 let no_path = PathBuf::from(".");
119 let import_cycle_detector = CycleDetector::new()
120 .enter(
121 fs::canonicalize(source.file_path().unwrap_or(&no_path))
122 .map_err(|e| collector.report(CompileDiagnostic::IOError(e.to_string())))?,
123 )
124 .expect("unreachable!");
125 let mut comptime_solver =
126 ComptimeSolver::new(Arc::new(RwLock::new(HashMap::new())), import_cycle_detector);
127 let solve_result = comptime_solver.solve(&ast);
128 match comptime_solver.diagnostics().read() {
129 Ok(diagnostics) => {
130 for diag in diagnostics.diagnostics() {
131 collector.report(diag.copy());
132 }
133 }
134 Err(_) => {
135 return collector.fatal(CompileDiagnostic::BorrowError(
136 "Failed to read diagnostics".to_string(),
137 ));
138 }
139 }
140
141 let ast = solve_result?;
142
143 let (_required_vars, ast) = auto_capture_and_rebuild(&ast);
144
145 let _analyze_result = analyze_ast(&ast, collector, &None)?;
146
147 let namespace = ir_generator::NameSpace::new("Main".to_string(), None);
148 let mut functions = Functions::new();
149 let mut ir_generator = ir_generator::IRGenerator::new(&mut functions, namespace);
150
151 let ir = ir_generator.generate(collector, &ast)?;
152
153 let mut ir = ir;
154 ir.push((DebugInfo::new((0, 0)), IR::Return));
155 functions.append("__main__".to_string(), ir);
156
157 Ok(functions.build_instructions(Some(source.content_str())))
158}
159
160pub fn compile_to_bytecode(package: &IRPackage) -> Result<VMInstructionPackage, String> {
171 let mut translator = IRTranslator::new(package);
172 match translator.translate() {
173 Ok(_) => Ok(translator.get_result()),
174 Err(e) => Err(format!("IR translation failed: {:?}", e)),
175 }
176}