1use std::{borrow::Cow, error::Error, fmt::Display, ops::Range};
3
4#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6pub enum BaseType {
7 Byte, Char, Double, Float, Int, Long, Short, Boolean, }
16
17#[derive(Debug)]
18pub enum JavaType {
19 Base(BaseType),
20 Reference(ReferenceType),
21}
22
23#[derive(Debug)]
24pub enum TypeArgument {
25 Unbounded,
26 Default(ReferenceType),
27 Extends(ReferenceType),
28 Super(ReferenceType),
29}
30
31#[derive(Debug, PartialEq, Eq)]
32pub struct Slice {
33 start: u16, end: u16, }
36
37impl Slice {
38 pub fn start(&self) -> usize {
39 self.start as usize
40 }
41
42 pub fn apply<'a>(&self, s: &'a str) -> &'a str {
44 &s[self.start as usize..self.end as usize]
45 }
46}
47
48impl From<Range<usize>> for Slice {
51 fn from(value: Range<usize>) -> Self {
52 if value.start >= value.end {
53 panic!("{} >= {}!", value.start, value.end);
54 }
55 if value.start >= u16::MAX as usize || value.end >= u16::MAX as usize {
56 panic!("boundary/ies too big!");
57 }
58 Self {
59 start: value.start as u16,
60 end: value.end as u16,
61 }
62 }
63}
64
65impl From<Slice> for Range<usize> {
66 fn from(val: Slice) -> Self {
67 (val.start as usize)..(val.end as usize)
68 }
69}
70
71#[derive(Debug)]
72pub struct SimpleClassType(pub Slice, pub Vec<TypeArgument>);
73
74#[derive(Debug)]
75pub struct ClassType(pub SimpleClassType, pub Vec<SimpleClassType>);
76
77#[derive(Debug)]
78pub enum ReferenceType {
79 Class(ClassType),
80 Variable(Slice),
81 Array { dimension: usize, ty: Box<JavaType> },
82}
83
84#[derive(Debug)]
85pub struct TypeParameter {
86 pub name: Slice,
87 pub class_bound: Option<ReferenceType>,
88 pub iface_bounds: Vec<ReferenceType>,
89}
90
91#[derive(Debug)]
92pub enum ResultType {
93 VoidType,
94 ValueType(JavaType),
95}
96
97#[derive(Debug)]
98pub enum ThrowsType {
99 ClassType(ClassType),
100 TypeVariable(Slice),
102}
103
104#[derive(Debug)]
105pub struct ClassSignature {
106 pub type_params: Vec<TypeParameter>,
107 pub super_class: ClassType,
108 pub super_ifaces: Vec<ClassType>,
109}
110
111#[derive(Debug)]
112pub struct MethodSignature {
113 pub type_params: Vec<TypeParameter>,
114 pub parameters: Vec<JavaType>,
115 pub result: ResultType,
116 pub throws: Vec<ThrowsType>,
117}
118
119pub fn parse<'a, F, T, MI, I>(name: &'static str, parser: F, s: &'a str, make_iter: MI) -> Result<T>
122where
123 I: Iterator<Item = Character>,
124 F: Fn(&mut I) -> Result<T>,
125 MI: Fn(&'a str) -> I + 'a,
126{
127 if s.is_empty() {
128 Err(ParseError::new(name, 0, "empty input"))
129 } else {
130 let mut chars = make_iter(s);
131 parser(&mut chars)
132 .map_err(|mut e| {
133 if e.position == EOF_POSITION {
134 e.position = s.len();
135 }
136 e
137 })
138 .and_then(|value| {
139 if let Some((pos, _)) = chars.next() {
140 Err(ParseError::new(
141 name,
142 pos,
143 "bad input; expected end of input",
144 ))
145 } else {
146 Ok(value)
147 }
148 })
149 }
150}
151
152const EOF_POSITION: usize = usize::MAX;
159
160#[derive(Debug, PartialEq)]
161pub struct ParseError {
162 pub context: &'static str,
163 pub position: usize,
164 pub error: Cow<'static, str>,
165}
166
167impl Display for ParseError {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 write!(
170 f,
171 "{}: [position: {} / context: {}]",
172 self.error, self.position, self.context
173 )
174 }
175}
176
177impl Error for ParseError {}
178
179impl ParseError {
180 fn new<E: Into<Cow<'static, str>>>(context: &'static str, position: usize, error: E) -> Self {
181 Self {
182 position,
183 error: error.into(),
184 context,
185 }
186 }
187 fn eof(context: &'static str) -> Self {
188 Self {
189 position: EOF_POSITION,
190 error: Cow::Borrowed("unexpected end of input"),
191 context,
192 }
193 }
194}
195
196type Result<T> = std::result::Result<T, ParseError>;
197
198fn consume_next(
201 context: &'static str,
202 chars: &mut impl Iterator<Item = Character>,
203) -> Result<Character> {
204 match chars.next() {
205 None => Err(ParseError::eof(context)),
206 Some(c) => Ok(c),
207 }
208}
209
210fn consume_next_expected(
214 context: &'static str,
215 next: Option<Character>,
216 expected: char,
217) -> Result<()> {
218 match next {
219 None => Err(ParseError::eof(context)),
220 Some((_, next)) if next == expected => Ok(()),
221 Some((pos, _)) => Err(ParseError::new(
222 context,
223 pos,
224 format!("bad input; expected: `{expected}`"),
225 )),
226 }
227}
228
229fn consume_next_eof_or_expected(
234 context: &'static str,
235 chars: &mut impl Iterator<Item = Character>,
236 expected: char,
237) -> Result<Option<()>> {
238 match chars.next() {
239 None => Ok(None),
240 c => {
241 consume_next_expected(context, c, expected)?;
242 Ok(Some(()))
243 }
244 }
245}
246
247type Character = (usize, char);
251
252fn to_base_type(c: char) -> Option<BaseType> {
253 match c {
254 'B' => Some(BaseType::Byte),
255 'C' => Some(BaseType::Char),
256 'D' => Some(BaseType::Double),
257 'F' => Some(BaseType::Float),
258 'I' => Some(BaseType::Int),
259 'J' => Some(BaseType::Long),
260 'S' => Some(BaseType::Short),
261 'Z' => Some(BaseType::Boolean),
262 _ => None,
263 }
264}
265
266pub fn consume_reference_type_signature(
267 chars: &mut impl Iterator<Item = Character>,
268) -> Result<ReferenceType> {
269 consume_next("ReferenceTypeSignature", chars)
270 .and_then(|c| consume_reference_type_signature_(c, chars))
271}
272
273fn consume_reference_type_signature_(
274 mut c: Character,
275 more_chars: &mut impl Iterator<Item = Character>,
276) -> Result<ReferenceType> {
277 fn maybe_as_array(dimension: usize, ty: ReferenceType) -> ReferenceType {
278 if dimension == 0 {
279 ty
280 } else {
281 ReferenceType::Array {
282 dimension,
283 ty: Box::new(JavaType::Reference(ty)),
284 }
285 }
286 }
287 let mut dimension = 0;
292 loop {
293 match c.1 {
294 '[' => {
295 dimension += 1;
296
297 let next = consume_next("ReferenceTypeSignature", more_chars)?;
299 match to_base_type(next.1) {
300 Some(ty) => {
301 debug_assert!(dimension > 0);
302 return Ok(ReferenceType::Array {
303 dimension,
304 ty: Box::new(JavaType::Base(ty)),
305 });
306 }
307 None => {
308 c = next; }
310 }
311 }
312 'L' => {
313 return consume_class_type_signature(more_chars)
315 .map(|ty| maybe_as_array(dimension, ReferenceType::Class(ty)));
316 }
317 'T' => {
318 let r = consume_unqualified_identifer(more_chars)?;
320 return match r.1 {
321 None => Err(ParseError::eof("ReferenceTypeSignature")),
322 Some((_, ';')) => Ok(maybe_as_array(dimension, ReferenceType::Variable(r.0))),
323 Some((pos, _)) => Err(ParseError::new(
324 "ReferenceTypeSignature",
325 pos,
326 "bad input; expected `;`",
327 )),
328 };
329 }
330 _ => {
331 return Err(ParseError::new(
332 "ReferenceTypeSignature",
333 c.0,
334 "bad input; expected `[`, `L`, or `T`",
335 ));
336 }
337 }
338 }
339}
340
341fn consume_class_type_signature(chars: &mut impl Iterator<Item = Character>) -> Result<ClassType> {
342 let mut r = consume_unqualified_identifer(chars)?;
343 let start_pos = r.0.start();
344 loop {
345 match r.1 {
346 Some((end_pos, ';')) => {
347 return Ok(ClassType(
348 SimpleClassType((start_pos..end_pos).into(), Vec::new()),
349 Vec::new(),
350 ));
351 }
352 Some((_, '/')) => {
353 }
355 Some((end_pos, '.')) => {
356 return Ok(ClassType(
357 SimpleClassType((start_pos..end_pos).into(), Vec::new()),
358 consume_class_type_signature_suffixes(chars)?,
359 ));
360 }
361 Some((end_pos, '<')) => {
362 let class_type =
363 SimpleClassType((start_pos..end_pos).into(), consume_type_arguments(chars)?);
364 return match consume_next("ClassTypeSignature", chars)? {
365 (_, '.') => Ok(ClassType(
366 class_type,
367 consume_class_type_signature_suffixes(chars)?,
368 )),
369 (_, ';') => Ok(ClassType(class_type, Vec::new())),
370 (pos, _) => Err(ParseError::new(
371 "ClassTypeSignature",
372 pos,
373 "bad input; expected `.` or `;`",
374 )),
375 };
376 }
377 Some((pos, _)) => {
378 return Err(ParseError::new(
379 "ClassTypeSignature",
380 pos,
381 "bad input; expected `;`, `/`, `.`, or `<`",
382 ))
383 }
384 None => return Err(ParseError::eof("ClassTypeSignature")),
385 }
386 r = consume_unqualified_identifer(chars)?;
387 }
388}
389
390fn consume_class_type_signature_suffixes(
391 chars: &mut impl Iterator<Item = Character>,
392) -> Result<Vec<SimpleClassType>> {
393 let mut suffixes = Vec::new();
394 loop {
395 let r = consume_unqualified_identifer(chars)?;
396 match r.1 {
397 Some((_, ';')) => {
398 suffixes.push(SimpleClassType(r.0, Vec::new()));
399 return Ok(suffixes);
400 }
401 Some((_, '.')) => {
402 suffixes.push(SimpleClassType(r.0, Vec::new()));
403 }
405 Some((_, '<')) => {
406 let args = consume_type_arguments(chars)?;
407 match consume_next("ClassTypeSignatureSuffix", chars)? {
408 (_, '.') => {
409 suffixes.push(SimpleClassType(r.0, args));
410 }
412 (_, ';') => {
413 suffixes.push(SimpleClassType(r.0, args));
414 return Ok(suffixes);
415 }
416 (pos, _) => {
417 return Err(ParseError::new(
418 "ClassTypeSignature",
419 pos,
420 "bad input; expected `.` or end of input",
421 ));
422 }
423 }
424 }
425 Some((pos, _)) => {
426 return Err(ParseError::new(
427 "ClassTypeSignatureSuffix",
428 pos,
429 "bad input; expected `;`, `.`, or `<`>",
430 ))
431 }
432 None => return Err(ParseError::eof("ClassTypeSignatureSuffix")),
433 }
434 }
435}
436
437fn consume_type_arguments(
440 chars: &mut impl Iterator<Item = Character>,
441) -> Result<Vec<TypeArgument>> {
442 let mut args = Vec::new();
443 loop {
444 match consume_next("TypeArgument", chars)? {
445 (pos, '>') => {
446 if args.is_empty() {
447 return Err(ParseError::new(
448 "TypeArguments",
449 pos,
450 "type-argument missing",
451 ));
452 } else {
453 return Ok(args);
454 }
455 }
456 (_, '*') => {
457 args.push(TypeArgument::Unbounded);
458 }
459 (_, '+') => {
460 args.push(TypeArgument::Extends(consume_reference_type_signature(
461 chars,
462 )?));
463 }
464 (_, '-') => {
465 args.push(TypeArgument::Super(consume_reference_type_signature(
466 chars,
467 )?));
468 }
469 c => {
470 args.push(TypeArgument::Default(consume_reference_type_signature_(
471 c, chars,
472 )?));
473 }
474 }
475 }
476}
477
478fn consume_unqualified_identifer(
482 chars: &mut impl Iterator<Item = Character>,
483) -> Result<(Slice, Option<Character>)> {
484 consume_unqualified_identifer_(consume_next("Identifier", chars)?, chars)
485}
486
487fn consume_unqualified_identifer_(
488 mut c: Character,
489 more_chars: &mut impl Iterator<Item = Character>,
490) -> Result<(Slice, Option<Character>)> {
491 let start_pos = c.0;
492 let mut len = 0;
493 loop {
494 if matches!(c.1, '.' | ';' | '[' | '/' | '<' | '>' | ':') {
495 if len == 0 {
496 return Err(ParseError::new("Identifier", c.0, "empty identifier"));
497 } else {
498 return Ok(((start_pos..c.0).into(), Some(c)));
499 }
500 } else {
501 }
504 len += 1;
505 match more_chars.next() {
506 None => return Ok(((start_pos..start_pos + len).into(), None)),
507 Some(next) => c = next,
508 }
509 }
510}
511
512pub fn consume_class_signature(
513 chars: &mut impl Iterator<Item = Character>,
514) -> Result<ClassSignature> {
515 let (type_params, next) = consume_type_parameters(chars)?;
516 consume_next_expected("ClassSignature", next, 'L')?;
517 let super_class = consume_class_type_signature(chars)?;
518 let mut super_ifaces = Vec::new();
519 loop {
520 match consume_next_eof_or_expected("ClassSignature", chars, 'L')? {
521 None => {
522 return Ok(ClassSignature {
523 type_params,
524 super_class,
525 super_ifaces,
526 });
527 }
528 Some(_) => {
529 super_ifaces.push(consume_class_type_signature(chars)?);
530 }
532 }
533 }
534}
535
536pub fn consume_method_signature(
537 chars: &mut impl Iterator<Item = Character>,
538) -> Result<MethodSignature> {
539 let (type_params, next) = consume_type_parameters(chars)?;
540 consume_next_expected("MethodSignature", next, '(')?;
541 let (parameters, next) = consume_method_parameters(chars)?;
542 let result = match next {
543 None => return Err(ParseError::eof("MethodSignature")),
544 Some((_, 'V')) => ResultType::VoidType,
545 Some(c) => ResultType::ValueType(consume_java_type_signature(c, chars)?),
546 };
547 let throws = consume_throws_signature(chars)?;
548 Ok(MethodSignature {
549 type_params,
550 parameters,
551 result,
552 throws,
553 })
554}
555
556fn consume_method_parameters(
557 chars: &mut impl Iterator<Item = Character>,
558) -> Result<(Vec<JavaType>, Option<Character>)> {
559 let mut params = Vec::new();
560 loop {
561 match consume_next("MethodParameter", chars)? {
562 (_, ')') => return Ok((params, chars.next())),
563 c => params.push(consume_java_type_signature(c, chars)?),
564 };
565 }
566}
567
568fn consume_throws_signature(
569 chars: &mut impl Iterator<Item = Character>,
570) -> Result<Vec<ThrowsType>> {
571 let mut throws = Vec::new();
572 loop {
573 match chars.next() {
574 None => return Ok(throws),
575 Some((_, '^')) => match consume_next("ThrowsSignature", chars)? {
576 (_, 'T') => {
577 throws.push(consume_unqualified_identifer(chars).and_then(
578 |(identifier, next)| {
579 consume_next_expected("ThrowsSignature", next, ';')?;
580 Ok(ThrowsType::TypeVariable(identifier))
581 },
582 )?);
583 }
584 (_, 'L') => {
585 throws.push(consume_class_type_signature(chars).map(ThrowsType::ClassType)?);
586 }
587 (pos, _) => {
588 return Err(ParseError::new(
589 "ThrowsSignature",
590 pos,
591 "bad input; expected `T` or `L`",
592 ))
593 }
594 },
595 Some((pos, _)) => {
596 return Err(ParseError::new(
597 "ThrowsSignature",
598 pos,
599 "bad input; expected `^` or end of input",
600 ))
601 }
602 }
603 }
604}
605
606fn consume_java_type_signature(
607 c: Character,
608 more_chars: &mut impl Iterator<Item = Character>,
609) -> Result<JavaType> {
610 if let Some(ty) = to_base_type(c.1) {
611 Ok(JavaType::Base(ty))
612 } else {
613 consume_reference_type_signature_(c, more_chars).map(JavaType::Reference)
614 }
615}
616
617fn consume_type_parameters(
620 chars: &mut impl Iterator<Item = Character>,
621) -> Result<(Vec<TypeParameter>, Option<Character>)> {
622 fn consume_more_reference_type_signatures(
623 mut c: Character,
624 more_chars: &mut impl Iterator<Item = Character>,
625 accumulator: &mut Vec<ReferenceType>,
626 ) -> Result<Option<Character>> {
627 loop {
628 match c {
629 (_, ':') => {
630 accumulator.push(consume_reference_type_signature(more_chars)?);
631 c = consume_next("TypeParameter", more_chars)?;
632 }
634 c => {
635 return Ok(Some(c));
636 }
637 }
638 }
639 }
640
641 let mut params = Vec::new();
642 match chars.next() {
643 Some((_, '<')) => {
644 let mut next = consume_unqualified_identifer(chars)?;
645 loop {
646 match next.1 {
647 Some((_, ':')) => {
648 match consume_next("TypeParameter", chars)? {
650 (_, '>') => {
651 params.push(TypeParameter {
652 name: next.0,
653 class_bound: None,
654 iface_bounds: Vec::new(),
655 });
656 return Ok((params, chars.next()));
657 }
658 c @ (_, ':') => {
659 let mut iface_bounds = Vec::new();
660 match consume_more_reference_type_signatures(
661 c,
662 chars,
663 &mut iface_bounds,
664 )? {
665 None => return Err(ParseError::eof("TypeParameter")),
666 Some((_, '>')) => {
667 params.push(TypeParameter {
668 name: next.0,
669 class_bound: None,
670 iface_bounds,
671 });
672 return Ok((params, chars.next()));
673 }
674 Some(c) => {
675 params.push(TypeParameter {
676 name: next.0,
677 class_bound: None,
678 iface_bounds,
679 });
680 next = consume_unqualified_identifer_(c, chars)?;
681 }
683 }
684 }
685 c => {
686 let class_bound = consume_reference_type_signature_(c, chars)?;
687 let mut iface_bounds = Vec::new();
688 match consume_more_reference_type_signatures(
689 consume_next("TypeParameter", chars)?,
690 chars,
691 &mut iface_bounds,
692 )? {
693 None => return Err(ParseError::eof("TypeParameter")),
694 Some(c) => {
695 params.push(TypeParameter {
696 name: next.0,
697 class_bound: Some(class_bound),
698 iface_bounds,
699 });
700 if c.1 == '>' {
701 return Ok((params, chars.next()));
702 } else {
703 next = consume_unqualified_identifer_(c, chars)?;
704 }
706 }
707 }
708 }
709 }
710 }
711 Some((pos, _)) => {
712 return Err(ParseError::new(
713 "TypeParameter",
714 pos,
715 "bad input; expected `:`",
716 ))
717 }
718 None => return Err(ParseError::eof("TypeParameter")),
719 }
720 }
721 }
722 c => Ok((params, c)),
723 }
724}
725
726#[cfg(test)]
727mod tests {
728 use super::*;
729
730 #[test]
731 fn test_consume_method_signature() {
732 let s = "([Ljava/lang/String;Ljava/util/Hashtable<**>;)Ljava/lang/Object;";
733 let mut chars = &mut s.char_indices();
734 let r = consume_method_signature(&mut chars);
735 assert_eq!(None, chars.next());
736 let r = r.expect("signature not parsed successfully");
737 assert!(r.type_params.is_empty());
738 assert_eq!(2, r.parameters.len());
739 assert!(matches!(
740 r.parameters[0],
741 JavaType::Reference(ReferenceType::Array {
742 dimension: 1,
743 ty: _
744 })
745 ));
746 }
747
748 #[test]
749 fn test_consume_type_parameters() {
750 for s in &[
751 "<T::Ljava/io/Serializable;>",
752 "<T::Ljava/io/Serializable;:Ljava/lang/Comparable<TT;>;>",
753 "<K:Ljava/lang/Object;V:Ljava/lang/Object;>",
754 "<OP::Ljdk/incubator/vector/VectorOperators$Operator;T:Ljava/lang/Object;>",
755 ] {
756 let mut chars = &mut s.char_indices();
757 assert_eq!(
758 Ok(None),
759 consume_type_parameters(&mut chars).map(|(_, next)| next),
760 "failed to recognize: `{}`",
761 s
762 );
763 }
764 }
765
766 #[test]
767 fn test_structure_consume_type_parameters() {
768 for s in &[
769 "<Entity::Lfoo/bar/core/model/Identifiable<TId;>;Id::Ljava/io/Serializable;>",
770 "<K:Ljava/lang/Object;V:Ljava/lang/Object;>",
771 ] {
772 let (params, next) =
773 consume_type_parameters(&mut s.char_indices()).expect("invalid signature");
774 assert_eq!(None, next, "failed on signature: {}", s);
775 assert_eq!(2, params.len(), "on signature: {}", s);
776 }
777 }
778
779 #[test]
780 fn test_consume_unqualified_identifer() {
781 let chars = &mut ".".char_indices();
782 assert!(consume_unqualified_identifer(chars).is_err());
783
784 let chars = &mut "foobar".char_indices();
785 assert_eq!(
786 Ok(((0..6).into(), None)),
787 consume_unqualified_identifer(chars)
788 );
789
790 let chars = &mut "foo/bar".char_indices();
791 assert_eq!(
792 Ok(((0..3).into(), Some((3, '/')))),
793 consume_unqualified_identifer(chars)
794 );
795 assert_eq!(Some((4, 'b')), chars.next());
796 }
797}