Skip to main content

oxilean_codegen/idris_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5/// A `data` declaration in Idris 2.
6#[derive(Debug, Clone, PartialEq)]
7pub struct IdrisData {
8    /// Type name.
9    pub name: String,
10    /// Type parameters: `(a : Type)`, `(n : Nat)`.
11    pub params: Vec<(String, IdrisType)>,
12    /// The kind of this type (usually `Type`).
13    pub kind: IdrisType,
14    /// Constructors.
15    pub constructors: Vec<IdrisConstructor>,
16    /// Visibility.
17    pub visibility: Visibility,
18    /// Optional doc comment.
19    pub doc: Option<String>,
20}
21impl IdrisData {
22    /// Emit this data declaration.
23    pub fn emit(&self, indent: usize) -> String {
24        let pad = " ".repeat(indent);
25        let mut out = String::new();
26        if let Some(doc) = &self.doc {
27            for line in doc.lines() {
28                out.push_str(&format!("{}||| {}\n", pad, line));
29            }
30        }
31        let params_str: String = self
32            .params
33            .iter()
34            .map(|(n, t)| format!(" ({} : {})", n, t))
35            .collect();
36        out.push_str(&format!(
37            "{}{}data {}{} : {} where\n",
38            pad, self.visibility, self.name, params_str, self.kind
39        ));
40        for ctor in &self.constructors {
41            if let Some(doc) = &ctor.doc {
42                out.push_str(&format!("{}  ||| {}\n", pad, doc));
43            }
44            out.push_str(&format!("{}  {} : {}\n", pad, ctor.name, ctor.ty));
45        }
46        out
47    }
48}
49/// A `record` declaration in Idris 2.
50#[derive(Debug, Clone, PartialEq)]
51pub struct IdrisRecord {
52    /// Record name.
53    pub name: String,
54    /// Type parameters.
55    pub params: Vec<(String, IdrisType)>,
56    /// The kind (usually `Type`).
57    pub kind: IdrisType,
58    /// Constructor name (e.g. `MkPoint`).
59    pub constructor: String,
60    /// Fields: `(name, type)`.
61    pub fields: Vec<(String, IdrisType)>,
62    /// Visibility.
63    pub visibility: Visibility,
64    /// Optional doc comment.
65    pub doc: Option<String>,
66}
67impl IdrisRecord {
68    /// Emit this record declaration.
69    pub fn emit(&self, indent: usize) -> String {
70        let pad = " ".repeat(indent);
71        let mut out = String::new();
72        if let Some(doc) = &self.doc {
73            for line in doc.lines() {
74                out.push_str(&format!("{}||| {}\n", pad, line));
75            }
76        }
77        let params_str: String = self
78            .params
79            .iter()
80            .map(|(n, t)| format!(" ({} : {})", n, t))
81            .collect();
82        out.push_str(&format!(
83            "{}{}record {}{} : {} where\n",
84            pad, self.visibility, self.name, params_str, self.kind
85        ));
86        out.push_str(&format!("{}  constructor {}\n", pad, self.constructor));
87        for (fname, ftype) in &self.fields {
88            out.push_str(&format!("{}  {} : {}\n", pad, fname, ftype));
89        }
90        out
91    }
92}
93/// An Idris 2 `namespace` block.
94#[derive(Debug, Clone)]
95#[allow(dead_code)]
96pub struct IdrisNamespaceBlock {
97    /// Namespace name.
98    pub name: String,
99    /// Declarations in this namespace.
100    pub decls: Vec<IdrisDecl>,
101}
102impl IdrisNamespaceBlock {
103    /// Create a new namespace block.
104    #[allow(dead_code)]
105    pub fn new(name: impl Into<String>) -> Self {
106        IdrisNamespaceBlock {
107            name: name.into(),
108            decls: Vec::new(),
109        }
110    }
111    /// Add a declaration.
112    #[allow(dead_code)]
113    pub fn add(&mut self, decl: IdrisDecl) {
114        self.decls.push(decl);
115    }
116    /// Emit the namespace block.
117    #[allow(dead_code)]
118    pub fn emit(&self, backend: &IdrisBackend) -> String {
119        let mut out = format!("namespace {}\n", self.name);
120        for decl in &self.decls {
121            for line in backend.emit_decl(decl).lines() {
122                out.push_str("    ");
123                out.push_str(line);
124                out.push('\n');
125            }
126        }
127        out
128    }
129}
130/// A tactic in an Idris 2 proof script.
131#[derive(Debug, Clone)]
132#[allow(dead_code)]
133pub enum IdrisTactic {
134    /// `intro x` — introduce a variable.
135    Intro(String),
136    /// `intros` — introduce all variables.
137    Intros,
138    /// `exact e` — close goal with exact term.
139    Exact(IdrisExpr),
140    /// `refl` — close reflexivity goal.
141    Refl,
142    /// `trivial` — close trivial goal.
143    Trivial,
144    /// `decide` — close decidable goal.
145    Decide,
146    /// `rewrite h` — rewrite using equality.
147    Rewrite(String),
148    /// `rewrite <- h` — rewrite backwards.
149    RewriteBack(String),
150    /// `apply f` — apply a function.
151    Apply(String),
152    /// `cases x` — case split on x.
153    Cases(String),
154    /// `induction x` — do induction on x.
155    Induction(String),
156    /// `search` — auto-search for a term.
157    Search,
158    /// `auto` — auto-search.
159    Auto,
160    /// `with e` — with view pattern.
161    With(String),
162    /// `let x = e` — introduce local definition.
163    Let(String, IdrisExpr),
164    /// `have x : T by tac` — prove an intermediate.
165    Have(String, IdrisType),
166    /// `focus n` — focus on sub-goal n.
167    Focus(usize),
168    /// `claim n t` — claim sub-goal.
169    Claim(String, IdrisType),
170    /// `unfold n` — unfold a definition.
171    Unfold(String),
172    /// `compute` — reduce to normal form.
173    Compute,
174    /// `normals` — normalize.
175    Normals,
176    /// `fail msg` — fail with message.
177    Fail(String),
178    /// Sequence of tactics.
179    Seq(Vec<IdrisTactic>),
180}
181/// A top-level Idris 2 function definition.
182#[derive(Debug, Clone, PartialEq)]
183pub struct IdrisFunction {
184    /// Function name.
185    pub name: String,
186    /// Type signature (the full type).
187    pub type_sig: IdrisType,
188    /// Function clauses: `(patterns, rhs)`.
189    pub clauses: Vec<(Vec<IdrisPattern>, IdrisExpr)>,
190    /// Totality annotation.
191    pub totality: Totality,
192    /// Visibility.
193    pub visibility: Visibility,
194    /// Optional `%inline` or other pragmas.
195    pub pragmas: Vec<String>,
196    /// Optional doc comment.
197    pub doc: Option<String>,
198}
199impl IdrisFunction {
200    /// Create a new function with a single clause.
201    pub fn new(name: impl Into<String>, ty: IdrisType, body: IdrisExpr) -> Self {
202        IdrisFunction {
203            name: name.into(),
204            type_sig: ty,
205            clauses: vec![(vec![], body)],
206            totality: Totality::Default,
207            visibility: Visibility::Default,
208            pragmas: vec![],
209            doc: None,
210        }
211    }
212    /// Create a function with multiple clauses.
213    pub fn with_clauses(
214        name: impl Into<String>,
215        ty: IdrisType,
216        clauses: Vec<(Vec<IdrisPattern>, IdrisExpr)>,
217    ) -> Self {
218        IdrisFunction {
219            name: name.into(),
220            type_sig: ty,
221            clauses,
222            totality: Totality::Default,
223            visibility: Visibility::Default,
224            pragmas: vec![],
225            doc: None,
226        }
227    }
228    /// Emit this function definition.
229    pub fn emit(&self, indent: usize) -> String {
230        let pad = " ".repeat(indent);
231        let mut out = String::new();
232        if let Some(doc) = &self.doc {
233            for line in doc.lines() {
234                out.push_str(&format!("{}||| {}\n", pad, line));
235            }
236        }
237        for pragma in &self.pragmas {
238            out.push_str(&format!("{}%{}\n", pad, pragma));
239        }
240        let tot = format!("{}", self.totality);
241        if !tot.is_empty() {
242            out.push_str(&format!("{}{}", pad, tot));
243        }
244        out.push_str(&format!(
245            "{}{}{} : {}\n",
246            pad, self.visibility, self.name, self.type_sig
247        ));
248        for (pats, rhs) in &self.clauses {
249            if pats.is_empty() {
250                out.push_str(&format!("{}{} = {}\n", pad, self.name, rhs));
251            } else {
252                let pat_str = pats
253                    .iter()
254                    .map(|p| format!("{}", p))
255                    .collect::<Vec<_>>()
256                    .join(" ");
257                out.push_str(&format!("{}{} {} = {}\n", pad, self.name, pat_str, rhs));
258            }
259        }
260        out
261    }
262}
263/// An import directive in an Idris 2 module.
264#[derive(Debug, Clone, PartialEq)]
265pub struct IdrisImport {
266    /// Module path, e.g. `["Data", "List"]`.
267    pub path: Vec<String>,
268    /// Optional `as` alias.
269    pub alias: Option<String>,
270    /// Whether this is a `public import`.
271    pub public: bool,
272}
273impl IdrisImport {
274    /// Create a simple import.
275    pub fn new(path: Vec<String>) -> Self {
276        IdrisImport {
277            path,
278            alias: None,
279            public: false,
280        }
281    }
282    /// Create a public import.
283    pub fn public_import(path: Vec<String>) -> Self {
284        IdrisImport {
285            path,
286            alias: None,
287            public: true,
288        }
289    }
290    /// Emit this import directive.
291    pub fn emit(&self) -> String {
292        let path_str = self.path.join(".");
293        let prefix = if self.public {
294            "public import "
295        } else {
296            "import "
297        };
298        if let Some(alias) = &self.alias {
299            format!("{}{} as {}", prefix, path_str, alias)
300        } else {
301            format!("{}{}", prefix, path_str)
302        }
303    }
304}
305/// Fluent helper for building Idris 2 patterns.
306#[allow(dead_code)]
307pub struct IdrisPatternBuilder;
308impl IdrisPatternBuilder {
309    /// Build a constructor pattern `Con p1 p2 p3`.
310    #[allow(dead_code)]
311    pub fn con(name: impl Into<String>, args: Vec<IdrisPattern>) -> IdrisPattern {
312        IdrisPattern::Con(name.into(), args)
313    }
314    /// Build a variable binding pattern.
315    #[allow(dead_code)]
316    pub fn var(name: impl Into<String>) -> IdrisPattern {
317        IdrisPattern::Var(name.into())
318    }
319    /// Build a wildcard pattern `_`.
320    #[allow(dead_code)]
321    pub fn wildcard() -> IdrisPattern {
322        IdrisPattern::Wildcard
323    }
324    /// Build a literal pattern.
325    #[allow(dead_code)]
326    pub fn lit(l: IdrisLiteral) -> IdrisPattern {
327        IdrisPattern::Lit(l)
328    }
329    /// Build a tuple pattern `(p1, p2)`.
330    #[allow(dead_code)]
331    pub fn tuple(pats: Vec<IdrisPattern>) -> IdrisPattern {
332        IdrisPattern::Tuple(pats)
333    }
334    /// Build an `as` pattern `pat@name`.
335    #[allow(dead_code)]
336    pub fn as_pat(name: impl Into<String>, pat: IdrisPattern) -> IdrisPattern {
337        IdrisPattern::As(name.into(), Box::new(pat))
338    }
339}
340/// A type in Idris 2's type theory.
341#[derive(Debug, Clone, PartialEq)]
342pub enum IdrisType {
343    /// `Type` — the type of types (universe).
344    Type,
345    /// `Integer` — arbitrary-precision integer.
346    Integer,
347    /// `Nat` — natural number.
348    Nat,
349    /// `Bool` — boolean.
350    Bool,
351    /// `String` — text string.
352    String,
353    /// `Char` — unicode character.
354    Char,
355    /// `Double` — 64-bit floating-point.
356    Double,
357    /// `List a` — list type.
358    List(Box<IdrisType>),
359    /// `Vect n a` — length-indexed vector.
360    Vect(Box<IdrisExpr>, Box<IdrisType>),
361    /// `(a, b)` — pair / product type.
362    Pair(Box<IdrisType>, Box<IdrisType>),
363    /// `()` / `Unit` — unit type.
364    Unit,
365    /// `a -> b` — function type (unrestricted arrow).
366    Function(Box<IdrisType>, Box<IdrisType>),
367    /// `(1 x : a) -> b` — linear function type.
368    Linear(Box<IdrisType>, Box<IdrisType>),
369    /// `(0 x : a) -> b` — erased argument function.
370    Erased(Box<IdrisType>, Box<IdrisType>),
371    /// `(x : a) -> b x` — dependent function type (Pi).
372    Pi(String, Box<IdrisType>, Box<IdrisType>),
373    /// A named data type reference, e.g. `MyType`, `Maybe Int`.
374    Data(String, Vec<IdrisType>),
375    /// An interface constraint, e.g. `Eq a => ...`
376    Interface(String, Vec<IdrisType>),
377    /// A type variable (used in polymorphic types).
378    Var(String),
379    /// `IO a` — IO action type.
380    IO(Box<IdrisType>),
381    /// `Maybe a` — optional type.
382    Maybe(Box<IdrisType>),
383    /// `Either a b` — sum type.
384    Either(Box<IdrisType>, Box<IdrisType>),
385}
386impl IdrisType {
387    /// Whether this type needs parentheses in argument position.
388    pub(super) fn needs_parens(&self) -> bool {
389        matches!(
390            self,
391            IdrisType::Function(_, _)
392                | IdrisType::Linear(_, _)
393                | IdrisType::Erased(_, _)
394                | IdrisType::Pi(_, _, _)
395                | IdrisType::Interface(_, _)
396        ) || matches!(self, IdrisType::Data(_, args) if ! args.is_empty())
397    }
398    /// Format with optional parenthesisation.
399    pub(super) fn fmt_parens(&self) -> String {
400        if self.needs_parens() {
401            format!("({})", self)
402        } else {
403            format!("{}", self)
404        }
405    }
406}
407/// A constructor in a `data` or `record` type.
408#[derive(Debug, Clone, PartialEq)]
409pub struct IdrisConstructor {
410    /// Constructor name.
411    pub name: String,
412    /// Constructor type signature (usually a chain of `->` ending at the data type).
413    pub ty: IdrisType,
414    /// Optional doc comment.
415    pub doc: Option<String>,
416}
417/// An `interface` (type class) declaration.
418#[derive(Debug, Clone, PartialEq)]
419pub struct IdrisInterface {
420    /// Interface name.
421    pub name: String,
422    /// Superclass constraints: `Eq a =>`.
423    pub constraints: Vec<(String, Vec<IdrisType>)>,
424    /// Type parameters.
425    pub params: Vec<(String, IdrisType)>,
426    /// Methods: `(name, type_sig)`.
427    pub methods: Vec<(String, IdrisType)>,
428    /// Default method implementations.
429    pub defaults: Vec<IdrisFunction>,
430    /// Visibility.
431    pub visibility: Visibility,
432    /// Optional doc comment.
433    pub doc: Option<String>,
434}
435impl IdrisInterface {
436    /// Emit this interface declaration.
437    pub fn emit(&self, indent: usize) -> String {
438        let pad = " ".repeat(indent);
439        let mut out = String::new();
440        if let Some(doc) = &self.doc {
441            for line in doc.lines() {
442                out.push_str(&format!("{}||| {}\n", pad, line));
443            }
444        }
445        let constraints_str: String = self
446            .constraints
447            .iter()
448            .map(|(c, args)| {
449                if args.is_empty() {
450                    c.clone()
451                } else {
452                    format!(
453                        "{} {}",
454                        c,
455                        args.iter()
456                            .map(|a| format!("{}", a))
457                            .collect::<Vec<_>>()
458                            .join(" ")
459                    )
460                }
461            })
462            .collect::<Vec<_>>()
463            .join(", ");
464        let params_str: String = self
465            .params
466            .iter()
467            .map(|(n, t)| format!(" ({} : {})", n, t))
468            .collect();
469        if constraints_str.is_empty() {
470            out.push_str(&format!(
471                "{}{}interface {}{} where\n",
472                pad, self.visibility, self.name, params_str
473            ));
474        } else {
475            out.push_str(&format!(
476                "{}{}interface {} => {}{} where\n",
477                pad, self.visibility, constraints_str, self.name, params_str
478            ));
479        }
480        for (mname, mtype) in &self.methods {
481            out.push_str(&format!("{}  {} : {}\n", pad, mname, mtype));
482        }
483        for default in &self.defaults {
484            out.push_str(&default.emit(indent + 2));
485        }
486        out
487    }
488}
489/// A `parameters` block, grouping shared implicit parameters.
490#[derive(Debug, Clone)]
491#[allow(dead_code)]
492pub struct IdrisParametersBlock {
493    /// Shared parameters declared for all contained definitions.
494    pub params: Vec<(String, IdrisType)>,
495    /// Declarations inside the block.
496    pub decls: Vec<IdrisDecl>,
497}
498impl IdrisParametersBlock {
499    /// Create a new parameters block.
500    #[allow(dead_code)]
501    pub fn new(params: Vec<(String, IdrisType)>) -> Self {
502        IdrisParametersBlock {
503            params,
504            decls: Vec::new(),
505        }
506    }
507    /// Add a declaration to the block.
508    #[allow(dead_code)]
509    pub fn add(&mut self, decl: IdrisDecl) {
510        self.decls.push(decl);
511    }
512    /// Emit the parameters block.
513    #[allow(dead_code)]
514    pub fn emit(&self, backend: &IdrisBackend) -> String {
515        let params_str: Vec<String> = self
516            .params
517            .iter()
518            .map(|(n, t)| format!("({} : {})", n, t))
519            .collect();
520        let mut out = format!("parameters {}\n", params_str.join(" "));
521        for decl in &self.decls {
522            for line in backend.emit_decl(decl).lines() {
523                out.push_str("    ");
524                out.push_str(line);
525                out.push('\n');
526            }
527        }
528        out
529    }
530}
531/// An Idris 2 `implementation` (instance) of an interface.
532#[derive(Debug, Clone)]
533#[allow(dead_code)]
534pub struct IdrisImplementation {
535    /// Optional implementation name.
536    pub name: Option<String>,
537    /// Interface name being implemented.
538    pub interface: String,
539    /// Type arguments.
540    pub type_args: Vec<IdrisType>,
541    /// Constraints on the implementation.
542    pub constraints: Vec<IdrisType>,
543    /// Method clauses: function definitions.
544    pub clauses: Vec<IdrisFunction>,
545    /// Visibility.
546    pub visibility: Visibility,
547}
548impl IdrisImplementation {
549    /// Create a new implementation.
550    #[allow(dead_code)]
551    pub fn new(interface: impl Into<String>, type_args: Vec<IdrisType>) -> Self {
552        IdrisImplementation {
553            name: None,
554            interface: interface.into(),
555            type_args,
556            constraints: Vec::new(),
557            clauses: Vec::new(),
558            visibility: Visibility::Default,
559        }
560    }
561    /// Add a method clause.
562    #[allow(dead_code)]
563    pub fn add_method(&mut self, func: IdrisFunction) {
564        self.clauses.push(func);
565    }
566    /// Emit the implementation block.
567    #[allow(dead_code)]
568    pub fn emit(&self, backend: &IdrisBackend) -> String {
569        let name_part = self
570            .name
571            .as_ref()
572            .map(|n| format!("[{}] ", n))
573            .unwrap_or_default();
574        let constraints_str = if self.constraints.is_empty() {
575            String::new()
576        } else {
577            let cs: Vec<String> = self.constraints.iter().map(|c| format!("{}", c)).collect();
578            format!("{} => ", cs.join(", "))
579        };
580        let type_args_str: Vec<String> = self.type_args.iter().map(|t| format!("{}", t)).collect();
581        let mut out = format!(
582            "{}implementation {}{}{} {} where\n",
583            self.visibility,
584            name_part,
585            constraints_str,
586            self.interface,
587            type_args_str.join(" "),
588        );
589        for clause in &self.clauses {
590            let decl = IdrisDecl::Func(clause.clone());
591            for line in backend.emit_decl(&decl).lines() {
592                out.push_str("    ");
593                out.push_str(line);
594                out.push('\n');
595            }
596        }
597        out
598    }
599}
600/// Idris 2 compiler pragmas and directives.
601#[derive(Debug, Clone, PartialEq, Eq)]
602#[allow(dead_code)]
603pub enum IdrisPragma {
604    /// `%name x xs, xss` — suggest names for case-split.
605    Name(String, Vec<String>),
606    /// `%auto_implicit` — enable auto-implicit arguments.
607    AutoImplicit,
608    /// `%default total` — make all definitions total by default.
609    DefaultTotal,
610    /// `%default partial` — allow partial definitions by default.
611    DefaultPartial,
612    /// `%default covering` — require covering definitions by default.
613    DefaultCovering,
614    /// `%inline` — hint that function should be inlined.
615    Inline,
616    /// `%noinline` — hint that function should not be inlined.
617    NoInline,
618    /// `%hint` — register as an auto-search hint.
619    Hint,
620    /// `%extern` — mark function as externally defined.
621    Extern,
622    /// `%builtin NaturalToInteger` etc.
623    Builtin(String),
624    /// `%foreign <backend> <impl>`.
625    Foreign { backend: String, impl_str: String },
626    /// `%transform` — mark as a rewrite rule.
627    Transform(String),
628    /// `%deprecate` — mark as deprecated.
629    Deprecate(Option<String>),
630    /// `%hide Module.name` — hide from namespace.
631    Hide(String),
632    /// `%unbound_implicits off`.
633    UnboundImplicitsOff,
634    /// `%ambiguity_depth N`.
635    AmbiguityDepth(u32),
636    /// `%search_timeout N`.
637    SearchTimeout(u32),
638    /// `%logging topic N`.
639    Logging { topic: String, level: u32 },
640    /// `%language ElabReflection` or similar.
641    Language(String),
642    /// `%run_elab <expr>` — run elaborator reflection.
643    RunElab(String),
644}
645/// A pattern in an Idris 2 function clause.
646#[derive(Debug, Clone, PartialEq)]
647pub enum IdrisPattern {
648    /// Wildcard `_`.
649    Wildcard,
650    /// Variable `x`.
651    Var(String),
652    /// Constructor application `Ctor p1 p2`.
653    Con(String, Vec<IdrisPattern>),
654    /// Literal pattern.
655    Lit(IdrisLiteral),
656    /// Tuple pattern `(p1, p2)`.
657    Tuple(Vec<IdrisPattern>),
658    /// Nil `[]`.
659    Nil,
660    /// Cons `x :: xs`.
661    Cons(Box<IdrisPattern>, Box<IdrisPattern>),
662    /// As-pattern `n@p`.
663    As(String, Box<IdrisPattern>),
664    /// Implicit argument pattern `{p}`.
665    Implicit(Box<IdrisPattern>),
666    /// Inaccessible (dot) pattern `.t`.
667    Dot(Box<IdrisExpr>),
668}
669/// A top-level declaration in an Idris 2 module.
670#[derive(Debug, Clone, PartialEq)]
671pub enum IdrisDecl {
672    /// A function definition.
673    Func(IdrisFunction),
674    /// A `data` declaration.
675    Data(IdrisData),
676    /// A `record` declaration.
677    Record(IdrisRecord),
678    /// An `interface` declaration.
679    Interface(IdrisInterface),
680    /// An `implementation` block.
681    Implementation(IdrisImpl),
682    /// A `namespace N where` block.
683    Namespace(String, Vec<IdrisDecl>),
684    /// A `mutual` block for mutually recursive definitions.
685    Mutual(Vec<IdrisDecl>),
686    /// A `parameters` block: `parameters (x : T) where`.
687    Parameters(Vec<(String, IdrisType)>, Vec<IdrisDecl>),
688    /// A `%` pragma: `%name T x, y, z`.
689    Pragma(String),
690    /// A type-level `postulate` (axiom).
691    Postulate(String, IdrisType, Visibility),
692    /// A line comment.
693    Comment(String),
694    /// A blank separator.
695    Blank,
696}
697impl IdrisDecl {
698    /// Emit this declaration at the given indent level.
699    pub fn emit(&self, indent: usize) -> String {
700        let pad = " ".repeat(indent);
701        match self {
702            IdrisDecl::Func(f) => f.emit(indent),
703            IdrisDecl::Data(d) => d.emit(indent),
704            IdrisDecl::Record(r) => r.emit(indent),
705            IdrisDecl::Interface(i) => i.emit(indent),
706            IdrisDecl::Implementation(im) => im.emit(indent),
707            IdrisDecl::Namespace(name, decls) => {
708                let mut out = format!("{}namespace {} where\n", pad, name);
709                for d in decls {
710                    out.push_str(&d.emit(indent + 2));
711                }
712                out
713            }
714            IdrisDecl::Mutual(decls) => {
715                let mut out = format!("{}mutual\n", pad);
716                for d in decls {
717                    out.push_str(&d.emit(indent + 2));
718                }
719                out
720            }
721            IdrisDecl::Parameters(params, decls) => {
722                let params_str: String = params
723                    .iter()
724                    .map(|(n, t)| format!("({} : {})", n, t))
725                    .collect::<Vec<_>>()
726                    .join(" ");
727                let mut out = format!("{}parameters {}\n", pad, params_str);
728                for d in decls {
729                    out.push_str(&d.emit(indent + 2));
730                }
731                out
732            }
733            IdrisDecl::Pragma(s) => format!("{}%{}\n", pad, s),
734            IdrisDecl::Postulate(name, ty, vis) => {
735                format!("{}{}postulate {} : {}\n", pad, vis, name, ty)
736            }
737            IdrisDecl::Comment(s) => format!("{}-- {}\n", pad, s),
738            IdrisDecl::Blank => String::from("\n"),
739        }
740    }
741}
742/// Collection of common Idris 2 standard library patterns for code generation.
743#[allow(dead_code)]
744pub struct IdrisStdlibSnippets;
745impl IdrisStdlibSnippets {
746    /// Emit a `mapMaybe` helper over a list.
747    #[allow(dead_code)]
748    pub fn map_maybe_fn() -> IdrisFunction {
749        IdrisFunction::with_clauses(
750            "mapMaybe",
751            IdrisTypeBuilder::arrow(vec![
752                IdrisTypeBuilder::arrow(vec![
753                    IdrisType::Var("a".to_string()),
754                    IdrisTypeBuilder::maybe(IdrisType::Var("b".to_string())),
755                ]),
756                IdrisTypeBuilder::list(IdrisType::Var("a".to_string())),
757                IdrisTypeBuilder::list(IdrisType::Var("b".to_string())),
758            ]),
759            vec![
760                (
761                    vec![
762                        IdrisPatternBuilder::wildcard(),
763                        IdrisPatternBuilder::con("Nil", vec![]),
764                    ],
765                    IdrisExpr::Var("Nil".to_string()),
766                ),
767                (
768                    vec![
769                        IdrisPatternBuilder::var("f"),
770                        IdrisPatternBuilder::con(
771                            "::",
772                            vec![
773                                IdrisPatternBuilder::var("x"),
774                                IdrisPatternBuilder::var("xs"),
775                            ],
776                        ),
777                    ],
778                    IdrisExprBuilder::case_of(
779                        IdrisExprBuilder::app_chain(
780                            IdrisExpr::Var("f".to_string()),
781                            vec![IdrisExpr::Var("x".to_string())],
782                        ),
783                        vec![
784                            (
785                                IdrisPatternBuilder::con("Nothing", vec![]),
786                                IdrisExprBuilder::app_chain(
787                                    IdrisExpr::Var("mapMaybe".to_string()),
788                                    vec![
789                                        IdrisExpr::Var("f".to_string()),
790                                        IdrisExpr::Var("xs".to_string()),
791                                    ],
792                                ),
793                            ),
794                            (
795                                IdrisPatternBuilder::con(
796                                    "Just",
797                                    vec![IdrisPatternBuilder::var("y")],
798                                ),
799                                IdrisExprBuilder::app_chain(
800                                    IdrisExpr::Var("::".to_string()),
801                                    vec![
802                                        IdrisExpr::Var("y".to_string()),
803                                        IdrisExprBuilder::app_chain(
804                                            IdrisExpr::Var("mapMaybe".to_string()),
805                                            vec![
806                                                IdrisExpr::Var("f".to_string()),
807                                                IdrisExpr::Var("xs".to_string()),
808                                            ],
809                                        ),
810                                    ],
811                                ),
812                            ),
813                        ],
814                    ),
815                ),
816            ],
817        )
818    }
819    /// Emit a `foldr` implementation.
820    #[allow(dead_code)]
821    pub fn foldr_fn() -> String {
822        "foldr : (a -> b -> b) -> b -> List a -> b\nfoldr f z [] = z\nfoldr f z (x :: xs) = f x (foldr f z xs)\n"
823            .to_string()
824    }
825    /// Emit a `zip` implementation.
826    #[allow(dead_code)]
827    pub fn zip_fn() -> String {
828        "zip : List a -> List b -> List (a, b)\nzip [] _ = []\nzip _ [] = []\nzip (x :: xs) (y :: ys) = (x, y) :: zip xs ys\n"
829            .to_string()
830    }
831    /// Emit a `nub` (remove duplicates) implementation using DecEq.
832    #[allow(dead_code)]
833    pub fn nub_fn() -> String {
834        "nub : DecEq a => List a -> List a\nnub [] = []\nnub (x :: xs) = x :: nub (filter (/= x) xs)\n"
835            .to_string()
836    }
837    /// Emit a simple `show` implementation for a nat-like type.
838    #[allow(dead_code)]
839    pub fn show_nat_instance(type_name: &str) -> String {
840        format!("Show {} where\n    show x = show (toNat x)\n", type_name)
841    }
842}
843/// A literal value in Idris 2.
844#[derive(Debug, Clone, PartialEq)]
845pub enum IdrisLiteral {
846    /// Integer literal `42`, `-7`.
847    Int(i64),
848    /// Natural number literal `3`.
849    Nat(u64),
850    /// Float literal `3.14`.
851    Float(f64),
852    /// Character literal `'a'`.
853    Char(char),
854    /// String literal `"hello"`.
855    Str(String),
856    /// Boolean `True`.
857    True,
858    /// Boolean `False`.
859    False,
860    /// Unit `()`.
861    Unit,
862}
863/// An expression in Idris 2.
864#[derive(Debug, Clone, PartialEq)]
865pub enum IdrisExpr {
866    /// A literal value.
867    Lit(IdrisLiteral),
868    /// A variable reference `x`.
869    Var(String),
870    /// A fully qualified name `Module.name`.
871    Qualified(Vec<String>),
872    /// Function application `f x`.
873    App(Box<IdrisExpr>, Box<IdrisExpr>),
874    /// Lambda `\x => body`.
875    Lam(Vec<String>, Box<IdrisExpr>),
876    /// Let binding `let x = val in body`.
877    Let(String, Box<IdrisExpr>, Box<IdrisExpr>),
878    /// `case scrutinee of { alts }`.
879    CaseOf(Box<IdrisExpr>, Vec<(IdrisPattern, IdrisExpr)>),
880    /// `if cond then t else e`.
881    IfThenElse(Box<IdrisExpr>, Box<IdrisExpr>, Box<IdrisExpr>),
882    /// A `do` block: list of statements.
883    Do(Vec<IdrisDoStmt>),
884    /// Tuple `(e1, e2, ...)`.
885    Tuple(Vec<IdrisExpr>),
886    /// List literal `[e1, e2, ...]`.
887    ListLit(Vec<IdrisExpr>),
888    /// Type annotation `(e : T)`.
889    Annot(Box<IdrisExpr>, Box<IdrisType>),
890    /// An idiom bracket `[| f x y |]`.
891    Idiom(Box<IdrisExpr>),
892    /// A proof term / tactic block `believe_me x`.
893    ProofTerm(Box<IdrisExpr>),
894    /// `with` view pattern expression.
895    WithPattern(Box<IdrisExpr>, Vec<(IdrisPattern, IdrisExpr)>),
896    /// Infix operator expression `a `op` b`.
897    Infix(String, Box<IdrisExpr>, Box<IdrisExpr>),
898    /// A hole `?name`.
899    Hole(String),
900    /// `refl` — reflexivity proof.
901    Refl,
902    /// `?_` — anonymous hole.
903    AnonHole,
904    /// A record update `{ field = val }`.
905    RecordUpdate(Box<IdrisExpr>, Vec<(String, IdrisExpr)>),
906    /// A negative integer `-n`.
907    Neg(Box<IdrisExpr>),
908}
909impl IdrisExpr {
910    /// Whether this expression needs parentheses in application position.
911    pub(super) fn needs_parens(&self) -> bool {
912        matches!(
913            self,
914            IdrisExpr::App(_, _)
915                | IdrisExpr::Lam(_, _)
916                | IdrisExpr::Let(_, _, _)
917                | IdrisExpr::CaseOf(_, _)
918                | IdrisExpr::IfThenElse(_, _, _)
919                | IdrisExpr::Do(_)
920                | IdrisExpr::Infix(_, _, _)
921                | IdrisExpr::Annot(_, _)
922                | IdrisExpr::Neg(_)
923        )
924    }
925    /// Format with parens if needed.
926    pub(super) fn fmt_arg(&self) -> String {
927        if self.needs_parens() {
928            format!("({})", self)
929        } else {
930            format!("{}", self)
931        }
932    }
933}
934/// An `implementation` (type class instance) block.
935#[derive(Debug, Clone, PartialEq)]
936pub struct IdrisImpl {
937    /// Optional implementation name (e.g. `[NatEq]`).
938    pub impl_name: Option<String>,
939    /// Constraints: `Eq a =>`.
940    pub constraints: Vec<(String, Vec<IdrisType>)>,
941    /// Interface being implemented.
942    pub interface: String,
943    /// Type arguments.
944    pub args: Vec<IdrisType>,
945    /// Method implementations.
946    pub methods: Vec<IdrisFunction>,
947    /// Visibility.
948    pub visibility: Visibility,
949}
950impl IdrisImpl {
951    /// Emit this implementation block.
952    pub fn emit(&self, indent: usize) -> String {
953        let pad = " ".repeat(indent);
954        let mut out = String::new();
955        let constraints_str: String = self
956            .constraints
957            .iter()
958            .map(|(c, args)| {
959                if args.is_empty() {
960                    c.clone()
961                } else {
962                    format!(
963                        "{} {}",
964                        c,
965                        args.iter()
966                            .map(|a| format!("{}", a))
967                            .collect::<Vec<_>>()
968                            .join(" ")
969                    )
970                }
971            })
972            .collect::<Vec<_>>()
973            .join(", ");
974        let args_str: String = self.args.iter().map(|a| format!(" {}", a)).collect();
975        let name_str = self
976            .impl_name
977            .as_ref()
978            .map(|n| format!(" [{}]", n))
979            .unwrap_or_default();
980        if constraints_str.is_empty() {
981            out.push_str(&format!(
982                "{}{}implementation{} {}{} where\n",
983                pad, self.visibility, name_str, self.interface, args_str
984            ));
985        } else {
986            out.push_str(&format!(
987                "{}{}implementation{} {} => {}{} where\n",
988                pad, self.visibility, name_str, constraints_str, self.interface, args_str
989            ));
990        }
991        for method in &self.methods {
992            out.push_str(&method.emit(indent + 2));
993        }
994        out
995    }
996}
997/// The Idris 2 code generation backend.
998///
999/// Converts `IdrisModule` / individual declarations into `.idr` source text.
1000#[derive(Debug, Default)]
1001pub struct IdrisBackend {
1002    /// Whether to add `-- AUTO-GENERATED` header.
1003    pub add_header: bool,
1004    /// Whether to emit `%default total` at the top of each module.
1005    pub default_total: bool,
1006    /// Whether to emit `%auto_implicit` pragmas.
1007    pub auto_implicit: bool,
1008    /// Configuration options.
1009    pub options: IdrisBackendOptions,
1010}
1011impl IdrisBackend {
1012    /// Create a backend with default settings.
1013    pub fn new() -> Self {
1014        IdrisBackend {
1015            add_header: false,
1016            default_total: false,
1017            auto_implicit: false,
1018            options: IdrisBackendOptions {
1019                blank_between_decls: true,
1020                emit_docs: true,
1021            },
1022        }
1023    }
1024    /// Create a backend optimised for proof-oriented Idris 2 output.
1025    pub fn proof_mode() -> Self {
1026        IdrisBackend {
1027            add_header: true,
1028            default_total: true,
1029            auto_implicit: true,
1030            options: IdrisBackendOptions {
1031                blank_between_decls: true,
1032                emit_docs: true,
1033            },
1034        }
1035    }
1036    /// Emit a complete `IdrisModule` as `.idr` source text.
1037    pub fn emit_module(&self, module: &IdrisModule) -> String {
1038        let mut out = String::new();
1039        if self.add_header {
1040            out.push_str("-- AUTO-GENERATED by OxiLean\n\n");
1041        }
1042        if let Some(doc) = &module.doc {
1043            for line in doc.lines() {
1044                out.push_str(&format!("||| {}\n", line));
1045            }
1046        }
1047        let module_str = module.module_name.join(".");
1048        out.push_str(&format!("module {}\n\n", module_str));
1049        if self.default_total {
1050            out.push_str("%default total\n\n");
1051        }
1052        if self.auto_implicit {
1053            out.push_str("%auto_implicit_depth 50\n\n");
1054        }
1055        for imp in &module.imports {
1056            out.push_str(&imp.emit());
1057            out.push('\n');
1058        }
1059        if !module.imports.is_empty() {
1060            out.push('\n');
1061        }
1062        for decl in &module.declarations {
1063            let s = decl.emit(0);
1064            out.push_str(&s);
1065            if self.options.blank_between_decls
1066                && !matches!(decl, IdrisDecl::Blank | IdrisDecl::Comment(_))
1067            {
1068                out.push('\n');
1069            }
1070        }
1071        out
1072    }
1073    /// Emit a single declaration.
1074    pub fn emit_decl(&self, decl: &IdrisDecl) -> String {
1075        decl.emit(0)
1076    }
1077    /// Emit a single function.
1078    pub fn emit_function(&self, func: &IdrisFunction) -> String {
1079        func.emit(0)
1080    }
1081    /// Emit a single data declaration.
1082    pub fn emit_data(&self, data: &IdrisData) -> String {
1083        data.emit(0)
1084    }
1085    /// Emit a single record.
1086    pub fn emit_record(&self, rec: &IdrisRecord) -> String {
1087        rec.emit(0)
1088    }
1089    /// Emit a single interface.
1090    pub fn emit_interface(&self, iface: &IdrisInterface) -> String {
1091        iface.emit(0)
1092    }
1093    /// Emit a single implementation.
1094    pub fn emit_impl(&self, im: &IdrisImpl) -> String {
1095        im.emit(0)
1096    }
1097}
1098/// Export visibility of a top-level declaration.
1099#[derive(Debug, Clone, PartialEq, Eq)]
1100pub enum Visibility {
1101    /// `public export` — type and implementation visible.
1102    PublicExport,
1103    /// `export` — type visible, implementation hidden.
1104    Export,
1105    /// `private` — hidden from other modules.
1106    Private,
1107    /// No annotation (module-local default).
1108    Default,
1109}
1110/// Totality annotation for a function.
1111#[derive(Debug, Clone, PartialEq, Eq)]
1112pub enum Totality {
1113    /// `total` — must be total (no partial/diverging cases).
1114    Total,
1115    /// `partial` — allowed to be partial.
1116    Partial,
1117    /// `covering` — all cases must be handled but may be partial.
1118    Covering,
1119    /// No explicit annotation (use module default).
1120    Default,
1121}
1122/// A statement inside a `do` block.
1123#[derive(Debug, Clone, PartialEq)]
1124pub enum IdrisDoStmt {
1125    /// `x <- action`
1126    Bind(String, IdrisExpr),
1127    /// `let x = val`
1128    Let(String, IdrisExpr),
1129    /// A bare expression (last statement or side-effect).
1130    Expr(IdrisExpr),
1131    /// `let x : T = val`
1132    LetTyped(String, IdrisType, IdrisExpr),
1133    /// `ignore action`
1134    Ignore(IdrisExpr),
1135}
1136/// Configuration options for the Idris backend.
1137#[derive(Debug, Default, Clone)]
1138pub struct IdrisBackendOptions {
1139    /// Emit blank lines between top-level declarations.
1140    pub blank_between_decls: bool,
1141    /// Emit `||| doc` comments for items with doc strings.
1142    pub emit_docs: bool,
1143}
1144/// An Idris 2 `interface` definition.
1145#[derive(Debug, Clone)]
1146#[allow(dead_code)]
1147pub struct IdrisInterfaceExt {
1148    /// Interface name.
1149    pub name: String,
1150    /// Type parameters.
1151    pub params: Vec<(String, IdrisType)>,
1152    /// Superclass constraints.
1153    pub constraints: Vec<IdrisType>,
1154    /// Method declarations: (name, type, optional default impl).
1155    pub methods: Vec<(String, IdrisType, Option<IdrisExpr>)>,
1156    /// Visibility.
1157    pub visibility: Visibility,
1158    /// Optional doc comment.
1159    pub doc: Option<String>,
1160}
1161impl IdrisInterfaceExt {
1162    /// Create a minimal interface definition.
1163    #[allow(dead_code)]
1164    pub fn new(name: impl Into<String>, params: Vec<(String, IdrisType)>) -> Self {
1165        IdrisInterfaceExt {
1166            name: name.into(),
1167            params,
1168            constraints: Vec::new(),
1169            methods: Vec::new(),
1170            visibility: Visibility::PublicExport,
1171            doc: None,
1172        }
1173    }
1174    /// Add a method signature.
1175    #[allow(dead_code)]
1176    pub fn add_method(&mut self, name: impl Into<String>, ty: IdrisType) {
1177        self.methods.push((name.into(), ty, None));
1178    }
1179    /// Add a method with a default implementation.
1180    #[allow(dead_code)]
1181    pub fn add_method_with_default(
1182        &mut self,
1183        name: impl Into<String>,
1184        ty: IdrisType,
1185        default: IdrisExpr,
1186    ) {
1187        self.methods.push((name.into(), ty, Some(default)));
1188    }
1189    /// Emit the interface definition.
1190    #[allow(dead_code)]
1191    pub fn emit(&self) -> String {
1192        let mut out = String::new();
1193        if let Some(doc) = &self.doc {
1194            for line in doc.lines() {
1195                out.push_str(&format!("||| {}\n", line));
1196            }
1197        }
1198        let params_str: Vec<String> = self
1199            .params
1200            .iter()
1201            .map(|(n, t)| format!("({} : {})", n, t))
1202            .collect();
1203        let constraints_str = if self.constraints.is_empty() {
1204            String::new()
1205        } else {
1206            let cs: Vec<String> = self.constraints.iter().map(|c| format!("{}", c)).collect();
1207            format!("{} => ", cs.join(", "))
1208        };
1209        out.push_str(&format!(
1210            "{}interface {}{} {} where\n",
1211            self.visibility,
1212            constraints_str,
1213            self.name,
1214            params_str.join(" ")
1215        ));
1216        for (mname, mty, mdefault) in &self.methods {
1217            out.push_str(&format!("    {} : {}\n", mname, mty));
1218            if let Some(def) = mdefault {
1219                out.push_str(&format!("    {} _ = {}\n", mname, def));
1220            }
1221        }
1222        out
1223    }
1224}
1225/// Fluent helper for building complex Idris 2 types.
1226#[allow(dead_code)]
1227pub struct IdrisTypeBuilder;
1228impl IdrisTypeBuilder {
1229    /// Build a function type `a -> b -> ... -> z`.
1230    #[allow(dead_code)]
1231    pub fn arrow(types: Vec<IdrisType>) -> IdrisType {
1232        assert!(!types.is_empty(), "arrow type must have at least one type");
1233        let mut it = types.into_iter().rev();
1234        let mut result = it
1235            .next()
1236            .expect("types is non-empty; guaranteed by assert above");
1237        for ty in it {
1238            result = IdrisType::Function(Box::new(ty), Box::new(result));
1239        }
1240        result
1241    }
1242    /// Build a type application `T a b c`.
1243    #[allow(dead_code)]
1244    pub fn app(head: impl Into<String>, args: Vec<IdrisType>) -> IdrisType {
1245        IdrisType::Data(head.into(), args)
1246    }
1247    /// Build a `Vect n a` type.
1248    #[allow(dead_code)]
1249    pub fn vect(n_expr: impl Into<String>, elem_ty: IdrisType) -> IdrisType {
1250        IdrisType::Data(
1251            "Vect".to_string(),
1252            vec![IdrisType::Var(n_expr.into()), elem_ty],
1253        )
1254    }
1255    /// Build a `List a` type.
1256    #[allow(dead_code)]
1257    pub fn list(elem_ty: IdrisType) -> IdrisType {
1258        IdrisType::List(Box::new(elem_ty))
1259    }
1260    /// Build a `Maybe a` type.
1261    #[allow(dead_code)]
1262    pub fn maybe(ty: IdrisType) -> IdrisType {
1263        IdrisType::Data("Maybe".to_string(), vec![ty])
1264    }
1265    /// Build an `Either a b` type.
1266    #[allow(dead_code)]
1267    pub fn either(left: IdrisType, right: IdrisType) -> IdrisType {
1268        IdrisType::Data("Either".to_string(), vec![left, right])
1269    }
1270    /// Build a `Pair a b` (tuple) type.
1271    #[allow(dead_code)]
1272    pub fn pair(a: IdrisType, b: IdrisType) -> IdrisType {
1273        IdrisType::Data("Pair".to_string(), vec![a, b])
1274    }
1275    /// Build an `IO a` type.
1276    #[allow(dead_code)]
1277    pub fn io(ty: IdrisType) -> IdrisType {
1278        IdrisType::Data("IO".to_string(), vec![ty])
1279    }
1280    /// `Nat`
1281    #[allow(dead_code)]
1282    pub fn nat() -> IdrisType {
1283        IdrisType::Nat
1284    }
1285    /// `Bool`
1286    #[allow(dead_code)]
1287    pub fn bool() -> IdrisType {
1288        IdrisType::Bool
1289    }
1290    /// `String`
1291    #[allow(dead_code)]
1292    pub fn string() -> IdrisType {
1293        IdrisType::String
1294    }
1295    /// `Integer`
1296    #[allow(dead_code)]
1297    pub fn integer() -> IdrisType {
1298        IdrisType::Integer
1299    }
1300    /// Dependent function type `(x : a) -> b`.
1301    #[allow(dead_code)]
1302    pub fn pi(param: impl Into<String>, domain: IdrisType, codomain: IdrisType) -> IdrisType {
1303        IdrisType::Pi(param.into(), Box::new(domain), Box::new(codomain))
1304    }
1305}
1306/// Fluent builder for constructing complete IdrisModule objects.
1307#[derive(Debug)]
1308#[allow(dead_code)]
1309pub struct IdrisModuleBuilder {
1310    pub(super) module: IdrisModule,
1311}
1312impl IdrisModuleBuilder {
1313    /// Start building a new module with the given hierarchical name.
1314    #[allow(dead_code)]
1315    pub fn new(parts: Vec<String>) -> Self {
1316        IdrisModuleBuilder {
1317            module: IdrisModule::new(parts),
1318        }
1319    }
1320    /// Add an import.
1321    #[allow(dead_code)]
1322    pub fn import(mut self, imp: IdrisImport) -> Self {
1323        self.module.import(imp);
1324        self
1325    }
1326    /// Add a public import.
1327    #[allow(dead_code)]
1328    pub fn public_import(mut self, parts: Vec<String>) -> Self {
1329        self.module.import(IdrisImport::public_import(parts));
1330        self
1331    }
1332    /// Add a declaration.
1333    #[allow(dead_code)]
1334    pub fn decl(mut self, decl: IdrisDecl) -> Self {
1335        self.module.add(decl);
1336        self
1337    }
1338    /// Add a pragma.
1339    #[allow(dead_code)]
1340    pub fn pragma(mut self, pragma: IdrisPragma) -> Self {
1341        self.module.add(IdrisDecl::Pragma(format!("{}", pragma)));
1342        self
1343    }
1344    /// Add a comment.
1345    #[allow(dead_code)]
1346    pub fn comment(mut self, text: impl Into<String>) -> Self {
1347        self.module.add(IdrisDecl::Comment(text.into()));
1348        self
1349    }
1350    /// Consume the builder and produce the module.
1351    #[allow(dead_code)]
1352    pub fn build(self) -> IdrisModule {
1353        self.module
1354    }
1355}
1356/// Fluent helper for building complex Idris 2 expressions.
1357#[allow(dead_code)]
1358pub struct IdrisExprBuilder;
1359impl IdrisExprBuilder {
1360    /// Build a function application chain: `f x y z`.
1361    #[allow(dead_code)]
1362    pub fn app_chain(func: IdrisExpr, args: Vec<IdrisExpr>) -> IdrisExpr {
1363        args.into_iter().fold(func, |acc, arg| {
1364            IdrisExpr::App(Box::new(acc), Box::new(arg))
1365        })
1366    }
1367    /// Build a `case expr of` expression.
1368    #[allow(dead_code)]
1369    pub fn case_of(scrutinee: IdrisExpr, alts: Vec<(IdrisPattern, IdrisExpr)>) -> IdrisExpr {
1370        IdrisExpr::CaseOf(Box::new(scrutinee), alts)
1371    }
1372    /// Build a let-in chain: `let x1=e1; x2=e2; ... in body`.
1373    #[allow(dead_code)]
1374    pub fn let_chain(bindings: Vec<(String, IdrisExpr)>, body: IdrisExpr) -> IdrisExpr {
1375        bindings.into_iter().rev().fold(body, |acc, (name, val)| {
1376            IdrisExpr::Let(name, Box::new(val), Box::new(acc))
1377        })
1378    }
1379    /// Build a lambda over multiple parameters: `\x, y, z => body`.
1380    #[allow(dead_code)]
1381    pub fn lam(params: Vec<impl Into<String>>, body: IdrisExpr) -> IdrisExpr {
1382        IdrisExpr::Lam(
1383            params.into_iter().map(|p| p.into()).collect(),
1384            Box::new(body),
1385        )
1386    }
1387    /// Build a do-block.
1388    #[allow(dead_code)]
1389    pub fn do_block(stmts: Vec<IdrisDoStmt>) -> IdrisExpr {
1390        IdrisExpr::Do(stmts)
1391    }
1392    /// Build `if c then t else e`.
1393    #[allow(dead_code)]
1394    pub fn if_then_else(cond: IdrisExpr, then_e: IdrisExpr, else_e: IdrisExpr) -> IdrisExpr {
1395        IdrisExpr::IfThenElse(Box::new(cond), Box::new(then_e), Box::new(else_e))
1396    }
1397    /// Build a tuple expression.
1398    #[allow(dead_code)]
1399    pub fn tuple(elems: Vec<IdrisExpr>) -> IdrisExpr {
1400        IdrisExpr::Tuple(elems)
1401    }
1402    /// Build a list literal.
1403    #[allow(dead_code)]
1404    pub fn list_lit(elems: Vec<IdrisExpr>) -> IdrisExpr {
1405        IdrisExpr::ListLit(elems)
1406    }
1407    /// Build a type-annotated expression `(e : T)`.
1408    #[allow(dead_code)]
1409    pub fn annot(expr: IdrisExpr, ty: IdrisType) -> IdrisExpr {
1410        IdrisExpr::Annot(Box::new(expr), Box::new(ty))
1411    }
1412    /// Build an infix expression `l op r`.
1413    #[allow(dead_code)]
1414    pub fn infix(op: impl Into<String>, l: IdrisExpr, r: IdrisExpr) -> IdrisExpr {
1415        IdrisExpr::Infix(op.into(), Box::new(l), Box::new(r))
1416    }
1417}
1418/// Elaboration attributes that can be applied to types, functions, or constructors.
1419#[derive(Debug, Clone, PartialEq, Eq)]
1420#[allow(dead_code)]
1421pub enum IdrisAttribute {
1422    /// `@{auto}` — auto-implicit solve.
1423    Auto,
1424    /// `@{interface}` — interface auto-search.
1425    Interface,
1426    /// `@{search}` — proof search.
1427    Search,
1428    /// `[totality]` — totality requirement.
1429    Totality(Totality),
1430    /// `[inline]` — inline hint.
1431    Inline,
1432    /// `[static]` — static argument.
1433    Static,
1434}
1435/// Configuration controlling how Idris 2 code is generated.
1436#[derive(Debug, Clone)]
1437#[allow(dead_code)]
1438pub struct IdrisCodegenConfig {
1439    /// Whether to emit docstring comments.
1440    pub emit_docs: bool,
1441    /// Whether to emit `%logging` pragmas for debugging.
1442    pub emit_logging: bool,
1443    /// Default totality annotation.
1444    pub default_totality: Totality,
1445    /// Whether to emit `%inline` on small functions.
1446    pub auto_inline: bool,
1447    /// Maximum body size (in lines) for auto-inlining.
1448    pub auto_inline_limit: usize,
1449    /// Whether to add `%name` pragmas.
1450    pub emit_name_pragmas: bool,
1451    /// Whether to emit a module header comment.
1452    pub emit_header_comment: bool,
1453    /// Target backend: `"chez"`, `"node"`, `"refc"`, etc.
1454    pub target_backend: String,
1455}
1456/// Metrics about a generated Idris 2 module.
1457#[derive(Debug, Clone, Default)]
1458#[allow(dead_code)]
1459pub struct IdrisModuleMetrics {
1460    /// Number of function definitions.
1461    pub num_functions: usize,
1462    /// Number of data type definitions.
1463    pub num_data_types: usize,
1464    /// Number of record definitions.
1465    pub num_records: usize,
1466    /// Number of import declarations.
1467    pub num_imports: usize,
1468    /// Total number of clauses across all functions.
1469    pub total_clauses: usize,
1470    /// Number of mutual blocks.
1471    pub num_mutual_blocks: usize,
1472    /// Number of pragma declarations.
1473    pub num_pragmas: usize,
1474}
1475impl IdrisModuleMetrics {
1476    /// Compute metrics from an IdrisModule.
1477    #[allow(dead_code)]
1478    pub fn compute(module: &IdrisModule) -> Self {
1479        let mut m = IdrisModuleMetrics {
1480            num_imports: module.imports.len(),
1481            ..Default::default()
1482        };
1483        for decl in &module.declarations {
1484            Self::count_decl(decl, &mut m);
1485        }
1486        m
1487    }
1488    pub(super) fn count_decl(decl: &IdrisDecl, m: &mut IdrisModuleMetrics) {
1489        match decl {
1490            IdrisDecl::Func(f) => {
1491                m.num_functions += 1;
1492                m.total_clauses += f.clauses.len();
1493            }
1494            IdrisDecl::Data(_) => {
1495                m.num_data_types += 1;
1496            }
1497            IdrisDecl::Record(_) => {
1498                m.num_records += 1;
1499            }
1500            IdrisDecl::Mutual(decls) => {
1501                m.num_mutual_blocks += 1;
1502                for d in decls {
1503                    Self::count_decl(d, m);
1504                }
1505            }
1506            IdrisDecl::Pragma(_) => {
1507                m.num_pragmas += 1;
1508            }
1509            _ => {}
1510        }
1511    }
1512    /// Return a human-readable summary.
1513    #[allow(dead_code)]
1514    pub fn summary(&self) -> String {
1515        format!(
1516            "functions={} data_types={} records={} imports={} total_clauses={} mutual_blocks={} pragmas={}",
1517            self.num_functions, self.num_data_types, self.num_records, self.num_imports,
1518            self.total_clauses, self.num_mutual_blocks, self.num_pragmas,
1519        )
1520    }
1521}
1522/// A complete Idris 2 proof in elaborator-reflection style.
1523#[derive(Debug, Clone)]
1524#[allow(dead_code)]
1525pub struct IdrisProofScript {
1526    /// The theorem name being proved.
1527    pub theorem_name: String,
1528    /// The type being proved.
1529    pub goal_type: IdrisType,
1530    /// Sequence of tactics.
1531    pub tactics: Vec<IdrisTactic>,
1532}
1533impl IdrisProofScript {
1534    /// Create a new proof script.
1535    #[allow(dead_code)]
1536    pub fn new(theorem_name: impl Into<String>, goal_type: IdrisType) -> Self {
1537        IdrisProofScript {
1538            theorem_name: theorem_name.into(),
1539            goal_type,
1540            tactics: Vec::new(),
1541        }
1542    }
1543    /// Append a tactic.
1544    #[allow(dead_code)]
1545    pub fn push(&mut self, tactic: IdrisTactic) {
1546        self.tactics.push(tactic);
1547    }
1548    /// Emit the proof as an Idris 2 function definition using proof-by-reflection.
1549    #[allow(dead_code)]
1550    pub fn emit(&self) -> String {
1551        let mut out = format!(
1552            "{} : {}\n{} = ?{}_proof\n",
1553            self.theorem_name, self.goal_type, self.theorem_name, self.theorem_name
1554        );
1555        out.push_str(&format!("-- Proof sketch for {}:\n", self.theorem_name));
1556        for tac in &self.tactics {
1557            out.push_str(&format!("--   {}\n", tac));
1558        }
1559        out
1560    }
1561}
1562/// The quantity/multiplicity annotation on a binder in Idris 2.
1563#[derive(Debug, Clone, PartialEq, Eq)]
1564pub enum Quantity {
1565    /// `0` — erased, not available at runtime.
1566    Zero,
1567    /// `1` — linear, used exactly once.
1568    One,
1569    /// Unrestricted (the default, no annotation).
1570    Unrestricted,
1571}
1572/// A complete Idris 2 source module (maps to a `.idr` file).
1573#[derive(Debug, Clone)]
1574pub struct IdrisModule {
1575    /// Module name, e.g. `["Data", "MyList"]`.
1576    pub module_name: Vec<String>,
1577    /// Import directives.
1578    pub imports: Vec<IdrisImport>,
1579    /// Top-level declarations.
1580    pub declarations: Vec<IdrisDecl>,
1581    /// Optional module-level doc comment.
1582    pub doc: Option<String>,
1583}
1584impl IdrisModule {
1585    /// Create a new module.
1586    pub fn new(name: Vec<String>) -> Self {
1587        IdrisModule {
1588            module_name: name,
1589            imports: vec![],
1590            declarations: vec![],
1591            doc: None,
1592        }
1593    }
1594    /// Set the module doc comment.
1595    pub fn with_doc(mut self, doc: impl Into<String>) -> Self {
1596        self.doc = Some(doc.into());
1597        self
1598    }
1599    /// Add an import.
1600    pub fn import(&mut self, imp: IdrisImport) {
1601        self.imports.push(imp);
1602    }
1603    /// Add a declaration.
1604    pub fn add(&mut self, decl: IdrisDecl) {
1605        self.declarations.push(decl);
1606    }
1607    /// Add a blank line.
1608    pub fn blank(&mut self) {
1609        self.declarations.push(IdrisDecl::Blank);
1610    }
1611}