1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::priv_prelude::*;

#[derive(Clone, Debug, Serialize)]
pub struct Annotated<T> {
    pub attribute_list: Vec<AttributeDecl>,
    pub value: T,
}

// Attributes can have any number of arguments:
//
//    #[attribute]
//    #[attribute()]
//    #[attribute(value)]
//    #[attribute(value0, value1, value2)]

#[derive(Clone, Debug, Serialize)]
pub struct AttributeDecl {
    pub hash_kind: AttributeHashKind,
    pub attribute: SquareBrackets<Punctuated<Attribute, CommaToken>>,
}

impl Spanned for AttributeDecl {
    fn span(&self) -> Span {
        let hash_span = match &self.hash_kind {
            AttributeHashKind::Inner(hash_bang_token) => hash_bang_token.span(),
            AttributeHashKind::Outer(hash_token) => hash_token.span(),
        };
        Span::join(hash_span, &self.attribute.span())
    }
}

/// Denotes the target direction of an [AttributeDecl] and
/// the hash token kind associated.
///
/// Example:
/// ```sway
/// // outer (after), written as `///`
/// #[doc("a Sway struct")]
/// struct Foo {}
///
/// // inner (before), written as `//!`
/// enum Bar {}
/// #![doc("a Sway enum")]
/// ```
#[derive(Clone, Debug, Serialize)]
pub enum AttributeHashKind {
    /// Inner specifies that the attribute belongs to
    /// the item before it.
    Inner(HashBangToken),
    /// Outer specifies that the attribute belongs to
    /// the item after it.
    Outer(HashToken),
}

#[derive(Clone, Debug, Serialize)]
pub struct AttributeArg {
    pub name: Ident,
    pub value: Option<Literal>,
}

impl Spanned for AttributeArg {
    fn span(&self) -> Span {
        if let Some(value) = &self.value {
            Span::join(self.name.span(), &value.span())
        } else {
            self.name.span()
        }
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct Attribute {
    pub name: Ident,
    pub args: Option<Parens<Punctuated<AttributeArg, CommaToken>>>,
}

impl Spanned for Attribute {
    fn span(&self) -> Span {
        self.args
            .as_ref()
            .map(|args| Span::join(self.name.span(), &args.span()))
            .unwrap_or_else(|| self.name.span())
    }
}