Skip to main content

lisette_syntax/parse/
definitions.rs

1use ecow::EcoString;
2
3use super::Parser;
4use crate::ast::{
5    Annotation, Attribute, AttributeArg, EnumFieldDefinition, EnumVariant, Expression, Generic,
6    Literal, ParentInterface, Span, StructFieldDefinition, StructKind, ValueEnumVariant,
7    VariantFields, Visibility,
8};
9use crate::lex::Token;
10use crate::lex::TokenKind::*;
11use crate::parse::error::ParseError;
12use crate::types::Type;
13
14impl<'source> Parser<'source> {
15    pub(crate) fn parse_attributes(&mut self) -> Vec<Attribute> {
16        let mut attributes = vec![];
17        loop {
18            self.advance_if(Semicolon);
19            if !self.is(Hash) {
20                break;
21            }
22            if let Some(attribute) = self.parse_attribute() {
23                attributes.push(attribute);
24            }
25        }
26        attributes
27    }
28
29    fn parse_attribute(&mut self) -> Option<Attribute> {
30        let start = self.current_token();
31        self.ensure(Hash);
32
33        if !self.is(LeftSquareBracket) {
34            self.track_error("expected `[` after `#`", "Add `[` to start the attribute");
35            return None;
36        }
37        self.next();
38
39        if !self.is(Identifier) {
40            self.track_error(
41                "expected attribute name",
42                "Add an attribute name like `json` or `db`",
43            );
44            while self.is_not(RightSquareBracket) && !self.at_eof() {
45                self.next();
46            }
47            self.advance_if(RightSquareBracket);
48            return None;
49        }
50
51        let name = self.read_identifier();
52        let args = if self.advance_if(LeftParen) {
53            self.parse_attribute_args()
54        } else {
55            vec![]
56        };
57
58        if !self.advance_if(RightSquareBracket) {
59            self.track_error("expected `]`", "Add `]` to close the attribute");
60        }
61
62        Some(Attribute {
63            name: name.to_string(),
64            args,
65            span: self.span_from_tokens(start),
66        })
67    }
68
69    fn parse_attribute_args(&mut self) -> Vec<AttributeArg> {
70        let mut args = vec![];
71
72        while self.is_not(RightParen) && !self.at_eof() {
73            if let Some(arg) = self.parse_attribute_arg() {
74                args.push(arg);
75            }
76
77            if !self.advance_if(Comma) {
78                break;
79            }
80        }
81
82        self.ensure(RightParen);
83        args
84    }
85
86    fn parse_attribute_arg(&mut self) -> Option<AttributeArg> {
87        if self.advance_if(Bang) {
88            if self.is(Identifier) {
89                return Some(AttributeArg::NegatedFlag(
90                    self.read_identifier().to_string(),
91                ));
92            } else {
93                self.track_error(
94                    "expected identifier after `!`",
95                    "Add an identifier like `omitempty` after `!`",
96                );
97                return None;
98            }
99        }
100
101        if self.is(Identifier) {
102            return Some(AttributeArg::Flag(self.read_identifier().to_string()));
103        }
104
105        if self.is(String) {
106            let token = self.current_token();
107            self.next();
108            let text = token.text;
109            let value = if text.len() >= 2 {
110                &text[1..text.len() - 1]
111            } else {
112                text
113            };
114            return Some(AttributeArg::String(value.to_string()));
115        }
116
117        if self.is(Backtick) {
118            let token = self.current_token();
119            self.next();
120            let text = token.text;
121            let value = if text.len() >= 2 {
122                &text[1..text.len() - 1]
123            } else {
124                text
125            };
126            return Some(AttributeArg::Raw(value.to_string()));
127        }
128
129        self.track_error(
130            "expected attribute argument",
131            "Add a flag (e.g. `omitempty`), string (e.g. `\"name\"`), or raw tag (e.g. `` `json:\"name\"` ``)",
132        );
133        None
134    }
135
136    pub fn parse_enum_definition(
137        &mut self,
138        doc: Option<std::string::String>,
139        attributes: Vec<Attribute>,
140    ) -> Expression {
141        let start = self.current_token();
142
143        self.ensure(Enum);
144
145        let name_token = self.current_token();
146        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
147        let name = self.read_identifier();
148        let generics = self.parse_generics();
149
150        let underlying_start = self.current_token();
151        let underlying_ty = if self.advance_if(Colon) {
152            let annotation = self.parse_annotation();
153            Some((annotation, underlying_start))
154        } else {
155            None
156        };
157
158        self.ensure(LeftCurlyBrace);
159
160        if self.peek_is_value_enum_variant() {
161            if !generics.is_empty() {
162                let generics_span = generics.first().expect("non-empty").span;
163                let param_word = if generics.len() == 1 {
164                    "parameter"
165                } else {
166                    "parameters"
167                };
168                let error = ParseError::new(
169                    "Value enum with generics",
170                    generics_span,
171                    "not allowed on value enums",
172                )
173                .with_parse_code("value_enum_generics")
174                .with_help(format!(
175                    "Remove the generic {}. Value enums represent Go const groups, which cannot be generic.",
176                    param_word
177                ));
178                self.errors.push(error);
179            }
180
181            let underlying_ty = underlying_ty.map(|(annotation, _)| annotation);
182            return self.parse_value_enum_body(doc, name, name_span, underlying_ty, start);
183        }
184
185        if let Some((_, underlying_token)) = underlying_ty {
186            let underlying_span = Span::new(
187                self.file_id,
188                underlying_token.byte_offset,
189                underlying_token.byte_length,
190            );
191            let error = ParseError::new(
192                "Underlying type on regular enum",
193                underlying_span,
194                "only allowed on value enums",
195            )
196            .with_parse_code("enum_underlying_type")
197            .with_help(
198                "Remove the `: type` annotation. Underlying types are allowed only on value enums, which represent Go const groups.",
199            );
200            self.errors.push(error);
201        }
202
203        self.parse_regular_enum_body(doc, attributes, name, name_span, generics, start)
204    }
205
206    fn peek_is_value_enum_variant(&self) -> bool {
207        if self.is(RightCurlyBrace) {
208            return false;
209        }
210
211        let mut offset = 0;
212        while self.stream.peek_ahead(offset).kind == DocComment {
213            offset += 1;
214        }
215
216        self.stream.peek_ahead(offset).kind == Identifier
217            && self.stream.peek_ahead(offset + 1).kind == Equal
218    }
219
220    fn parse_regular_enum_body(
221        &mut self,
222        doc: Option<std::string::String>,
223        attributes: Vec<Attribute>,
224        name: EcoString,
225        name_span: Span,
226        generics: Vec<Generic>,
227        start: Token<'source>,
228    ) -> Expression {
229        let mut variants = vec![];
230        let mut seen_variants: Vec<(EcoString, Span)> = vec![];
231
232        while self.is_not(RightCurlyBrace) {
233            let start_position = self.stream.position;
234
235            let variant_doc = self.collect_doc_comments().map(|(text, _)| text);
236            if let Some(variant) = self.parse_enum_variant_with_doc(variant_doc) {
237                if let Some((_, first_span)) =
238                    seen_variants.iter().find(|(n, _)| n == &variant.name)
239                {
240                    self.error_duplicate_enum_variant(
241                        &variant.name,
242                        *first_span,
243                        variant.name_span,
244                    );
245                } else {
246                    seen_variants.push((variant.name.clone(), variant.name_span));
247                }
248                variants.push(variant);
249            }
250            self.expect_comma_or(RightCurlyBrace);
251            self.ensure_progress(start_position, RightCurlyBrace);
252        }
253
254        self.ensure(RightCurlyBrace);
255
256        Expression::Enum {
257            doc,
258            attributes,
259            name,
260            name_span,
261            generics,
262            variants,
263            visibility: Visibility::Private,
264            span: self.span_from_tokens(start),
265        }
266    }
267
268    fn parse_value_enum_body(
269        &mut self,
270        doc: Option<std::string::String>,
271        name: EcoString,
272        name_span: Span,
273        underlying_ty: Option<Annotation>,
274        start: Token<'source>,
275    ) -> Expression {
276        let mut variants = vec![];
277        let mut seen_variants: Vec<(EcoString, Span)> = vec![];
278
279        while self.is_not(RightCurlyBrace) {
280            let start_position = self.stream.position;
281
282            let variant_doc = self.collect_doc_comments().map(|(text, _)| text);
283            if let Some(variant) = self.parse_value_enum_variant_with_doc(variant_doc) {
284                if let Some((_, first_span)) =
285                    seen_variants.iter().find(|(n, _)| n == &variant.name)
286                {
287                    self.error_duplicate_enum_variant(
288                        &variant.name,
289                        *first_span,
290                        variant.name_span,
291                    );
292                } else {
293                    seen_variants.push((variant.name.clone(), variant.name_span));
294                }
295                variants.push(variant);
296            }
297            self.expect_comma_or(RightCurlyBrace);
298            self.ensure_progress(start_position, RightCurlyBrace);
299        }
300
301        self.ensure(RightCurlyBrace);
302
303        Expression::ValueEnum {
304            doc,
305            name,
306            name_span,
307            underlying_ty,
308            variants,
309            visibility: Visibility::Public,
310            span: self.span_from_tokens(start),
311        }
312    }
313
314    fn parse_enum_variant_with_doc(
315        &mut self,
316        doc: Option<std::string::String>,
317    ) -> Option<EnumVariant> {
318        if self.is_not(Identifier) {
319            self.track_error(
320                "expected variant name",
321                "Variant names must be identifiers.",
322            );
323            return None;
324        }
325
326        let name_token = self.current_token();
327        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
328        let name = self.read_identifier();
329        let fields = self.parse_enum_variant_fields();
330
331        Some(EnumVariant {
332            doc,
333            name,
334            name_span,
335            fields,
336        })
337    }
338
339    fn parse_value_enum_variant_with_doc(
340        &mut self,
341        doc: Option<std::string::String>,
342    ) -> Option<ValueEnumVariant> {
343        if self.is_not(Identifier) {
344            self.track_error(
345                "expected variant name",
346                "Variant names must be identifiers.",
347            );
348            return None;
349        }
350
351        let name_token = self.current_token();
352        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
353        let name = self.read_identifier();
354
355        let (value, value_span) = if self.is(Equal) {
356            let eq_token = self.current_token();
357            let start_offset = eq_token.byte_offset;
358            self.next(); // consume `=`
359            let (value, value_end) = self.parse_value_enum_variant_value();
360            let span = Span::new(self.file_id, start_offset, value_end - start_offset);
361            (value, span)
362        } else {
363            (
364                Literal::Integer {
365                    value: 0,
366                    text: None,
367                },
368                name_span,
369            )
370        };
371
372        Some(ValueEnumVariant {
373            doc,
374            name,
375            name_span,
376            value,
377            value_span,
378        })
379    }
380
381    fn parse_value_enum_variant_value(&mut self) -> (Literal, u32) {
382        const EMPTY: Literal = Literal::Integer {
383            value: 0,
384            text: None,
385        };
386
387        let token = self.current_token();
388
389        match token.kind {
390            Integer => {
391                let text = token.text;
392                let end = token.byte_offset + token.byte_length;
393                let literal = self.parse_integer_text_with(text, true);
394                self.next();
395                (literal, end)
396            }
397            String => {
398                let text = token.text;
399                let end = token.byte_offset + token.byte_length;
400                self.next();
401                (
402                    Literal::String {
403                        value: text[1..text.len() - 1].to_string(),
404                        raw: false,
405                    },
406                    end,
407                )
408            }
409            Minus => {
410                let minus_offset = token.byte_offset;
411                self.next();
412                let next_token = self.current_token();
413                if next_token.kind != Integer {
414                    self.track_error(
415                        "expected integer after `-`",
416                        "Use `-42` for negative integers.",
417                    );
418                    return (EMPTY, next_token.byte_offset);
419                }
420                let text = next_token.text;
421                let end = next_token.byte_offset + next_token.byte_length;
422                let neg_span = Span::new(self.file_id, minus_offset, end - minus_offset);
423                let literal = self.parse_integer_text_with(text, true);
424                self.next();
425                let Literal::Integer { value, text: orig } = literal else {
426                    return (EMPTY, end);
427                };
428                if value > i64::MIN.unsigned_abs() {
429                    self.track_error_at(
430                        neg_span,
431                        "negative integer out of range",
432                        "Negative integer must be ≥ -9223372036854775808 (i64 minimum).",
433                    );
434                    return (EMPTY, end);
435                }
436                (
437                    Literal::Integer {
438                        value: value.wrapping_neg(),
439                        text: orig.map(|t| format!("-{t}")),
440                    },
441                    end,
442                )
443            }
444            _ => {
445                self.track_error(
446                    "expected integer or string literal",
447                    "Value enum variants require integer or string values.",
448                );
449                (EMPTY, token.byte_offset)
450            }
451        }
452    }
453
454    fn parse_enum_variant_fields(&mut self) -> VariantFields {
455        if self.advance_if(LeftParen) {
456            return self.parse_tuple_variant_fields();
457        }
458
459        if self.advance_if(LeftCurlyBrace) {
460            return self.parse_struct_variant_fields();
461        }
462
463        VariantFields::Unit
464    }
465
466    fn parse_tuple_variant_fields(&mut self) -> VariantFields {
467        let mut fields = vec![];
468
469        loop {
470            if self.at_eof()
471                || self.is(RightParen)
472                || self.is(RightCurlyBrace)
473                || !self.can_start_annotation()
474            {
475                break;
476            }
477
478            let field = EnumFieldDefinition {
479                name: format!("field{}", fields.len()).into(),
480                name_span: Span::dummy(),
481                annotation: self.parse_annotation(),
482                ty: Type::uninferred(),
483            };
484
485            fields.push(field);
486
487            self.expect_comma_or(RightParen);
488        }
489
490        self.ensure(RightParen);
491
492        VariantFields::Tuple(fields)
493    }
494
495    fn parse_struct_variant_fields(&mut self) -> VariantFields {
496        let mut fields = vec![];
497        let mut seen_fields: Vec<(EcoString, Span)> = vec![];
498
499        loop {
500            if self.at_eof()
501                || self.is(RightCurlyBrace)
502                || self.at_item_boundary()
503                || self.is_not(Identifier)
504            {
505                break;
506            }
507
508            let name_token = self.current_token();
509            let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
510            let name = self.read_identifier();
511            self.ensure(Colon);
512            let annotation = self.parse_annotation();
513
514            if let Some((_, first_span)) = seen_fields.iter().find(|(n, _)| n == &name) {
515                self.error_duplicate_struct_field(&name, *first_span, name_span);
516            } else {
517                seen_fields.push((name.clone(), name_span));
518            }
519
520            let field = EnumFieldDefinition {
521                name,
522                name_span,
523                annotation,
524                ty: Type::uninferred(),
525            };
526
527            fields.push(field);
528
529            self.expect_comma_or(RightCurlyBrace);
530        }
531
532        self.ensure(RightCurlyBrace);
533
534        VariantFields::Struct(fields)
535    }
536
537    pub fn parse_struct_definition(
538        &mut self,
539        doc: Option<std::string::String>,
540        attributes: Vec<Attribute>,
541    ) -> Expression {
542        let start = self.current_token();
543
544        self.ensure(Struct);
545
546        let name_token = self.current_token();
547        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
548        let name = self.read_identifier();
549        let generics = self.parse_generics();
550
551        if self.is(LeftParen) {
552            return self.parse_tuple_struct(doc, attributes, name, name_span, generics, start);
553        }
554
555        self.parse_named_struct(doc, attributes, name, name_span, generics, start)
556    }
557
558    fn parse_named_struct(
559        &mut self,
560        doc: Option<std::string::String>,
561        attributes: Vec<Attribute>,
562        name: EcoString,
563        name_span: Span,
564        generics: Vec<Generic>,
565        start: Token<'source>,
566    ) -> Expression {
567        let mut fields = vec![];
568        let mut seen_fields: Vec<(EcoString, Span)> = vec![];
569
570        self.ensure(LeftCurlyBrace);
571
572        while self.is_not(RightCurlyBrace) {
573            let start_position = self.stream.position;
574
575            let field_attributes = self.parse_attributes();
576            let field_doc = self.collect_doc_comments().map(|(text, _)| text);
577            if let Some(field) = self.parse_struct_field_with_doc(field_doc, field_attributes) {
578                if let Some((_, first_span)) = seen_fields.iter().find(|(n, _)| n == &field.name) {
579                    self.error_duplicate_struct_field(&field.name, *first_span, field.name_span);
580                } else {
581                    seen_fields.push((field.name.clone(), field.name_span));
582                }
583                fields.push(field);
584            }
585            self.expect_comma_or(RightCurlyBrace);
586            self.ensure_progress(start_position, RightCurlyBrace);
587        }
588
589        self.ensure(RightCurlyBrace);
590
591        Expression::Struct {
592            doc,
593            attributes,
594            name,
595            name_span,
596            generics,
597            fields,
598            kind: StructKind::Record,
599            visibility: Visibility::Private,
600            span: self.span_from_tokens(start),
601        }
602    }
603
604    fn parse_tuple_struct(
605        &mut self,
606        doc: Option<std::string::String>,
607        attributes: Vec<Attribute>,
608        name: EcoString,
609        name_span: Span,
610        generics: Vec<Generic>,
611        start: Token<'source>,
612    ) -> Expression {
613        self.ensure(LeftParen);
614
615        let mut fields = vec![];
616        let mut index = 0;
617
618        while self.is_not(RightParen) {
619            if self.at_eof() || self.at_item_boundary() || !self.can_start_annotation() {
620                break;
621            }
622
623            let field_start = self.current_token();
624            let annotation = self.parse_annotation();
625            let field_span = self.span_from_tokens(field_start);
626
627            fields.push(StructFieldDefinition {
628                doc: None,
629                attributes: vec![],
630                name: format!("_{}", index).into(),
631                name_span: field_span,
632                annotation,
633                visibility: Visibility::Private,
634                ty: Type::uninferred(),
635            });
636
637            index += 1;
638            self.expect_comma_or(RightParen);
639        }
640
641        self.ensure(RightParen);
642
643        Expression::Struct {
644            doc,
645            attributes,
646            name,
647            name_span,
648            generics,
649            fields,
650            kind: StructKind::Tuple,
651            visibility: Visibility::Private,
652            span: self.span_from_tokens(start),
653        }
654    }
655
656    fn parse_struct_field_with_doc(
657        &mut self,
658        doc: Option<std::string::String>,
659        attributes: Vec<Attribute>,
660    ) -> Option<StructFieldDefinition> {
661        let visibility = if self.advance_if(Pub) {
662            Visibility::Public
663        } else {
664            Visibility::Private
665        };
666
667        if self.is_not(Identifier) {
668            self.track_error("expected field name", "Field names must be identifiers.");
669            return None;
670        }
671
672        let name_token = self.current_token();
673        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
674        let name = self.read_identifier();
675
676        self.ensure(Colon);
677
678        Some(StructFieldDefinition {
679            doc,
680            attributes,
681            visibility,
682            name,
683            name_span,
684            annotation: self.parse_annotation(),
685            ty: Type::uninferred(),
686        })
687    }
688
689    pub fn parse_const_definition(&mut self, doc: Option<std::string::String>) -> Expression {
690        let start = self.current_token();
691
692        self.ensure(Const);
693
694        let identifier_token = self.current_token();
695        let identifier_span = Span::new(
696            self.file_id,
697            identifier_token.byte_offset,
698            identifier_token.byte_length,
699        );
700        let identifier = self.read_identifier();
701        let annotation = if self.advance_if(Colon) {
702            Some(self.parse_annotation())
703        } else {
704            None
705        };
706
707        let expression = if self.advance_if(Equal) {
708            self.parse_expression()
709        } else {
710            Expression::NoOp
711        };
712
713        Expression::Const {
714            doc,
715            identifier,
716            identifier_span,
717            annotation,
718            expression: expression.into(),
719            visibility: Visibility::Private,
720            ty: Type::uninferred(),
721            span: self.span_from_tokens(start),
722        }
723    }
724
725    pub fn parse_var_declaration(&mut self, doc: Option<std::string::String>) -> Expression {
726        let start = self.current_token();
727
728        self.ensure(Var);
729
730        let name_token = self.current_token();
731        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
732        let name = self.read_identifier();
733
734        self.ensure(Colon);
735        let annotation = self.parse_annotation();
736
737        Expression::VariableDeclaration {
738            doc,
739            name,
740            name_span,
741            annotation,
742            visibility: Visibility::Private,
743            ty: Type::uninferred(),
744            span: self.span_from_tokens(start),
745        }
746    }
747
748    pub fn parse_impl_block(&mut self) -> Expression {
749        let start = self.current_token();
750
751        self.ensure(Impl);
752
753        let generics = self.parse_generics();
754
755        let receiver = self.parse_annotation(); // e.g. List<T>
756
757        let (receiver_name, annotation) = match &receiver {
758            Annotation::Constructor { name, .. } => (name.clone(), receiver),
759            _ => {
760                self.track_error("expected `impl` receiver", "Use `impl TypeName { ... }`.");
761                ("".into(), Annotation::Unknown)
762            }
763        };
764
765        if self.is(For) {
766            self.track_error(
767                "invalid syntax",
768                "Lisette types satisfy interfaces automatically by having the required methods. Use `impl Type { ... }` to add methods.",
769            );
770            self.next();
771            self.parse_annotation();
772        }
773
774        let mut methods = vec![];
775
776        self.ensure(LeftCurlyBrace);
777
778        while self.is_not(RightCurlyBrace) {
779            self.advance_if(Semicolon);
780            if self.is(RightCurlyBrace) {
781                break;
782            }
783
784            let method_doc = self.collect_doc_comments();
785            let method_attrs = self.parse_attributes();
786            let is_public = self.advance_if(Pub);
787
788            if self.is(Function) {
789                let method = self.parse_function(method_doc.map(|(text, _)| text), method_attrs);
790                let method = if is_public {
791                    method.set_public()
792                } else {
793                    method
794                };
795                methods.push(method);
796            } else {
797                if let Some((_, span)) = method_doc {
798                    self.error_detached_doc_comment(span);
799                }
800                self.track_error(
801                    "expected `fn` in impl block",
802                    "Only functions are allowed in `impl` blocks.",
803                );
804                self.next();
805            }
806        }
807
808        self.ensure(RightCurlyBrace);
809
810        Expression::ImplBlock {
811            annotation,
812            methods,
813            receiver_name,
814            generics,
815            ty: Type::uninferred(),
816            span: self.span_from_tokens(start),
817        }
818    }
819
820    pub fn parse_interface_definition(&mut self, doc: Option<std::string::String>) -> Expression {
821        let start = self.current_token();
822
823        self.ensure(Interface);
824
825        let name_token = self.current_token();
826        let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
827        let name = self.read_identifier();
828
829        let generics = self.parse_generics();
830
831        let mut parents = vec![];
832        let mut seen_parents: Vec<(EcoString, Span)> = vec![];
833        let mut method_signatures = vec![];
834        let mut seen_methods: Vec<(EcoString, Span)> = vec![];
835
836        self.ensure(LeftCurlyBrace);
837
838        while self.is_not(RightCurlyBrace) {
839            self.advance_if(Semicolon);
840            if self.is(RightCurlyBrace) {
841                break;
842            }
843
844            let item_doc = self.collect_doc_comments();
845            let method_attrs = self.parse_attributes();
846            match self.current_token().kind {
847                Function => {
848                    let method =
849                        self.parse_interface_method(item_doc.map(|(text, _)| text), method_attrs);
850                    if let Expression::Function {
851                        ref name,
852                        ref name_span,
853                        ..
854                    } = method
855                    {
856                        if let Some((_, first_span)) = seen_methods.iter().find(|(n, _)| n == name)
857                        {
858                            self.error_duplicate_interface_method(name, *first_span, *name_span);
859                        } else {
860                            seen_methods.push((name.clone(), *name_span));
861                        }
862                    }
863                    method_signatures.push(method);
864                    self.advance_if(Semicolon);
865                }
866
867                Impl => {
868                    if let Some((_, span)) = item_doc {
869                        self.error_detached_doc_comment(span);
870                    }
871                    self.ensure(Impl);
872
873                    let parent_start = self.current_token();
874                    let annotation = self.parse_annotation();
875                    let parent_span = self.span_from_tokens(parent_start);
876
877                    if let Annotation::Constructor { name, .. } = &annotation {
878                        if let Some((_, first_span)) =
879                            seen_parents.iter().find(|(n, _)| n == name.as_str())
880                        {
881                            self.error_duplicate_impl_parent(*first_span, parent_span);
882                        } else {
883                            seen_parents.push((name.clone(), parent_span));
884                        }
885                    }
886
887                    parents.push(ParentInterface {
888                        annotation,
889                        ty: Type::uninferred(),
890                        span: parent_span,
891                    });
892                    self.advance_if(Semicolon);
893                }
894
895                _ => {
896                    if let Some((_, span)) = item_doc {
897                        self.error_detached_doc_comment(span);
898                    }
899                    self.track_error(
900                        "expected `fn` or `impl`",
901                        "Only functions and `impl` blocks are allowed in interfaces.",
902                    );
903                    self.next();
904                }
905            }
906        }
907
908        self.ensure(RightCurlyBrace);
909
910        Expression::Interface {
911            doc,
912            name,
913            name_span,
914            generics,
915            parents,
916            method_signatures,
917            visibility: Visibility::Private,
918            span: self.span_from_tokens(start),
919        }
920    }
921}