mon_core/
parser.rs

1use crate::ast::{MonDocument, ImportStatement, MonValue, MonValueKind, Member, Pair, ImportSpec, ImportSpecifier, TypeDefinition, TypeDef, StructDef, FieldDef, EnumDef, TypeSpec};
2use crate::error::{MonError, ParserError};
3use crate::lexer::{Lexer, Token, TokenType};
4use miette::{GraphicalReportHandler, NamedSource, Report};
5use std::panic::Location;
6use std::sync::Arc;
7
8/// A recursive descent parser for the MON language, built according to the EBNF grammar.
9#[derive(Debug)]
10pub struct Parser<'a> {
11    source: Arc<NamedSource<String>>,
12    tokens: Vec<Token>,
13    position: usize,
14    source_text: &'a str,
15}
16
17impl<'a> Parser<'a> {
18    /// Creates a new `Parser` instance with a default file name "source.mon".
19    ///
20    /// # Arguments
21    ///
22    /// * `source_text` - The MON source code as a string.
23    ///
24    /// # Errors
25    ///
26    /// Returns a `MonError` if lexing the source text fails.
27    pub fn new(source_text: &'a str) -> Result<Self, MonError> {
28        Self::new_with_name(source_text, "source.mon".to_string())
29    }
30
31    /// Creates a new `Parser` instance with a specified file name.
32    ///
33    /// # Arguments
34    ///
35    /// * `source_text` - The MON source code as a string.
36    /// * `name` - The name of the file being parsed (used for error reporting).
37    ///
38    /// # Errors
39    ///
40    /// Returns a `MonError` if lexing the source text fails.
41    pub fn new_with_name(source_text: &'a str, name: String) -> Result<Self, MonError> {
42        let source = Arc::new(NamedSource::new(name, source_text.to_string()));
43        let mut lexer = Lexer::new(source_text);
44        let tokens: Vec<Token> = lexer
45            .lex()
46            .into_iter()
47            .filter(|t| !matches!(t.ttype, TokenType::Whitespace | TokenType::Comment(_)))
48            .collect();
49
50        Ok(Self {
51            source,
52            tokens,
53            position: 0,
54            source_text,
55        })
56    }
57
58    // === Main Parsing Methods ===
59
60    /// Parses the entire MON document, including import statements and the root object.
61    ///
62    /// # Errors
63    ///
64    /// Returns a `MonError` if parsing fails at any point.
65    pub fn parse_document(&mut self) -> Result<MonDocument, MonError> {
66        let mut imports: Vec<ImportStatement> = Vec::new();
67
68        // consume zero-or-more import statements
69        while self.check(&TokenType::Import) {
70            let imp = self.parse_import_statement()?;
71            imports.push(imp);
72            // DON'T call self.advance() here — parse_import_statement already advances
73        }
74
75        // After imports, we expect the root object.
76        let root = self.parse_object()?;
77
78        // After the root object, we expect the end of the file.
79        self.expect(&TokenType::Eof)?;
80        Ok(MonDocument { root, imports })
81    }
82
83    /// Object ::= "{" [ `MemberList` ] "}"
84    /// `MemberList` ::= `Member { , Member } [ , ]`
85    fn parse_object(&mut self) -> Result<MonValue, MonError> {
86        let start_token = self.current_token()?.clone();
87        self.expect(&TokenType::LBrace)?;
88        let mut members = Vec::new();
89        if !self.check(&TokenType::RBrace) {
90            // Parse the first member
91            members.push(self.parse_member()?);
92            // Keep parsing members as long as they are preceded by a comma
93            while self.match_token(&TokenType::Comma) {
94                // If we match a comma but the next token is a brace, it's a trailing comma
95                if self.check(&TokenType::RBrace) {
96                    break;
97                }
98                members.push(self.parse_member()?);
99            }
100        }
101        let end_token = self.current_token()?.clone();
102        self.expect(&TokenType::RBrace)?;
103        Ok(MonValue {
104            kind: MonValueKind::Object(members),
105            anchor: None, // Anchors are attached to values, not objects themselves
106            pos_start: start_token.pos_start,
107            pos_end: end_token.pos_end,
108        })
109    }
110
111    /// Array ::= "[" [ `ValueList` ] "]"
112    /// `ValueList` ::= `Value { , Value } [ , ]`
113    fn parse_array(&mut self) -> Result<MonValue, MonError> {
114        let start_token = self.current_token()?.clone();
115        self.expect(&TokenType::LBracket)?;
116        let mut values = Vec::new();
117        if !self.check(&TokenType::RBracket) {
118            loop {
119                if self.check(&TokenType::Spread) {
120                    let spread_start_token = self.current_token()?.clone();
121                    let spread_name = self.parse_spread()?;
122                    let spread_end_token = self.current_token_before_advance()?.clone(); // Get token before advance
123                    values.push(MonValue {
124                        kind: MonValueKind::ArraySpread(spread_name),
125                        anchor: None,
126                        pos_start: spread_start_token.pos_start,
127                        pos_end: spread_end_token.pos_end,
128                    });
129                } else {
130                    values.push(self.parse_value()?);
131                }
132
133                if !self.match_token(&TokenType::Comma) {
134                    break;
135                }
136                if self.check(&TokenType::RBracket) {
137                    break; // Allow trailing comma
138                }
139            }
140        }
141        let end_token = self.current_token()?.clone();
142        self.expect(&TokenType::RBracket)?;
143        Ok(MonValue {
144            kind: MonValueKind::Array(values),
145            anchor: None,
146            pos_start: start_token.pos_start,
147            pos_end: end_token.pos_end,
148        })
149    }
150
151    /// Value ::= Object | Array | Alias | `EnumValue` | Literal
152    /// Attaches an anchor if one is present.
153    fn parse_value(&mut self) -> Result<MonValue, MonError> {
154        let anchor = self.parse_optional_anchor()?;
155
156        let start_token = self.current_token()?.clone(); // Capture start token for pos_start
157
158        let mut value = match &start_token.ttype.clone() {
159            // Use start_token here
160            TokenType::LBrace => self.parse_object(),
161            TokenType::LBracket => self.parse_array(),
162            TokenType::String(s) => {
163                self.advance();
164                Ok(MonValue {
165                    kind: MonValueKind::String(s.clone()),
166                    anchor: None,
167                    pos_start: start_token.pos_start,
168                    pos_end: start_token.pos_end,
169                })
170            }
171            TokenType::Number(n) => {
172                self.advance();
173                Ok(MonValue {
174                    kind: MonValueKind::Number(*n),
175                    anchor: None,
176                    pos_start: start_token.pos_start,
177                    pos_end: start_token.pos_end,
178                })
179            }
180            TokenType::True => {
181                self.advance();
182                Ok(MonValue {
183                    kind: MonValueKind::Boolean(true),
184                    anchor: None,
185                    pos_start: start_token.pos_start,
186                    pos_end: start_token.pos_end,
187                })
188            }
189            TokenType::False => {
190                self.advance();
191                Ok(MonValue {
192                    kind: MonValueKind::Boolean(false),
193                    anchor: None,
194                    pos_start: start_token.pos_start,
195                    pos_end: start_token.pos_end,
196                })
197            }
198            TokenType::Null => {
199                self.advance();
200                Ok(MonValue {
201                    kind: MonValueKind::Null,
202                    anchor: None,
203                    pos_start: start_token.pos_start,
204                    pos_end: start_token.pos_end,
205                })
206            }
207            TokenType::Asterisk => self.parse_alias(),
208            TokenType::Dollar => self.parse_enum_value(),
209            _ => self.err_unexpected("a value"),
210        }?;
211
212        value.anchor = anchor;
213        Ok(value)
214    }
215
216    /// Member ::= Pair | `TypeDefinition` | Spread
217    fn parse_member(&mut self) -> Result<Member, MonError> {
218        match self.current_token()?.ttype {
219            TokenType::Spread => self.parse_spread().map(Member::Spread),
220            // A TypeDefinition starts with an Identifier followed by a Colon and a Hash
221            TokenType::Identifier(_)
222                if self.peek_is(&TokenType::Colon) && self.peek_next_is(&TokenType::Hash) =>
223            {
224                self.parse_type_definition().map(Member::TypeDefinition)
225            }
226            // Otherwise, it's a regular pair
227            _ => self.parse_pair().map(Member::Pair),
228        }
229    }
230
231    /// Pair ::= `KeyPart` [ Validation ] ( ":" | "=" ) Value
232    /// `KeyPart` ::= [ Anchor ] Key
233    /// Key ::= Identifier | String
234    fn parse_pair(&mut self) -> Result<Pair, MonError> {
235        let mut anchor_from_key: Option<String> = None;
236
237        // Handle the case where the key itself is an anchor, e.g., `&my_anchor: value`
238        let key = if self.match_token(&TokenType::Ampersand) {
239            let key_name = self.parse_key()?;
240            anchor_from_key = Some(key_name.clone());
241            key_name
242        } else {
243            self.parse_key()?
244        };
245
246        let validation = self.parse_optional_validation()?;
247
248        if !self.match_token(&TokenType::Colon) && !self.match_token(&TokenType::Equals) {
249            return self.err_unexpected("':' or '=' after key");
250        }
251
252        let mut value = self.parse_value()?;
253
254        // If the key was an anchor, attach the anchor to the value.
255        // This handles `&anchor: value`.
256        // The `parse_value` function handles the `key: &anchor value` case on its own.
257        if let Some(anchor_name) = anchor_from_key {
258            value.anchor = Some(anchor_name);
259        }
260
261        Ok(Pair {
262            key,
263            value,
264            validation,
265        })
266    }
267
268    // === EBNF Sub-Rules ===
269
270    /// Key ::= Identifier | String
271    fn parse_key(&mut self) -> Result<String, MonError> {
272        let token = self.current_token()?;
273        let mut key_parts = Vec::new();
274
275        match &token.ttype {
276            TokenType::Identifier(s) | TokenType::String(s) => {
277                key_parts.push(s.clone());
278                self.advance();
279            }
280            _ => return self.err_unexpected("an identifier or string for a key"),
281        }
282
283        // Handle dotted keys like `schemas.User`
284        while self.match_token(&TokenType::Dot) {
285            let token = self.current_token()?;
286            if let TokenType::Identifier(s) = &token.ttype {
287                key_parts.push(s.clone());
288                self.advance();
289            } else {
290                return self.err_unexpected("an identifier after a dot in a key");
291            }
292        }
293
294        Ok(key_parts.join("."))
295    }
296
297    /// Anchor ::= "&" Identifier
298    fn parse_optional_anchor(&mut self) -> Result<Option<String>, MonError> {
299        if self.match_token(&TokenType::Ampersand) {
300            let token = self.current_token()?;
301            if let TokenType::Identifier(name) = &token.ttype {
302                let name = name.clone();
303                self.advance();
304                Ok(Some(name))
305            } else {
306                self.err_unexpected("an identifier for the anchor name")
307            }
308        } else {
309            Ok(None)
310        }
311    }
312
313    /// Alias ::= "*" Identifier { "." Identifier }
314    fn parse_alias(&mut self) -> Result<MonValue, MonError> {
315        let start_token = self.current_token()?.clone();
316        self.expect(&TokenType::Asterisk)?;
317        let mut name = self.parse_key()?;
318        let mut end_pos = self.current_token_before_advance()?.pos_end; // End of the first key part
319
320        while self.match_token(&TokenType::Dot) {
321            name.push('.');
322            let key_part = self.parse_key()?;
323            end_pos = self.current_token_before_advance()?.pos_end; // Update end_pos
324            name.push_str(&key_part);
325        }
326        Ok(MonValue {
327            kind: MonValueKind::Alias(name),
328            anchor: None,
329            pos_start: start_token.pos_start,
330            pos_end: end_pos,
331        })
332    }
333
334    /// Spread ::= "..." Alias
335    fn parse_spread(&mut self) -> Result<String, MonError> {
336        self.expect(&TokenType::Spread)?;
337        let alias = self.parse_alias()?;
338        if let MonValueKind::Alias(name) = alias.kind {
339            Ok(name)
340        } else {
341            // This should be unreachable if parse_alias is correct
342            self.err_unexpected("an alias after '...'")
343        }
344    }
345
346    /// `ImportStatement` ::= "import" ( `NamespaceImport` | `NamedImport` ) "from" String
347    fn parse_import_statement(&mut self) -> Result<ImportStatement, MonError> {
348        let start_token = self.current_token()?.clone(); // Capture start token for pos_start
349        self.expect(&TokenType::Import)?;
350
351        let spec = if self.match_token(&TokenType::Asterisk) {
352            // NamespaceImport ::= "*" "as" Identifier
353            self.expect(&TokenType::As)?;
354            let name = self.parse_key()?;
355            ImportSpec::Namespace(name)
356        } else {
357            // NamedImport ::= "{" [ ImportSpecifier { "," ImportSpecifier } [ "," ] ] "}"
358            self.expect(&TokenType::LBrace)?;
359            let mut specifiers = Vec::new();
360            if !self.check(&TokenType::RBrace) {
361                loop {
362                    // ImportSpecifier ::= [ "&" ] Identifier
363                    let is_anchor = self.match_token(&TokenType::Ampersand);
364                    let name = self.parse_key()?;
365                    specifiers.push(ImportSpecifier { name, is_anchor });
366                    if !self.match_token(&TokenType::Comma) {
367                        break;
368                    }
369                    if self.check(&TokenType::RBrace) {
370                        break;
371                    }
372                }
373            }
374            self.expect(&TokenType::RBrace)?;
375            ImportSpec::Named(specifiers)
376        };
377
378        self.expect(&TokenType::From)?;
379        let path_token = self.current_token()?.clone(); // Capture path token for pos_end
380        let path = self.parse_key()?;
381
382        Ok(ImportStatement {
383            path,
384            spec,
385            pos_start: start_token.pos_start,
386            pos_end: path_token.pos_end,
387        })
388    }
389
390    /// `TypeDefinition` ::= Identifier ":" ( `StructDefinition` | `EnumDefinition` )
391    fn parse_type_definition(&mut self) -> Result<TypeDefinition, MonError> {
392        let name_token = self.current_token()?.clone();
393        let name = self.parse_key()?;
394        self.expect(&TokenType::Colon)?;
395        let hash_token = self.current_token()?.clone();
396        self.expect(&TokenType::Hash)?;
397
398        let token = self.current_token()?;
399        let (def_type, end_pos) = match &token.ttype {
400            TokenType::Identifier(s) if s == "struct" => {
401                self.advance();
402                let mut struct_def = self.parse_struct_definition()?;
403                let end_pos = struct_def.pos_end;
404                struct_def.pos_start = hash_token.pos_start;
405                Ok((TypeDef::Struct(struct_def), end_pos))
406            }
407            TokenType::Identifier(s) if s == "enum" => {
408                self.advance();
409                let mut enum_def = self.parse_enum_definition()?;
410                let end_pos = enum_def.pos_end;
411                enum_def.pos_start = hash_token.pos_start;
412                Ok((TypeDef::Enum(enum_def), end_pos))
413            }
414            _ => self.err_unexpected("'struct' or 'enum' keyword"),
415        }?;
416
417        Ok(TypeDefinition {
418            name,
419            name_span: (
420                name_token.pos_start,
421                name_token.pos_end - name_token.pos_start,
422            )
423                .into(),
424            def_type,
425            pos_start: name_token.pos_start,
426            pos_end: end_pos,
427        })
428    }
429
430    /// `StructDefinition` ::= "{" [ `FieldList` ] "}"
431    fn parse_struct_definition(&mut self) -> Result<StructDef, MonError> {
432        let start_token = self.current_token()?.clone();
433        self.expect(&TokenType::LBrace)?;
434        let mut fields = Vec::new();
435        if !self.check(&TokenType::RBrace) {
436            loop {
437                fields.push(self.parse_field_definition()?);
438                if !self.match_token(&TokenType::Comma) {
439                    break;
440                }
441                if self.check(&TokenType::RBrace) {
442                    break;
443                }
444            }
445        }
446        let end_token = self.current_token()?.clone();
447        self.expect(&TokenType::RBrace)?;
448        Ok(StructDef {
449            fields,
450            pos_start: start_token.pos_start,
451            pos_end: end_token.pos_end,
452        })
453    }
454
455    /// `FieldDefinition` ::= Identifier "(" Type ")" [ "=" Value ]
456    fn parse_field_definition(&mut self) -> Result<FieldDef, MonError> {
457        let name = self.parse_key()?;
458        self.expect(&TokenType::LParen)?;
459        let type_spec = self.parse_type_spec()?;
460        self.expect(&TokenType::RParen)?;
461
462        let default_value = if self.match_token(&TokenType::Equals) {
463            Some(self.parse_value()?)
464        } else {
465            None
466        };
467
468        Ok(FieldDef {
469            name,
470            type_spec,
471            default_value,
472        })
473    }
474
475    /// `EnumDefinition` ::= `{ [ Identifier { , Identifier } [ , ] ] }`
476    fn parse_enum_definition(&mut self) -> Result<EnumDef, MonError> {
477        let start_token = self.current_token()?.clone();
478        self.expect(&TokenType::LBrace)?;
479        let mut variants = Vec::new();
480        if !self.check(&TokenType::RBrace) {
481            loop {
482                variants.push(self.parse_key()?);
483                if !self.match_token(&TokenType::Comma) {
484                    break;
485                }
486                if self.check(&TokenType::RBrace) {
487                    break;
488                }
489            }
490        }
491        let end_token = self.current_token()?.clone();
492        self.expect(&TokenType::RBrace)?;
493        Ok(EnumDef {
494            variants,
495            pos_start: start_token.pos_start,
496            pos_end: end_token.pos_end,
497        })
498    }
499
500    /// Validation ::= "::" Type
501    fn parse_optional_validation(&mut self) -> Result<Option<TypeSpec>, MonError> {
502        if self.match_token(&TokenType::DoubleColon) {
503            self.parse_type_spec().map(Some)
504        } else {
505            Ok(None)
506        }
507    }
508
509    /// Type ::= `CollectionType` | Identifier | "String" | ...
510    fn parse_type_spec(&mut self) -> Result<TypeSpec, MonError> {
511        let start_token = self.current_token()?.clone();
512        if self.check(&TokenType::LBracket) {
513            // CollectionType ::= "[" Type [ "..." ] { "," Type [ "..." ] } "]"
514            self.expect(&TokenType::LBracket)?;
515            let mut types = Vec::new();
516            if !self.check(&TokenType::RBracket) {
517                loop {
518                    let mut type_spec = self.parse_type_spec()?;
519                    if self.match_token(&TokenType::Spread) {
520                        let end_token = self.current_token_before_advance()?.clone();
521                        let span = (
522                            type_spec.get_span().offset(),
523                            end_token.pos_end - type_spec.get_span().offset(),
524                        )
525                            .into();
526                        type_spec = TypeSpec::Spread(Box::new(type_spec), span);
527                    }
528                    types.push(type_spec);
529
530                    if !self.match_token(&TokenType::Comma) {
531                        break;
532                    }
533                    if self.check(&TokenType::RBracket) {
534                        break;
535                    }
536                }
537            }
538            let end_token = self.current_token()?.clone();
539            self.expect(&TokenType::RBracket)?;
540            let span = (
541                start_token.pos_start,
542                end_token.pos_end - start_token.pos_start,
543            )
544                .into();
545            Ok(TypeSpec::Collection(types, span))
546        } else {
547            // Simple Type
548            let name = self.parse_key()?;
549            let end_token = self.current_token_before_advance()?.clone();
550            let span = (
551                start_token.pos_start,
552                end_token.pos_end - start_token.pos_start,
553            )
554                .into();
555            Ok(TypeSpec::Simple(name, span))
556        }
557    }
558
559    /// `EnumValue` ::= "$" Identifier "." Identifier
560    fn parse_enum_value(&mut self) -> Result<MonValue, MonError> {
561        let start_token = self.current_token()?.clone();
562        self.expect(&TokenType::Dollar)?;
563        let enum_name = self.parse_key()?;
564        self.expect(&TokenType::Dot)?;
565        let variant_name = self.parse_key()?;
566        let end_token = self.current_token_before_advance()?.clone(); // End of the variant_name
567
568        Ok(MonValue {
569            kind: MonValueKind::EnumValue {
570                enum_name,
571                variant_name,
572            },
573            anchor: None,
574            pos_start: start_token.pos_start,
575            pos_end: end_token.pos_end,
576        })
577    }
578
579    // === Tokenizer Helper Methods ===
580
581    fn current_token(&self) -> Result<&Token, MonError> {
582        self.tokens.get(self.position).ok_or_else(|| {
583            let pos = self.source_text.len().saturating_sub(1);
584            ParserError::UnexpectedEof {
585                src: (*self.source).clone().into(), // ineficiency is my passion
586                span: (pos, 0).into(),
587            }
588            .into()
589        })
590    }
591
592    fn current_token_before_advance(&self) -> Result<&Token, MonError> {
593        self.tokens
594            .get(self.position.saturating_sub(1))
595            .ok_or_else(|| {
596                let pos = self.source_text.len().saturating_sub(1);
597                ParserError::UnexpectedEof {
598                    src: (*self.source).clone().into(),
599                    span: (pos, 0).into(),
600                }
601                .into()
602            })
603    }
604
605    fn advance(&mut self) {
606        if self.position < self.tokens.len() {
607            self.position += 1;
608        }
609    }
610
611    #[track_caller]
612    fn expect(&mut self, expected: &TokenType) -> Result<(), MonError> {
613        let token = self.current_token()?.clone();
614        if std::mem::discriminant(&token.ttype) == std::mem::discriminant(expected) {
615            self.advance();
616            Ok(())
617        } else {
618            self.err_unexpected(&format!("{expected:?}"))
619        }
620    }
621
622    fn match_token(&mut self, ttype: &TokenType) -> bool {
623        if self.check(ttype) {
624            self.advance();
625            true
626        } else {
627            false
628        }
629    }
630
631    fn check(&self, ttype: &TokenType) -> bool {
632        if let Ok(token) = self.current_token() {
633            std::mem::discriminant(&token.ttype) == std::mem::discriminant(ttype)
634        } else {
635            false
636        }
637    }
638
639    fn peek_is(&self, ttype: &TokenType) -> bool {
640        if let Some(token) = self.tokens.get(self.position + 1) {
641            std::mem::discriminant(&token.ttype) == std::mem::discriminant(ttype)
642        } else {
643            false
644        }
645    }
646
647    fn peek_next_is(&self, ttype: &TokenType) -> bool {
648        if let Some(token) = self.tokens.get(self.position + 2) {
649            std::mem::discriminant(&token.ttype) == std::mem::discriminant(ttype)
650        } else {
651            false
652        }
653    }
654
655    #[track_caller]
656    fn err_unexpected<T>(&self, expected: &str) -> Result<T, MonError> {
657        let token = self.current_token()?; // Should be safe if we got here
658        print!("caller: {}", Location::caller());
659        Err(ParserError::UnexpectedToken {
660            src: (*self.source).clone().into(),
661            span: (token.pos_start, token.pos_end - token.pos_start).into(),
662            expected: expected.to_string(),
663        }
664        .into())
665    }
666}
667
668// internal debug function. I really can't stand bad strings
669#[allow(dead_code)]
670fn pretty_result(out: Result<MonDocument, MonError>) -> String {
671    match out {
672        Ok(doc) => format!("{doc:#?}"), // debug format for success
673        Err(err) => {
674            let report: Report = Report::new(err);
675            let handler = GraphicalReportHandler::new(); // pretty ANSI colors
676            let mut buffer = String::new();
677            handler.render_report(&mut buffer, &*report).unwrap();
678            buffer
679        }
680    }
681}
682
683#[cfg(test)]
684#[allow(clippy::match_wildcard_for_single_variants)]
685mod tests {
686    use super::*;
687    use miette::Report;
688    use std::fs;
689
690    fn parse_ok(source: &str) -> MonDocument {
691        let mut parser = Parser::new_with_name(source, "test.mon".to_string()).unwrap();
692        match parser.parse_document() {
693            Ok(doc) => doc,
694            Err(err) => {
695                let report = Report::from(err);
696                print!("{report:?}");
697
698                panic!("{report:#}");
699            }
700        }
701    }
702
703    #[test]
704    fn test_empty_object() {
705        let doc = parse_ok("{}");
706        assert_eq!(doc.root.kind, MonValueKind::Object(vec![]));
707    }
708
709    #[test]
710    fn test_simple_pair() {
711        let doc = parse_ok(r#"{ key: "value" }"#);
712        let members = match doc.root.kind {
713            MonValueKind::Object(m) => m,
714            _ => panic!(),
715        };
716        assert_eq!(members.len(), 1);
717        match &members[0] {
718            Member::Pair(p) => {
719                assert_eq!(p.key, "key");
720                assert!(matches!(p.value.kind, MonValueKind::String(_)));
721            }
722            _ => panic!(),
723        }
724    }
725
726    #[test]
727    fn test_anchor_and_alias() {
728        let doc = parse_ok(r"{ &anchor1 : 123, key2: *anchor1 }");
729        let members = match doc.root.kind {
730            MonValueKind::Object(m) => m,
731            _ => panic!(),
732        };
733        assert_eq!(members.len(), 2);
734        match &members[0] {
735            Member::Pair(p) => {
736                assert_eq!(p.key, "anchor1");
737                assert_eq!(p.value.anchor, Some("anchor1".to_string()));
738            }
739            _ => panic!(),
740        }
741        match &members[1] {
742            Member::Pair(p) => {
743                assert_eq!(p.key, "key2");
744                assert!(matches!(p.value.kind, MonValueKind::Alias(_)));
745            }
746            _ => panic!(),
747        }
748    }
749
750    #[test]
751    fn test_spread() {
752        let doc = parse_ok(r"{ ...*my_anchor }");
753        let members = match doc.root.kind {
754            MonValueKind::Object(m) => m,
755            _ => panic!(),
756        };
757        assert_eq!(members.len(), 1);
758        match &members[0] {
759            Member::Spread(name) => assert_eq!(name, "my_anchor"),
760            _ => panic!(),
761        }
762    }
763
764    #[test]
765    fn test_namespace_import() {
766        let doc = parse_ok(r#"import * as my_schemas from "./schemas.mon" {}"#);
767        assert_eq!(doc.imports.len(), 1);
768        let i = &doc.imports[0];
769        assert_eq!(i.path, "./schemas.mon");
770        assert!(matches!(i.spec, ImportSpec::Namespace(ref s) if s == "my_schemas"));
771
772        // Root object should be empty
773        let members = match doc.root.kind {
774            MonValueKind::Object(m) => m,
775            _ => panic!("Root was not an object"),
776        };
777        assert!(members.is_empty());
778    }
779
780    #[test]
781    fn test_named_import() {
782        let doc = parse_ok(r#"import { User, &Template } from "./file.mon" {}"#);
783        assert_eq!(doc.imports.len(), 1);
784        let i = &doc.imports[0];
785        assert_eq!(i.path, "./file.mon");
786        match &i.spec {
787            ImportSpec::Named(specs) => {
788                assert_eq!(specs.len(), 2);
789                assert_eq!(specs[0].name, "User");
790                assert!(!specs[0].is_anchor);
791                assert_eq!(specs[1].name, "Template");
792                assert!(specs[1].is_anchor);
793            }
794            _ => panic!(),
795        }
796        // Root object should be empty
797        let members = match doc.root.kind {
798            MonValueKind::Object(m) => m,
799            _ => panic!("Root was not an object"),
800        };
801        assert!(members.is_empty());
802    }
803
804    #[test]
805    fn test_enum_definition() {
806        let doc = parse_ok(r"{ Status: #enum { Active, Inactive } }");
807        let members = match doc.root.kind {
808            MonValueKind::Object(m) => m,
809            _ => panic!(),
810        };
811        assert_eq!(members.len(), 1);
812        match &members[0] {
813            Member::TypeDefinition(t) => {
814                assert_eq!(t.name, "Status");
815                assert!(matches!(t.def_type, TypeDef::Enum(_)));
816            }
817            _ => panic!(),
818        }
819    }
820
821    #[test]
822    fn test_struct_definition() {
823        let doc = parse_ok(r#"{ User: #struct { id(Number), name(String) = "Guest" } }"#);
824        let members = match doc.root.kind {
825            MonValueKind::Object(m) => m,
826            _ => panic!(),
827        };
828        assert_eq!(members.len(), 1);
829        match &members[0] {
830            Member::TypeDefinition(t) => {
831                assert_eq!(t.name, "User");
832                match &t.def_type {
833                    TypeDef::Struct(s) => {
834                        assert_eq!(s.fields.len(), 2);
835                        assert_eq!(s.fields[0].name, "id");
836                        assert!(s.fields[1].default_value.is_some());
837                    }
838                    _ => panic!(),
839                }
840            }
841            _ => panic!(),
842        }
843    }
844
845    #[test]
846    fn test_validation_pair() {
847        let doc = parse_ok(r#"{ my_user :: User = { name: "Alice" } }"#);
848        let members = match doc.root.kind {
849            MonValueKind::Object(m) => m,
850            _ => panic!(),
851        };
852        assert_eq!(members.len(), 1);
853        match &members[0] {
854            Member::Pair(p) => {
855                assert_eq!(p.key, "my_user");
856                assert!(p.validation.is_some());
857                assert!(matches!(p.value.kind, MonValueKind::Object(_)));
858            }
859            _ => panic!(),
860        }
861    }
862
863    #[test]
864    #[ignore = "This test is for visual confirmation and is ignored by default."]
865    fn visual_conformation_from_golden() {
866        let contents = fs::read_to_string("tests/ok/golden.mon").unwrap();
867        let parsed = Parser::new_with_name(&contents, "test.mon".to_string())
868            .unwrap()
869            .parse_document();
870
871        print!("parsed: \n{}", pretty_result(parsed));
872    }
873
874    #[test]
875    fn test_all_mon_files() {
876        let tests_dir = "./tests";
877        let entries = fs::read_dir(tests_dir).expect("Failed to read tests directory");
878
879        for entry in entries {
880            let entry = entry.expect("Failed to read directory entry");
881            let path = entry.path();
882
883            if path.is_file() && path.extension().is_some_and(|ext| ext == "mon") {
884                println!("Parsing file: {path:?}");
885                let source = fs::read_to_string(&path)
886                    .unwrap_or_else(|_| panic!("Failed to read file: {path:?}"));
887
888                let mut parser = Parser::new_with_name(&source, path.to_str().unwrap().to_string())
889                    .expect("Lexer failed");
890
891                if let Err(err) = parser.parse_document() {
892                    panic!("Failed to parse {:?}. Error: {:#?}", path, Report::new(err));
893                }
894            }
895        }
896    }
897}