witx_codegen/cpp/
mod.rs

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        //         w.write_lines(format!(
50        //             "namespace {} {{
51        // using namespace WitxCodegenHeader;",
52        //             &module_name.as_namespace()
53        //         ))?;
54
55        //         for r in   module_witx.resources() {
56        //             w.write_line(format!("using namespace {};",r.resource_id.name.as_str()))?;
57        //         }
58
59        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, /* &module_name, */ func.as_ref())?;
84        }
85
86        // w.write_line("}")?;
87
88        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            // w.write_line(format!("use super::{};", name.as_type()))?;
151            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("#[allow(non_snake_case)]")?;
219        w.write_line(format!("namespace {} {{", type_name.as_const()))?;
220        {
221            let mut w = w.new_block();
222            // w.write_line(format!("using {};", type_name.as_type()))?;
223
224            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}