duchess_reflect/
argument.rs1use proc_macro2::Span;
2
3use crate::{
4 class_info::{ClassDecl, ClassInfo, DotId, Id},
5 parse::{Parse, Parser},
6};
7
8pub struct DuchessDeclaration {
9 pub packages: Vec<JavaPackage>,
10}
11
12impl Parse for DuchessDeclaration {
13 fn parse(p: &mut Parser) -> syn::Result<Option<Self>> {
14 let packages = JavaPackage::parse_many(p)?;
15 Ok(Some(DuchessDeclaration { packages }))
16 }
17
18 fn description() -> String {
19 format!("list of classes whose methods you would like to call (e.g., `java.lang.Object`)")
20 }
21}
22
23pub enum MethodSelector {
30 ClassName(JavaPath),
32
33 MethodName(JavaPath, Ident),
35
36 ClassInfo(ClassInfo),
39}
40
41impl MethodSelector {
42 pub fn span(&self) -> Span {
44 match self {
45 MethodSelector::ClassName(jp) => jp.span,
46 MethodSelector::MethodName(_, ident) => ident.span,
47 MethodSelector::ClassInfo(ci) => ci.span,
48 }
49 }
50
51 pub fn class_span(&self) -> Span {
53 match self {
54 MethodSelector::ClassName(jp) => jp.span,
55 MethodSelector::MethodName(jp, _) => jp.span,
56 MethodSelector::ClassInfo(ci) => ci.span,
57 }
58 }
59
60 pub fn class_name(&self) -> DotId {
61 match self {
62 MethodSelector::ClassName(c) => c.to_dot_id(),
63 MethodSelector::MethodName(c, _) => c.to_dot_id(),
64 MethodSelector::ClassInfo(_) => todo!(),
65 }
66 }
67
68 pub fn method_name(&self) -> String {
70 match self {
71 MethodSelector::ClassName(_) => self.class_name().split().1.to_string(),
72 MethodSelector::MethodName(_, m) => m.to_string(),
73 MethodSelector::ClassInfo(_) => todo!(),
74 }
75 }
76}
77
78impl Parse for MethodSelector {
79 fn parse(p: &mut crate::parse::Parser) -> syn::Result<Option<Self>> {
80 if let Some(c) = ClassDecl::parse(p)? {
82 return match c {
83 ClassDecl::Reflected(r) => Err(syn::Error::new(
84 r.span,
85 format!("expected a class with a single member, not `*`"),
86 )),
87 ClassDecl::Specified(c) => {
88 let members = c.constructors.len() + c.fields.len() + c.methods.len();
89 if members != 1 {
90 Err(syn::Error::new(
91 c.span,
92 format!(
93 "expected a class with exactly one member, but {} members found",
94 members
95 ),
96 ))
97 } else {
98 Ok(Some(MethodSelector::ClassInfo(c)))
99 }
100 }
101 };
102 }
103
104 let Some(path) = JavaPath::parse(p)? else {
106 return Ok(None);
107 };
108
109 if let Some(_) = p.eat_punct(':') {
110 if let Some(_) = p.eat_punct(':') {
111 if let Some(ident) = Ident::parse(p)? {
112 return Ok(Some(MethodSelector::MethodName(path, ident)));
113 }
114 }
115 Err(syn::Error::new(
116 p.peek_span().unwrap_or(Span::call_site()),
117 "expected method name after `::`",
118 ))
119 } else {
120 Ok(Some(MethodSelector::ClassName(path)))
121 }
122 }
123
124 fn description() -> String {
125 format!("method selector, e.g. `java.package.Class`, `java.package.Class::method`, or full details")
126 }
127}
128
129pub struct JavaPackage {
130 pub package_name: JavaPath,
131 pub classes: Vec<ClassDecl>,
132}
133
134impl Parse for JavaPackage {
135 fn parse(p: &mut Parser) -> syn::Result<Option<Self>> {
136 let Some(()) = p.eat_keyword("package") else {
137 return Ok(None);
138 };
139
140 let Some(package_name) = JavaPath::parse(p)? else {
141 return Err(syn::Error::new(
142 p.last_span().unwrap(),
143 "expected package name",
144 ));
145 };
146
147 let Some(_) = p.eat_punct(';') else {
148 return Err(syn::Error::new(
149 p.last_span().unwrap(),
150 "expected `;` after package name",
151 ));
152 };
153
154 let classes = ClassDecl::parse_many(p)?;
155
156 Ok(Some(JavaPackage {
157 package_name,
158 classes,
159 }))
160 }
161
162 fn description() -> String {
163 format!("java package to reflect (e.g., `package foo; ...`)")
164 }
165}
166
167pub struct JavaPath {
168 pub ids: Vec<Ident>,
169 pub span: Span,
170}
171
172impl JavaPath {
173 pub fn to_dot_id(&self) -> DotId {
174 self.ids.iter().map(|ident| ident.to_id()).collect()
175 }
176}
177
178impl Parse for JavaPath {
179 fn parse(p: &mut Parser) -> syn::Result<Option<Self>> {
180 let Some(text) = Ident::parse(p)? else {
181 return Ok(None);
182 };
183
184 let mut span = text.span;
185 let mut ids = vec![text];
186
187 while let Some(_) = p.eat_punct('.') {
188 let Some(next) = Ident::parse(p)? else {
189 return Err(syn::Error::new(
190 p.last_span().unwrap(),
191 format!("expected identifier after `.`"),
192 ));
193 };
194 span = span.join(next.span).unwrap_or(span);
195 ids.push(next);
196 }
197
198 Ok(Some(JavaPath { ids, span }))
199 }
200
201 fn description() -> String {
202 format!("java class name (e.g., `java.lang.Object`)")
203 }
204}
205
206impl std::fmt::Display for JavaPath {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 if let Some((id0, ids)) = self.ids.split_first() {
209 write!(f, "{}", id0)?;
210 for id in ids {
211 write!(f, ".{}", id)?;
212 }
213 Ok(())
214 } else {
215 Ok(())
216 }
217 }
218}
219
220pub struct Ident {
221 pub text: String,
222 pub span: Span,
223}
224
225impl Ident {
226 pub fn to_id(&self) -> Id {
227 Id::from(&self.text[..])
228 }
229}
230
231impl Parse for Ident {
232 fn parse(p: &mut Parser) -> syn::Result<Option<Self>> {
233 let Some(text) = p.eat_ident() else {
234 return Ok(None);
235 };
236
237 Ok(Some(Ident {
238 text,
239 span: p.last_span().unwrap(),
240 }))
241 }
242
243 fn description() -> String {
244 format!("Java identifier")
245 }
246}
247
248impl std::fmt::Display for Ident {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 write!(f, "{}", &self.text)
251 }
252}