zerodds_corba_rust/
emitter.rs1use std::collections::{BTreeMap, HashMap};
6
7use zerodds_idl::ast::types::{Definition, Export, InterfaceDcl, InterfaceDef, Specification};
8
9use crate::error::Result;
10
11fn collect_exception_repo_ids(spec: &Specification) -> BTreeMap<String, String> {
16 let mut prefixes: BTreeMap<String, String> = BTreeMap::new();
17 collect_prefixes(&spec.definitions, &mut prefixes);
18 let mut out = BTreeMap::new();
19 let mut path: Vec<String> = Vec::new();
20 walk_exceptions(&spec.definitions, &mut path, &prefixes, &mut out);
21 out
22}
23
24fn collect_prefixes(defs: &[Definition], prefixes: &mut BTreeMap<String, String>) {
28 for d in defs {
29 match d {
30 Definition::TypePrefix(tp) => {
31 if let Some(last) = tp.target.parts.last() {
32 prefixes.insert(last.text.clone(), tp.prefix.clone());
33 }
34 }
35 Definition::Module(m) => collect_prefixes(&m.definitions, prefixes),
36 _ => {}
37 }
38 }
39}
40
41fn rid_for(path: &[String], name: &str) -> String {
42 let parts: Vec<&str> = path.iter().map(String::as_str).collect();
43 zerodds_corba_codegen::build_repository_id(&parts, name, 1, 0)
44}
45
46fn walk_exceptions(
48 defs: &[Definition],
49 path: &mut Vec<String>,
50 prefixes: &BTreeMap<String, String>,
51 out: &mut BTreeMap<String, String>,
52) {
53 for d in defs {
54 match d {
55 Definition::Except(e) => {
56 out.insert(e.name.text.clone(), rid_for(path, &e.name.text));
57 }
58 Definition::Module(m) => {
59 let mut pushed = 0;
60 if let Some(p) = prefixes.get(&m.name.text) {
62 for seg in p.split('/').filter(|s| !s.is_empty()) {
63 path.push(seg.to_string());
64 pushed += 1;
65 }
66 }
67 path.push(m.name.text.clone());
68 pushed += 1;
69 walk_exceptions(&m.definitions, path, prefixes, out);
70 for _ in 0..pushed {
71 path.pop();
72 }
73 }
74 Definition::Interface(InterfaceDcl::Def(i)) => {
75 path.push(i.name.text.clone());
76 for ex in &i.exports {
77 if let Export::Except(e) = ex {
78 out.insert(e.name.text.clone(), rid_for(path, &e.name.text));
79 }
80 }
81 path.pop();
82 }
83 _ => {}
84 }
85 }
86}
87
88pub(crate) type InterfaceRegistry<'a> = HashMap<String, &'a InterfaceDef>;
92
93#[derive(Debug, Clone, Default)]
95pub struct CorbaRustGenOptions {
96 pub header_comment: Option<String>,
99}
100
101pub fn generate_corba_rust_module(
107 spec: &Specification,
108 opts: &CorbaRustGenOptions,
109) -> Result<String> {
110 zerodds_idl_rust::type_map::set_any_target_corba(true);
112 let mut out = String::new();
113 out.push_str("// SPDX-License-Identifier: Apache-2.0\n");
114 if let Some(c) = &opts.header_comment {
115 for line in c.lines() {
116 out.push_str("// ");
117 out.push_str(line);
118 out.push('\n');
119 }
120 }
121 out.push_str("// Auto-generated by `zerodds-corba-rust`. Do not edit by hand.\n\n");
122 out.push_str("#![allow(clippy::too_many_lines)]\n");
123 out.push_str("#![allow(unused_imports, unused_variables)]\n\n");
124
125 let mut registry: InterfaceRegistry<'_> = HashMap::new();
126 collect_interfaces(spec, &mut registry);
127 zerodds_idl_rust::type_map::set_interface_refs(registry.keys().cloned());
130 crate::interface_emit::set_exception_repo_ids(collect_exception_repo_ids(spec));
133
134 crate::valuetype_emit::register_value_states(spec)?;
136
137 for def in &spec.definitions {
138 emit_definition(&mut out, def, ®istry, &[])?;
139 }
140 Ok(out)
141}
142
143fn collect_interfaces<'a>(spec: &'a Specification, reg: &mut InterfaceRegistry<'a>) {
145 for def in &spec.definitions {
146 collect_from_def(def, reg);
147 }
148}
149
150fn collect_from_def<'a>(def: &'a Definition, reg: &mut InterfaceRegistry<'a>) {
152 use zerodds_idl::ast::types::InterfaceDcl;
153 match def {
154 Definition::Interface(InterfaceDcl::Def(d)) => {
155 reg.insert(d.name.text.clone(), d);
156 }
157 Definition::Module(m) => {
158 for inner in &m.definitions {
159 collect_from_def(inner, reg);
160 }
161 }
162 _ => {}
163 }
164}
165
166fn emit_definition(
170 out: &mut String,
171 def: &Definition,
172 registry: &InterfaceRegistry<'_>,
173 scope: &[&str],
174) -> Result<()> {
175 match def {
176 Definition::Module(m) => emit_module(out, m, registry, scope)?,
177 Definition::Interface(i_dcl) => {
178 use zerodds_idl::ast::types::InterfaceDcl;
179 match i_dcl {
180 InterfaceDcl::Def(def) => {
181 crate::interface_emit::emit_interface(out, def, registry)?;
182 out.push('\n');
183 }
184 InterfaceDcl::Forward(_) => {}
185 }
186 }
187 Definition::ValueDef(v) => {
188 crate::valuetype_emit::emit_valuetype(out, v, scope)?;
189 out.push('\n');
190 }
191 Definition::Component(c) => {
192 crate::component_emit::emit_component(out, c)?;
193 out.push('\n');
194 }
195 Definition::Home(h) => {
196 crate::component_emit::emit_home(out, h)?;
197 out.push('\n');
198 }
199 _ => {}
202 }
203 Ok(())
204}
205
206fn emit_module(
208 out: &mut String,
209 m: &zerodds_idl::ast::types::ModuleDef,
210 registry: &InterfaceRegistry<'_>,
211 scope: &[&str],
212) -> Result<()> {
213 out.push_str("pub mod ");
214 out.push_str(&m.name.text);
215 out.push_str(" {\n");
216 let mut child_scope: Vec<&str> = scope.to_vec();
217 child_scope.push(&m.name.text);
218 for inner in &m.definitions {
219 let mut inner_out = String::new();
220 emit_definition(&mut inner_out, inner, registry, &child_scope)?;
221 for line in inner_out.lines() {
222 if line.is_empty() {
223 out.push('\n');
224 } else {
225 out.push_str(" ");
226 out.push_str(line);
227 out.push('\n');
228 }
229 }
230 }
231 out.push_str("}\n\n");
232 Ok(())
233}