wright/parser/ty/
named.rs1use crate::{
2 ast::{
3 path::Path,
4 ty::{NamedTy, Type},
5 },
6 lexer::token::TokenTy,
7 parser::{
8 Parser,
9 error::{ParserError, ParserErrorKind},
10 },
11 source_tracking::fragment::Fragment,
12};
13
14impl NamedTy {
15 pub fn parse(parser: &mut Parser) -> Result<NamedTy, ParserError> {
17 let path = Path::parse(parser)?;
19
20 let mut generic_tys = Vec::new();
21
22 if parser.matches_ignore_whitespace(&[TokenTy::Lt]) {
24 parser.consume_optional_whitespace();
26
27 parser.advance(1);
29
30 loop {
31 let t = Type::parse(parser)?;
33
34 generic_tys.push(t);
36
37 const ENDING_SEQUENCES: &[&[TokenTy]] =
39 &[&[TokenTy::Comma, TokenTy::Gt], &[TokenTy::Gt]];
40
41 for seq in ENDING_SEQUENCES {
42 if parser.matches_ignore_whitespace(seq) {
43 for _ in 0..(seq.len() - 1) {
45 parser.consume_optional_whitespace();
46 parser.advance(1);
47 }
48
49 parser.consume_optional_whitespace();
50
51 let last_token =
53 unsafe { parser.next_token().unwrap_unchecked().unwrap_unchecked() };
54
55 let matching_source =
57 Fragment::cover(&path.full_path, &last_token.fragment);
58
59 return Ok(NamedTy {
60 matching_source,
61 name: path,
62 generic_tys,
63 });
65 }
66 }
67
68 if !parser.matches_ignore_whitespace(&[TokenTy::Comma]) {
71 let fragment = parser.peek_fragment_or_rest_cloned();
72 return Err(ParserErrorKind::UnterminatedGenericTypeSignature.at(fragment));
73 }
74
75 parser.consume_optional_whitespace();
77 parser.advance(1);
78 parser.consume_optional_whitespace();
79
80 }
82 }
83
84 Ok(NamedTy {
87 matching_source: path.full_path.clone(),
88 name: path,
89 generic_tys,
90 })
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use crate::{
98 ast::ty::{AtomicTyVariant, NamedTy},
99 lexer::Lexer,
100 parser::Parser,
101 };
102
103 #[test]
104 fn test_basic_named_type() {
105 let mut parser = Parser::new(Lexer::new_test("MyType"));
106 let named_ty = NamedTy::parse(&mut parser).expect("Failed to parse named type");
107 assert_eq!(named_ty.name.full_path.as_str(), "MyType");
108 assert_eq!(named_ty.name.full_path, named_ty.matching_source);
109 assert!(named_ty.generic_tys.is_empty());
110 }
111
112 #[test]
113 fn test_named_type_with_generics() {
114 let mut parser = Parser::new(Lexer::new_test("MyType<i8, @@@i8, OtherType<ThirdType>, >"));
115 let named_ty = NamedTy::parse(&mut parser).unwrap();
116 assert_eq!(named_ty.name.full_path.as_str(), "MyType");
117 assert_eq!(
118 named_ty.generic_tys[0]
119 .downcast_primitive()
120 .unwrap()
121 .variant,
122 AtomicTyVariant::I8
123 );
124 assert_eq!(named_ty.generic_tys[1].matching_source().as_str(), "@@@i8");
125 assert_eq!(
126 named_ty.generic_tys[2]
127 .downcast_named()
128 .unwrap()
129 .name
130 .full_path
131 .as_str(),
132 "OtherType"
133 );
134 assert_eq!(
135 named_ty.generic_tys[2]
136 .downcast_named()
137 .unwrap()
138 .matching_source
139 .as_str(),
140 "OtherType<ThirdType>"
141 );
142 }
143}