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 => break,
78                    Comma => self.next(),
79                    _ => break,
80                }
81                if self.is(RightAngleBracket) {
82                    self.track_error("expected type", "Add a type or remove the trailing comma.");
83                }
84            }
85
86            if !self.advance_if(RightAngleBracket) {
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_not(RightAngleBracket) {
171            generics.push(self.parse_generic());
172            self.expect_comma_or(RightAngleBracket);
173        }
174
175        self.ensure(RightAngleBracket);
176
177        generics
178    }
179
180    fn parse_generic(&mut self) -> Generic {
181        let start = self.current_token();
182
183        Generic {
184            name: self.read_identifier(),
185            bounds: self.parse_generic_bounds(),
186            span: self.span_from_tokens(start),
187        }
188    }
189
190    fn parse_generic_bounds(&mut self) -> Vec<Annotation> {
191        if !self.advance_if(Colon) {
192            return vec![];
193        }
194
195        if self.is(RightAngleBracket) || self.is(Comma) {
196            self.track_error(
197                "expected bound after `:`",
198                "Provide a bound like `T: Display`.",
199            );
200            return vec![];
201        }
202
203        let mut bounds = vec![];
204
205        while self.is_not(RightAngleBracket) && self.is_not(Comma) {
206            bounds.push(self.parse_annotation());
207            if self.is(RightAngleBracket) || self.is(Comma) {
208                break;
209            }
210            if !self.advance_if(Plus) {
211                self.track_error(
212                    "missing `+` between bounds",
213                    "Use `+` to separate multiple bounds.",
214                );
215                break;
216            }
217            if self.is(RightAngleBracket) || self.is(Comma) {
218                self.track_error(
219                    "expected bound after `+`",
220                    "Provide a bound or remove the trailing `+`.",
221                );
222            }
223        }
224
225        bounds
226    }
227
228    pub fn parse_function_return_annotation(&mut self) -> Annotation {
229        if self.advance_if(Arrow) {
230            return self.parse_annotation();
231        }
232
233        Annotation::Unknown
234    }
235
236    pub fn parse_interface_method(
237        &mut self,
238        doc: Option<std::string::String>,
239        attributes: Vec<crate::ast::Attribute>,
240    ) -> Expression {
241        self.ensure(Function);
242
243        let start = self.current_token();
244        let name_token = self.current_token();
245        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
246        let name = self.read_identifier();
247
248        if self.is(LeftAngleBracket) {
249            let generics_start = self.current_token();
250            let generics = self.parse_generics(); // consume and discard
251            let generics_span = self.span_from_tokens(generics_start);
252            self.error_interface_method_with_type_parameters(generics_span, generics.len());
253        }
254
255        Expression::Function {
256            doc,
257            attributes,
258            name,
259            name_span,
260            generics: vec![],
261            params: self.parse_function_params(),
262            return_annotation: self.parse_function_return_annotation(),
263            return_type: Type::uninferred(),
264            visibility: Visibility::Private,
265            body: Expression::NoOp.into(),
266            ty: Type::uninferred(),
267            span: self.span_from_tokens(start),
268        }
269    }
270
271    pub fn parse_type_alias_with_doc(&mut self, doc: Option<std::string::String>) -> Expression {
272        let start = self.current_token();
273
274        self.ensure(Type);
275
276        let name_token = self.current_token();
277        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
278        let name = self.read_identifier();
279        let generics = self.parse_generics();
280
281        let annotation = if self.advance_if(Equal) {
282            self.parse_annotation()
283        } else {
284            Annotation::Opaque {
285                span: self.span_from_tokens(start),
286            }
287        };
288
289        Expression::TypeAlias {
290            doc,
291            name,
292            name_span,
293            generics,
294            annotation,
295            ty: Type::uninferred(),
296            visibility: Visibility::Private,
297            span: self.span_from_tokens(start),
298        }
299    }
300}