Skip to main content

microcom_codegen/
cpp.rs

1//! C++ header generator (same output shape as MicroCom's C++ generator).
2
3use std::fmt::Write;
4
5use crate::ast::*;
6
7/// IDL type name -> C++ spelling.
8fn cpp_type_name(name: &str) -> &str {
9    match name {
10        "uint" => "unsigned int",
11        "byte" => "unsigned char",
12        other => other,
13    }
14}
15
16fn cpp_type(ty: &TypeRef, is_const: bool) -> String {
17    let mut s = String::new();
18    if is_const {
19        s.push_str("const ");
20    }
21    s.push_str(cpp_type_name(&ty.name));
22    for _ in 0..ty.pointers {
23        s.push('*');
24    }
25    if ty.reference {
26        s.push('&');
27    }
28    s
29}
30
31/// Splits `809c652e-7396-11d2-9771-00a0c9b4d50c` into the eleven
32/// `COMINTERFACE` macro arguments.
33fn uuid_macro_args(uuid: &str) -> Result<String, String> {
34    let hex: String = uuid.chars().filter(|c| *c != '-').collect();
35    if hex.len() != 32 || !hex.chars().all(|c| c.is_ascii_hexdigit()) {
36        return Err(format!("invalid uuid '{uuid}'"));
37    }
38    let mut parts = vec![hex[0..8].to_string(), hex[8..12].to_string(), hex[12..16].to_string()];
39    for i in 0..8 {
40        parts.push(hex[16 + i * 2..18 + i * 2].to_string());
41    }
42    Ok(parts.join(", "))
43}
44
45pub fn generate(idl: &Idl) -> Result<String, String> {
46    let mut out = String::new();
47    let w = &mut out;
48
49    if let Some(preamble) = idl.directive("cpp-preamble") {
50        writeln!(w, "{preamble}").unwrap();
51    }
52
53    for s in &idl.structs {
54        writeln!(w, "struct {};", s.name).unwrap();
55    }
56    for i in &idl.interfaces {
57        writeln!(w, "struct {};", i.name).unwrap();
58    }
59
60    for e in &idl.enums {
61        let kw = if e.is_class_enum() { "enum class" } else { "enum" };
62        writeln!(w, "{kw} {}\n{{", e.name).unwrap();
63        for m in &e.members {
64            match &m.value {
65                Some(v) => writeln!(w, "    {} = {},", m.name, v).unwrap(),
66                None => writeln!(w, "    {},", m.name).unwrap(),
67            }
68        }
69        writeln!(w, "}};").unwrap();
70    }
71
72    for s in &idl.structs {
73        writeln!(w, "struct {}\n{{", s.name).unwrap();
74        for f in &s.fields {
75            writeln!(w, "    {} {};", cpp_type(&f.ty, false), f.name).unwrap();
76        }
77        writeln!(w, "}};").unwrap();
78    }
79
80    for i in &idl.interfaces {
81        let uuid = i.uuid().ok_or_else(|| format!("interface {} has no uuid", i.name))?;
82        let virt = if i.cpp_virtual_inherits() { "virtual " } else { "" };
83        writeln!(
84            w,
85            "COMINTERFACE({}, {}) : {}{}\n{{",
86            i.name,
87            uuid_macro_args(uuid)?,
88            virt,
89            i.base_name()
90        )
91        .unwrap();
92        for m in &i.methods {
93            write!(w, "    virtual {} {} (", cpp_type(&m.return_type, false), m.name).unwrap();
94            if m.params.is_empty() {
95                writeln!(w, ") = 0;").unwrap();
96                continue;
97            }
98            writeln!(w).unwrap();
99            for (idx, p) in m.params.iter().enumerate() {
100                let sep = if idx + 1 < m.params.len() { ", " } else { "" };
101                writeln!(w, "        {} {}{}", cpp_type(&p.ty, p.is_const()), p.name, sep).unwrap();
102            }
103            writeln!(w, "    ) = 0;").unwrap();
104        }
105        writeln!(w, "}};").unwrap();
106    }
107
108    Ok(out)
109}