1pub mod ast;
6pub mod builtins;
7pub mod codegen;
8pub mod parser;
9pub mod resolver;
10pub mod typechecker;
11pub mod types;
12pub mod unification;
13
14pub use ast::Program;
15pub use codegen::CodeGen;
16pub use parser::Parser;
17pub use resolver::{Resolver, check_collisions, find_stdlib};
18pub use typechecker::TypeChecker;
19pub use types::{Effect, StackType, Type};
20
21use std::fs;
22use std::path::Path;
23use std::process::Command;
24
25pub fn compile_file(source_path: &Path, output_path: &Path, keep_ir: bool) -> Result<(), String> {
27 let source = fs::read_to_string(source_path)
29 .map_err(|e| format!("Failed to read source file: {}", e))?;
30
31 let mut parser = Parser::new(&source);
33 let program = parser.parse()?;
34
35 let program = if !program.includes.is_empty() {
37 let stdlib_path = find_stdlib()?;
38 let mut resolver = Resolver::new(stdlib_path);
39 resolver.resolve(source_path, program)?
40 } else {
41 program
42 };
43
44 check_collisions(&program.words)?;
46
47 if program.find_word("main").is_none() {
49 return Err("No main word defined".to_string());
50 }
51
52 program.validate_word_calls()?;
54
55 let mut type_checker = TypeChecker::new();
57 type_checker.check_program(&program)?;
58
59 let quotation_types = type_checker.take_quotation_types();
61
62 let mut codegen = CodeGen::new();
64 let ir = codegen.codegen_program(&program, quotation_types)?;
65
66 let ir_path = output_path.with_extension("ll");
68 fs::write(&ir_path, ir).map_err(|e| format!("Failed to write IR file: {}", e))?;
69
70 let runtime_lib = Path::new("target/release/libseq_runtime.a");
72 if !runtime_lib.exists() {
73 return Err(format!(
74 "Runtime library not found at {}. \
75 Please run 'cargo build --release -p seq-runtime' first.",
76 runtime_lib.display()
77 ));
78 }
79
80 let output = Command::new("clang")
82 .arg(&ir_path)
83 .arg("-o")
84 .arg(output_path)
85 .arg("-L")
86 .arg("target/release")
87 .arg("-lseq_runtime")
88 .output()
89 .map_err(|e| format!("Failed to run clang: {}", e))?;
90
91 if !output.status.success() {
92 let stderr = String::from_utf8_lossy(&output.stderr);
93 return Err(format!("Clang compilation failed:\n{}", stderr));
94 }
95
96 if !keep_ir {
98 fs::remove_file(&ir_path).ok();
99 }
100
101 Ok(())
102}
103
104pub fn compile_to_ir(source: &str) -> Result<String, String> {
106 let mut parser = Parser::new(source);
107 let program = parser.parse()?;
108
109 program.validate_word_calls()?;
110
111 let mut type_checker = TypeChecker::new();
112 type_checker.check_program(&program)?;
113
114 let quotation_types = type_checker.take_quotation_types();
115
116 let mut codegen = CodeGen::new();
117 codegen.codegen_program(&program, quotation_types)
118}