mod builtins;
mod expr;
mod law_auto;
mod pattern;
mod prelude;
pub(crate) mod recurrence;
mod sample_literal;
mod shared;
pub mod tactic_ir;
#[cfg(test)]
mod tests;
mod toplevel;
mod transpile;
mod types;
pub(crate) use expr::aver_name_to_lean;
pub(crate) use prelude::prelude_spec_lemmas_for_builtins;
pub use law_auto::residual_probe_body;
#[cfg(test)]
use prelude::generate_prelude;
use transpile::{LeanEmitMode, transpile_unified};
use std::collections::HashSet;
use crate::ast::{FnDef, Spanned};
use crate::codegen::{CodegenContext, ProjectOutput};
pub const LAW_CLASS_MARKER_PREFIX: &str = "-- aver:law-class ";
pub const LAW_CLASS_UNIVERSAL: &str = "universal";
pub const LAW_CLASS_BOUNDED_DOMAIN: &str = "bounded-domain";
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum VerifyEmitMode {
NativeDecide,
Sorry,
TheoremSkeleton,
}
pub use crate::codegen::recursion::{ProofModeIssue, RecursionPlan};
pub use toplevel::PROOF_FUEL_EXHAUSTED_MSG;
pub const LEAN_PANIC_LINE_MARKER: &str = "PANIC at ";
pub fn count_model_panic_lines(output: &str) -> usize {
output
.lines()
.filter(|l| l.contains(LEAN_PANIC_LINE_MARKER))
.count()
}
pub(crate) fn pure_fns(ctx: &CodegenContext) -> Vec<&FnDef> {
ctx.modules
.iter()
.flat_map(|m| m.fn_defs.iter())
.chain(ctx.fn_defs.iter())
.filter(|fd| toplevel::is_pure_fn(fd))
.collect()
}
pub(crate) fn recursive_type_names(ctx: &CodegenContext) -> HashSet<String> {
ctx.modules
.iter()
.flat_map(|m| m.type_defs.iter())
.chain(ctx.type_defs.iter())
.filter(|td| toplevel::is_recursive_type_def(td))
.map(|td| toplevel::type_def_name(td).to_string())
.collect()
}
pub(crate) fn recursive_pure_fn_names(ctx: &CodegenContext) -> HashSet<String> {
let symbols = &ctx.symbol_table;
let pure_ids: HashSet<crate::ir::FnId> = pure_fns(ctx)
.into_iter()
.filter_map(|fd| crate::codegen::common::fn_id_for_decl(ctx, fd))
.collect();
ctx.recursive_fns
.intersection(&pure_ids)
.map(|id| symbols.fn_entry(*id).key.name.clone())
.collect()
}
fn verify_counter_key(vb: &crate::ast::VerifyBlock) -> String {
crate::codegen::common::verify_block_counter_key(vb)
}
fn lean_project_name(ctx: &CodegenContext) -> String {
crate::codegen::common::entry_basename(ctx)
}
pub(super) fn bound_expr_to_lean(expr: &Spanned<crate::ir::hir::ResolvedExpr>) -> String {
use crate::ir::hir::{ResolvedCallee, ResolvedExpr};
match &expr.node {
ResolvedExpr::Literal(crate::ast::Literal::Int(n)) => format!("{}", n),
ResolvedExpr::Ident(name) | ResolvedExpr::Resolved { name, .. } => {
expr::aver_name_to_lean(name)
}
ResolvedExpr::Call(callee, args) => {
let dotted = match callee {
ResolvedCallee::Builtin(name) => Some(name.clone()),
_ => None,
};
if let Some(dotted) = dotted {
if dotted == "List.len" && args.len() == 1 {
return format!("{}.length", bound_expr_to_lean(&args[0]));
}
let lean_args: Vec<String> = args.iter().map(bound_expr_to_lean).collect();
format!(
"({} {})",
expr::aver_name_to_lean(&dotted),
lean_args.join(" ")
)
} else {
"0".to_string()
}
}
ResolvedExpr::Attr(obj, field) => format!(
"{}.{}",
bound_expr_to_lean(obj),
expr::aver_name_to_lean(field)
),
_ => "0".to_string(),
}
}
pub(crate) use crate::codegen::recursion::detect::sizeof_measure_param_indices;
pub fn proof_mode_findings(ctx: &CodegenContext) -> Vec<ProofModeIssue> {
ctx.proof_ir
.unclassified_fns
.iter()
.map(|uf| ProofModeIssue {
line: uf.line,
message: uf.message.clone(),
})
.collect()
}
pub fn proof_mode_issues(ctx: &CodegenContext) -> Vec<String> {
proof_mode_findings(ctx)
.into_iter()
.map(|issue| issue.message)
.collect()
}
pub fn transpile(ctx: &mut CodegenContext) -> ProjectOutput {
transpile_with_verify_mode(ctx, VerifyEmitMode::NativeDecide)
}
pub fn transpile_for_proof_mode(
ctx: &mut CodegenContext,
verify_mode: VerifyEmitMode,
) -> ProjectOutput {
transpile_unified(ctx, verify_mode, LeanEmitMode::Proof)
}
pub fn transpile_with_verify_mode(
ctx: &mut CodegenContext,
verify_mode: VerifyEmitMode,
) -> ProjectOutput {
transpile_unified(ctx, verify_mode, LeanEmitMode::Standard)
}