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 parser::parse_path;
27pub use project::{Project, SourceTree, SymbolInfo};
28
29pub use lutra_bin::{ir, rr};
30
31#[derive(Debug, Clone, Copy)]
32#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
33pub enum ProgramFormat {
34 SqlPg,
35 SqlDuckdb,
36 BytecodeLt,
37}
38
39pub fn compile(
40 project: &Project,
41 program: &str,
42 name_hint: Option<&str>,
43 format: ProgramFormat,
44) -> Result<(rr::Program, rr::ProgramType), error::Error> {
45 let program_pr = self::check::check_overlay(project, program, name_hint)?;
47
48 let program_ir = intermediate::lowerer::lower_expr(project, &program_pr);
50 tracing::debug!("ir:\n{}\n", lutra_bin::ir::print(&program_ir));
51
52 let program_ir = intermediate::inline(program_ir);
54 tracing::debug!("ir (inlined):\n{}\n", lutra_bin::ir::print(&program_ir));
55 let program_ir = intermediate::layouter::on_program(program_ir);
56
57 let program = match format {
59 ProgramFormat::SqlPg => rr::Program::SqlPostgres(Box::new(sql::compile_ir(
60 &program_ir,
61 sql::Dialect::Postgres,
62 ))),
63 ProgramFormat::SqlDuckdb => {
64 rr::Program::SqlDuckDB(Box::new(sql::compile_ir(&program_ir, sql::Dialect::DuckDB)))
65 }
66 ProgramFormat::BytecodeLt => {
67 rr::Program::BytecodeLt(bytecoding::compile_program(program_ir.clone()))
68 }
69 };
70
71 let ir_func_ty = program_ir.main.ty.kind.into_function().unwrap();
73 let ty = rr::ProgramType {
74 input: ir_func_ty.params.into_iter().next().unwrap(),
75 output: ir_func_ty.body,
76 defs: program_ir.defs,
77 };
78
79 Ok((program, ty))
80}
81
82pub fn project_to_types(project: &Project) -> ir::Module {
83 let module = intermediate::lowerer::lower_type_defs(project);
84
85 intermediate::layouter::on_root_module(module)
86}
87
88#[doc(hidden)]
91pub mod _lexer {
92 pub use crate::diagnostic::Diagnostic;
93 pub use crate::parser::{Token, TokenKind, lex_source_recovery as lex};
94}
95
96#[doc(hidden)]
99pub mod _bench {
100 pub use crate::check::{check_std_lib, parse_std_lib, std_lib};
101 pub use crate::diagnostic::Diagnostic;
102 pub use crate::parser::{parse_expr, parse_source};
103}
104
105#[track_caller]
106pub fn _test_compile_ty(ty_source: &str) -> ir::Ty {
107 let source = format!("type t: {ty_source}");
108
109 let source = SourceTree::single("".into(), source);
110 let project = check(source, Default::default()).unwrap_or_else(|e| panic!("{e}"));
111
112 let module = project_to_types(&project);
113
114 let item = module.decls.into_iter().next().unwrap();
115 assert_eq!(item.name, "t");
116 let ir::Decl::Type(mut ty) = item.decl else {
117 panic!()
118 };
119
120 ty.name = None;
121 ty
122}
123
124pub fn _test_compile_main(source: &str) -> Result<ir::Program, error::Error> {
125 let source = SourceTree::single("".into(), source.to_string());
126 let project = check(source, Default::default())?;
127 _test_compile_main_in(&project)
128}
129
130pub fn _test_compile_main_in(project: &Project) -> Result<ir::Program, error::Error> {
131 let main = check_overlay(project, "main", None)?;
132 let program = intermediate::lowerer::lower_expr(project, &main);
133 Ok(intermediate::layouter::on_program(program))
134}