lisette_syntax/parse/
annotations.rs1use super::{MAX_TUPLE_ARITY, Parser};
2use crate::ast::{Annotation, Expression, Generic, Span, Visibility};
3use crate::lex::TokenKind::*;
4use crate::types::Type;
5
6impl<'source> Parser<'source> {
7 pub fn parse_annotation(&mut self) -> Annotation {
8 if !self.enter_recursion() {
9 self.resync_on_error();
10 return Annotation::Unknown;
11 }
12 let result = self.parse_annotation_inner();
13 self.leave_recursion();
14 result
15 }
16
17 fn parse_annotation_inner(&mut self) -> Annotation {
18 match self.current_token().kind {
19 Function => self.parse_function_annotation(),
20 LeftParen => self.parse_tuple_annotation(),
21 LeftSquareBracket => {
22 let start = self.current_token();
23 self.next();
24 if self.advance_if(RightSquareBracket) {
25 let type_token = self.current_token();
26 let type_name = if type_token.kind == Identifier {
27 type_token.text.to_string()
28 } else {
29 "T".to_string()
30 };
31 let span_end = if type_token.kind == Identifier {
32 type_token.byte_offset + type_token.byte_length
33 } else {
34 start.byte_offset + 2
35 };
36 let error_span = Span::new(
37 self.file_id,
38 start.byte_offset,
39 span_end - start.byte_offset,
40 );
41 self.track_error_at(
42 error_span,
43 "invalid syntax for `Slice`",
44 format!("Use `Slice<{}>` instead of `[]{}`", type_name, type_name),
45 );
46 if self.current_token().kind == Identifier {
47 return self.parse_named_annotation();
48 }
49 return Annotation::Constructor {
50 name: "Slice".into(),
51 params: vec![],
52 span: error_span,
53 };
54 }
55 let span = self.span_from_tokens(start);
56 self.track_error("unexpected `[` in type", "Use `Slice<T>` for slice types.");
57 Annotation::Constructor {
58 name: "".into(),
59 params: vec![],
60 span,
61 }
62 }
63 _ => self.parse_named_annotation(),
64 }
65 }
66
67 fn parse_named_annotation(&mut self) -> Annotation {
68 let start = self.current_token();
69 let name = self.read_identifier_sequence();
70
71 let params = if self.advance_if(LeftAngleBracket) {
72 let mut type_params = vec![];
73
74 while self.can_start_annotation() {
75 type_params.push(self.parse_annotation());
76 match self.current_token().kind {
77 RightAngleBracket | ShiftRight => break,
78 Comma => self.next(),
79 _ => break,
80 }
81 if self.is_right_angle_like() {
82 self.track_error("expected type", "Add a type or remove the trailing comma.");
83 }
84 }
85
86 if !self.advance_if_right_angle() {
87 self.track_error("expected `>`", "Add `>` to close the type arguments.");
88 }
89
90 type_params
91 } else {
92 vec![]
93 };
94
95 Annotation::Constructor {
96 name,
97 params,
98 span: self.span_from_tokens(start),
99 }
100 }
101
102 fn parse_function_annotation(&mut self) -> Annotation {
103 let start = self.current_token();
104 self.ensure(Function);
105 self.ensure(LeftParen);
106
107 let mut params = vec![];
108
109 while self.is_not(RightParen) {
110 params.push(self.parse_annotation());
111 self.expect_comma_or(RightParen);
112 }
113
114 self.ensure(RightParen);
115
116 let return_type = self.parse_function_return_annotation();
117
118 Annotation::Function {
119 params,
120 return_type: return_type.into(),
121 span: self.span_from_tokens(start),
122 }
123 }
124
125 fn parse_tuple_annotation(&mut self) -> Annotation {
126 let start = self.current_token();
127 self.ensure(LeftParen);
128
129 let mut annotations = vec![];
130 let mut has_trailing_comma = false;
131
132 while self.is_not(RightParen) {
133 annotations.push(self.parse_annotation());
134 has_trailing_comma = self.is(Comma);
135 self.expect_comma_or(RightParen);
136 }
137
138 self.ensure(RightParen);
139
140 let span = self.span_from_tokens(start);
141
142 if annotations.is_empty() {
143 return Annotation::unit();
144 }
145
146 if annotations.len() == 1 {
147 if has_trailing_comma {
148 self.error_tuple_arity(1, span);
149 }
150 return annotations.into_iter().next().expect("len is 1");
151 }
152
153 if annotations.len() > MAX_TUPLE_ARITY {
154 self.error_tuple_arity(annotations.len(), span);
155 }
156
157 Annotation::Tuple {
158 elements: annotations,
159 span,
160 }
161 }
162
163 pub fn parse_generics(&mut self) -> Vec<Generic> {
164 if !self.advance_if(LeftAngleBracket) {
165 return vec![];
166 }
167
168 let mut generics = vec![];
169
170 while !self.is_right_angle_like() && !self.at_eof() {
171 generics.push(self.parse_generic());
172 self.expect_comma_or(RightAngleBracket);
173 }
174
175 if !self.advance_if_right_angle() {
176 self.ensure(RightAngleBracket);
177 }
178
179 generics
180 }
181
182 fn parse_generic(&mut self) -> Generic {
183 let start = self.current_token();
184
185 Generic {
186 name: self.read_identifier(),
187 bounds: self.parse_generic_bounds(),
188 span: self.span_from_tokens(start),
189 }
190 }
191
192 fn parse_generic_bounds(&mut self) -> Vec<Annotation> {
193 if !self.advance_if(Colon) {
194 return vec![];
195 }
196
197 if self.is_right_angle_like() || self.is(Comma) {
198 self.track_error(
199 "expected bound after `:`",
200 "Provide a bound like `T: Display`.",
201 );
202 return vec![];
203 }
204
205 let mut bounds = vec![];
206
207 while !self.is_right_angle_like() && self.is_not(Comma) {
208 bounds.push(self.parse_annotation());
209 if self.is_right_angle_like() || self.is(Comma) {
210 break;
211 }
212 if !self.advance_if(Plus) {
213 self.track_error(
214 "missing `+` between bounds",
215 "Use `+` to separate multiple bounds.",
216 );
217 break;
218 }
219 if self.is_right_angle_like() || self.is(Comma) {
220 self.track_error(
221 "expected bound after `+`",
222 "Provide a bound or remove the trailing `+`.",
223 );
224 }
225 }
226
227 bounds
228 }
229
230 pub fn parse_function_return_annotation(&mut self) -> Annotation {
231 if self.advance_if(Arrow) {
232 return self.parse_annotation();
233 }
234
235 Annotation::Unknown
236 }
237
238 pub fn parse_interface_method(
239 &mut self,
240 doc: Option<std::string::String>,
241 attributes: Vec<crate::ast::Attribute>,
242 ) -> Expression {
243 self.ensure(Function);
244
245 let start = self.current_token();
246 let name_token = self.current_token();
247 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
248 let name = self.read_identifier();
249
250 if self.is(LeftAngleBracket) {
251 let generics_start = self.current_token();
252 let generics = self.parse_generics(); let generics_span = self.span_from_tokens(generics_start);
254 self.error_interface_method_with_type_parameters(generics_span, generics.len());
255 }
256
257 Expression::Function {
258 doc,
259 attributes,
260 name,
261 name_span,
262 generics: vec![],
263 params: self.parse_function_params(),
264 return_annotation: self.parse_function_return_annotation(),
265 return_type: Type::uninferred(),
266 visibility: Visibility::Private,
267 body: Expression::NoOp.into(),
268 ty: Type::uninferred(),
269 span: self.span_from_tokens(start),
270 }
271 }
272
273 pub fn parse_type_alias_with_doc(&mut self, doc: Option<std::string::String>) -> Expression {
274 let start = self.current_token();
275
276 self.ensure(Type);
277
278 let name_token = self.current_token();
279 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
280 let name = self.read_identifier();
281 let generics = self.parse_generics();
282
283 let annotation = if self.advance_if(Equal) {
284 self.parse_annotation()
285 } else {
286 Annotation::Opaque {
287 span: self.span_from_tokens(start),
288 }
289 };
290
291 Expression::TypeAlias {
292 doc,
293 name,
294 name_span,
295 generics,
296 annotation,
297 ty: Type::uninferred(),
298 visibility: Visibility::Private,
299 span: self.span_from_tokens(start),
300 }
301 }
302}