1use std::io::Seek;
2use std::io::Read;
3use std::io::Write;
4use std::convert::TryInto;
5
6fn gen_method(mut outfile: &std::fs::File, mut outfile_hdr: &std::fs::File, class: &clang::Entity, method: &clang::Entity) -> std::io::Result<()> {
7 let mut outbuf = Vec::new();
8 let mut method_name = method.get_name().unwrap();
9
10 if let clang::EntityKind::Destructor = method.get_kind() {
11 method_name = "destructor".to_string();
12 };
13
14 if let clang::EntityKind::Constructor = method.get_kind() {
15 method_name = "constructor".to_string();
16 };
17
18 write!(&mut outbuf, "{} vwrap_{}_{}({} *thiz", method.get_result_type().unwrap().get_display_name(),
20 class.get_type().unwrap().get_display_name(),
21 method_name, class.get_type().unwrap().get_display_name())?;
22 if let Some(arguments) = method.get_arguments() {
23 for argument in arguments {
24 write!(&mut outbuf, ", ")?;
25
26 let range = argument.get_range().unwrap();
27 let loc_start = range.get_start().get_spelling_location();
28 let loc_end = range.get_end().get_spelling_location();
29 assert!(loc_start.file == loc_end.file);
30 assert!(loc_start.offset < loc_end.offset);
31 let filepath = loc_start.file.unwrap().get_path();
32
33 let mut file = std::fs::File::open(filepath).unwrap();
34 file.seek(std::io::SeekFrom::Start(loc_start.offset.into())).unwrap();
35 let mut buf = vec![0; (loc_end.offset - loc_start.offset).try_into().unwrap()];
36 file.read_exact(&mut buf)?;
37 outbuf.write_all(&buf)?;
38 }
39 }
40 write!(&mut outbuf, ")")?;
41
42 outfile_hdr.write_all(&outbuf)?;
44 writeln!(&mut outfile_hdr, ";")?;
45
46 outfile.write_all(&outbuf)?;
48 writeln!(&mut outfile, " {{")?;
49
50 write!(&mut outfile, " ")?;
51 if method.get_result_type().unwrap().get_kind() != clang::TypeKind::Void {
52 write!(&mut outfile, "return ")?;
53 }
54
55 if let clang::EntityKind::Constructor = method.get_kind() {
56 write!(&mut outfile, "new(thiz) ")?;
57 }
58 else {
59 write!(&mut outfile, "thiz->")?;
60 }
61 write!(&mut outfile, "{}(", method.get_name().unwrap())?;
62 if let Some(arguments) = method.get_arguments() {
63 let mut first = true;
64 for argument in arguments {
65 if first {
66 first = false;
67 }
68 else {
69 write!(&mut outfile, ", ")?;
70 }
71
72 write!(&mut outfile, "{}", argument.get_display_name().unwrap())?;
73 }
74 }
75 writeln!(&mut outfile, ");")?;
76
77 writeln!(&mut outfile, "}}")?;
78
79 Ok(())
80}
81
82pub fn generate<F: Into<std::path::PathBuf>, S: AsRef<str>>(outpath_src: F, outpath_hdr: F, inpath: F, arguments: &[S]) -> std::io::Result<()> {
83 let clang = clang::Clang::new().unwrap();
84 let index = clang::Index::new(&clang, false, false);
85
86 let inpath2 = inpath.into();
87 let outpath_hdr2 = outpath_hdr.into();
88 let mut parser = index.parser(&inpath2);
89 let mut clang_args:Vec<std::string::String> = Vec::new();
90
91 if let Some(clang) = clang_sys::support::Clang::find(None, &[]) {
92 if let Some(paths) = clang.cpp_search_paths {
93 for path in paths.into_iter() {
94 clang_args.push("-isystem".to_string());
95 clang_args.push(path.to_str().unwrap().to_string());
96 }
97 }
98 }
99
100 for arg in arguments {
101 clang_args.push(arg.as_ref().to_string());
102 }
103
104 parser.arguments(&clang_args);
105
106 let tu = parser.parse().unwrap();
107 let mut has_diag = false;
108 for diag in &tu.get_diagnostics() {
109 eprintln!("{}", diag.formatter().format());
110 has_diag = true;
111 }
112 if has_diag {
113 std::process::exit(1);
114 }
115
116 let mut outfile = std::fs::File::create(outpath_src.into())?;
117 let mut outfile_hdr = std::fs::File::create(&outpath_hdr2)?;
118
119 writeln!(&mut outfile_hdr, "#pragma once")?;
120 writeln!(&mut outfile_hdr, "#include \"{}\"", inpath2.display())?;
121
122 writeln!(&mut outfile, "#include \"{}\"", outpath_hdr2.display())?;
123 writeln!(&mut outfile, "#include <new>")?;
124
125 let mut classes = std::collections::HashMap::new();
127 for class in tu.get_entity().get_children() {
128 if class.get_kind() != clang::EntityKind::ClassDecl {
129 continue;
130 }
131
132 let type_ = class.get_type().unwrap();
133 classes.insert(type_.get_display_name(), class);
134 }
135
136 for class in classes.values() {
137 let type_ = class.get_type().unwrap();
138 let mut base_classes = Vec::new();
139 let mut changed = true;
140
141 base_classes.push(type_.get_display_name());
143 while changed {
144 changed = false;
145
146 for entity in class.get_children() {
147 if entity.get_kind() != clang::EntityKind::BaseSpecifier {
148 continue;
149 }
150
151 let display_name = entity.get_type().unwrap().get_display_name();
152 if !base_classes.contains(&display_name) {
153 base_classes.push(display_name);
154 changed = true;
155 }
156 }
157 }
158
159 for base_class_name in &base_classes {
160 let base_class = classes.get(base_class_name).unwrap();
161
162 for method in &base_class.get_children() {
163 match method.get_kind() {
164 clang::EntityKind::Method => {
165 if class == base_class && !method.is_virtual_method() && !method.is_inline_function() {
169 continue;
170 }
171 if method.get_overridden_methods().is_some() {
174 continue;
175 }
176 if method.get_accessibility().unwrap() != clang::Accessibility::Public {
179 continue;
180 }
181 },
182 clang::EntityKind::Destructor | clang::EntityKind::Constructor => {
184 if class != base_class {
185 continue;
186 }
187
188 if class.is_abstract_record() {
189 continue;
190 }
191
192 if method.get_accessibility().unwrap() != clang::Accessibility::Public {
193 continue;
194 }
195 },
196 _ => continue
197 }
198
199 gen_method(&outfile, &outfile_hdr, &class, &method)?;
200 }
201 }
202 writeln!(&mut outfile)?;
203 }
204 Ok(())
205}