Skip to main content

oxilean_codegen/csharp_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6use std::fmt::Write as FmtWrite;
7
8use super::functions::CSHARP_RUNTIME;
9use super::functions::*;
10
11/// A `case` inside a `switch` statement.
12#[derive(Debug, Clone, PartialEq)]
13pub struct CSharpSwitchCase {
14    /// The case label expression (or pattern string for C# 8+ pattern matching)
15    pub label: std::string::String,
16    pub stmts: Vec<CSharpStmt>,
17}
18/// C# statement AST.
19#[derive(Debug, Clone, PartialEq)]
20pub enum CSharpStmt {
21    /// Expression statement: `expr;`
22    Expr(CSharpExpr),
23    /// Assignment: `target = value;`
24    Assign {
25        target: CSharpExpr,
26        value: CSharpExpr,
27    },
28    /// Local variable declaration: `var name = expr;` or `Type name = expr;`
29    LocalVar {
30        name: std::string::String,
31        ty: Option<CSharpType>,
32        init: Option<CSharpExpr>,
33        is_const: bool,
34    },
35    /// `if (cond) { ... } else { ... }`
36    If {
37        cond: CSharpExpr,
38        then_stmts: Vec<CSharpStmt>,
39        else_stmts: Vec<CSharpStmt>,
40    },
41    /// `switch (expr) { case ...: ... }`
42    Switch {
43        expr: CSharpExpr,
44        cases: Vec<CSharpSwitchCase>,
45        default: Vec<CSharpStmt>,
46    },
47    /// `while (cond) { ... }`
48    While {
49        cond: CSharpExpr,
50        body: Vec<CSharpStmt>,
51    },
52    /// `for (init; cond; step) { ... }`
53    For {
54        init: Option<Box<CSharpStmt>>,
55        cond: Option<CSharpExpr>,
56        step: Option<CSharpExpr>,
57        body: Vec<CSharpStmt>,
58    },
59    /// `foreach (var item in collection) { ... }`
60    ForEach {
61        var_name: std::string::String,
62        var_ty: Option<CSharpType>,
63        collection: CSharpExpr,
64        body: Vec<CSharpStmt>,
65    },
66    /// `return expr;` or `return;`
67    Return(Option<CSharpExpr>),
68    /// `throw expr;`
69    Throw(CSharpExpr),
70    /// `try { ... } catch (Type e) { ... } finally { ... }`
71    TryCatch {
72        try_stmts: Vec<CSharpStmt>,
73        catches: Vec<CSharpCatchClause>,
74        finally_stmts: Vec<CSharpStmt>,
75    },
76    /// `using (expr) { ... }` or `using var x = expr;`
77    Using {
78        resource: CSharpExpr,
79        var_name: Option<std::string::String>,
80        body: Vec<CSharpStmt>,
81    },
82    /// `lock (obj) { ... }`
83    Lock {
84        obj: CSharpExpr,
85        body: Vec<CSharpStmt>,
86    },
87    /// `break;`
88    Break,
89    /// `continue;`
90    Continue,
91    /// `yield return expr;`
92    YieldReturn(CSharpExpr),
93    /// `yield break;`
94    YieldBreak,
95}
96/// A C# interface declaration.
97#[derive(Debug, Clone, PartialEq)]
98pub struct CSharpInterface {
99    pub name: std::string::String,
100    /// Interface method signatures (body must be empty or default impl)
101    pub methods: Vec<CSharpMethod>,
102    /// Properties in the interface
103    pub properties: Vec<CSharpProperty>,
104    /// Extends other interfaces
105    pub extends: Vec<std::string::String>,
106    pub visibility: CSharpVisibility,
107    pub type_params: Vec<std::string::String>,
108}
109impl CSharpInterface {
110    pub fn new(name: &str) -> Self {
111        CSharpInterface {
112            name: name.to_string(),
113            methods: Vec::new(),
114            properties: Vec::new(),
115            extends: Vec::new(),
116            visibility: CSharpVisibility::Public,
117            type_params: Vec::new(),
118        }
119    }
120    pub fn emit(&self, indent: &str) -> std::string::String {
121        let inner = format!("{}    ", indent);
122        let mut out = std::string::String::new();
123        let type_params_str = if self.type_params.is_empty() {
124            std::string::String::new()
125        } else {
126            format!("<{}>", self.type_params.join(", "))
127        };
128        let extends_str = if self.extends.is_empty() {
129            std::string::String::new()
130        } else {
131            format!(" : {}", self.extends.join(", "))
132        };
133        let _ = writeln!(
134            out,
135            "{}{} interface {}{}{}",
136            indent, self.visibility, self.name, type_params_str, extends_str
137        );
138        let _ = writeln!(out, "{}{{", indent);
139        for prop in &self.properties {
140            out.push_str(&prop.emit(&inner));
141        }
142        for method in &self.methods {
143            // In a C# interface, methods are implicitly abstract.
144            // Emit without the `abstract` keyword.
145            let mut iface_method = method.clone();
146            iface_method.is_abstract = false;
147            if method.body.is_empty() && method.expr_body.is_none() {
148                // Emit as a signature with semicolon, no `abstract` keyword.
149                let params_str = method
150                    .params
151                    .iter()
152                    .map(|(n, t)| format!("{} {}", t, n))
153                    .collect::<Vec<_>>()
154                    .join(", ");
155                let type_params_str = if method.type_params.is_empty() {
156                    std::string::String::new()
157                } else {
158                    format!("<{}>", method.type_params.join(", "))
159                };
160                let _ = writeln!(
161                    out,
162                    "{}{} {} {}{}({});",
163                    inner,
164                    method.visibility,
165                    method.return_type,
166                    method.name,
167                    type_params_str,
168                    params_str
169                );
170            } else {
171                out.push_str(&iface_method.emit(&inner));
172            }
173        }
174        let _ = writeln!(out, "{}}}", indent);
175        out
176    }
177}
178/// A C# field declaration.
179#[derive(Debug, Clone, PartialEq)]
180pub struct CSharpField {
181    pub name: std::string::String,
182    pub ty: CSharpType,
183    pub visibility: CSharpVisibility,
184    pub is_static: bool,
185    pub is_readonly: bool,
186    pub is_const: bool,
187    pub default_value: Option<CSharpExpr>,
188}
189impl CSharpField {
190    pub fn new(name: &str, ty: CSharpType) -> Self {
191        CSharpField {
192            name: name.to_string(),
193            ty,
194            visibility: CSharpVisibility::Private,
195            is_static: false,
196            is_readonly: false,
197            is_const: false,
198            default_value: None,
199        }
200    }
201    pub fn emit(&self, indent: &str) -> std::string::String {
202        let mut out = std::string::String::new();
203        let mut mods = vec![format!("{}", self.visibility)];
204        if self.is_static {
205            mods.push("static".to_string());
206        }
207        if self.is_const {
208            mods.push("const".to_string());
209        }
210        if self.is_readonly {
211            mods.push("readonly".to_string());
212        }
213        if let Some(val) = &self.default_value {
214            let _ = writeln!(
215                out,
216                "{}{} {} {} = {};",
217                indent,
218                mods.join(" "),
219                self.ty,
220                self.name,
221                val
222            );
223        } else {
224            let _ = writeln!(
225                out,
226                "{}{} {} {};",
227                indent,
228                mods.join(" "),
229                self.ty,
230                self.name
231            );
232        }
233        out
234    }
235}
236/// A C# method (member function).
237#[derive(Debug, Clone, PartialEq)]
238pub struct CSharpMethod {
239    /// Method name
240    pub name: std::string::String,
241    /// Return type
242    pub return_type: CSharpType,
243    /// Parameters: `(name, type)`
244    pub params: Vec<(std::string::String, CSharpType)>,
245    /// Method body statements
246    pub body: Vec<CSharpStmt>,
247    /// Access modifier
248    pub visibility: CSharpVisibility,
249    /// `static` modifier
250    pub is_static: bool,
251    /// `async` modifier
252    pub is_async: bool,
253    /// `override` modifier
254    pub is_override: bool,
255    /// `virtual` modifier
256    pub is_virtual: bool,
257    /// `abstract` modifier (body must be empty)
258    pub is_abstract: bool,
259    /// Generic type parameters: `<T, U>`
260    pub type_params: Vec<std::string::String>,
261    /// Expression body (for `=> expr` methods)
262    pub expr_body: Option<CSharpExpr>,
263}
264impl CSharpMethod {
265    /// Create a new method with default settings (public, non-static).
266    pub fn new(name: &str, return_type: CSharpType) -> Self {
267        CSharpMethod {
268            name: name.to_string(),
269            return_type,
270            params: Vec::new(),
271            body: Vec::new(),
272            visibility: CSharpVisibility::Public,
273            is_static: false,
274            is_async: false,
275            is_override: false,
276            is_virtual: false,
277            is_abstract: false,
278            type_params: Vec::new(),
279            expr_body: None,
280        }
281    }
282    /// Emit the method as C# source code.
283    pub fn emit(&self, indent: &str) -> std::string::String {
284        let inner = format!("{}    ", indent);
285        let mut out = std::string::String::new();
286        let mut mods = vec![format!("{}", self.visibility)];
287        if self.is_static {
288            mods.push("static".to_string());
289        }
290        if self.is_async {
291            mods.push("async".to_string());
292        }
293        if self.is_abstract {
294            mods.push("abstract".to_string());
295        }
296        if self.is_override {
297            mods.push("override".to_string());
298        }
299        if self.is_virtual {
300            mods.push("virtual".to_string());
301        }
302        let type_params_str = if self.type_params.is_empty() {
303            std::string::String::new()
304        } else {
305            format!("<{}>", self.type_params.join(", "))
306        };
307        let params_str = self
308            .params
309            .iter()
310            .map(|(n, t)| format!("{} {}", t, n))
311            .collect::<Vec<_>>()
312            .join(", ");
313        let _ = write!(
314            out,
315            "{}{} {} {}{}({})",
316            indent,
317            mods.join(" "),
318            self.return_type,
319            self.name,
320            type_params_str,
321            params_str
322        );
323        if self.is_abstract {
324            let _ = writeln!(out, ";");
325            return out;
326        }
327        if let Some(expr) = &self.expr_body {
328            let _ = writeln!(out, " => {};", expr);
329            return out;
330        }
331        let _ = writeln!(out);
332        let _ = writeln!(out, "{}{{", indent);
333        emit_stmts(&self.body, &inner, &mut out);
334        let _ = writeln!(out, "{}}}", indent);
335        out
336    }
337}
338/// A complete C# compilation unit (one `.cs` file).
339#[derive(Debug, Clone)]
340pub struct CSharpModule {
341    /// The namespace for all contained types
342    pub namespace: std::string::String,
343    /// `using` directives (namespaces to import)
344    pub using_directives: Vec<std::string::String>,
345    /// Class declarations
346    pub classes: Vec<CSharpClass>,
347    /// Record declarations
348    pub records: Vec<CSharpRecord>,
349    /// Interface declarations
350    pub interfaces: Vec<CSharpInterface>,
351    /// Enum declarations
352    pub enums: Vec<CSharpEnum>,
353    /// Top-level comment / header
354    pub header_comment: Option<std::string::String>,
355    /// `#nullable enable` directive
356    pub nullable_enable: bool,
357}
358impl CSharpModule {
359    /// Create a new module with the given namespace.
360    pub fn new(namespace: &str) -> Self {
361        CSharpModule {
362            namespace: namespace.to_string(),
363            using_directives: Vec::new(),
364            classes: Vec::new(),
365            records: Vec::new(),
366            interfaces: Vec::new(),
367            enums: Vec::new(),
368            header_comment: None,
369            nullable_enable: true,
370        }
371    }
372    /// Add a using directive, deduplicating automatically.
373    pub fn add_using(&mut self, ns: &str) {
374        if !self.using_directives.iter().any(|u| u == ns) {
375            self.using_directives.push(ns.to_string());
376        }
377    }
378    /// Emit the complete C# source file as a string.
379    pub fn emit(&self) -> std::string::String {
380        let mut out = std::string::String::new();
381        if let Some(comment) = &self.header_comment {
382            for line in comment.lines() {
383                let _ = writeln!(out, "// {}", line);
384            }
385            let _ = writeln!(out);
386        }
387        if self.nullable_enable {
388            let _ = writeln!(out, "#nullable enable");
389            let _ = writeln!(out);
390        }
391        let mut usings = self.using_directives.clone();
392        usings.sort();
393        usings.dedup();
394        for u in &usings {
395            let _ = writeln!(out, "using {};", u);
396        }
397        if !usings.is_empty() {
398            let _ = writeln!(out);
399        }
400        let _ = writeln!(out, "namespace {};", self.namespace);
401        let _ = writeln!(out);
402        for e in &self.enums {
403            out.push_str(&e.emit(""));
404            let _ = writeln!(out);
405        }
406        for iface in &self.interfaces {
407            out.push_str(&iface.emit(""));
408            let _ = writeln!(out);
409        }
410        for rec in &self.records {
411            out.push_str(&rec.emit(""));
412            let _ = writeln!(out);
413        }
414        for cls in &self.classes {
415            out.push_str(&cls.emit(""));
416            let _ = writeln!(out);
417        }
418        out.push_str(CSHARP_RUNTIME);
419        out
420    }
421}
422/// A C# constructor.
423#[derive(Debug, Clone, PartialEq)]
424pub struct CSharpConstructor {
425    pub class_name: std::string::String,
426    pub params: Vec<(std::string::String, CSharpType)>,
427    pub body: Vec<CSharpStmt>,
428    pub visibility: CSharpVisibility,
429    /// `(is_base, args)` — `true` means `base(...)`, `false` means `this(...)`
430    pub base_call: Option<(bool, Vec<CSharpExpr>)>,
431}
432impl CSharpConstructor {
433    pub fn new(class_name: &str) -> Self {
434        CSharpConstructor {
435            class_name: class_name.to_string(),
436            params: Vec::new(),
437            body: Vec::new(),
438            visibility: CSharpVisibility::Public,
439            base_call: None,
440        }
441    }
442    pub fn emit(&self, indent: &str) -> std::string::String {
443        let inner = format!("{}    ", indent);
444        let mut out = std::string::String::new();
445        let params_str = self
446            .params
447            .iter()
448            .map(|(n, t)| format!("{} {}", t, n))
449            .collect::<Vec<_>>()
450            .join(", ");
451        let base_str = match &self.base_call {
452            None => std::string::String::new(),
453            Some((is_base, args)) => {
454                let kw = if *is_base { "base" } else { "this" };
455                let args_str = args
456                    .iter()
457                    .map(|a| format!("{}", a))
458                    .collect::<Vec<_>>()
459                    .join(", ");
460                format!(" : {}({})", kw, args_str)
461            }
462        };
463        let _ = writeln!(
464            out,
465            "{}{} {}({}){}",
466            indent, self.visibility, self.class_name, params_str, base_str
467        );
468        let _ = writeln!(out, "{}{{", indent);
469        emit_stmts(&self.body, &inner, &mut out);
470        let _ = writeln!(out, "{}}}", indent);
471        out
472    }
473}
474/// Part of a string interpolation `$"..."`.
475#[derive(Debug, Clone, PartialEq)]
476pub enum CSharpInterpolationPart {
477    /// Literal text segment
478    Text(std::string::String),
479    /// `{expr}` hole
480    Expr(CSharpExpr),
481    /// `{expr:format}` hole with format specifier
482    ExprFmt(CSharpExpr, std::string::String),
483}
484/// A C# class declaration.
485#[derive(Debug, Clone, PartialEq)]
486pub struct CSharpClass {
487    pub name: std::string::String,
488    /// Base class (single inheritance)
489    pub base_class: Option<std::string::String>,
490    /// Implemented interfaces
491    pub interfaces: Vec<std::string::String>,
492    /// Methods
493    pub methods: Vec<CSharpMethod>,
494    /// Properties (auto-properties and expression-body)
495    pub properties: Vec<CSharpProperty>,
496    /// Constructors
497    pub constructors: Vec<CSharpConstructor>,
498    /// `sealed` — cannot be inherited
499    pub is_sealed: bool,
500    /// `abstract` — cannot be instantiated directly
501    pub is_abstract: bool,
502    /// `static` — no instances
503    pub is_static: bool,
504    /// `partial` modifier
505    pub is_partial: bool,
506    pub visibility: CSharpVisibility,
507    pub type_params: Vec<std::string::String>,
508    /// Fields
509    pub fields: Vec<CSharpField>,
510}
511impl CSharpClass {
512    pub fn new(name: &str) -> Self {
513        CSharpClass {
514            name: name.to_string(),
515            base_class: None,
516            interfaces: Vec::new(),
517            methods: Vec::new(),
518            properties: Vec::new(),
519            constructors: Vec::new(),
520            is_sealed: false,
521            is_abstract: false,
522            is_static: false,
523            is_partial: false,
524            visibility: CSharpVisibility::Public,
525            type_params: Vec::new(),
526            fields: Vec::new(),
527        }
528    }
529    /// Emit the class as C# source code.
530    pub fn emit(&self, indent: &str) -> std::string::String {
531        let inner = format!("{}    ", indent);
532        let mut out = std::string::String::new();
533        let mut mods = vec![format!("{}", self.visibility)];
534        if self.is_static {
535            mods.push("static".to_string());
536        }
537        if self.is_sealed {
538            mods.push("sealed".to_string());
539        }
540        if self.is_abstract {
541            mods.push("abstract".to_string());
542        }
543        if self.is_partial {
544            mods.push("partial".to_string());
545        }
546        let type_params_str = if self.type_params.is_empty() {
547            std::string::String::new()
548        } else {
549            format!("<{}>", self.type_params.join(", "))
550        };
551        let mut inherits: Vec<std::string::String> = Vec::new();
552        if let Some(base) = &self.base_class {
553            inherits.push(base.clone());
554        }
555        inherits.extend(self.interfaces.iter().cloned());
556        let inherit_str = if inherits.is_empty() {
557            std::string::String::new()
558        } else {
559            format!(" : {}", inherits.join(", "))
560        };
561        let _ = writeln!(
562            out,
563            "{}{} class {}{}{}",
564            indent,
565            mods.join(" "),
566            self.name,
567            type_params_str,
568            inherit_str
569        );
570        let _ = writeln!(out, "{}{{", indent);
571        for field in &self.fields {
572            out.push_str(&field.emit(&inner));
573        }
574        for ctor in &self.constructors {
575            out.push_str(&ctor.emit(&inner));
576        }
577        for prop in &self.properties {
578            out.push_str(&prop.emit(&inner));
579        }
580        for method in &self.methods {
581            out.push_str(&method.emit(&inner));
582        }
583        let _ = writeln!(out, "{}}}", indent);
584        out
585    }
586}
587/// C# expression AST for code generation.
588#[derive(Debug, Clone, PartialEq)]
589pub enum CSharpExpr {
590    /// A literal value: `42`, `"hello"`, `true`, `null`
591    Lit(CSharpLit),
592    /// A variable or identifier: `x`, `myVar`, `MyType`
593    Var(std::string::String),
594    /// Binary operator: `lhs + rhs`, `a == b`
595    BinOp {
596        op: std::string::String,
597        lhs: Box<CSharpExpr>,
598        rhs: Box<CSharpExpr>,
599    },
600    /// Unary operator: `!x`, `-n`, `~flags`
601    UnaryOp {
602        op: std::string::String,
603        operand: Box<CSharpExpr>,
604    },
605    /// Static/free function call: `Math.Abs(x)`, `Foo(a, b)`
606    Call {
607        callee: Box<CSharpExpr>,
608        args: Vec<CSharpExpr>,
609    },
610    /// Method call on a receiver: `list.Where(pred)`
611    MethodCall {
612        receiver: Box<CSharpExpr>,
613        method: std::string::String,
614        type_args: Vec<CSharpType>,
615        args: Vec<CSharpExpr>,
616    },
617    /// Object creation: `new Foo(a, b)`
618    New {
619        ty: CSharpType,
620        args: Vec<CSharpExpr>,
621    },
622    /// Lambda / anonymous function: `x => x + 1` or `(x, y) => x + y`
623    Lambda {
624        params: Vec<(std::string::String, Option<CSharpType>)>,
625        body: Box<CSharpExpr>,
626    },
627    /// Ternary conditional: `cond ? then_expr : else_expr`
628    Ternary {
629        cond: Box<CSharpExpr>,
630        then_expr: Box<CSharpExpr>,
631        else_expr: Box<CSharpExpr>,
632    },
633    /// `null` literal (convenience alias)
634    Null,
635    /// `default(T)` or `default`
636    Default(Option<CSharpType>),
637    /// `nameof(x)` expression
638    NameOf(std::string::String),
639    /// `typeof(T)` expression
640    TypeOf(CSharpType),
641    /// `await expr`
642    Await(Box<CSharpExpr>),
643    /// `throw new Exception(msg)` as expression (C# 7+)
644    Throw(Box<CSharpExpr>),
645    /// `expr is Pattern` / `expr is Type varName`
646    Is {
647        expr: Box<CSharpExpr>,
648        pattern: std::string::String,
649    },
650    /// `expr as Type`
651    As {
652        expr: Box<CSharpExpr>,
653        ty: CSharpType,
654    },
655    /// Member access: `obj.Field`
656    Member(Box<CSharpExpr>, std::string::String),
657    /// Index access: `arr[idx]`
658    Index(Box<CSharpExpr>, Box<CSharpExpr>),
659    /// Switch expression: `expr switch { arm1, arm2, ... }`
660    SwitchExpr {
661        scrutinee: Box<CSharpExpr>,
662        arms: Vec<CSharpSwitchArm>,
663    },
664    /// String interpolation: `$"Hello {name}!"`
665    Interpolated(Vec<CSharpInterpolationPart>),
666    /// Collection expression: `[a, b, c]` (C# 12)
667    CollectionExpr(Vec<CSharpExpr>),
668}
669/// A C# auto-property or expression-body property.
670#[derive(Debug, Clone, PartialEq)]
671pub struct CSharpProperty {
672    pub name: std::string::String,
673    pub ty: CSharpType,
674    pub visibility: CSharpVisibility,
675    pub has_getter: bool,
676    pub has_setter: bool,
677    pub is_init_only: bool,
678    pub is_static: bool,
679    pub default_value: Option<CSharpExpr>,
680    /// Expression body: `public int X => 42;`
681    pub expr_body: Option<CSharpExpr>,
682}
683impl CSharpProperty {
684    pub fn new_auto(name: &str, ty: CSharpType) -> Self {
685        CSharpProperty {
686            name: name.to_string(),
687            ty,
688            visibility: CSharpVisibility::Public,
689            has_getter: true,
690            has_setter: true,
691            is_init_only: false,
692            is_static: false,
693            default_value: None,
694            expr_body: None,
695        }
696    }
697    pub fn emit(&self, indent: &str) -> std::string::String {
698        let mut out = std::string::String::new();
699        let mut mods = vec![format!("{}", self.visibility)];
700        if self.is_static {
701            mods.push("static".to_string());
702        }
703        if let Some(expr) = &self.expr_body {
704            let _ = writeln!(
705                out,
706                "{}{} {} {} => {};",
707                indent,
708                mods.join(" "),
709                self.ty,
710                self.name,
711                expr
712            );
713            return out;
714        }
715        let accessors = match (self.has_getter, self.has_setter, self.is_init_only) {
716            (true, true, false) => "{ get; set; }",
717            (true, false, false) => "{ get; }",
718            (true, _, true) => "{ get; init; }",
719            (false, true, false) => "{ set; }",
720            _ => "{ get; set; }",
721        };
722        if let Some(val) = &self.default_value {
723            let _ = writeln!(
724                out,
725                "{}{} {} {} {} = {};",
726                indent,
727                mods.join(" "),
728                self.ty,
729                self.name,
730                accessors,
731                val
732            );
733        } else {
734            let _ = writeln!(
735                out,
736                "{}{} {} {} {};",
737                indent,
738                mods.join(" "),
739                self.ty,
740                self.name,
741                accessors
742            );
743        }
744        out
745    }
746}
747/// A C# enum declaration.
748#[derive(Debug, Clone, PartialEq)]
749pub struct CSharpEnum {
750    pub name: std::string::String,
751    pub variants: Vec<(std::string::String, Option<i64>)>,
752    pub visibility: CSharpVisibility,
753    pub underlying_type: Option<CSharpType>,
754}
755impl CSharpEnum {
756    pub fn new(name: &str) -> Self {
757        CSharpEnum {
758            name: name.to_string(),
759            variants: Vec::new(),
760            visibility: CSharpVisibility::Public,
761            underlying_type: None,
762        }
763    }
764    pub fn emit(&self, indent: &str) -> std::string::String {
765        let inner = format!("{}    ", indent);
766        let mut out = std::string::String::new();
767        let base_str = match &self.underlying_type {
768            None => std::string::String::new(),
769            Some(t) => format!(" : {}", t),
770        };
771        let _ = writeln!(
772            out,
773            "{}{} enum {}{}",
774            indent, self.visibility, self.name, base_str
775        );
776        let _ = writeln!(out, "{}{{", indent);
777        for (name, val) in &self.variants {
778            if let Some(v) = val {
779                let _ = writeln!(out, "{}{} = {},", inner, name, v);
780            } else {
781                let _ = writeln!(out, "{}{},", inner, name);
782            }
783        }
784        let _ = writeln!(out, "{}}}", indent);
785        out
786    }
787}
788/// C# access modifier.
789#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
790pub enum CSharpVisibility {
791    Public,
792    Private,
793    Protected,
794    Internal,
795    ProtectedInternal,
796    PrivateProtected,
797}
798/// C# type representation for type-directed code generation.
799#[derive(Debug, Clone, PartialEq, Eq, Hash)]
800pub enum CSharpType {
801    /// `int` — 32-bit signed integer
802    Int,
803    /// `long` — 64-bit signed integer (used for Nat)
804    Long,
805    /// `double` — 64-bit IEEE 754 float
806    Double,
807    /// `float` — 32-bit IEEE 754 float
808    Float,
809    /// `bool`
810    Bool,
811    /// `string`
812    String,
813    /// `void`
814    Void,
815    /// `object`
816    Object,
817    /// `List<T>`
818    List(Box<CSharpType>),
819    /// `Dictionary<K, V>`
820    Dict(Box<CSharpType>, Box<CSharpType>),
821    /// `(T0, T1, ...)` — value tuple
822    Tuple(Vec<CSharpType>),
823    /// Named type (class, record, interface, enum, …)
824    Custom(std::string::String),
825    /// `T?` — nullable reference / value type
826    Nullable(Box<CSharpType>),
827    /// `Task<T>` — async task
828    Task(Box<CSharpType>),
829    /// `IEnumerable<T>`
830    IEnumerable(Box<CSharpType>),
831    /// `Func<T0, T1, ..., R>` — delegate type
832    Func(Vec<CSharpType>, Box<CSharpType>),
833    /// `Action<T0, T1, ...>` — void delegate
834    Action(Vec<CSharpType>),
835}
836/// C# literal values.
837#[derive(Debug, Clone, PartialEq)]
838pub enum CSharpLit {
839    /// Integer literal: `42`, `-7`
840    Int(i64),
841    /// Long literal: `42L`
842    Long(i64),
843    /// Boolean literal: `true` / `false`
844    Bool(bool),
845    /// String literal: `"hello"`
846    Str(std::string::String),
847    /// `null` literal
848    Null,
849    /// Float literal: `3.14f`
850    Float(f64),
851    /// Double literal: `3.14`
852    Double(f64),
853    /// Character literal: `'x'`
854    Char(char),
855}
856/// A `catch` clause in a `try`/`catch` block.
857#[derive(Debug, Clone, PartialEq)]
858pub struct CSharpCatchClause {
859    /// Exception type (e.g. `Exception`, `InvalidOperationException`)
860    pub exception_type: CSharpType,
861    /// Bound name for the exception variable
862    pub var_name: std::string::String,
863    /// Body statements
864    pub stmts: Vec<CSharpStmt>,
865}
866/// A C# record (C# 9+).
867/// `public record Foo(int X, string Y);`
868#[derive(Debug, Clone, PartialEq)]
869pub struct CSharpRecord {
870    pub name: std::string::String,
871    /// Positional parameters (primary constructor parameters)
872    pub fields: Vec<(std::string::String, CSharpType)>,
873    /// Additional methods
874    pub methods: Vec<CSharpMethod>,
875    /// `readonly` record (record struct)
876    pub is_readonly: bool,
877    /// `sealed` modifier
878    pub is_sealed: bool,
879    /// Base record to inherit from
880    pub base_record: Option<std::string::String>,
881    /// Implemented interfaces
882    pub interfaces: Vec<std::string::String>,
883    pub visibility: CSharpVisibility,
884}
885impl CSharpRecord {
886    pub fn new(name: &str) -> Self {
887        CSharpRecord {
888            name: name.to_string(),
889            fields: Vec::new(),
890            methods: Vec::new(),
891            is_readonly: false,
892            is_sealed: false,
893            base_record: None,
894            interfaces: Vec::new(),
895            visibility: CSharpVisibility::Public,
896        }
897    }
898    /// Emit the record as C# source code.
899    pub fn emit(&self, indent: &str) -> std::string::String {
900        let inner = format!("{}    ", indent);
901        let mut out = std::string::String::new();
902        let mut mods = vec![format!("{}", self.visibility)];
903        if self.is_sealed {
904            mods.push("sealed".to_string());
905        }
906        if self.is_readonly {
907            mods.push("readonly".to_string());
908        }
909        let fields_str = self
910            .fields
911            .iter()
912            .map(|(n, t)| format!("{} {}", t, n))
913            .collect::<Vec<_>>()
914            .join(", ");
915        let mut inherits: Vec<std::string::String> = Vec::new();
916        if let Some(base) = &self.base_record {
917            inherits.push(base.clone());
918        }
919        inherits.extend(self.interfaces.iter().cloned());
920        let inherit_str = if inherits.is_empty() {
921            std::string::String::new()
922        } else {
923            format!(" : {}", inherits.join(", "))
924        };
925        let record_kw = if self.is_readonly {
926            "record struct"
927        } else {
928            "record"
929        };
930        if self.methods.is_empty() {
931            let _ = writeln!(
932                out,
933                "{}{} {} {}({}){}",
934                indent,
935                mods.join(" "),
936                record_kw,
937                self.name,
938                fields_str,
939                inherit_str
940            );
941            if out.ends_with('\n') {
942                out.pop();
943                out.push(';');
944                out.push('\n');
945            }
946        } else {
947            let _ = writeln!(
948                out,
949                "{}{} {} {}({}){}",
950                indent,
951                mods.join(" "),
952                record_kw,
953                self.name,
954                fields_str,
955                inherit_str
956            );
957            let _ = writeln!(out, "{}{{", indent);
958            for method in &self.methods {
959                out.push_str(&method.emit(&inner));
960            }
961            let _ = writeln!(out, "{}}}", indent);
962        }
963        out
964    }
965}
966/// C# code generation backend for OxiLean.
967///
968/// Transforms LCNF declarations into idiomatic C# 12 source code.
969pub struct CSharpBackend {
970    /// Whether to emit `public` visibility on generated declarations
971    pub emit_public: bool,
972    /// Whether to emit XML doc comments
973    pub emit_comments: bool,
974    /// Counter for fresh variable names
975    pub(super) var_counter: u64,
976    /// Whether to prefer async method generation
977    pub prefer_async: bool,
978}
979impl CSharpBackend {
980    /// Create a new backend with default settings.
981    pub fn new() -> Self {
982        CSharpBackend {
983            emit_public: true,
984            emit_comments: true,
985            var_counter: 0,
986            prefer_async: false,
987        }
988    }
989    /// Generate a fresh local variable name.
990    pub fn fresh_var(&mut self) -> std::string::String {
991        let n = self.var_counter;
992        self.var_counter += 1;
993        format!("_cs{}", n)
994    }
995    /// Mangle an LCNF name into a valid C# identifier.
996    pub fn mangle_name(name: &str) -> std::string::String {
997        if name.is_empty() {
998            return "ox_empty".to_string();
999        }
1000        let mangled: std::string::String = name
1001            .chars()
1002            .map(|c| {
1003                if c.is_alphanumeric() || c == '_' {
1004                    c
1005                } else {
1006                    '_'
1007                }
1008            })
1009            .collect();
1010        if mangled
1011            .chars()
1012            .next()
1013            .map(|c| c.is_ascii_digit())
1014            .unwrap_or(false)
1015            || is_csharp_keyword(&mangled)
1016        {
1017            format!("ox_{}", mangled)
1018        } else {
1019            mangled
1020        }
1021    }
1022    /// Compile a single LCNF function declaration into a C# method.
1023    pub fn compile_decl(&self, decl: &LcnfFunDecl) -> CSharpMethod {
1024        let ret_ty = lcnf_type_to_csharp(&decl.ret_type);
1025        let mut method = CSharpMethod::new(&Self::mangle_name(&decl.name), ret_ty);
1026        method.visibility = if self.emit_public {
1027            CSharpVisibility::Public
1028        } else {
1029            CSharpVisibility::Private
1030        };
1031        method.is_static = true;
1032        for param in &decl.params {
1033            if param.erased {
1034                continue;
1035            }
1036            let param_ty = lcnf_type_to_csharp(&param.ty);
1037            let param_name = format!("_x{}", param.id.0);
1038            method.params.push((param_name, param_ty));
1039        }
1040        let mut stmts: Vec<CSharpStmt> = Vec::new();
1041        let result = self.compile_expr_to_stmts(&decl.body, &mut stmts);
1042        stmts.push(CSharpStmt::Return(Some(result)));
1043        method.body = stmts;
1044        method
1045    }
1046    /// Compile an LCNF expression, appending any needed statements to `stmts`,
1047    /// and returning a C# expression that yields the final value.
1048    pub(super) fn compile_expr_to_stmts(
1049        &self,
1050        expr: &LcnfExpr,
1051        stmts: &mut Vec<CSharpStmt>,
1052    ) -> CSharpExpr {
1053        match expr {
1054            LcnfExpr::Return(arg) => self.compile_arg(arg),
1055            LcnfExpr::Unreachable => CSharpExpr::Throw(Box::new(CSharpExpr::New {
1056                ty: CSharpType::Custom("InvalidOperationException".to_string()),
1057                args: vec![CSharpExpr::Lit(CSharpLit::Str(
1058                    "OxiLean: unreachable code reached".to_string(),
1059                ))],
1060            })),
1061            LcnfExpr::TailCall(func, args) => {
1062                let callee = self.compile_arg(func);
1063                let cs_args: Vec<CSharpExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1064                CSharpExpr::Call {
1065                    callee: Box::new(callee),
1066                    args: cs_args,
1067                }
1068            }
1069            LcnfExpr::Let {
1070                id, value, body, ..
1071            } => {
1072                let val_expr = self.compile_let_value(value);
1073                let var_name = format!("_x{}", id.0);
1074                stmts.push(CSharpStmt::LocalVar {
1075                    name: var_name,
1076                    ty: None,
1077                    init: Some(val_expr),
1078                    is_const: false,
1079                });
1080                self.compile_expr_to_stmts(body, stmts)
1081            }
1082            LcnfExpr::Case {
1083                scrutinee,
1084                alts,
1085                default,
1086                ..
1087            } => {
1088                let scrutinee_expr = CSharpExpr::Var(format!("_x{}", scrutinee.0));
1089                let tag_expr =
1090                    CSharpExpr::Member(Box::new(scrutinee_expr.clone()), "Tag".to_string());
1091                let result_var = format!("_cs_case{}", stmts.len());
1092                stmts.push(CSharpStmt::LocalVar {
1093                    name: result_var.clone(),
1094                    ty: Some(CSharpType::Object),
1095                    init: Some(CSharpExpr::Null),
1096                    is_const: false,
1097                });
1098                let mut cases: Vec<CSharpSwitchCase> = Vec::new();
1099                for alt in alts {
1100                    let mut branch_stmts: Vec<CSharpStmt> = Vec::new();
1101                    for (field_idx, param) in alt.params.iter().enumerate() {
1102                        if param.erased {
1103                            continue;
1104                        }
1105                        let field_access = CSharpExpr::Member(
1106                            Box::new(scrutinee_expr.clone()),
1107                            format!("Field{}", field_idx),
1108                        );
1109                        branch_stmts.push(CSharpStmt::LocalVar {
1110                            name: format!("_x{}", param.id.0),
1111                            ty: Some(lcnf_type_to_csharp(&param.ty)),
1112                            init: Some(field_access),
1113                            is_const: false,
1114                        });
1115                    }
1116                    let branch_result = self.compile_expr_to_stmts(&alt.body, &mut branch_stmts);
1117                    branch_stmts.push(CSharpStmt::Assign {
1118                        target: CSharpExpr::Var(result_var.clone()),
1119                        value: branch_result,
1120                    });
1121                    branch_stmts.push(CSharpStmt::Break);
1122                    cases.push(CSharpSwitchCase {
1123                        label: format!("{}", alt.ctor_tag),
1124                        stmts: branch_stmts,
1125                    });
1126                }
1127                let mut default_stmts: Vec<CSharpStmt> = Vec::new();
1128                if let Some(def) = default {
1129                    let def_result = self.compile_expr_to_stmts(def, &mut default_stmts);
1130                    default_stmts.push(CSharpStmt::Assign {
1131                        target: CSharpExpr::Var(result_var.clone()),
1132                        value: def_result,
1133                    });
1134                } else {
1135                    default_stmts.push(CSharpStmt::Throw(CSharpExpr::New {
1136                        ty: CSharpType::Custom("InvalidOperationException".to_string()),
1137                        args: vec![CSharpExpr::Lit(CSharpLit::Str(
1138                            "OxiLean: unreachable case".to_string(),
1139                        ))],
1140                    }));
1141                }
1142                stmts.push(CSharpStmt::Switch {
1143                    expr: tag_expr,
1144                    cases,
1145                    default: default_stmts,
1146                });
1147                CSharpExpr::Var(result_var)
1148            }
1149        }
1150    }
1151    /// Compile an LCNF let-value to a C# expression.
1152    pub(super) fn compile_let_value(&self, value: &LcnfLetValue) -> CSharpExpr {
1153        match value {
1154            LcnfLetValue::Lit(lit) => self.compile_lit(lit),
1155            LcnfLetValue::Erased => CSharpExpr::Null,
1156            LcnfLetValue::FVar(id) => CSharpExpr::Var(format!("_x{}", id.0)),
1157            LcnfLetValue::App(func, args) => {
1158                let callee = self.compile_arg(func);
1159                let cs_args: Vec<CSharpExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1160                CSharpExpr::Call {
1161                    callee: Box::new(callee),
1162                    args: cs_args,
1163                }
1164            }
1165            LcnfLetValue::Proj(_name, idx, var) => {
1166                let base = CSharpExpr::Var(format!("_x{}", var.0));
1167                CSharpExpr::Member(Box::new(base), format!("Field{}", idx))
1168            }
1169            LcnfLetValue::Ctor(name, _tag, args) => {
1170                let ctor_name = Self::mangle_name(name);
1171                let cs_args: Vec<CSharpExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1172                CSharpExpr::New {
1173                    ty: CSharpType::Custom(ctor_name),
1174                    args: cs_args,
1175                }
1176            }
1177            LcnfLetValue::Reset(_var) => CSharpExpr::Null,
1178            LcnfLetValue::Reuse(_slot, name, _tag, args) => {
1179                let ctor_name = Self::mangle_name(name);
1180                let cs_args: Vec<CSharpExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1181                CSharpExpr::New {
1182                    ty: CSharpType::Custom(ctor_name),
1183                    args: cs_args,
1184                }
1185            }
1186        }
1187    }
1188    /// Compile an LCNF argument to a C# expression.
1189    pub(super) fn compile_arg(&self, arg: &LcnfArg) -> CSharpExpr {
1190        match arg {
1191            LcnfArg::Var(id) => CSharpExpr::Var(format!("_x{}", id.0)),
1192            LcnfArg::Lit(lit) => self.compile_lit(lit),
1193            LcnfArg::Erased => CSharpExpr::Null,
1194            LcnfArg::Type(_) => CSharpExpr::Null,
1195        }
1196    }
1197    /// Compile an LCNF literal to a C# expression.
1198    pub(super) fn compile_lit(&self, lit: &LcnfLit) -> CSharpExpr {
1199        match lit {
1200            LcnfLit::Nat(n) => CSharpExpr::Lit(CSharpLit::Long(*n as i64)),
1201            LcnfLit::Str(s) => CSharpExpr::Lit(CSharpLit::Str(s.clone())),
1202        }
1203    }
1204    /// Compile a complete list of LCNF declarations into a `CSharpModule`.
1205    pub fn emit_module(&self, namespace: &str, decls: &[LcnfFunDecl]) -> CSharpModule {
1206        let mut module = CSharpModule::new(namespace);
1207        module.header_comment = Some(format!(
1208            "OxiLean-generated C# module: {}\nGenerated by OxiLean CSharpBackend",
1209            namespace
1210        ));
1211        module.add_using("System");
1212        module.add_using("System.Collections.Generic");
1213        module.add_using("System.Linq");
1214        module.add_using("System.Threading.Tasks");
1215        let mut runtime_class = CSharpClass::new("OxiLeanRuntime");
1216        runtime_class.is_static = true;
1217        runtime_class.visibility = CSharpVisibility::Internal;
1218        for decl in decls {
1219            let method = self.compile_decl(decl);
1220            runtime_class.methods.push(method);
1221        }
1222        module.classes.push(runtime_class);
1223        module
1224    }
1225}
1226/// One arm in a `switch` expression.
1227#[derive(Debug, Clone, PartialEq)]
1228pub struct CSharpSwitchArm {
1229    /// Pattern string (e.g. `Foo(var a, var b)`, `> 0`, `_`)
1230    pub pattern: std::string::String,
1231    /// Optional guard: `when condition`
1232    pub guard: Option<CSharpExpr>,
1233    /// Result expression
1234    pub body: CSharpExpr,
1235}