wright/parser/ty/
reference.rs

1//! Referenced types. Types that are defined by users or in the standard library.
2
3use crate::{
4    ast::ty::{ReferenceTy, Type},
5    lexer::token::TokenTy,
6    parser::{
7        Parser,
8        error::{ParserError, ParserErrorKind},
9    },
10    source_tracking::fragment::Fragment,
11};
12
13impl ReferenceTy {
14    /// Attempt to parse a reference type signature, i.e. `@u64`.
15    ///
16    /// This will leave the parser unmodified and return an error if it doesn't match the `@` symbol, however
17    /// if it does match the `@` symbol it will advance the parser and then may still return an error if the
18    /// `@` symbol is not followed by a type signature.
19    pub fn parse(parser: &mut Parser) -> Result<Self, ParserError> {
20        let Some(at_symbol) = parser.next_if_is(TokenTy::At) else {
21            return Err(ParserErrorKind::ExpectedReferenceTypeSignature
22                .at(parser.peek_fragment_or_rest_cloned()));
23        };
24
25        parser.consume_optional_whitespace();
26
27        let referenced_type = Type::parse(parser)?;
28
29        Ok(ReferenceTy {
30            matching_source: Fragment::cover(
31                &at_symbol.fragment,
32                referenced_type.matching_source(),
33            ),
34            target_ty: Box::new(referenced_type),
35        })
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use crate::{
42        ast::ty::{AtomicTyVariant, ReferenceTy},
43        lexer::Lexer,
44        parser::Parser,
45    };
46
47    #[test]
48    fn test_reference_to_atomic() {
49        let mut parser = Parser::new(Lexer::new_test("@u64"));
50        let result = ReferenceTy::parse(&mut parser).unwrap();
51
52        assert_eq!(result.matching_source.as_str(), "@u64");
53        assert_eq!(result.target_ty.downcast_primitive().unwrap().variant, AtomicTyVariant::U64);
54    }
55
56    #[test]
57    fn test_reference_to_a_reference_to_atomic() {
58        let mut parser = Parser::new(Lexer::new_test("@@u64"));
59        let result = ReferenceTy::parse(&mut parser).unwrap();
60
61        assert_eq!(result.matching_source.as_str(), "@@u64");
62        assert!(result.target_ty.downcast_reference().is_some());
63    }
64
65    #[test]
66    fn test_u8_ref() {
67        let mut parser = Parser::new(Lexer::new_test("@u8"));
68        let ref_ty = ReferenceTy::parse(&mut parser).unwrap();
69        assert_eq!(ref_ty.matching_source.len(), 3);
70        assert_eq!(ref_ty.target_ty.downcast_primitive().unwrap().variant, AtomicTyVariant::U8);
71    }
72
73    #[test]
74    fn test_nested_ref() {
75        let mut parser = Parser::new(Lexer::new_test("@@u8"));
76        let ref_ty = ReferenceTy::parse(&mut parser).unwrap();
77        assert_eq!(ref_ty.matching_source.len(), 4);
78        let inner_ref = ref_ty.target_ty.downcast_reference().unwrap();
79        assert_eq!(inner_ref.matching_source.len(), 3);
80        assert_eq!(inner_ref.target_ty.downcast_primitive().unwrap().variant, AtomicTyVariant::U8);
81    }
82}