1mod bytecoding;
2mod check;
3mod diagnostic;
4mod discover;
5mod format;
6mod intermediate;
7mod parser;
8mod project;
9mod resolver;
10mod sql;
11mod utils;
12
13type Result<T, E = diagnostic::Diagnostic> = core::result::Result<T, E>;
14
15pub mod codespan;
16pub mod error;
17pub mod pr;
18pub mod printer;
19
20pub use bytecoding::compile_program as bytecode_program;
21pub use check::{CheckParams, check, check_overlay};
22pub use codespan::Span;
23pub use discover::{DiscoverParams, discover};
24pub use format::format;
25pub use intermediate::inline;
26pub use lutra_bin::{ir, rr};
27pub use project::{Project, SourceTree};
28
29#[derive(Debug, Clone, Copy)]
30#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
31pub enum ProgramFormat {
32 SqlPg,
33 SqlDuckdb,
34 BytecodeLt,
35}
36
37pub fn compile(
38 project: &Project,
39 program: &str,
40 name_hint: Option<&str>,
41 format: ProgramFormat,
42) -> Result<(rr::Program, rr::ProgramType), error::Error> {
43 let program_pr = self::check::check_overlay(project, program, name_hint)?;
45
46 let program_ir = intermediate::lowerer::lower_expr(project, &program_pr);
48 tracing::debug!("ir:\n{}\n", lutra_bin::ir::print(&program_ir));
49
50 let program_ir = intermediate::inline(program_ir);
52 tracing::debug!("ir (inlined):\n{}\n", lutra_bin::ir::print(&program_ir));
53 let program_ir = intermediate::layouter::on_program(program_ir);
54
55 let program = match format {
57 ProgramFormat::SqlPg => rr::Program::SqlPostgres(Box::new(sql::compile_ir(
58 &program_ir,
59 sql::Dialect::Postgres,
60 ))),
61 ProgramFormat::SqlDuckdb => {
62 rr::Program::SqlDuckDB(Box::new(sql::compile_ir(&program_ir, sql::Dialect::DuckDB)))
63 }
64 ProgramFormat::BytecodeLt => {
65 rr::Program::BytecodeLt(bytecoding::compile_program(program_ir.clone()))
66 }
67 };
68
69 let ir_func_ty = program_ir.main.ty.kind.into_function().unwrap();
71 let ty = rr::ProgramType {
72 input: ir_func_ty.params.into_iter().next().unwrap(),
73 output: ir_func_ty.body,
74 defs: program_ir.defs,
75 };
76
77 Ok((program, ty))
78}
79
80pub fn project_to_types(project: &Project) -> ir::Module {
81 let module = intermediate::lowerer::lower_type_defs(project);
82
83 intermediate::layouter::on_root_module(module)
84}
85
86pub mod _lexer {
89 pub use crate::diagnostic::Diagnostic;
90 pub use crate::parser::lexer::{Token, TokenKind};
91
92 pub use crate::parser::lexer::lex_source_recovery as lex;
93}
94
95#[track_caller]
96pub fn _test_compile_ty(ty_source: &str) -> ir::Ty {
97 let source = format!("type t: {ty_source}");
98
99 let source = SourceTree::single("".into(), source);
100 let project = check(source, CheckParams {}).unwrap_or_else(|e| panic!("{e}"));
101
102 let module = project_to_types(&project);
103
104 let item = module.decls.into_iter().next().unwrap();
105 assert_eq!(item.name, "t");
106 let ir::Decl::Type(mut ty) = item.decl else {
107 panic!()
108 };
109
110 ty.name = None;
111 ty
112}
113
114pub fn _test_compile_main(source: &str) -> Result<ir::Program, error::Error> {
115 let source = SourceTree::single("".into(), source.to_string());
116 let project = check(source, CheckParams {})?;
117
118 let main = check_overlay(&project, "main", None)?;
119 let program = intermediate::lowerer::lower_expr(&project, &main);
120 Ok(intermediate::layouter::on_program(program))
121}