1mod common;
2mod function;
3mod header;
4mod r#struct;
5mod tuple;
6mod union;
7
8use super::*;
9use crate::astype::*;
10use crate::error::*;
11use crate::pretty_writer::PrettyWriter;
12use common::*;
13use std::io::Write;
14
15pub struct CppGenerator {
16 module_name: Option<String>,
17}
18
19impl CppGenerator {
20 pub fn new(module_name: Option<String>) -> Self {
21 CppGenerator { module_name }
22 }
23}
24
25impl<T: Write> Generator<T> for CppGenerator {
26 fn generate(
27 &self,
28 writer: &mut T,
29 module_witx: witx::Module,
30 options: &Options,
31 ) -> Result<(), Error> {
32 let mut w = PrettyWriter::new(writer, " ");
33 let module_name = match &self.module_name {
34 None => module_witx.name().as_str().to_string(),
35 Some(module_name) => module_name.to_string(),
36 };
37 let module_id = module_witx.module_id();
38 let skip_imports = options.skip_imports;
39
40 if !options.skip_header {
41 Self::header(&mut w)?;
42 }
43
44 let module_title_comments = format!(
45 "---------------------- Module: [{}] ----------------------",
46 module_name
47 );
48
49 Self::write_comments(&mut w, &module_title_comments)?;
60 w.eob()?;
61
62 for type_ in module_witx.typenames() {
63 if skip_imports && &type_.module != module_id {
64 continue;
65 }
66 let constants_for_type: Vec<_> = module_witx
67 .constants()
68 .filter_map(|x| {
69 if x.ty == type_.name {
70 Some(ASConstant {
71 name: x.name.as_str().to_string(),
72 value: x.value,
73 })
74 } else {
75 None
76 }
77 })
78 .collect();
79 Self::define_type(&mut w, type_.as_ref(), &constants_for_type)?;
80 }
81
82 for func in module_witx.funcs() {
83 Self::define_func(&mut w, func.as_ref())?;
84 }
85
86 Ok(())
89 }
90}
91
92impl CppGenerator {
93 fn write_docs<T: Write>(w: &mut PrettyWriter<T>, docs: &str) -> Result<(), Error> {
94 if docs.is_empty() {
95 return Ok(());
96 }
97 w.write_line("/**")?;
98 for docs_line in docs.lines() {
99 w.write_line(format!("* {}", docs_line))?;
100 }
101 w.write_line("**/")?;
102 Ok(())
103 }
104
105 fn write_comments<T: Write>(w: &mut PrettyWriter<T>, docs: &str) -> Result<(), Error> {
106 if docs.is_empty() {
107 return Ok(());
108 }
109 for docs_line in docs.lines() {
110 w.write_line(format!("// {}", docs_line))?;
111 }
112 Ok(())
113 }
114
115 fn define_as_alias<T: Write>(
116 w: &mut PrettyWriter<T>,
117 name: &str,
118 other_type: &ASType,
119 ) -> Result<(), Error> {
120 w.write_line(format!(
121 "using {} = {};",
122 name.as_type(),
123 other_type.as_lang()
124 ))?;
125 Ok(())
126 }
127
128 fn define_as_atom<T: Write>(
129 w: &mut PrettyWriter<T>,
130 name: &str,
131 type_: &ASType,
132 ) -> Result<(), Error> {
133 w.write_line(format!("using {} = {};", name.as_type(), type_.as_lang()))?;
134 Ok(())
135 }
136
137 fn define_as_enum<T: Write>(
138 w: &mut PrettyWriter<T>,
139 name: &str,
140 enum_: &ASEnum,
141 ) -> Result<(), Error> {
142 let repr = enum_.repr.as_ref();
143 w.write_line(format!(
144 "enum class {} : {} {{",
145 name.as_type(),
146 repr.as_lang()
147 ))?;
148 {
149 let mut w = w.new_block();
150 for choice in &enum_.choices {
152 w.write_line(format!("{} = {},", choice.name.as_const(), choice.value))?;
153 }
154 }
155 w.write_line("};")?;
156 Ok(())
157 }
158
159 fn define_as_constants<T: Write>(
160 w: &mut PrettyWriter<T>,
161 name: &str,
162 constants: &ASConstants,
163 ) -> Result<(), Error> {
164 let repr = constants.repr.as_ref();
165 w.write_line(format!("using {} = {};", name.as_type(), repr.as_lang()))?;
166 w.eob()?;
167 Self::define_constants_for_type(w, name, &constants.constants)?;
168 Ok(())
169 }
170
171 fn define_as_type<T: Write>(
172 w: &mut PrettyWriter<T>,
173 name: &str,
174 type_: &ASType,
175 ) -> Result<(), Error> {
176 match type_ {
177 ASType::Alias(_)
178 | ASType::Bool
179 | ASType::Char8
180 | ASType::Char32
181 | ASType::F32
182 | ASType::F64
183 | ASType::U8
184 | ASType::U16
185 | ASType::U32
186 | ASType::U64
187 | ASType::S8
188 | ASType::S16
189 | ASType::S32
190 | ASType::S64
191 | ASType::USize
192 | ASType::Handle(_)
193 | ASType::Slice(_)
194 | ASType::String(_)
195 | ASType::ReadBuffer(_)
196 | ASType::WriteBuffer(_) => Self::define_as_atom(w, name, type_)?,
197 ASType::Enum(enum_) => Self::define_as_enum(w, name, enum_)?,
198 ASType::Union(union_) => Self::define_as_union(w, name, union_)?,
199 ASType::Constants(constants) => Self::define_as_constants(w, name, constants)?,
200 ASType::Tuple(members) => Self::define_as_tuple(w, name, members)?,
201 ASType::Struct(members) => Self::define_as_struct(w, name, members)?,
202 _ => {
203 dbg!(type_);
204 unimplemented!();
205 }
206 }
207 Ok(())
208 }
209
210 fn define_constants_for_type<T: Write>(
211 w: &mut PrettyWriter<T>,
212 type_name: &str,
213 constants: &[ASConstant],
214 ) -> Result<(), Error> {
215 if constants.is_empty() {
216 return Ok(());
217 }
218 w.write_line(format!("namespace {} {{", type_name.as_const()))?;
220 {
221 let mut w = w.new_block();
222 let mut hex = false;
225 let mut single_bits: usize = 0;
226 for constant in constants {
227 if constant.value > 0xffff {
228 hex = true;
229 }
230 if constant.value.count_ones() == 1 {
231 single_bits += 1;
232 }
233 }
234 if constants.len() > 2 && single_bits == constants.len() {
235 hex = true;
236 }
237 for constant in constants {
238 let value_s = if hex {
239 format!("0x{:x}", constant.value)
240 } else {
241 format!("{}", constant.value)
242 };
243 w.write_line(format!(
244 "const {} {} = {};",
245 type_name.as_type(),
246 constant.name.as_const(),
247 value_s
248 ))?;
249 }
250 }
251 w.write_line("}")?;
252 w.eob()?;
253 Ok(())
254 }
255
256 fn define_type<T: Write>(
257 w: &mut PrettyWriter<T>,
258 type_witx: &witx::NamedType,
259 constants: &[ASConstant],
260 ) -> Result<(), Error> {
261 let docs = &type_witx.docs;
262 if !docs.is_empty() {
263 Self::write_docs(w, docs)?;
264 }
265 let type_name = type_witx.name.as_str();
266 let tref = &type_witx.tref;
267 match tref {
268 witx::TypeRef::Name(other_type) => {
269 Self::define_as_alias(w, type_name, &ASType::from(&other_type.tref))?
270 }
271 witx::TypeRef::Value(type_witx) => {
272 let t = ASType::from(type_witx.as_ref());
273 Self::define_as_type(w, type_name, &t)?
274 }
275 }
276 w.eob()?;
277 Self::define_constants_for_type(w, type_name, constants)?;
278 Ok(())
279 }
280}