mon_core/
parser.rs

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