1use std::{cell::RefCell, collections::BTreeMap, env, path::PathBuf, process::Command, sync::Arc};
2
3use proc_macro2::Span;
4
5use crate::{
6 argument::{DuchessDeclaration, Ident, JavaPackage, MethodSelector},
7 class_info::{
8 ClassDecl, ClassInfo, DotId, Generic, Id, Method, RootMap, SpannedPackageInfo, Type,
9 },
10 upcasts::Upcasts,
11};
12
13impl DuchessDeclaration {
14 pub fn to_root_map(&self, reflector: &mut Reflector) -> syn::Result<RootMap> {
15 let mut subpackages = BTreeMap::new();
16 let mut classes = BTreeMap::new();
17 for package in &self.packages {
18 package.to_spanned_packages(
19 &package.package_name.ids,
20 reflector,
21 &mut subpackages,
22 &mut classes,
23 )?;
24 }
25
26 let upcasts: Upcasts = Upcasts::from_iter(classes.values().map(|v| &**v));
27
28 Ok(RootMap {
29 subpackages,
30 classes,
31 upcasts,
32 })
33 }
34}
35
36impl JavaPackage {
37 fn to_spanned_packages(
38 &self,
39 name: &[Ident],
40 reflector: &mut Reflector,
41 map: &mut BTreeMap<Id, SpannedPackageInfo>,
42 classes: &mut BTreeMap<DotId, Arc<ClassInfo>>,
43 ) -> syn::Result<()> {
44 let (first, rest) = name.split_first().unwrap();
45
46 let package_info = || SpannedPackageInfo {
47 name: first.to_id(),
48 span: first.span,
49 subpackages: Default::default(),
50 classes: Default::default(),
51 };
52
53 let first_id = first.to_id();
54
55 let parent = map.entry(first_id).or_insert_with(package_info);
58
59 if rest.is_empty() {
60 self.insert_classes_into_root_map(reflector, parent, classes)
61 } else {
62 self.to_spanned_packages(rest, reflector, &mut parent.subpackages, classes)
63 }
64 }
65
66 fn insert_classes_into_root_map(
67 &self,
68 reflector: &mut Reflector,
69 package: &mut SpannedPackageInfo,
70 classes: &mut BTreeMap<DotId, Arc<ClassInfo>>,
71 ) -> syn::Result<()> {
72 for c in &self.classes {
73 let (dot_id, info) = match c {
74 ClassDecl::Reflected(c) => {
75 let dot_id = self.make_absolute_dot_id(c.span, &c.name)?;
76 let info = reflector.reflect(&dot_id, c.span)?;
77
78 (
80 dot_id,
81 Arc::new(ClassInfo {
82 span: c.span,
83 kind: c.kind,
84 ..(*info).clone()
85 }),
86 )
87 }
88 ClassDecl::Specified(c) => {
89 let dot_id = self.make_absolute_dot_id(c.span, &c.name)?;
90 (
91 dot_id.clone(),
92 Arc::new(ClassInfo {
93 name: dot_id,
94 ..c.clone()
95 }),
96 )
97 }
98 };
99
100 package.classes.push(dot_id.clone());
101 classes.insert(dot_id, info);
102 }
103 Ok(())
104 }
105
106 fn make_absolute_dot_id(&self, span: Span, class_dot_id: &DotId) -> syn::Result<DotId> {
108 let package_ids: Vec<Id> = self.package_name.ids.iter().map(|n| n.to_id()).collect();
109
110 let (package, class) = class_dot_id.split();
111
112 if package.is_empty() {
114 return Ok(DotId::new(&package_ids, &class));
115 }
116
117 if &package_ids[..] != package {
119 return Err(syn::Error::new(
120 span,
121 format!("expected package `{}`", self.package_name),
122 ));
123 }
124
125 Ok(class_dot_id.clone())
126 }
127}
128
129#[derive(Default)]
132pub struct Reflector {
133 classes: RefCell<BTreeMap<DotId, Arc<ClassInfo>>>,
134}
135
136impl Reflector {
137 pub fn reflect(&self, class_name: &DotId, span: Span) -> syn::Result<Arc<ClassInfo>> {
139 if let Some(class) = self.classes.borrow().get(class_name).map(Arc::clone) {
141 return Ok(class);
142 }
143
144 let mut javap_path = PathBuf::new();
145 if let Ok(java_home) = env::var("JAVA_HOME") {
146 javap_path.extend([java_home.as_str(), "bin"]);
147 }
148 javap_path.push("javap");
149
150 let mut command = Command::new(javap_path);
151
152 if let Some(classpath) = env::var("CLASSPATH").ok() {
154 command.arg("-cp").arg(classpath);
155 }
156
157 command.arg("-p").arg(format!("{}", class_name));
158
159 let output_or_err = command.output();
160
161 let output = match output_or_err {
162 Ok(o) => o,
163 Err(err) => {
164 return Err(syn::Error::new(
165 span,
166 format!("failed to execute `{command:?}`: {err}"),
167 ));
168 }
169 };
170
171 if !output.status.success() {
172 return Err(syn::Error::new(
173 span,
174 format!(
175 "unsuccessful execution of `{command:?}` (exit status: {}): {}",
176 output.status,
177 String::from_utf8(output.stderr).unwrap_or(String::from("error"))
178 ),
179 ));
180 }
181
182 let s = match String::from_utf8(output.stdout) {
183 Ok(o) => o,
184 Err(err) => {
185 return Err(syn::Error::new(
186 span,
187 format!("failed to parse output of `{command:?}` as utf-8: {err}"),
188 ));
189 }
190 };
191
192 let mut ci = ClassInfo::parse(&s, span)?;
193
194 ci.span = Span::call_site();
197 Ok(self
198 .classes
199 .borrow_mut()
200 .entry(class_name.clone())
201 .or_insert(Arc::new(ci))
202 .clone())
203 }
204
205 pub fn reflect_method(&self, method_selector: &MethodSelector) -> syn::Result<ReflectedMethod> {
207 match method_selector {
208 MethodSelector::ClassName(cn) => {
209 let dot_id = cn.to_dot_id();
210 let class_info = self.reflect(&dot_id, cn.span)?;
211 match class_info.constructors.len() {
212 1 => Ok(ReflectedMethod::Constructor(class_info, 0)),
213 0 => Err(syn::Error::new(cn.span, "no constructors found".to_string())),
214 n => Err(syn::Error::new(cn.span, format!("{n} constructors found, use an explicit class declaration to disambiguate")))
215 }
216 }
217 MethodSelector::MethodName(cn, mn) => {
218 let dot_id = cn.to_dot_id();
219 let class_info = self.reflect(&dot_id, cn.span)?;
220 let methods: Vec<(MethodIndex, &Method)> = class_info
221 .methods
222 .iter()
223 .enumerate()
224 .filter(|(_i, m)| &m.name[..] == &mn.text[..])
225 .collect();
226 match methods.len() {
227 1 => {
228 let (id, _method) = methods[0];
229 Ok(ReflectedMethod::Method(class_info, id))
230 },
231 0 => Err(syn::Error::new(cn.span, format!("no methods named `{mn}` found"))),
232 n => Err(syn::Error::new(cn.span, format!("{n} methods named `{mn}` found, use an explicit class declaration to disambiguate") )),
233 }
234 }
235 MethodSelector::ClassInfo(_) => todo!(),
236 }
237 }
238}
239
240pub type ConstructorIndex = usize;
241pub type MethodIndex = usize;
242
243#[derive(Clone, Debug)]
245pub enum ReflectedMethod {
246 Constructor(Arc<ClassInfo>, ConstructorIndex),
247 Method(Arc<ClassInfo>, MethodIndex),
248}
249
250impl ReflectedMethod {
251 pub fn name(&self) -> Id {
253 match self {
254 ReflectedMethod::Constructor(..) => Id::from("new"),
255 ReflectedMethod::Method(c, m) => c.methods[*m].name.clone(),
256 }
257 }
258
259 pub fn class(&self) -> &ClassInfo {
260 match self {
261 ReflectedMethod::Constructor(c, _) => c,
262 ReflectedMethod::Method(c, _) => c,
263 }
264 }
265
266 pub fn is_static(&self) -> bool {
268 match self {
269 ReflectedMethod::Constructor(..) => true,
270 ReflectedMethod::Method(c, m) => c.methods[*m].flags.is_static,
271 }
272 }
273
274 pub fn generics(&self) -> &Vec<Generic> {
275 match self {
276 ReflectedMethod::Constructor(c, t) => &c.constructors[*t].generics,
277 ReflectedMethod::Method(c, m) => &c.methods[*m].generics,
278 }
279 }
280
281 pub fn argument_tys(&self) -> &Vec<Type> {
282 match self {
283 ReflectedMethod::Constructor(c, t) => &c.constructors[*t].argument_tys,
284 ReflectedMethod::Method(c, m) => &c.methods[*m].argument_tys,
285 }
286 }
287}