Skip to main content

java_lang/ast/
path.rs

1//! Path types.
2
3use std::fmt;
4
5use crate::{ident::Ident, span::Span};
6
7use super::ty::Type;
8
9/// A qualified path like `java.util.List` or just `List`.
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Path {
12    pub segments: Vec<PathSegment>,
13    pub span: Span,
14}
15
16impl Path {
17    /// Create a path from a single identifier.
18    pub fn from_ident(ident: Ident) -> Self {
19        let span = ident.span();
20        Path {
21            segments: vec![PathSegment { ident, args: None }],
22            span,
23        }
24    }
25
26    /// Check if this path is a simple identifier (single segment, no type args).
27    pub fn is_ident(&self) -> bool {
28        self.segments.len() == 1 && self.segments[0].args.is_none()
29    }
30
31    /// Get the last identifier in the path.
32    pub fn last_ident(&self) -> &Ident {
33        &self.segments.last().unwrap().ident
34    }
35
36    /// Get the last segment of the path.
37    pub fn last_segment(&self) -> &PathSegment {
38        self.segments.last().unwrap()
39    }
40}
41
42impl fmt::Display for Path {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        for (i, seg) in self.segments.iter().enumerate() {
45            if i > 0 {
46                write!(f, ".")?;
47            }
48            write!(f, "{}", seg.ident)?;
49            if let Some(args) = &seg.args {
50                write!(f, "<")?;
51                for (j, arg) in args.args.iter().enumerate() {
52                    if j > 0 {
53                        write!(f, ", ")?;
54                    }
55                    match arg {
56                        TypeArgument::Type(ty) => write!(f, "{:?}", ty)?,
57                        TypeArgument::Wildcard(w) => write!(f, "{:?}", w)?,
58                    }
59                }
60                write!(f, ">")?;
61            }
62        }
63        Ok(())
64    }
65}
66
67impl fmt::Display for PathSegment {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(f, "{}", self.ident)?;
70        if let Some(args) = &self.args {
71            write!(f, "<")?;
72            for (j, arg) in args.args.iter().enumerate() {
73                if j > 0 {
74                    write!(f, ", ")?;
75                }
76                match arg {
77                    TypeArgument::Type(ty) => write!(f, "{:?}", ty)?,
78                    TypeArgument::Wildcard(w) => write!(f, "{:?}", w)?,
79                }
80            }
81            write!(f, ">")?;
82        }
83        Ok(())
84    }
85}
86
87/// A segment of a path, optionally with type arguments.
88#[derive(Debug, Clone, PartialEq, Eq, Hash)]
89pub struct PathSegment {
90    pub ident: Ident,
91    pub args: Option<TypeArguments>,
92}
93
94/// Type arguments: `<String, Integer>`.
95#[derive(Debug, Clone, PartialEq, Eq, Hash)]
96pub struct TypeArguments {
97    pub args: Vec<TypeArgument>,
98    pub lt_token: Span,
99    pub gt_tokens: Vec<Span>, // Multiple > tokens for nested generics
100}
101
102/// A type argument, which can be a concrete type or a wildcard.
103#[derive(Debug, Clone, PartialEq, Eq, Hash)]
104pub enum TypeArgument {
105    /// A specific type: `String`, `List<Integer>`.
106    Type(Box<Type>),
107    /// A wildcard: `?`, `? extends Number`, `? super String`.
108    Wildcard(Wildcard),
109}
110
111/// A wildcard type argument: `? extends T` or `? super T`.
112#[derive(Debug, Clone, PartialEq, Eq, Hash)]
113pub struct Wildcard {
114    pub bound: Option<WildcardBound>,
115    pub span: Span,
116}
117
118/// The bound of a wildcard type argument.
119#[derive(Debug, Clone, PartialEq, Eq, Hash)]
120pub enum WildcardBound {
121    Extends(Box<Type>),
122    Super(Box<Type>),
123}