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(
57                    "unexpected `[` in type",
58                    "Use `Slice<T>` for slice types or `Array<T, N>` for fixed-size arrays.",
59                );
60                Annotation::Constructor {
61                    name: "".into(),
62                    params: vec![],
63                    span,
64                }
65            }
66            _ => self.parse_named_annotation(),
67        }
68    }
69
70    fn parse_named_annotation(&mut self) -> Annotation {
71        let start = self.current_token();
72        let name = self.read_identifier_sequence();
73
74        let params = if self.advance_if(LeftAngleBracket) {
75            let mut type_params = vec![];
76
77            while self.can_start_annotation() {
78                type_params.push(self.parse_annotation());
79                match self.current_token().kind {
80                    RightAngleBracket => break,
81                    Comma => self.next(),
82                    _ => break,
83                }
84                if self.is(RightAngleBracket) {
85                    self.track_error("expected type", "Add a type or remove the trailing comma.");
86                }
87            }
88
89            if !self.advance_if(RightAngleBracket) {
90                self.track_error("expected `>`", "Add `>` to close the type arguments.");
91            }
92
93            type_params
94        } else {
95            vec![]
96        };
97
98        Annotation::Constructor {
99            name,
100            params,
101            span: self.span_from_tokens(start),
102        }
103    }
104
105    fn parse_function_annotation(&mut self) -> Annotation {
106        let start = self.current_token();
107        self.ensure(Function);
108        self.ensure(LeftParen);
109
110        let mut params = vec![];
111
112        while self.is_not(RightParen) {
113            params.push(self.parse_annotation());
114            self.expect_comma_or(RightParen);
115        }
116
117        self.ensure(RightParen);
118
119        let return_type = self.parse_function_return_annotation();
120
121        Annotation::Function {
122            params,
123            return_type: return_type.into(),
124            span: self.span_from_tokens(start),
125        }
126    }
127
128    fn parse_tuple_annotation(&mut self) -> Annotation {
129        let start = self.current_token();
130        self.ensure(LeftParen);
131
132        let mut annotations = vec![];
133        let mut has_trailing_comma = false;
134
135        while self.is_not(RightParen) {
136            annotations.push(self.parse_annotation());
137            has_trailing_comma = self.is(Comma);
138            self.expect_comma_or(RightParen);
139        }
140
141        self.ensure(RightParen);
142
143        let span = self.span_from_tokens(start);
144
145        if annotations.is_empty() {
146            return Annotation::unit();
147        }
148
149        if annotations.len() == 1 {
150            if has_trailing_comma {
151                self.error_tuple_arity(1, span);
152            }
153            return annotations.into_iter().next().expect("len is 1");
154        }
155
156        if annotations.len() > MAX_TUPLE_ARITY {
157            self.error_tuple_arity(annotations.len(), span);
158        }
159
160        Annotation::Tuple {
161            elements: annotations,
162            span,
163        }
164    }
165
166    pub fn parse_generics(&mut self) -> Vec<Generic> {
167        if !self.advance_if(LeftAngleBracket) {
168            return vec![];
169        }
170
171        let mut generics = vec![];
172
173        while self.is_not(RightAngleBracket) {
174            generics.push(self.parse_generic());
175            self.expect_comma_or(RightAngleBracket);
176        }
177
178        self.ensure(RightAngleBracket);
179
180        generics
181    }
182
183    fn parse_generic(&mut self) -> Generic {
184        let start = self.current_token();
185
186        Generic {
187            name: self.read_identifier(),
188            bounds: self.parse_generic_bounds(),
189            span: self.span_from_tokens(start),
190        }
191    }
192
193    fn parse_generic_bounds(&mut self) -> Vec<Annotation> {
194        if !self.advance_if(Colon) {
195            return vec![];
196        }
197
198        if self.is(RightAngleBracket) || self.is(Comma) {
199            self.track_error(
200                "expected bound after `:`",
201                "Provide a bound like `T: Display`.",
202            );
203            return vec![];
204        }
205
206        let mut bounds = vec![];
207
208        while self.is_not(RightAngleBracket) && self.is_not(Comma) {
209            bounds.push(self.parse_annotation());
210            if self.is(RightAngleBracket) || self.is(Comma) {
211                break;
212            }
213            if !self.advance_if(Plus) {
214                self.track_error(
215                    "missing `+` between bounds",
216                    "Use `+` to separate multiple bounds.",
217                );
218                break;
219            }
220            if self.is(RightAngleBracket) || self.is(Comma) {
221                self.track_error(
222                    "expected bound after `+`",
223                    "Provide a bound or remove the trailing `+`.",
224                );
225            }
226        }
227
228        bounds
229    }
230
231    pub fn parse_function_return_annotation(&mut self) -> Annotation {
232        if self.advance_if(Arrow) {
233            return self.parse_annotation();
234        }
235
236        Annotation::Unknown
237    }
238
239    pub fn parse_interface_method(
240        &mut self,
241        doc: Option<std::string::String>,
242        attributes: Vec<crate::ast::Attribute>,
243    ) -> Expression {
244        self.ensure(Function);
245
246        let start = self.current_token();
247        let name_token = self.current_token();
248        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
249        let name = self.read_identifier();
250
251        if self.is(LeftAngleBracket) {
252            let generics_start = self.current_token();
253            let generics = self.parse_generics(); // consume and discard
254            let generics_span = self.span_from_tokens(generics_start);
255            self.error_interface_method_with_type_parameters(generics_span, generics.len());
256        }
257
258        Expression::Function {
259            doc,
260            attributes,
261            name,
262            name_span,
263            generics: vec![],
264            params: self.parse_function_params(),
265            return_annotation: self.parse_function_return_annotation(),
266            return_type: Type::uninferred(),
267            visibility: Visibility::Private,
268            body: Expression::NoOp.into(),
269            ty: Type::uninferred(),
270            span: self.span_from_tokens(start),
271        }
272    }
273
274    pub fn parse_type_alias_with_doc(&mut self, doc: Option<std::string::String>) -> Expression {
275        let start = self.current_token();
276
277        self.ensure(Type);
278
279        let name_token = self.current_token();
280        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
281        let name = self.read_identifier();
282        let generics = self.parse_generics();
283
284        let annotation = if self.advance_if(Equal) {
285            self.parse_annotation()
286        } else {
287            Annotation::Opaque {
288                span: self.span_from_tokens(start),
289            }
290        };
291
292        Expression::TypeAlias {
293            doc,
294            name,
295            name_span,
296            generics,
297            annotation,
298            ty: Type::uninferred(),
299            visibility: Visibility::Private,
300            span: self.span_from_tokens(start),
301        }
302    }
303}