weedle/
types.rs

1use crate::attribute::ExtendedAttributeList;
2use crate::common::{Generics, Identifier, Parenthesized, Punctuated};
3use crate::term;
4use crate::Parse;
5
6/// Parses a union of types
7pub type UnionType<'a> = Parenthesized<Punctuated<UnionMemberType<'a>, term!(or)>>;
8
9ast_types! {
10    /// Parses either single type or a union type
11    enum Type<'a> {
12        /// Parses one of the single types
13        Single(enum SingleType<'a> {
14            Any(term!(any)),
15            NonAny(NonAnyType<'a>),
16        }),
17        Union(MayBeNull<UnionType<'a>>),
18    }
19
20    // Parses any single non-any type
21    enum NonAnyType<'a> {
22        Promise(PromiseType<'a>),
23        Integer(MayBeNull<IntegerType>),
24        FloatingPoint(MayBeNull<FloatingPointType>),
25        Boolean(MayBeNull<term!(boolean)>),
26        Byte(MayBeNull<term!(byte)>),
27        Octet(MayBeNull<term!(octet)>),
28        ByteString(MayBeNull<term!(ByteString)>),
29        DOMString(MayBeNull<term!(DOMString)>),
30        USVString(MayBeNull<term!(USVString)>),
31        Sequence(MayBeNull<SequenceType<'a>>),
32        Object(MayBeNull<term!(object)>),
33        Symbol(MayBeNull<term!(symbol)>),
34        Error(MayBeNull<term!(Error)>),
35        ArrayBuffer(MayBeNull<term!(ArrayBuffer)>),
36        DataView(MayBeNull<term!(DataView)>),
37        Int8Array(MayBeNull<term!(Int8Array)>),
38        Int16Array(MayBeNull<term!(Int16Array)>),
39        Int32Array(MayBeNull<term!(Int32Array)>),
40        Uint8Array(MayBeNull<term!(Uint8Array)>),
41        Uint16Array(MayBeNull<term!(Uint16Array)>),
42        Uint32Array(MayBeNull<term!(Uint32Array)>),
43        Uint8ClampedArray(MayBeNull<term!(Uint8ClampedArray)>),
44        Float32Array(MayBeNull<term!(Float32Array)>),
45        Float64Array(MayBeNull<term!(Float64Array)>),
46        ArrayBufferView(MayBeNull<term!(ArrayBufferView)>),
47        BufferSource(MayBeNull<term!(BufferSource)>),
48        FrozenArrayType(MayBeNull<FrozenArrayType<'a>>),
49        RecordType(MayBeNull<RecordType<'a>>),
50        Identifier(MayBeNull<Identifier<'a>>),
51    }
52
53    /// Parses `sequence<Type>`
54    struct SequenceType<'a> {
55        sequence: term!(sequence),
56        generics: Generics<Box<Type<'a>>>,
57    }
58
59    /// Parses `FrozenArray<Type>`
60    struct FrozenArrayType<'a> {
61        frozen_array: term!(FrozenArray),
62        generics: Generics<Box<Type<'a>>>,
63    }
64
65    /// Parses a nullable type. Ex: `object | object??`
66    ///
67    /// `??` means an actual ? not an optional requirement
68    #[derive(Copy)]
69    struct MayBeNull<T> where [T: Parse<'a>] {
70        type_: T,
71        q_mark: Option<term::QMark>,
72    }
73
74    /// Parses a `Promise<Type|undefined>` type
75    struct PromiseType<'a> {
76        promise: term!(Promise),
77        generics: Generics<Box<ReturnType<'a>>>,
78    }
79
80    /// Parses `unsigned? short|long|(long long)`
81    #[derive(Copy)]
82    enum IntegerType {
83        /// Parses `unsigned? long long`
84        #[derive(Copy)]
85        LongLong(struct LongLongType {
86            unsigned: Option<term!(unsigned)>,
87            long_long: (term!(long), term!(long)),
88        }),
89        /// Parses `unsigned? long`
90        #[derive(Copy)]
91        Long(struct LongType {
92            unsigned: Option<term!(unsigned)>,
93            long: term!(long),
94        }),
95        /// Parses `unsigned? short`
96        #[derive(Copy)]
97        Short(struct ShortType {
98            unsigned: Option<term!(unsigned)>,
99            short: term!(short),
100        }),
101    }
102
103    /// Parses `unrestricted? float|double`
104    #[derive(Copy)]
105    enum FloatingPointType {
106        /// Parses `unrestricted? float`
107        #[derive(Copy)]
108        Float(struct FloatType {
109            unrestricted: Option<term!(unrestricted)>,
110            float: term!(float),
111        }),
112        /// Parses `unrestricted? double`
113        #[derive(Copy)]
114        Double(struct DoubleType {
115            unrestricted: Option<term!(unrestricted)>,
116            double: term!(double),
117        }),
118    }
119
120    /// Parses `record<StringType, Type>`
121    struct RecordType<'a> {
122        record: term!(record),
123        generics: Generics<(Box<RecordKeyType<'a>>, term!(,), Box<Type<'a>>)>,
124    }
125
126    /// Parses one of the string types `ByteString|DOMString|USVString` or any other type.
127    enum RecordKeyType<'a> {
128        Byte(term!(ByteString)),
129        DOM(term!(DOMString)),
130        USV(term!(USVString)),
131        NonAny(NonAnyType<'a>),
132    }
133
134    /// Parses one of the member of a union type
135    enum UnionMemberType<'a> {
136        Single(AttributedNonAnyType<'a>),
137        Union(MayBeNull<UnionType<'a>>),
138    }
139
140    /// Parses a const type
141    enum ConstType<'a> {
142        Integer(MayBeNull<IntegerType>),
143        FloatingPoint(MayBeNull<FloatingPointType>),
144        Boolean(MayBeNull<term!(boolean)>),
145        Byte(MayBeNull<term!(byte)>),
146        Octet(MayBeNull<term!(octet)>),
147        Identifier(MayBeNull<Identifier<'a>>),
148    }
149
150    /// Parses the return type which may be `undefined` or any given Type
151    enum ReturnType<'a> {
152        Undefined(term!(undefined)),
153        Type(Type<'a>),
154    }
155
156    /// Parses `[attributes]? type`
157    struct AttributedType<'a> {
158        attributes: Option<ExtendedAttributeList<'a>>,
159        type_: Type<'a>,
160    }
161
162    /// Parses `[attributes]? type` where the type is a single non-any type
163    struct AttributedNonAnyType<'a> {
164        attributes: Option<ExtendedAttributeList<'a>>,
165        type_: NonAnyType<'a>,
166    }
167}
168
169#[cfg(test)]
170mod test {
171    use super::*;
172
173    test!(should_parse_may_be_null { "short" =>
174        "";
175        MayBeNull<crate::types::IntegerType>;
176        q_mark.is_none();
177    });
178
179    test!(should_parse_nullable { "short?" =>
180        "";
181        MayBeNull<crate::types::IntegerType>;
182        q_mark.is_some();
183    });
184
185    test_variants!(
186        ReturnType {
187            Undefined == "undefined",
188            Type == "any",
189        }
190    );
191
192    test_variants!(
193        ConstType {
194            Integer == "short",
195            FloatingPoint == "float",
196            Boolean == "boolean",
197            Byte == "byte",
198            Octet == "octet",
199            Identifier == "name",
200        }
201    );
202
203    test_variants!(
204        NonAnyType {
205            Promise == "Promise<long>",
206            Integer == "long",
207            FloatingPoint == "float",
208            Boolean == "boolean",
209            Byte == "byte",
210            Octet == "octet",
211            ByteString == "ByteString",
212            DOMString == "DOMString",
213            USVString == "USVString",
214            Sequence == "sequence<short>",
215            Object == "object",
216            Symbol == "symbol",
217            Error == "Error",
218            ArrayBuffer == "ArrayBuffer",
219            DataView == "DataView",
220            Int8Array == "Int8Array",
221            Int16Array == "Int16Array",
222            Int32Array == "Int32Array",
223            Uint8Array == "Uint8Array",
224            Uint16Array == "Uint16Array",
225            Uint32Array == "Uint32Array",
226            Uint8ClampedArray == "Uint8ClampedArray",
227            Float32Array == "Float32Array",
228            Float64Array == "Float64Array",
229            ArrayBufferView == "ArrayBufferView",
230            BufferSource == "BufferSource",
231            FrozenArrayType == "FrozenArray<short>",
232            RecordType == "record<DOMString, short>",
233            Identifier == "mango"
234        }
235    );
236
237    test_variants!(
238        UnionMemberType {
239            Single == "byte",
240            Union == "([Clamp] unsigned long or byte)"
241        }
242    );
243
244    test_variants!(
245        RecordKeyType {
246            DOM == "DOMString",
247            USV == "USVString",
248            Byte == "ByteString"
249        }
250    );
251
252    test!(should_parse_record_type { "record<DOMString, short>" =>
253        "";
254        RecordType;
255    });
256
257    test!(should_parse_record_type_alt_types { "record<u64, short>" =>
258        "";
259        RecordType;
260    });
261
262    test!(should_parse_double_type { "double" =>
263        "";
264        DoubleType;
265    });
266
267    test!(should_parse_float_type { "float" =>
268        "";
269        FloatType;
270    });
271
272    test_variants!(
273        FloatingPointType {
274            Float == "float",
275            Double == "double"
276        }
277    );
278
279    test!(should_parse_long_long_type { "long long" =>
280        "";
281        LongLongType;
282    });
283
284    test!(should_parse_long_type { "long" =>
285        "";
286        LongType;
287    });
288
289    test!(should_parse_short_type { "short" =>
290        "";
291        ShortType;
292    });
293
294    test_variants!(
295        IntegerType {
296            Short == "short",
297            Long == "long",
298            LongLong == "long long"
299        }
300    );
301
302    test!(should_parse_promise_type { "Promise<short>" =>
303        "";
304        PromiseType;
305    });
306
307    test!(should_parse_frozen_array_type { "FrozenArray<short>" =>
308        "";
309        FrozenArrayType;
310    });
311
312    test!(should_parse_sequence_type { "sequence<short>" =>
313        "";
314        SequenceType;
315    });
316
317    test_variants!(
318        SingleType {
319            Any == "any",
320            NonAny == "Promise<short>",
321        }
322    );
323
324    test_variants!(
325        Type {
326            Single == "short",
327            Union == "(short or float)"
328        }
329    );
330
331    test!(should_parse_attributed_type { "[Named] short" =>
332        "";
333        AttributedType;
334        attributes.is_some();
335    });
336
337    test!(should_parse_type_as_identifier { "DOMStringMap" =>
338        // if type is not parsed as identifier, it is parsed as `DOMString` and 'Map' is left
339        "";
340        crate::types::Type;
341    });
342
343    #[test]
344    fn should_parse_union_member_type_attributed_union() {
345        use crate::types::UnionMemberType;
346        let (rem, parsed) = UnionMemberType::parse("([Clamp] byte or [Named] byte)").unwrap();
347        assert_eq!(rem, "");
348        match parsed {
349            UnionMemberType::Union(MayBeNull {
350                type_:
351                    Parenthesized {
352                        body: Punctuated { list, .. },
353                        ..
354                    },
355                ..
356            }) => {
357                assert_eq!(list.len(), 2);
358
359                match list[0] {
360                    UnionMemberType::Single(AttributedNonAnyType { ref attributes, .. }) => {
361                        assert!(attributes.is_some());
362                    }
363
364                    _ => {
365                        panic!("Failed to parse list[0] attributes");
366                    }
367                };
368
369                match list[1] {
370                    UnionMemberType::Single(AttributedNonAnyType { ref attributes, .. }) => {
371                        assert!(attributes.is_some());
372                    }
373
374                    _ => {
375                        panic!("Failed to parse list[1] attributes");
376                    }
377                };
378            }
379
380            _ => {
381                panic!("Failed to parse");
382            }
383        }
384    }
385}