Skip to main content

wdl_ast/v1/
struct.rs

1//! V1 AST representation for struct definitions.
2
3use std::fmt;
4
5use wdl_grammar::SyntaxTokenExt;
6
7use super::MetadataSection;
8use super::ParameterMetadataSection;
9use super::StructKeyword;
10use super::UnboundDecl;
11use crate::AstNode;
12use crate::AstToken;
13use crate::Comment;
14use crate::Documented;
15use crate::Ident;
16use crate::SyntaxKind;
17use crate::SyntaxNode;
18use crate::TreeNode;
19
20/// Represents a struct definition.
21#[derive(Clone, Debug, PartialEq, Eq)]
22pub struct StructDefinition<N: TreeNode = SyntaxNode>(N);
23
24impl<N: TreeNode> StructDefinition<N> {
25    /// Gets the name of the struct.
26    pub fn name(&self) -> Ident<N::Token> {
27        self.token().expect("struct should have a name")
28    }
29
30    /// Gets the `struct` keyword of the struct definition.
31    pub fn keyword(&self) -> StructKeyword<N::Token> {
32        self.token().expect("struct should have a keyword")
33    }
34
35    /// Gets the items in the struct definition.
36    pub fn items(&self) -> impl Iterator<Item = StructItem<N>> + use<'_, N> {
37        StructItem::children(&self.0)
38    }
39
40    /// Gets the member declarations of the struct.
41    pub fn members(&self) -> impl Iterator<Item = UnboundDecl<N>> + use<'_, N> {
42        self.children()
43    }
44
45    /// Gets the metadata sections of the struct.
46    pub fn metadata(&self) -> impl Iterator<Item = MetadataSection<N>> + use<'_, N> {
47        self.children()
48    }
49
50    /// Gets the parameter metadata sections of the struct.
51    pub fn parameter_metadata(
52        &self,
53    ) -> impl Iterator<Item = ParameterMetadataSection<N>> + use<'_, N> {
54        self.children()
55    }
56}
57
58impl<N: TreeNode> fmt::Display for StructDefinition<N> {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        writeln!(f, "struct {} {{", self.name().text())?;
61        for member in self.members() {
62            writeln!(
63                f,
64                "  {} {}",
65                member.ty().inner().text(),
66                member.name().text()
67            )?;
68        }
69        writeln!(f, "}}")?;
70        Ok(())
71    }
72}
73
74impl<N: TreeNode> AstNode<N> for StructDefinition<N> {
75    fn can_cast(kind: SyntaxKind) -> bool {
76        kind == SyntaxKind::StructDefinitionNode
77    }
78
79    fn cast(inner: N) -> Option<Self> {
80        match inner.kind() {
81            SyntaxKind::StructDefinitionNode => Some(Self(inner)),
82            _ => None,
83        }
84    }
85
86    fn inner(&self) -> &N {
87        &self.0
88    }
89}
90
91impl Documented<SyntaxNode> for StructDefinition<SyntaxNode> {
92    fn doc_comments(&self) -> Option<Vec<Comment<<SyntaxNode as TreeNode>::Token>>> {
93        Some(crate::doc_comments::<SyntaxNode>(self.keyword().inner().preceding_trivia()).collect())
94    }
95}
96
97/// Represents an item in a struct definition.
98#[derive(Clone, Debug, PartialEq, Eq)]
99pub enum StructItem<N: TreeNode = SyntaxNode> {
100    /// The item is a member declaration.
101    Member(UnboundDecl<N>),
102    /// The item is a metadata section.
103    Metadata(MetadataSection<N>),
104    /// The item is a parameter meta section.
105    ParameterMetadata(ParameterMetadataSection<N>),
106}
107
108impl<N: TreeNode> StructItem<N> {
109    /// Returns whether or not the given syntax kind can be cast to
110    /// [`StructItem`].
111    pub fn can_cast(kind: SyntaxKind) -> bool {
112        matches!(
113            kind,
114            SyntaxKind::UnboundDeclNode
115                | SyntaxKind::MetadataSectionNode
116                | SyntaxKind::ParameterMetadataSectionNode
117        )
118    }
119
120    /// Casts the given node to [`StructItem`].
121    ///
122    /// Returns `None` if the node cannot be cast.
123    pub fn cast(inner: N) -> Option<Self> {
124        match inner.kind() {
125            SyntaxKind::UnboundDeclNode => Some(Self::Member(
126                UnboundDecl::cast(inner).expect("unbound decl to cast"),
127            )),
128            SyntaxKind::MetadataSectionNode => Some(Self::Metadata(
129                MetadataSection::cast(inner).expect("metadata section to cast"),
130            )),
131            SyntaxKind::ParameterMetadataSectionNode => Some(Self::ParameterMetadata(
132                ParameterMetadataSection::cast(inner).expect("parameter metadata section to cast"),
133            )),
134            _ => None,
135        }
136    }
137
138    /// Gets a reference to the inner node.
139    pub fn inner(&self) -> &N {
140        match self {
141            Self::Member(element) => element.inner(),
142            Self::Metadata(element) => element.inner(),
143            Self::ParameterMetadata(element) => element.inner(),
144        }
145    }
146
147    /// Attempts to get a reference to the inner [`UnboundDecl`].
148    ///
149    /// * If `self` is a [`StructItem::Member`], then a reference to the inner
150    ///   [`UnboundDecl`] is returned wrapped in [`Some`].
151    /// * Else, [`None`] is returned.
152    pub fn as_unbound_decl(&self) -> Option<&UnboundDecl<N>> {
153        match self {
154            Self::Member(d) => Some(d),
155            _ => None,
156        }
157    }
158
159    /// Consumes `self` and attempts to return the inner [`UnboundDecl`].
160    ///
161    /// * If `self` is a [`StructItem::Member`], then the inner [`UnboundDecl`]
162    ///   is returned wrapped in [`Some`].
163    /// * Else, [`None`] is returned.
164    pub fn into_unbound_decl(self) -> Option<UnboundDecl<N>> {
165        match self {
166            Self::Member(d) => Some(d),
167            _ => None,
168        }
169    }
170
171    /// Attempts to get a reference to the inner [`MetadataSection`].
172    ///
173    /// * If `self` is a [`StructItem::Metadata`], then a reference to the inner
174    ///   [`MetadataSection`] is returned wrapped in [`Some`].
175    /// * Else, [`None`] is returned.
176    pub fn as_metadata_section(&self) -> Option<&MetadataSection<N>> {
177        match self {
178            Self::Metadata(s) => Some(s),
179            _ => None,
180        }
181    }
182
183    /// Consumes `self` and attempts to return the inner [`MetadataSection`].
184    ///
185    /// * If `self` is a [`StructItem::Metadata`], then the inner
186    ///   [`MetadataSection`] is returned wrapped in [`Some`].
187    /// * Else, [`None`] is returned.
188    pub fn into_metadata_section(self) -> Option<MetadataSection<N>> {
189        match self {
190            Self::Metadata(s) => Some(s),
191            _ => None,
192        }
193    }
194
195    /// Attempts to get a reference to the inner [`ParameterMetadataSection`].
196    ///
197    /// * If `self` is a [`StructItem::ParameterMetadata`], then a reference to
198    ///   the inner [`ParameterMetadataSection`] is returned wrapped in
199    ///   [`Some`].
200    /// * Else, [`None`] is returned.
201    pub fn as_parameter_metadata_section(&self) -> Option<&ParameterMetadataSection<N>> {
202        match self {
203            Self::ParameterMetadata(s) => Some(s),
204            _ => None,
205        }
206    }
207
208    /// Consumes `self` and attempts to return the inner
209    /// [`ParameterMetadataSection`].
210    ///
211    /// * If `self` is a [`StructItem::ParameterMetadata`], then the inner
212    ///   [`ParameterMetadataSection`] is returned wrapped in [`Some`].
213    /// * Else, [`None`] is returned.
214    pub fn into_parameter_metadata_section(self) -> Option<ParameterMetadataSection<N>> {
215        match self {
216            Self::ParameterMetadata(s) => Some(s),
217            _ => None,
218        }
219    }
220
221    /// Finds the first child that can be cast to a [`StructItem`].
222    pub fn child(node: &N) -> Option<Self> {
223        node.children().find_map(Self::cast)
224    }
225
226    /// Finds all children that can be cast to a [`StructItem`].
227    pub fn children(node: &N) -> impl Iterator<Item = Self> + use<'_, N> {
228        node.children().filter_map(Self::cast)
229    }
230}
231
232#[cfg(test)]
233mod test {
234    use pretty_assertions::assert_eq;
235
236    use crate::AstToken;
237    use crate::Document;
238
239    #[test]
240    fn struct_definitions() {
241        let (document, diagnostics) = Document::parse(
242            r#"
243version 1.1
244
245struct Empty {}
246
247struct PrimitiveTypes {
248    Boolean a
249    Boolean? b
250    Int c
251    Int? d
252    Float e
253    Float? f
254    String g
255    String? h
256    File i
257    File? j
258    Directory k
259    Directory? l
260
261    meta {
262        ok: "good"
263    }
264
265    parameter_meta {
266        a: "foo"
267    }
268}
269
270struct ComplexTypes {
271    Map[Boolean, String] a
272    Map[Int?, Array[String]]? b
273    Array[Boolean] c
274    Array[Array[Float]] d
275    Pair[Boolean, Boolean] e
276    Pair[Array[String], Array[String?]] f
277    Object g
278    Object? h
279    MyType i
280    MyType? j
281    Array[Directory] k
282
283    meta {
284        ok: "good"
285    }
286
287    parameter_meta {
288        a: "foo"
289    }
290}
291"#,
292        );
293        assert!(diagnostics.is_empty());
294        let ast = document.ast();
295        let ast = ast.as_v1().expect("should be a V1 AST");
296        let structs: Vec<_> = ast.structs().collect();
297        assert_eq!(structs.len(), 3);
298
299        // First struct definition
300        assert_eq!(structs[0].name().text(), "Empty");
301        assert_eq!(structs[0].members().count(), 0);
302
303        // Second struct definition
304        assert_eq!(structs[1].name().text(), "PrimitiveTypes");
305        let members: Vec<_> = structs[1].members().collect();
306        assert_eq!(members.len(), 12);
307
308        // First member
309        assert_eq!(members[0].name().text(), "a");
310        assert_eq!(members[0].ty().to_string(), "Boolean");
311        assert!(!members[0].ty().is_optional());
312
313        // Second member
314        assert_eq!(members[1].name().text(), "b");
315        assert_eq!(members[1].ty().to_string(), "Boolean?");
316        assert!(members[1].ty().is_optional());
317
318        // Third member
319        assert_eq!(members[2].name().text(), "c");
320        assert_eq!(members[2].ty().to_string(), "Int");
321        assert!(!members[2].ty().is_optional());
322
323        // Fourth member
324        assert_eq!(members[3].name().text(), "d");
325        assert_eq!(members[3].ty().to_string(), "Int?");
326        assert!(members[3].ty().is_optional());
327
328        // Fifth member
329        assert_eq!(members[4].name().text(), "e");
330        assert_eq!(members[4].ty().to_string(), "Float");
331        assert!(!members[4].ty().is_optional());
332
333        // Sixth member
334        assert_eq!(members[5].name().text(), "f");
335        assert_eq!(members[5].ty().to_string(), "Float?");
336        assert!(members[5].ty().is_optional());
337
338        // Seventh member
339        assert_eq!(members[6].name().text(), "g");
340        assert_eq!(members[6].ty().to_string(), "String");
341        assert!(!members[6].ty().is_optional());
342
343        // Eighth member
344        assert_eq!(members[7].name().text(), "h");
345        assert_eq!(members[7].ty().to_string(), "String?");
346        assert!(members[7].ty().is_optional());
347
348        // Ninth member
349        assert_eq!(members[8].name().text(), "i");
350        assert_eq!(members[8].ty().to_string(), "File");
351        assert!(!members[8].ty().is_optional());
352
353        // Tenth member
354        assert_eq!(members[9].name().text(), "j");
355        assert_eq!(members[9].ty().to_string(), "File?");
356        assert!(members[9].ty().is_optional());
357
358        // Eleventh member
359        assert_eq!(members[10].name().text(), "k");
360        assert_eq!(members[10].ty().to_string(), "Directory");
361        assert!(!members[10].ty().is_optional());
362
363        // Twelfth member
364        assert_eq!(members[11].name().text(), "l");
365        assert_eq!(members[11].ty().to_string(), "Directory?");
366        assert!(members[11].ty().is_optional());
367
368        // Third struct definition
369        assert_eq!(structs[2].name().text(), "ComplexTypes");
370        let members: Vec<_> = structs[2].members().collect();
371        assert_eq!(members.len(), 11);
372
373        // First member
374        assert_eq!(members[0].name().text(), "a");
375        assert_eq!(members[0].ty().to_string(), "Map[Boolean, String]");
376        assert!(!members[0].ty().is_optional());
377
378        // Second member
379        assert_eq!(members[1].name().text(), "b");
380        assert_eq!(members[1].ty().to_string(), "Map[Int?, Array[String]]?");
381        assert!(members[1].ty().is_optional());
382
383        // Third member
384        assert_eq!(members[2].name().text(), "c");
385        assert_eq!(members[2].ty().to_string(), "Array[Boolean]");
386        assert!(!members[2].ty().is_optional());
387
388        // Fourth member
389        assert_eq!(members[3].name().text(), "d");
390        assert_eq!(members[3].ty().to_string(), "Array[Array[Float]]");
391        assert!(!members[3].ty().is_optional());
392
393        // Fifth member
394        assert_eq!(members[4].name().text(), "e");
395        assert_eq!(members[4].ty().to_string(), "Pair[Boolean, Boolean]");
396        assert!(!members[4].ty().is_optional());
397
398        // Sixth member
399        assert_eq!(members[5].name().text(), "f");
400        assert_eq!(
401            members[5].ty().to_string(),
402            "Pair[Array[String], Array[String?]]"
403        );
404        assert!(!members[5].ty().is_optional());
405
406        // Seventh member
407        assert_eq!(members[6].name().text(), "g");
408        assert_eq!(members[6].ty().to_string(), "Object");
409        assert!(!members[6].ty().is_optional());
410
411        // Eighth member
412        assert_eq!(members[7].name().text(), "h");
413        assert_eq!(members[7].ty().to_string(), "Object?");
414        assert!(members[7].ty().is_optional());
415
416        // Ninth member
417        assert_eq!(members[8].name().text(), "i");
418        assert_eq!(members[8].ty().to_string(), "MyType");
419        assert!(!members[8].ty().is_optional());
420
421        // Tenth member
422        assert_eq!(members[9].name().text(), "j");
423        assert_eq!(members[9].ty().to_string(), "MyType?");
424        assert!(members[9].ty().is_optional());
425
426        // Eleventh member
427        assert_eq!(members[10].name().text(), "k");
428        assert_eq!(members[10].ty().to_string(), "Array[Directory]");
429        assert!(!members[10].ty().is_optional());
430    }
431}