Skip to main content

zerodds_corba_rust/
emitter.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! Top-Level-Emitter: AST → CORBA-Rust-Code.
4
5use std::collections::HashMap;
6
7use zerodds_idl::ast::types::{Definition, InterfaceDef, Specification};
8
9use crate::error::Result;
10
11/// Registry aller Interface-Definitionen indiziert nach Simple-Namen.
12/// Wird vor dem eigentlichen Emit aufgebaut, damit Stubs `impl Base for
13/// DerivedStub`-Bloecke fuer alle transitiven Basen emittieren koennen.
14pub(crate) type InterfaceRegistry<'a> = HashMap<String, &'a InterfaceDef>;
15
16/// Optionen fuer den CORBA-Codegen.
17#[derive(Debug, Clone, Default)]
18pub struct CorbaRustGenOptions {
19    /// Header-Kommentar oben in der erzeugten Datei. Wird verbatim
20    /// uebernommen.
21    pub header_comment: Option<String>,
22}
23
24/// Erzeugt aus einer geparsten IDL-Spec ein einzelnes Rust-Modul-File
25/// mit CORBA-Service-Konstrukten (Interface-Stubs/Skeletons +
26/// Valuetypes).
27///
28/// # Errors
29/// `Unsupported` fuer IDL-Konstrukte ausserhalb des Service-Scopes.
30pub fn generate_corba_rust_module(
31    spec: &Specification,
32    opts: &CorbaRustGenOptions,
33) -> Result<String> {
34    let mut out = String::new();
35    out.push_str("// SPDX-License-Identifier: Apache-2.0\n");
36    if let Some(c) = &opts.header_comment {
37        for line in c.lines() {
38            out.push_str("// ");
39            out.push_str(line);
40            out.push('\n');
41        }
42    }
43    out.push_str("// Auto-generated by `zerodds-corba-rust`. Do not edit by hand.\n\n");
44    out.push_str("#![allow(clippy::too_many_lines)]\n");
45    out.push_str("#![allow(unused_imports, unused_variables)]\n\n");
46
47    let mut registry: InterfaceRegistry<'_> = HashMap::new();
48    collect_interfaces(spec, &mut registry);
49
50    for def in &spec.definitions {
51        emit_definition(&mut out, def, &registry)?;
52    }
53    Ok(out)
54}
55
56/// zerodds-lint: recursion-depth 16
57fn collect_interfaces<'a>(spec: &'a Specification, reg: &mut InterfaceRegistry<'a>) {
58    for def in &spec.definitions {
59        collect_from_def(def, reg);
60    }
61}
62
63/// zerodds-lint: recursion-depth 16
64fn collect_from_def<'a>(def: &'a Definition, reg: &mut InterfaceRegistry<'a>) {
65    use zerodds_idl::ast::types::InterfaceDcl;
66    match def {
67        Definition::Interface(InterfaceDcl::Def(d)) => {
68            reg.insert(d.name.text.clone(), d);
69        }
70        Definition::Module(m) => {
71            for inner in &m.definitions {
72                collect_from_def(inner, reg);
73            }
74        }
75        _ => {}
76    }
77}
78
79/// zerodds-lint: recursion-depth 16
80/// IDL-Modul-Schachtelung — 16 Ebenen reichen fuer alle bekannten
81/// OMG-Spec-IDL-Files.
82fn emit_definition(
83    out: &mut String,
84    def: &Definition,
85    registry: &InterfaceRegistry<'_>,
86) -> Result<()> {
87    match def {
88        Definition::Module(m) => emit_module(out, m, registry)?,
89        Definition::Interface(i_dcl) => {
90            use zerodds_idl::ast::types::InterfaceDcl;
91            match i_dcl {
92                InterfaceDcl::Def(def) => {
93                    crate::interface_emit::emit_interface(out, def, registry)?;
94                    out.push('\n');
95                }
96                InterfaceDcl::Forward(_) => {}
97            }
98        }
99        Definition::ValueDef(v) => {
100            crate::valuetype_emit::emit_valuetype(out, v)?;
101            out.push('\n');
102        }
103        Definition::Component(c) => {
104            crate::component_emit::emit_component(out, c)?;
105            out.push('\n');
106        }
107        Definition::Home(h) => {
108            crate::component_emit::emit_home(out, h)?;
109            out.push('\n');
110        }
111        // ValueBox/ValueForward: Phase-2.
112        // Type/Const/Except sind im idl-rust-DataType-Pfad.
113        _ => {}
114    }
115    Ok(())
116}
117
118/// zerodds-lint: recursion-depth 16
119fn emit_module(
120    out: &mut String,
121    m: &zerodds_idl::ast::types::ModuleDef,
122    registry: &InterfaceRegistry<'_>,
123) -> Result<()> {
124    out.push_str("pub mod ");
125    out.push_str(&m.name.text);
126    out.push_str(" {\n");
127    for inner in &m.definitions {
128        let mut inner_out = String::new();
129        emit_definition(&mut inner_out, inner, registry)?;
130        for line in inner_out.lines() {
131            if line.is_empty() {
132                out.push('\n');
133            } else {
134                out.push_str("    ");
135                out.push_str(line);
136                out.push('\n');
137            }
138        }
139    }
140    out.push_str("}\n\n");
141    Ok(())
142}