mod bytecoding;
mod check;
mod diagnostic;
mod discover;
mod format;
mod intermediate;
mod parser;
mod project;
mod resolver;
mod sql;
mod utils;
type Result<T, E = diagnostic::Diagnostic> = core::result::Result<T, E>;
pub mod codespan;
pub mod error;
pub mod pr;
pub mod printer;
pub use bytecoding::compile_program as bytecode_program;
pub use check::{CheckParams, check, check_overlay};
pub use codespan::Span;
pub use discover::{DiscoverParams, discover};
pub use format::format;
pub use intermediate::inline;
pub use parser::parse_path;
pub use project::{Project, SourceTree, SymbolInfo};
pub use lutra_bin::{ir, rr};
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
pub enum ProgramFormat {
SqlPg,
SqlDuckdb,
BytecodeLt,
}
pub fn compile(
project: &Project,
program: &str,
name_hint: Option<&str>,
format: ProgramFormat,
) -> Result<(rr::Program, rr::ProgramType), error::Error> {
let program_pr = self::check::check_overlay(project, program, name_hint)?;
let program_ir = intermediate::lowerer::lower_expr(project, &program_pr);
tracing::debug!("ir:\n{}\n", lutra_bin::ir::print(&program_ir));
let program_ir = intermediate::inline(program_ir);
tracing::debug!("ir (inlined):\n{}\n", lutra_bin::ir::print(&program_ir));
let program_ir = intermediate::layouter::on_program(program_ir);
let program = match format {
ProgramFormat::SqlPg => rr::Program::SqlPostgres(Box::new(sql::compile_ir(
&program_ir,
sql::Dialect::Postgres,
))),
ProgramFormat::SqlDuckdb => {
rr::Program::SqlDuckDB(Box::new(sql::compile_ir(&program_ir, sql::Dialect::DuckDB)))
}
ProgramFormat::BytecodeLt => {
rr::Program::BytecodeLt(bytecoding::compile_program(program_ir.clone()))
}
};
let ir_func_ty = program_ir.main.ty.kind.into_function().unwrap();
let ty = rr::ProgramType {
input: ir_func_ty.params.into_iter().next().unwrap(),
output: ir_func_ty.body,
defs: program_ir.defs,
};
Ok((program, ty))
}
pub fn project_to_types(project: &Project) -> ir::Module {
let module = intermediate::lowerer::lower_type_defs(project);
intermediate::layouter::on_root_module(module)
}
#[doc(hidden)]
pub mod _lexer {
pub use crate::diagnostic::Diagnostic;
pub use crate::parser::{Token, TokenKind, lex_source_recovery as lex};
}
#[doc(hidden)]
pub mod _bench {
pub use crate::check::{check_std_lib, parse_std_lib, std_lib};
pub use crate::diagnostic::Diagnostic;
pub use crate::parser::{parse_expr, parse_source};
}
#[track_caller]
pub fn _test_compile_ty(ty_source: &str) -> ir::Ty {
let source = format!("type t: {ty_source}");
let source = SourceTree::single("".into(), source);
let project = check(source, Default::default()).unwrap_or_else(|e| panic!("{e}"));
let module = project_to_types(&project);
let item = module.decls.into_iter().next().unwrap();
assert_eq!(item.name, "t");
let ir::Decl::Type(mut ty) = item.decl else {
panic!()
};
ty.name = None;
ty
}
pub fn _test_compile_main(source: &str) -> Result<ir::Program, error::Error> {
let source = SourceTree::single("".into(), source.to_string());
let project = check(source, Default::default())?;
_test_compile_main_in(&project)
}
pub fn _test_compile_main_in(project: &Project) -> Result<ir::Program, error::Error> {
let main = check_overlay(project, "main", None)?;
let program = intermediate::lowerer::lower_expr(project, &main);
Ok(intermediate::layouter::on_program(program))
}