jvm_descriptors/
method.rs1use crate::r#type::Type;
2use chumsky::prelude::*;
3use std::{
4 fmt::{Display, Write},
5 str::FromStr,
6};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub enum Method {
10 Method {
11 name: String,
12 parameters: Vec<Type>,
13 return_type: Option<Type>,
14 },
15 Constructor {
16 parameters: Vec<Type>,
17 },
18}
19
20impl Display for Method {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 match self {
23 Method::Method {
24 name,
25 parameters,
26 return_type,
27 } => {
28 name.fmt(f)?;
29 f.write_char('(')?;
30 for parameter in parameters {
31 parameter.fmt(f)?;
32 }
33 f.write_char(')')?;
34 match return_type {
35 Some(ty) => ty.fmt(f),
36 None => f.write_char('V'),
37 }?;
38 }
39 Method::Constructor { parameters } => {
40 f.write_str("<init>")?;
41 f.write_char('(')?;
42 for parameter in parameters {
43 parameter.fmt(f)?;
44 }
45 f.write_char(')')?;
46 f.write_char('V')?;
47 }
48 }
49
50 Ok(())
51 }
52}
53
54impl FromStr for Method {
55 type Err = Vec<Simple<char>>;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 Self::parser().parse(s)
59 }
60}
61
62impl Method {
63 pub fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
64 text::ident()
65 .then(Type::parser().repeated().delimited_by(just('('), just(')')))
66 .then(Type::parser().map(Some).or(just('V').to(None)))
67 .map(|((name, parameters), return_type)| Method::Method {
68 name,
69 parameters,
70 return_type,
71 })
72 .or(
73 just("<init>")
74 .ignore_then(Type::parser().repeated().delimited_by(just('('), just(')')))
75 .then_ignore(just('V'))
76 .map(|parameters| Method::Constructor { parameters }),
77 )
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::class::Class;
84
85 use super::*;
86
87 #[test]
88 fn fmt() {
89 assert_eq!(
90 Method::Method {
91 name: "hello".to_string(),
92 parameters: vec![Type::Class(Class {
93 path: vec!["java".to_string(), "lang".to_string(), "String".to_string()],
94 subclasses: vec![]
95 })],
96 return_type: None,
97 }
98 .to_string(),
99 "hello(Ljava/lang/String;)V"
100 );
101
102 assert_eq!(
103 Method::Constructor {
104 parameters: vec![Type::Class(Class {
105 path: vec!["java".to_string(), "lang".to_string(), "String".to_string()],
106 subclasses: vec![]
107 })],
108 }
109 .to_string(),
110 "<init>(Ljava/lang/String;)V"
111 );
112 }
113
114 #[test]
115 fn parse() {
116 assert_eq!(
117 "hello(Ljava/lang/String;)V".parse(),
118 Ok(
119 Method::Method {
120 name: "hello".to_string(),
121 parameters: vec![Type::Class(Class {
122 path: vec!["java".to_string(), "lang".to_string(), "String".to_string()],
123 subclasses: vec![]
124 })],
125 return_type: None,
126 }
127 .to_string()
128 )
129 );
130
131 assert_eq!(
132 "<init>(Ljava/lang/String;)V".parse(),
133 Ok(Method::Constructor {
134 parameters: vec![Type::Class(Class {
135 path: vec!["java".to_string(), "lang".to_string(), "String".to_string()],
136 subclasses: vec![]
137 })],
138 })
139 );
140 }
141}