sway_ast/
token.rs

1use crate::priv_prelude::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4pub enum Spacing {
5    Joint,
6    Alone,
7}
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
10pub struct Punct {
11    pub span: Span,
12    pub kind: PunctKind,
13    pub spacing: Spacing,
14}
15
16impl Spanned for Punct {
17    fn span(&self) -> Span {
18        self.span.clone()
19    }
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
23pub struct GenericGroup<T> {
24    pub delimiter: Delimiter,
25    pub token_stream: T,
26    pub span: Span,
27}
28
29pub type Group = GenericGroup<TokenStream>;
30pub type CommentedGroup = GenericGroup<CommentedTokenStream>;
31
32impl<T> Spanned for GenericGroup<T> {
33    fn span(&self) -> Span {
34        self.span.clone()
35    }
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
39pub enum CommentKind {
40    /// A newlined comment is a comment with a preceding newline before another token.
41    ///
42    /// # Examples
43    ///
44    /// ```sway
45    /// pub fn main() -> bool {
46    ///     // Newlined comment
47    ///     true
48    /// }
49    /// ```
50    Newlined,
51
52    /// A trailing comment is a comment without a preceding newline before another token.
53    ///
54    /// # Examples
55    ///
56    /// ```sway
57    /// var foo = 1; // Trailing comment
58    /// ```
59    Trailing,
60
61    /// An inlined comment is a block comment nested between 2 tokens without a newline after it.
62    ///
63    /// # Examples
64    ///
65    /// ```sway
66    /// fn some_function(baz: /* inlined comment */ u64) {}
67    /// ```
68    Inlined,
69
70    /// A multiline comment is a block comment that may be nested between 2 tokens with 1 or more newlines within it.
71    ///
72    /// # Examples
73    ///
74    /// ```sway
75    /// fn some_function(baz: /* multiline
76    ///                          comment */ u64) {}
77    /// ```
78    Multilined,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
82pub struct Comment {
83    pub span: Span,
84    pub comment_kind: CommentKind,
85}
86
87impl Spanned for Comment {
88    fn span(&self) -> Span {
89        self.span.clone()
90    }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
94pub enum DocStyle {
95    Outer,
96    Inner,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
100pub struct DocComment {
101    pub span: Span,
102    pub content_span: Span,
103    pub doc_style: DocStyle,
104}
105
106impl Spanned for DocComment {
107    fn span(&self) -> Span {
108        self.span.clone()
109    }
110}
111
112/// Allows for generalizing over commented and uncommented token streams.
113#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
114pub enum GenericTokenTree<T> {
115    Punct(Punct),
116    Ident(Ident),
117    Group(GenericGroup<T>),
118    Literal(Literal),
119    DocComment(DocComment),
120}
121
122pub type TokenTree = GenericTokenTree<TokenStream>;
123pub type CommentedTree = GenericTokenTree<CommentedTokenStream>;
124
125#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
126pub enum CommentedTokenTree {
127    Comment(Comment),
128    Tree(CommentedTree),
129}
130
131impl CommentedGroup {
132    pub fn strip_comments(self) -> Group {
133        Group {
134            delimiter: self.delimiter,
135            token_stream: self.token_stream.strip_comments(),
136            span: self.span,
137        }
138    }
139}
140
141impl<T> Spanned for GenericTokenTree<T> {
142    fn span(&self) -> Span {
143        match self {
144            Self::Punct(punct) => punct.span(),
145            Self::Ident(ident) => ident.span(),
146            Self::Group(group) => group.span(),
147            Self::Literal(literal) => literal.span(),
148            Self::DocComment(doc_comment) => doc_comment.span(),
149        }
150    }
151}
152
153impl Spanned for CommentedTokenTree {
154    fn span(&self) -> Span {
155        match self {
156            Self::Comment(cmt) => cmt.span(),
157            Self::Tree(tt) => tt.span(),
158        }
159    }
160}
161
162impl<T> From<Punct> for GenericTokenTree<T> {
163    fn from(punct: Punct) -> Self {
164        Self::Punct(punct)
165    }
166}
167
168impl<T> From<Ident> for GenericTokenTree<T> {
169    fn from(ident: Ident) -> Self {
170        Self::Ident(ident)
171    }
172}
173
174impl<T> From<GenericGroup<T>> for GenericTokenTree<T> {
175    fn from(group: GenericGroup<T>) -> Self {
176        Self::Group(group)
177    }
178}
179
180impl<T> From<Literal> for GenericTokenTree<T> {
181    fn from(lit: Literal) -> Self {
182        Self::Literal(lit)
183    }
184}
185
186impl<T> From<DocComment> for GenericTokenTree<T> {
187    fn from(doc_comment: DocComment) -> Self {
188        Self::DocComment(doc_comment)
189    }
190}
191
192impl From<Comment> for CommentedTokenTree {
193    fn from(comment: Comment) -> Self {
194        Self::Comment(comment)
195    }
196}
197
198impl From<CommentedTree> for CommentedTokenTree {
199    fn from(tree: CommentedTree) -> Self {
200        Self::Tree(tree)
201    }
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
205pub struct TokenStream {
206    token_trees: Vec<TokenTree>,
207    full_span: Span,
208}
209
210#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
211pub struct CommentedTokenStream {
212    pub token_trees: Vec<CommentedTokenTree>,
213    pub full_span: Span,
214}
215
216#[extension_trait]
217impl CharExt for char {
218    fn as_open_delimiter(self) -> Option<Delimiter> {
219        match self {
220            '(' => Some(Delimiter::Parenthesis),
221            '{' => Some(Delimiter::Brace),
222            '[' => Some(Delimiter::Bracket),
223            _ => None,
224        }
225    }
226
227    fn as_close_delimiter(self) -> Option<Delimiter> {
228        match self {
229            ')' => Some(Delimiter::Parenthesis),
230            '}' => Some(Delimiter::Brace),
231            ']' => Some(Delimiter::Bracket),
232            _ => None,
233        }
234    }
235
236    fn as_punct_kind(self) -> Option<PunctKind> {
237        match self {
238            ';' => Some(PunctKind::Semicolon),
239            ':' => Some(PunctKind::Colon),
240            '/' => Some(PunctKind::ForwardSlash),
241            ',' => Some(PunctKind::Comma),
242            '*' => Some(PunctKind::Star),
243            '+' => Some(PunctKind::Add),
244            '-' => Some(PunctKind::Sub),
245            '<' => Some(PunctKind::LessThan),
246            '>' => Some(PunctKind::GreaterThan),
247            '=' => Some(PunctKind::Equals),
248            '.' => Some(PunctKind::Dot),
249            '!' => Some(PunctKind::Bang),
250            '%' => Some(PunctKind::Percent),
251            '&' => Some(PunctKind::Ampersand),
252            '^' => Some(PunctKind::Caret),
253            '|' => Some(PunctKind::Pipe),
254            '_' => Some(PunctKind::Underscore),
255            '#' => Some(PunctKind::Sharp),
256            _ => None,
257        }
258    }
259}
260
261impl TokenStream {
262    pub fn token_trees(&self) -> &[TokenTree] {
263        &self.token_trees
264    }
265}
266
267impl Spanned for TokenStream {
268    fn span(&self) -> Span {
269        self.full_span.clone()
270    }
271}
272
273impl CommentedTokenTree {
274    pub fn strip_comments(self) -> Option<TokenTree> {
275        let commented_tt = match self {
276            Self::Comment(_) => return None,
277            Self::Tree(commented_tt) => commented_tt,
278        };
279        let tt = match commented_tt {
280            CommentedTree::Punct(punct) => punct.into(),
281            CommentedTree::Ident(ident) => ident.into(),
282            CommentedTree::Group(group) => group.strip_comments().into(),
283            CommentedTree::Literal(lit) => lit.into(),
284            CommentedTree::DocComment(doc_comment) => doc_comment.into(),
285        };
286        Some(tt)
287    }
288}
289
290impl CommentedTokenStream {
291    pub fn token_trees(&self) -> &[CommentedTokenTree] {
292        &self.token_trees
293    }
294
295    pub fn strip_comments(self) -> TokenStream {
296        let token_trees = self
297            .token_trees
298            .into_iter()
299            .filter_map(|tree| tree.strip_comments())
300            .collect();
301        TokenStream {
302            token_trees,
303            full_span: self.full_span,
304        }
305    }
306}
307
308impl Spanned for CommentedTokenStream {
309    fn span(&self) -> Span {
310        self.full_span.clone()
311    }
312}