Skip to main content

lisette_syntax/parse/
annotations.rs

1use 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(); // consume and discard
253            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}