1use ecow::EcoString;
2
3use super::Parser;
4use crate::ast::{
5 Annotation, Attribute, AttributeArg, EnumFieldDefinition, EnumVariant, Expression, Generic,
6 ParentInterface, Span, StructFieldDefinition, StructKind, VariantFields, Visibility,
7};
8use crate::lex::Token;
9use crate::lex::TokenKind::*;
10use crate::parse::error::ParseError;
11use crate::types::Type;
12
13impl<'source> Parser<'source> {
14 pub(crate) fn parse_attributes(&mut self) -> Vec<Attribute> {
15 let mut attributes = vec![];
16 loop {
17 self.advance_if(Semicolon);
18 if !self.is(Hash) {
19 break;
20 }
21 if let Some(attribute) = self.parse_attribute() {
22 attributes.push(attribute);
23 }
24 }
25 attributes
26 }
27
28 fn parse_attribute(&mut self) -> Option<Attribute> {
29 let start = self.current_token();
30 self.ensure(Hash);
31
32 if !self.is(LeftSquareBracket) {
33 self.track_error("expected `[` after `#`", "Add `[` to start the attribute");
34 return None;
35 }
36 self.next();
37
38 if !self.is(Identifier) {
39 self.track_error(
40 "expected attribute name",
41 "Add an attribute name like `json` or `db`",
42 );
43 while self.is_not(RightSquareBracket) && !self.at_eof() {
44 self.next();
45 }
46 self.advance_if(RightSquareBracket);
47 return None;
48 }
49
50 let name = self.read_identifier();
51 let args = if self.advance_if(LeftParen) {
52 self.parse_attribute_args()
53 } else {
54 vec![]
55 };
56
57 if !self.advance_if(RightSquareBracket) {
58 self.track_error("expected `]`", "Add `]` to close the attribute");
59 }
60
61 Some(Attribute {
62 name: name.to_string(),
63 args,
64 span: self.span_from_tokens(start),
65 })
66 }
67
68 fn parse_attribute_args(&mut self) -> Vec<AttributeArg> {
69 let mut args = vec![];
70
71 while self.is_not(RightParen) && !self.at_eof() {
72 if let Some(arg) = self.parse_attribute_arg() {
73 args.push(arg);
74 }
75
76 if !self.advance_if(Comma) {
77 break;
78 }
79 }
80
81 self.ensure(RightParen);
82 args
83 }
84
85 fn parse_attribute_arg(&mut self) -> Option<AttributeArg> {
86 if self.advance_if(Bang) {
87 if self.is(Identifier) {
88 return Some(AttributeArg::NegatedFlag(
89 self.read_identifier().to_string(),
90 ));
91 } else {
92 self.track_error(
93 "expected identifier after `!`",
94 "Add an identifier like `omitempty` after `!`",
95 );
96 return None;
97 }
98 }
99
100 if self.is(Identifier) {
101 return Some(AttributeArg::Flag(self.read_identifier().to_string()));
102 }
103
104 if self.is(String) {
105 let token = self.current_token();
106 self.next();
107 let text = token.text;
108 let value = if text.len() >= 2 {
109 &text[1..text.len() - 1]
110 } else {
111 text
112 };
113 return Some(AttributeArg::String(value.to_string()));
114 }
115
116 if self.is(Backtick) {
117 let token = self.current_token();
118 self.next();
119 let text = token.text;
120 let value = if text.len() >= 2 {
121 &text[1..text.len() - 1]
122 } else {
123 text
124 };
125 return Some(AttributeArg::Raw(value.to_string()));
126 }
127
128 self.track_error(
129 "expected attribute argument",
130 "Add a flag (e.g. `omitempty`), string (e.g. `\"name\"`), or raw tag (e.g. `` `json:\"name\"` ``)",
131 );
132 None
133 }
134
135 pub fn parse_enum_definition(
136 &mut self,
137 doc: Option<std::string::String>,
138 attributes: Vec<Attribute>,
139 ) -> Expression {
140 let start = self.current_token();
141
142 self.ensure(Enum);
143
144 let name_token = self.current_token();
145 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
146 let name = self.read_identifier();
147 let generics = self.parse_generics();
148
149 let underlying_start = self.current_token();
150 if self.advance_if(Colon) {
151 let _ = self.parse_annotation();
152 let underlying_span = Span::new(
153 self.file_id,
154 underlying_start.byte_offset,
155 underlying_start.byte_length,
156 );
157 let error = ParseError::new(
158 "Enum with underlying type",
159 underlying_span,
160 "enums cannot have an underlying type",
161 )
162 .with_parse_code("enum_underlying_type")
163 .with_help(
164 "Remove the `: type` annotation. To model a Go defined primitive type, use a named primitive type such as `pub struct Weekday(int)` with package-level constants.",
165 );
166 self.errors.push(error);
167 }
168
169 self.ensure(LeftCurlyBrace);
170
171 self.parse_regular_enum_body(doc, attributes, name, name_span, generics, start)
172 }
173
174 fn parse_regular_enum_body(
175 &mut self,
176 doc: Option<std::string::String>,
177 attributes: Vec<Attribute>,
178 name: EcoString,
179 name_span: Span,
180 generics: Vec<Generic>,
181 start: Token<'source>,
182 ) -> Expression {
183 let mut variants = vec![];
184 let mut seen_variants: Vec<(EcoString, Span)> = vec![];
185
186 while self.is_not(RightCurlyBrace) {
187 let start_position = self.stream.position;
188
189 let variant_doc = self.collect_doc_comments().map(|(text, _)| text);
190 if let Some(variant) = self.parse_enum_variant_with_doc(variant_doc) {
191 if let Some((_, first_span)) =
192 seen_variants.iter().find(|(n, _)| n == &variant.name)
193 {
194 self.error_duplicate_enum_variant(
195 &variant.name,
196 *first_span,
197 variant.name_span,
198 );
199 } else {
200 seen_variants.push((variant.name.clone(), variant.name_span));
201 }
202 variants.push(variant);
203 }
204 self.expect_comma_or(RightCurlyBrace);
205 self.ensure_progress(start_position, RightCurlyBrace);
206 }
207
208 self.ensure(RightCurlyBrace);
209
210 Expression::Enum {
211 doc,
212 attributes,
213 name,
214 name_span,
215 generics,
216 variants,
217 visibility: Visibility::Private,
218 span: self.span_from_tokens(start),
219 }
220 }
221
222 fn parse_enum_variant_with_doc(
223 &mut self,
224 doc: Option<std::string::String>,
225 ) -> Option<EnumVariant> {
226 if self.is_not(Identifier) {
227 self.track_error(
228 "expected variant name",
229 "Variant names must be identifiers.",
230 );
231 return None;
232 }
233
234 let name_token = self.current_token();
235 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
236 let name = self.read_identifier();
237
238 if self.is(Equal) {
239 let eq_token = self.current_token();
240 let eq_span = Span::new(self.file_id, eq_token.byte_offset, eq_token.byte_length);
241 let error = ParseError::new(
242 "Assigned enum variant",
243 eq_span,
244 "enum variants cannot have assigned values",
245 )
246 .with_parse_code("enum_assigned_variant")
247 .with_help(
248 "Lisette enums are sum types, not Go const groups. To model a Go defined primitive type, use a named primitive type such as `pub struct Weekday(int)` with package-level constants.",
249 );
250 self.errors.push(error);
251 self.next(); self.skip_assigned_variant_value();
253 }
254
255 let fields = self.parse_enum_variant_fields();
256
257 Some(EnumVariant {
258 doc,
259 name,
260 name_span,
261 fields,
262 })
263 }
264
265 fn skip_assigned_variant_value(&mut self) {
266 self.advance_if(Minus);
267 if self.is(Integer) || self.is(String) {
268 self.next();
269 }
270 }
271
272 fn parse_enum_variant_fields(&mut self) -> VariantFields {
273 if self.advance_if(LeftParen) {
274 return self.parse_tuple_variant_fields();
275 }
276
277 if self.advance_if(LeftCurlyBrace) {
278 return self.parse_struct_variant_fields();
279 }
280
281 VariantFields::Unit
282 }
283
284 fn parse_tuple_variant_fields(&mut self) -> VariantFields {
285 let mut fields = vec![];
286
287 loop {
288 if self.at_eof()
289 || self.is(RightParen)
290 || self.is(RightCurlyBrace)
291 || !self.can_start_annotation()
292 {
293 break;
294 }
295
296 let field = EnumFieldDefinition {
297 name: format!("field{}", fields.len()).into(),
298 name_span: Span::dummy(),
299 annotation: self.parse_annotation(),
300 ty: Type::uninferred(),
301 };
302
303 fields.push(field);
304
305 self.expect_comma_or(RightParen);
306 }
307
308 self.ensure(RightParen);
309
310 VariantFields::Tuple(fields)
311 }
312
313 fn parse_struct_variant_fields(&mut self) -> VariantFields {
314 let mut fields = vec![];
315 let mut seen_fields: Vec<(EcoString, Span)> = vec![];
316
317 loop {
318 if self.at_eof()
319 || self.is(RightCurlyBrace)
320 || self.at_item_boundary()
321 || self.is_not(Identifier)
322 {
323 break;
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 self.ensure(Colon);
330 let annotation = self.parse_annotation();
331
332 if let Some((_, first_span)) = seen_fields.iter().find(|(n, _)| n == &name) {
333 self.error_duplicate_struct_field(&name, *first_span, name_span);
334 } else {
335 seen_fields.push((name.clone(), name_span));
336 }
337
338 let field = EnumFieldDefinition {
339 name,
340 name_span,
341 annotation,
342 ty: Type::uninferred(),
343 };
344
345 fields.push(field);
346
347 self.expect_comma_or(RightCurlyBrace);
348 }
349
350 self.ensure(RightCurlyBrace);
351
352 VariantFields::Struct(fields)
353 }
354
355 pub fn parse_struct_definition(
356 &mut self,
357 doc: Option<std::string::String>,
358 attributes: Vec<Attribute>,
359 ) -> Expression {
360 let start = self.current_token();
361
362 self.ensure(Struct);
363
364 let name_token = self.current_token();
365 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
366 let name = self.read_identifier();
367 let generics = self.parse_generics();
368
369 if self.is(LeftParen) {
370 return self.parse_tuple_struct(doc, attributes, name, name_span, generics, start);
371 }
372
373 self.parse_named_struct(doc, attributes, name, name_span, generics, start)
374 }
375
376 fn parse_named_struct(
377 &mut self,
378 doc: Option<std::string::String>,
379 attributes: Vec<Attribute>,
380 name: EcoString,
381 name_span: Span,
382 generics: Vec<Generic>,
383 start: Token<'source>,
384 ) -> Expression {
385 let mut fields = vec![];
386 let mut seen_fields: Vec<(EcoString, Span)> = vec![];
387
388 self.ensure(LeftCurlyBrace);
389
390 while self.is_not(RightCurlyBrace) {
391 let start_position = self.stream.position;
392
393 let field_attributes = self.parse_attributes();
394 let field_doc = self.collect_doc_comments().map(|(text, _)| text);
395 if let Some(field) = self.parse_struct_field_with_doc(field_doc, field_attributes) {
396 if let Some((_, first_span)) = seen_fields.iter().find(|(n, _)| n == &field.name) {
397 self.error_duplicate_struct_field(&field.name, *first_span, field.name_span);
398 } else {
399 seen_fields.push((field.name.clone(), field.name_span));
400 }
401 fields.push(field);
402 }
403 self.expect_comma_or(RightCurlyBrace);
404 self.ensure_progress(start_position, RightCurlyBrace);
405 }
406
407 self.ensure(RightCurlyBrace);
408
409 Expression::Struct {
410 doc,
411 attributes,
412 name,
413 name_span,
414 generics,
415 fields,
416 kind: StructKind::Record,
417 visibility: Visibility::Private,
418 span: self.span_from_tokens(start),
419 }
420 }
421
422 fn parse_tuple_struct(
423 &mut self,
424 doc: Option<std::string::String>,
425 attributes: Vec<Attribute>,
426 name: EcoString,
427 name_span: Span,
428 generics: Vec<Generic>,
429 start: Token<'source>,
430 ) -> Expression {
431 self.ensure(LeftParen);
432
433 let mut fields = vec![];
434 let mut index = 0;
435
436 while self.is_not(RightParen) {
437 if self.at_eof() || self.at_item_boundary() || !self.can_start_annotation() {
438 break;
439 }
440
441 let field_start = self.current_token();
442 let annotation = self.parse_annotation();
443 let field_span = self.span_from_tokens(field_start);
444
445 fields.push(StructFieldDefinition {
446 doc: None,
447 attributes: vec![],
448 name: format!("_{}", index).into(),
449 name_span: field_span,
450 annotation,
451 visibility: Visibility::Private,
452 ty: Type::uninferred(),
453 });
454
455 index += 1;
456 self.expect_comma_or(RightParen);
457 }
458
459 self.ensure(RightParen);
460
461 Expression::Struct {
462 doc,
463 attributes,
464 name,
465 name_span,
466 generics,
467 fields,
468 kind: StructKind::Tuple,
469 visibility: Visibility::Private,
470 span: self.span_from_tokens(start),
471 }
472 }
473
474 fn parse_struct_field_with_doc(
475 &mut self,
476 doc: Option<std::string::String>,
477 attributes: Vec<Attribute>,
478 ) -> Option<StructFieldDefinition> {
479 let visibility = if self.advance_if(Pub) {
480 Visibility::Public
481 } else {
482 Visibility::Private
483 };
484
485 if self.is(Mut) {
486 self.track_error(
487 "fields cannot be marked `mut`",
488 "Fields cannot be marked `mut`; mutability applies to bindings (`let mut x = ...`).",
489 );
490 self.next();
491 }
492
493 if self.is_not(Identifier) {
494 self.track_error("expected field name", "Field names must be identifiers.");
495 return None;
496 }
497
498 let name_token = self.current_token();
499 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
500 let name = self.read_identifier();
501
502 self.ensure(Colon);
503
504 Some(StructFieldDefinition {
505 doc,
506 attributes,
507 visibility,
508 name,
509 name_span,
510 annotation: self.parse_annotation(),
511 ty: Type::uninferred(),
512 })
513 }
514
515 pub fn parse_const_definition(&mut self, doc: Option<std::string::String>) -> Expression {
516 let start = self.current_token();
517
518 self.ensure(Const);
519
520 let identifier_token = self.current_token();
521 let identifier_span = Span::new(
522 self.file_id,
523 identifier_token.byte_offset,
524 identifier_token.byte_length,
525 );
526 let identifier = self.read_identifier();
527 let annotation = if self.advance_if(Colon) {
528 Some(self.parse_annotation())
529 } else {
530 None
531 };
532
533 let expression = if self.advance_if(Equal) {
534 self.parse_expression()
535 } else {
536 Expression::NoOp
537 };
538
539 Expression::Const {
540 doc,
541 identifier,
542 identifier_span,
543 annotation,
544 expression: expression.into(),
545 visibility: Visibility::Private,
546 ty: Type::uninferred(),
547 span: self.span_from_tokens(start),
548 }
549 }
550
551 pub fn parse_var_declaration(&mut self, doc: Option<std::string::String>) -> Expression {
552 let start = self.current_token();
553
554 self.ensure(Var);
555
556 let name_token = self.current_token();
557 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
558 let name = self.read_identifier();
559
560 self.ensure(Colon);
561 let annotation = self.parse_annotation();
562
563 Expression::VariableDeclaration {
564 doc,
565 name,
566 name_span,
567 annotation,
568 visibility: Visibility::Private,
569 ty: Type::uninferred(),
570 span: self.span_from_tokens(start),
571 }
572 }
573
574 pub fn parse_impl_block(&mut self) -> Expression {
575 let start = self.current_token();
576
577 self.ensure(Impl);
578
579 let generics = self.parse_generics();
580
581 let receiver = self.parse_annotation(); let (receiver_name, annotation) = match &receiver {
584 Annotation::Constructor { name, .. } => (name.clone(), receiver),
585 _ => {
586 self.track_error("expected `impl` receiver", "Use `impl TypeName { ... }`.");
587 ("".into(), Annotation::Unknown)
588 }
589 };
590
591 if self.is(For) {
592 self.track_error(
593 "invalid syntax",
594 "Lisette types satisfy interfaces automatically by having the required methods. Use `impl Type { ... }` to add methods.",
595 );
596 self.next();
597 self.parse_annotation();
598 }
599
600 let mut methods = vec![];
601
602 self.ensure(LeftCurlyBrace);
603
604 while self.is_not(RightCurlyBrace) {
605 self.advance_if(Semicolon);
606 if self.is(RightCurlyBrace) {
607 break;
608 }
609
610 let method_doc = self.collect_doc_comments();
611 let method_attrs = self.parse_attributes();
612 let is_public = self.advance_if(Pub);
613
614 if self.is(Function) {
615 let method = self.parse_function(method_doc.map(|(text, _)| text), method_attrs);
616 let method = if is_public {
617 method.set_public()
618 } else {
619 method
620 };
621 methods.push(method);
622 } else {
623 if let Some((_, span)) = method_doc {
624 self.error_detached_doc_comment(span);
625 }
626 self.track_error(
627 "expected `fn` in impl block",
628 "Only functions are allowed in `impl` blocks.",
629 );
630 self.next();
631 }
632 }
633
634 self.ensure(RightCurlyBrace);
635
636 Expression::ImplBlock {
637 annotation,
638 methods,
639 receiver_name,
640 generics,
641 ty: Type::uninferred(),
642 span: self.span_from_tokens(start),
643 }
644 }
645
646 pub fn parse_interface_definition(&mut self, doc: Option<std::string::String>) -> Expression {
647 let start = self.current_token();
648
649 self.ensure(Interface);
650
651 let name_token = self.current_token();
652 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
653 let name = self.read_identifier();
654
655 let generics = self.parse_generics();
656
657 let mut parents = vec![];
658 let mut seen_parents: Vec<(EcoString, Span)> = vec![];
659 let mut method_signatures = vec![];
660 let mut seen_methods: Vec<(EcoString, Span)> = vec![];
661
662 self.ensure(LeftCurlyBrace);
663
664 while self.is_not(RightCurlyBrace) {
665 self.advance_if(Semicolon);
666 if self.is(RightCurlyBrace) {
667 break;
668 }
669
670 let item_doc = self.collect_doc_comments();
671 let method_attrs = self.parse_attributes();
672 if !self.is(Function)
673 && let Some(attribute) = method_attrs.first()
674 {
675 self.error_misplaced_attribute(attribute.span);
676 }
677 match self.current_token().kind {
678 Function => {
679 let method =
680 self.parse_interface_method(item_doc.map(|(text, _)| text), method_attrs);
681 if let Expression::Function {
682 ref name,
683 ref name_span,
684 ..
685 } = method
686 {
687 if let Some((_, first_span)) = seen_methods.iter().find(|(n, _)| n == name)
688 {
689 self.error_duplicate_interface_method(name, *first_span, *name_span);
690 } else {
691 seen_methods.push((name.clone(), *name_span));
692 }
693 }
694 method_signatures.push(method);
695 self.advance_if(Semicolon);
696 }
697
698 Impl => {
699 if let Some((_, span)) = item_doc {
700 self.error_detached_doc_comment(span);
701 }
702 self.ensure(Impl);
703
704 let parent_start = self.current_token();
705 let annotation = self.parse_annotation();
706 let parent_span = self.span_from_tokens(parent_start);
707
708 if let Annotation::Constructor { name, .. } = &annotation {
709 if let Some((_, first_span)) =
710 seen_parents.iter().find(|(n, _)| n == name.as_str())
711 {
712 self.error_duplicate_impl_parent(*first_span, parent_span);
713 } else {
714 seen_parents.push((name.clone(), parent_span));
715 }
716 }
717
718 parents.push(ParentInterface {
719 annotation,
720 ty: Type::uninferred(),
721 span: parent_span,
722 });
723 self.advance_if(Semicolon);
724 }
725
726 _ => {
727 if let Some((_, span)) = item_doc {
728 self.error_detached_doc_comment(span);
729 }
730 self.track_error(
731 "expected `fn` or `impl`",
732 "Only functions and `impl` blocks are allowed in interfaces.",
733 );
734 self.next();
735 }
736 }
737 }
738
739 self.ensure(RightCurlyBrace);
740
741 Expression::Interface {
742 doc,
743 name,
744 name_span,
745 generics,
746 parents,
747 method_signatures,
748 visibility: Visibility::Private,
749 span: self.span_from_tokens(start),
750 }
751 }
752}