1use std::fmt::Write;
4
5use crate::ast::*;
6
7fn 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
31fn 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}