Skip to main content

nautilus_schema/
parser.rs

1//! Recursive descent parser for the nautilus schema language.
2//!
3//! This module provides a parser that transforms a stream of tokens into an AST.
4//!
5//! # Example
6//!
7//! ```ignore
8//! use nautilus_schema::{Lexer, Parser};
9//!
10//! let source = r#"
11//!     model User {
12//!       id    Int    @id
13//!       email String @unique
14//!     }
15//! "#;
16//!
17//! let tokens = Lexer::new(source).collect::<Result<Vec<_>, _>>().unwrap();
18//! let schema = Parser::new(&tokens, source).parse_schema().unwrap();
19//! ```
20
21use crate::ast::*;
22use crate::error::{Result, SchemaError};
23use crate::span::Span;
24use crate::token::{Token, TokenKind};
25
26/// Parser for schema files.
27pub struct Parser<'a> {
28    /// Token stream.
29    tokens: &'a [Token],
30    /// Current position in token stream.
31    pos: usize,
32    /// Errors collected during error-recovery (non-fatal parse failures).
33    recovered_errors: Vec<crate::error::SchemaError>,
34}
35
36impl<'a> Parser<'a> {
37    /// Creates a new parser from a token slice and the original source text.
38    pub fn new(tokens: &'a [Token], source: &'a str) -> Self {
39        let _ = source; // kept in signature for API compatibility
40        Self {
41            tokens,
42            pos: 0,
43            recovered_errors: Vec::new(),
44        }
45    }
46
47    /// Returns all errors that were silently recovered from during parsing.
48    ///
49    /// These are non-fatal: the parser managed to continue past them by
50    /// skipping to the next top-level declaration.  Call this after
51    /// [`parse_schema`] to collect the full set of parse diagnostics.
52    pub fn take_errors(&mut self) -> Vec<crate::error::SchemaError> {
53        std::mem::take(&mut self.recovered_errors)
54    }
55
56    /// Parses a complete schema.
57    pub fn parse_schema(&mut self) -> Result<Schema> {
58        let start = self.current_span();
59        self.skip_newlines();
60
61        let mut declarations = Vec::new();
62
63        while !self.is_at_end() {
64            match self.parse_declaration() {
65                Ok(decl) => declarations.push(decl),
66                Err(e) => {
67                    // Error recovery: record the error and skip to the next declaration.
68                    self.recovered_errors.push(e);
69                    self.recover_to_next_declaration();
70                }
71            }
72            self.skip_newlines();
73        }
74
75        let end = self.previous_span();
76        Ok(Schema::new(declarations, start.merge(end)))
77    }
78
79    /// Parses a top-level declaration.
80    fn parse_declaration(&mut self) -> Result<Declaration> {
81        self.skip_newlines();
82
83        match self.peek_kind() {
84            Some(TokenKind::Datasource) => Ok(Declaration::Datasource(self.parse_datasource()?)),
85            Some(TokenKind::Generator) => Ok(Declaration::Generator(self.parse_generator()?)),
86            Some(TokenKind::Model) => Ok(Declaration::Model(self.parse_model()?)),
87            Some(TokenKind::Enum) => Ok(Declaration::Enum(self.parse_enum()?)),
88            Some(TokenKind::Type) => Ok(Declaration::Type(self.parse_type_decl()?)),
89            Some(kind) => Err(SchemaError::Parse(
90                format!("Expected declaration, found {:?}", kind),
91                self.current_span(),
92            )),
93            None => Err(SchemaError::Parse(
94                "Unexpected end of file".to_string(),
95                self.current_span(),
96            )),
97        }
98    }
99
100    /// Parses a datasource block.
101    fn parse_datasource(&mut self) -> Result<DatasourceDecl> {
102        let start = self.expect(TokenKind::Datasource)?.span;
103        let name = self.parse_ident()?;
104        self.expect(TokenKind::LBrace)?;
105        self.skip_newlines();
106
107        let mut fields = Vec::new();
108        while !self.check(TokenKind::RBrace) && !self.is_at_end() {
109            fields.push(self.parse_config_field()?);
110            self.skip_newlines();
111        }
112
113        let end = self.expect(TokenKind::RBrace)?.span;
114        Ok(DatasourceDecl {
115            name,
116            fields,
117            span: start.merge(end),
118        })
119    }
120
121    /// Parses a generator block.
122    fn parse_generator(&mut self) -> Result<GeneratorDecl> {
123        let start = self.expect(TokenKind::Generator)?.span;
124        let name = self.parse_ident()?;
125        self.expect(TokenKind::LBrace)?;
126        self.skip_newlines();
127
128        let mut fields = Vec::new();
129        while !self.check(TokenKind::RBrace) && !self.is_at_end() {
130            fields.push(self.parse_config_field()?);
131            self.skip_newlines();
132        }
133
134        let end = self.expect(TokenKind::RBrace)?.span;
135        Ok(GeneratorDecl {
136            name,
137            fields,
138            span: start.merge(end),
139        })
140    }
141
142    /// Parses a configuration field (key = value).
143    fn parse_config_field(&mut self) -> Result<ConfigField> {
144        let name = self.parse_ident()?;
145        self.expect(TokenKind::Equal)?;
146        let value = self.parse_expr()?;
147        let span = name.span.merge(value.span());
148        Ok(ConfigField { name, value, span })
149    }
150
151    /// Parses a model block.
152    fn parse_model(&mut self) -> Result<ModelDecl> {
153        let start = self.expect(TokenKind::Model)?.span;
154        let name = self.parse_ident()?;
155        self.expect(TokenKind::LBrace)?;
156        self.skip_newlines();
157
158        let mut fields = Vec::new();
159        let mut attributes = Vec::new();
160
161        while !self.check(TokenKind::RBrace) && !self.is_at_end() {
162            if self.check(TokenKind::AtAt) {
163                attributes.push(self.parse_model_attribute()?);
164            } else {
165                fields.push(self.parse_field_decl()?);
166            }
167            self.skip_newlines();
168        }
169
170        let end = self.expect(TokenKind::RBrace)?.span;
171        Ok(ModelDecl {
172            name,
173            fields,
174            attributes,
175            span: start.merge(end),
176        })
177    }
178
179    /// Parses a composite type block.
180    fn parse_type_decl(&mut self) -> Result<TypeDecl> {
181        let start = self.expect(TokenKind::Type)?.span;
182        let name = self.parse_ident()?;
183        self.expect(TokenKind::LBrace)?;
184        self.skip_newlines();
185
186        let mut fields = Vec::new();
187
188        while !self.check(TokenKind::RBrace) && !self.is_at_end() {
189            // Type blocks do not support @@ model-level attributes
190            fields.push(self.parse_field_decl()?);
191            self.skip_newlines();
192        }
193
194        let end = self.expect(TokenKind::RBrace)?.span;
195        Ok(TypeDecl {
196            name,
197            fields,
198            span: start.merge(end),
199        })
200    }
201
202    /// Parses a field declaration.
203    fn parse_field_decl(&mut self) -> Result<FieldDecl> {
204        let name = self.parse_ident()?;
205        let field_type = self.parse_field_type()?;
206        let modifier = self.parse_field_modifier()?;
207        // Capture the span up through the type/modifier before attributes.
208        let base_span = name.span.merge(self.previous_span());
209
210        let mut attributes = Vec::new();
211        while self.check(TokenKind::At) && !self.check(TokenKind::AtAt) {
212            attributes.push(self.parse_field_attribute()?);
213        }
214
215        let span = if let Some(last_attr) = attributes.last() {
216            match last_attr {
217                FieldAttribute::Id => base_span,
218                FieldAttribute::Unique => base_span,
219                FieldAttribute::UpdatedAt { span } => base_span.merge(*span),
220                FieldAttribute::Default(_, span) => base_span.merge(*span),
221                FieldAttribute::Map(_) => base_span,
222                FieldAttribute::Store { .. } => base_span,
223                FieldAttribute::Relation { span, .. } => base_span.merge(*span),
224                FieldAttribute::Computed { span, .. } => base_span.merge(*span),
225                FieldAttribute::Check { span, .. } => base_span.merge(*span),
226            }
227        } else {
228            base_span
229        };
230
231        Ok(FieldDecl {
232            name,
233            field_type,
234            modifier,
235            attributes,
236            span,
237        })
238    }
239
240    /// Parses a field type.
241    fn parse_field_type(&mut self) -> Result<FieldType> {
242        let ident = self.parse_ident()?;
243
244        let field_type = match ident.value.as_str() {
245            "String" => FieldType::String,
246            "Boolean" => FieldType::Boolean,
247            "Int" => FieldType::Int,
248            "BigInt" => FieldType::BigInt,
249            "Float" => FieldType::Float,
250            "DateTime" => FieldType::DateTime,
251            "Bytes" => FieldType::Bytes,
252            "Json" => FieldType::Json,
253            "Uuid" => FieldType::Uuid,
254            "Jsonb" => FieldType::Jsonb,
255            "Xml" => FieldType::Xml,
256            "Char" => {
257                self.expect(TokenKind::LParen)?;
258                let length = self.parse_number()?.parse::<u32>().map_err(|_| {
259                    SchemaError::Parse("Invalid length value".to_string(), self.current_span())
260                })?;
261                self.expect(TokenKind::RParen)?;
262                FieldType::Char { length }
263            }
264            "VarChar" => {
265                self.expect(TokenKind::LParen)?;
266                let length = self.parse_number()?.parse::<u32>().map_err(|_| {
267                    SchemaError::Parse("Invalid length value".to_string(), self.current_span())
268                })?;
269                self.expect(TokenKind::RParen)?;
270                FieldType::VarChar { length }
271            }
272            "Decimal" => {
273                // Parse Decimal(precision, scale)
274                if self.check(TokenKind::LParen) {
275                    self.advance();
276                    let precision = self.parse_number()?.parse::<u32>().map_err(|_| {
277                        SchemaError::Parse(
278                            "Invalid precision value".to_string(),
279                            self.current_span(),
280                        )
281                    })?;
282                    self.expect(TokenKind::Comma)?;
283                    let scale = self.parse_number()?.parse::<u32>().map_err(|_| {
284                        SchemaError::Parse("Invalid scale value".to_string(), self.current_span())
285                    })?;
286                    self.expect(TokenKind::RParen)?;
287                    FieldType::Decimal { precision, scale }
288                } else {
289                    return Err(SchemaError::Parse(
290                        "Decimal type requires precision and scale: Decimal(p, s)".to_string(),
291                        ident.span,
292                    ));
293                }
294            }
295            _ => FieldType::UserType(ident.value),
296        };
297
298        Ok(field_type)
299    }
300
301    /// Parses field modifiers (?, !, or []).
302    fn parse_field_modifier(&mut self) -> Result<FieldModifier> {
303        if self.check(TokenKind::Question) {
304            self.advance();
305            Ok(FieldModifier::Optional)
306        } else if self.check(TokenKind::Bang) {
307            self.advance();
308            Ok(FieldModifier::NotNull)
309        } else if self.check(TokenKind::LBracket) {
310            self.advance();
311            self.expect(TokenKind::RBracket)?;
312            Ok(FieldModifier::Array)
313        } else {
314            Ok(FieldModifier::None)
315        }
316    }
317
318    /// Parses a field attribute (@id, @unique, etc.).
319    fn parse_field_attribute(&mut self) -> Result<FieldAttribute> {
320        let at_token = self.expect(TokenKind::At)?;
321        let at_span = at_token.span;
322        let name = self.parse_ident()?;
323
324        match name.value.as_str() {
325            "id" => Ok(FieldAttribute::Id),
326            "unique" => Ok(FieldAttribute::Unique),
327            "updatedAt" => Ok(FieldAttribute::UpdatedAt {
328                span: at_span.merge(name.span),
329            }),
330            "default" => {
331                self.expect(TokenKind::LParen)?;
332                let expr = self.parse_expr()?;
333                let rparen = self.expect(TokenKind::RParen)?;
334                let full_span = at_span.merge(rparen.span);
335                Ok(FieldAttribute::Default(expr, full_span))
336            }
337            "map" => {
338                self.expect(TokenKind::LParen)?;
339                let map_name = self.parse_string()?;
340                self.expect(TokenKind::RParen)?;
341                Ok(FieldAttribute::Map(map_name))
342            }
343            "store" => {
344                let start = name.span;
345                self.expect(TokenKind::LParen)?;
346                let strategy_ident = self.parse_ident()?;
347                let strategy = match strategy_ident.value.as_str() {
348                    "json" => StorageStrategy::Json,
349                    "native" => StorageStrategy::Native,
350                    _ => {
351                        return Err(SchemaError::Parse(
352                            format!(
353                                "Unknown storage strategy: '{}'. Valid options: 'json', 'native'",
354                                strategy_ident.value
355                            ),
356                            strategy_ident.span,
357                        ))
358                    }
359                };
360                let end = self.expect(TokenKind::RParen)?.span;
361                Ok(FieldAttribute::Store {
362                    strategy,
363                    span: start.merge(end),
364                })
365            }
366            "relation" => {
367                let start = name.span;
368                self.expect(TokenKind::LParen)?;
369
370                let mut rel_name = None;
371                let mut fields = None;
372                let mut references = None;
373                let mut on_delete = None;
374                let mut on_update = None;
375
376                // Parse named arguments
377                while !self.check(TokenKind::RParen) && !self.is_at_end() {
378                    let arg_name = self.parse_ident()?;
379                    self.expect(TokenKind::Colon)?;
380
381                    match arg_name.value.as_str() {
382                        "name" => rel_name = Some(self.parse_string()?),
383                        "fields" => fields = Some(self.parse_ident_array()?),
384                        "references" => references = Some(self.parse_ident_array()?),
385                        "onDelete" => on_delete = Some(self.parse_referential_action()?),
386                        "onUpdate" => on_update = Some(self.parse_referential_action()?),
387                        _ => {
388                            return Err(SchemaError::Parse(
389                                format!("Unknown relation argument: {}", arg_name.value),
390                                arg_name.span,
391                            ))
392                        }
393                    }
394
395                    if self.check(TokenKind::Comma) {
396                        self.advance();
397                    }
398                }
399
400                let end = self.expect(TokenKind::RParen)?.span;
401                Ok(FieldAttribute::Relation {
402                    name: rel_name,
403                    fields,
404                    references,
405                    on_delete,
406                    on_update,
407                    span: start.merge(end),
408                })
409            }
410            "computed" => {
411                let start = at_span;
412                self.expect(TokenKind::LParen)?;
413                let expr = self.parse_sql_expr()?;
414                self.expect(TokenKind::Comma)?;
415                let kind_ident = self.parse_ident()?;
416                let kind = match kind_ident.value.as_str() {
417                    "Stored" => ComputedKind::Stored,
418                    "Virtual" => ComputedKind::Virtual,
419                    other => {
420                        return Err(SchemaError::Parse(
421                            format!(
422                                "Unknown computed kind '{}'. Valid options: Stored, Virtual",
423                                other
424                            ),
425                            kind_ident.span,
426                        ))
427                    }
428                };
429                let end = self.expect(TokenKind::RParen)?.span;
430                Ok(FieldAttribute::Computed {
431                    expr,
432                    kind,
433                    span: start.merge(end),
434                })
435            }
436            "check" => {
437                let start = at_span;
438                self.expect(TokenKind::LParen)?;
439                let expr = self.parse_bool_expr()?;
440                let end = self.expect(TokenKind::RParen)?.span;
441                Ok(FieldAttribute::Check {
442                    expr,
443                    span: start.merge(end),
444                })
445            }
446            _ => Err(SchemaError::Parse(
447                format!("Unknown field attribute: @{}", name.value),
448                name.span,
449            )),
450        }
451    }
452
453    /// Collects SQL expression tokens until a top-level comma or closing paren,
454    /// then parses them into a validated [`SqlExpr`] tree.
455    fn parse_sql_expr(&mut self) -> Result<crate::sql_expr::SqlExpr> {
456        if self.pos >= self.tokens.len() {
457            return Err(SchemaError::Parse(
458                "Unexpected end of file in @computed expression".to_string(),
459                self.current_span(),
460            ));
461        }
462        let fallback_span = self.current_span();
463        let expr_start = self.pos;
464        let mut depth: i32 = 0;
465
466        loop {
467            match self.peek_kind() {
468                Some(TokenKind::LParen) => {
469                    depth += 1;
470                    self.advance();
471                }
472                Some(TokenKind::RParen) if depth == 0 => break,
473                Some(TokenKind::RParen) => {
474                    depth -= 1;
475                    self.advance();
476                }
477                Some(TokenKind::Comma) if depth == 0 => break,
478                None | Some(TokenKind::Eof) => {
479                    return Err(SchemaError::Parse(
480                        "Unexpected end of file in @computed expression".to_string(),
481                        self.current_span(),
482                    ));
483                }
484                _ => {
485                    self.advance();
486                }
487            }
488        }
489
490        let expr_tokens: Vec<_> = self.tokens[expr_start..self.pos]
491            .iter()
492            .filter(|t| !matches!(t.kind, TokenKind::Newline))
493            .cloned()
494            .collect();
495
496        crate::sql_expr::parse_sql_expr(&expr_tokens, fallback_span)
497    }
498
499    /// Collects boolean expression tokens until a top-level closing paren,
500    /// then parses them into a validated [`BoolExpr`] tree.
501    fn parse_bool_expr(&mut self) -> Result<crate::bool_expr::BoolExpr> {
502        if self.pos >= self.tokens.len() {
503            return Err(SchemaError::Parse(
504                "Unexpected end of file in @check expression".to_string(),
505                self.current_span(),
506            ));
507        }
508        let fallback_span = self.current_span();
509        let expr_start = self.pos;
510        let mut depth: i32 = 0;
511
512        loop {
513            match self.peek_kind() {
514                Some(TokenKind::LParen) => {
515                    depth += 1;
516                    self.advance();
517                }
518                Some(TokenKind::RParen) if depth == 0 => break,
519                Some(TokenKind::RParen) => {
520                    depth -= 1;
521                    self.advance();
522                }
523                None | Some(TokenKind::Eof) => {
524                    return Err(SchemaError::Parse(
525                        "Unexpected end of file in @check expression".to_string(),
526                        self.current_span(),
527                    ));
528                }
529                _ => {
530                    self.advance();
531                }
532            }
533        }
534
535        let expr_tokens: Vec<_> = self.tokens[expr_start..self.pos]
536            .iter()
537            .filter(|t| !matches!(t.kind, TokenKind::Newline))
538            .cloned()
539            .collect();
540
541        crate::bool_expr::parse_bool_expr(&expr_tokens, fallback_span)
542    }
543
544    /// Parses a model attribute (@@map, @@id, etc.).
545    fn parse_model_attribute(&mut self) -> Result<ModelAttribute> {
546        self.expect(TokenKind::AtAt)?;
547        let name = self.parse_ident()?;
548
549        match name.value.as_str() {
550            "map" => {
551                self.expect(TokenKind::LParen)?;
552                let map_name = self.parse_string()?;
553                self.expect(TokenKind::RParen)?;
554                Ok(ModelAttribute::Map(map_name))
555            }
556            "id" => {
557                self.expect(TokenKind::LParen)?;
558                let fields = self.parse_ident_array()?;
559                self.expect(TokenKind::RParen)?;
560                Ok(ModelAttribute::Id(fields))
561            }
562            "unique" => {
563                self.expect(TokenKind::LParen)?;
564                let fields = self.parse_ident_array()?;
565                self.expect(TokenKind::RParen)?;
566                Ok(ModelAttribute::Unique(fields))
567            }
568            "index" => {
569                self.expect(TokenKind::LParen)?;
570                let fields = self.parse_ident_array()?;
571                let mut index_type: Option<Ident> = None;
572                let mut index_name: Option<String> = None;
573                let mut index_map: Option<String> = None;
574                // Parse optional named arguments: type:, name:, map:
575                while self.check(TokenKind::Comma) {
576                    self.advance(); // consume ','
577                    if self.check(TokenKind::RParen) {
578                        break; // trailing comma
579                    }
580                    let key = self.parse_ident()?;
581                    self.expect(TokenKind::Colon)?;
582                    match key.value.as_str() {
583                        "type" => {
584                            index_type = Some(self.parse_ident()?);
585                        }
586                        "name" => {
587                            index_name = Some(self.parse_string()?);
588                        }
589                        "map" => {
590                            index_map = Some(self.parse_string()?);
591                        }
592                        _ => {
593                            return Err(SchemaError::Parse(
594                                format!("Unknown @@index argument: '{}'", key.value),
595                                key.span,
596                            ));
597                        }
598                    }
599                }
600                self.expect(TokenKind::RParen)?;
601                Ok(ModelAttribute::Index {
602                    fields,
603                    index_type,
604                    name: index_name,
605                    map: index_map,
606                })
607            }
608            "check" => {
609                self.expect(TokenKind::LParen)?;
610                let expr = self.parse_bool_expr()?;
611                let end = self.expect(TokenKind::RParen)?.span;
612                Ok(ModelAttribute::Check {
613                    expr,
614                    span: name.span.merge(end),
615                })
616            }
617            _ => Err(SchemaError::Parse(
618                format!("Unknown model attribute: @@{}", name.value),
619                name.span,
620            )),
621        }
622    }
623
624    /// Parses an array of identifiers [a, b, c].
625    fn parse_ident_array(&mut self) -> Result<Vec<Ident>> {
626        self.expect(TokenKind::LBracket)?;
627        let mut idents = Vec::new();
628
629        while !self.check(TokenKind::RBracket) && !self.is_at_end() {
630            idents.push(self.parse_ident()?);
631            if self.check(TokenKind::Comma) {
632                self.advance();
633            }
634        }
635
636        self.expect(TokenKind::RBracket)?;
637        Ok(idents)
638    }
639
640    /// Parses a referential action (Cascade, SetNull, etc.).
641    fn parse_referential_action(&mut self) -> Result<ReferentialAction> {
642        let ident = self.parse_ident()?;
643        match ident.value.as_str() {
644            "Cascade" => Ok(ReferentialAction::Cascade),
645            "Restrict" => Ok(ReferentialAction::Restrict),
646            "NoAction" => Ok(ReferentialAction::NoAction),
647            "SetNull" => Ok(ReferentialAction::SetNull),
648            "SetDefault" => Ok(ReferentialAction::SetDefault),
649            _ => Err(SchemaError::Parse(
650                format!("Unknown referential action: {}", ident.value),
651                ident.span,
652            )),
653        }
654    }
655
656    /// Parses an enum block.
657    fn parse_enum(&mut self) -> Result<EnumDecl> {
658        let start = self.expect(TokenKind::Enum)?.span;
659        let name = self.parse_ident()?;
660        self.expect(TokenKind::LBrace)?;
661        self.skip_newlines();
662
663        let mut variants = Vec::new();
664        while !self.check(TokenKind::RBrace) && !self.is_at_end() {
665            let variant_name = self.parse_ident()?;
666            let variant_span = variant_name.span;
667            variants.push(EnumVariant {
668                name: variant_name,
669                span: variant_span,
670            });
671            self.skip_newlines();
672        }
673
674        let end = self.expect(TokenKind::RBrace)?.span;
675        Ok(EnumDecl {
676            name,
677            variants,
678            span: start.merge(end),
679        })
680    }
681
682    /// Parses an expression.
683    fn parse_expr(&mut self) -> Result<Expr> {
684        match self.peek_kind() {
685            Some(TokenKind::String(_)) => {
686                let s = self.parse_string()?;
687                let span = self.previous_span();
688                Ok(Expr::Literal(Literal::String(s, span)))
689            }
690            Some(TokenKind::Number(_)) => {
691                let n = self.parse_number()?;
692                let span = self.previous_span();
693                Ok(Expr::Literal(Literal::Number(n, span)))
694            }
695            Some(TokenKind::True) => {
696                let span = self.advance().span;
697                Ok(Expr::Literal(Literal::Boolean(true, span)))
698            }
699            Some(TokenKind::False) => {
700                let span = self.advance().span;
701                Ok(Expr::Literal(Literal::Boolean(false, span)))
702            }
703            Some(TokenKind::LBracket) => self.parse_array_expr(),
704            Some(TokenKind::Ident(_)) => {
705                let ident = self.parse_ident()?;
706
707                // Check for function call
708                if self.check(TokenKind::LParen) {
709                    let start = ident.span;
710                    self.advance();
711
712                    let mut args = Vec::new();
713                    while !self.check(TokenKind::RParen) && !self.is_at_end() {
714                        args.push(self.parse_expr()?);
715                        if self.check(TokenKind::Comma) {
716                            self.advance();
717                        }
718                    }
719
720                    let end = self.expect(TokenKind::RParen)?.span;
721                    Ok(Expr::FunctionCall {
722                        name: ident,
723                        args,
724                        span: start.merge(end),
725                    })
726                } else {
727                    // Just an identifier reference
728                    Ok(Expr::Ident(ident))
729                }
730            }
731            Some(kind) => Err(SchemaError::Parse(
732                format!("Expected expression, found {:?}", kind),
733                self.current_span(),
734            )),
735            None => Err(SchemaError::Parse(
736                "Unexpected end of file in expression".to_string(),
737                self.current_span(),
738            )),
739        }
740    }
741
742    /// Parses an array expression [a, b, c].
743    fn parse_array_expr(&mut self) -> Result<Expr> {
744        let start = self.expect(TokenKind::LBracket)?.span;
745        let mut elements = Vec::new();
746
747        while !self.check(TokenKind::RBracket) && !self.is_at_end() {
748            elements.push(self.parse_expr()?);
749            if self.check(TokenKind::Comma) {
750                self.advance();
751            }
752        }
753
754        let end = self.expect(TokenKind::RBracket)?.span;
755        Ok(Expr::Array {
756            elements,
757            span: start.merge(end),
758        })
759    }
760
761    /// Parses an identifier.
762    fn parse_ident(&mut self) -> Result<Ident> {
763        match self.peek_kind() {
764            Some(TokenKind::Ident(ref name)) => {
765                let name = name.clone();
766                let span = self.advance().span;
767                Ok(Ident::new(name, span))
768            }
769            // Allow `type` keyword as an identifier in contexts like
770            // named arguments (e.g., `type: Hash` in @@index)
771            Some(TokenKind::Type) => {
772                let span = self.advance().span;
773                Ok(Ident::new("type".to_string(), span))
774            }
775            Some(kind) => Err(SchemaError::Parse(
776                format!("Expected identifier, found {:?}", kind),
777                self.current_span(),
778            )),
779            None => Err(SchemaError::Parse(
780                "Expected identifier, found EOF".to_string(),
781                self.current_span(),
782            )),
783        }
784    }
785
786    /// Parses a string literal.
787    fn parse_string(&mut self) -> Result<String> {
788        match self.peek_kind() {
789            Some(TokenKind::String(ref s)) => {
790                let s = s.clone();
791                self.advance();
792                Ok(s)
793            }
794            Some(kind) => Err(SchemaError::Parse(
795                format!("Expected string, found {:?}", kind),
796                self.current_span(),
797            )),
798            None => Err(SchemaError::Parse(
799                "Expected string, found EOF".to_string(),
800                self.current_span(),
801            )),
802        }
803    }
804
805    /// Parses a number literal.
806    fn parse_number(&mut self) -> Result<String> {
807        match self.peek_kind() {
808            Some(TokenKind::Number(ref n)) => {
809                let n = n.clone();
810                self.advance();
811                Ok(n)
812            }
813            Some(kind) => Err(SchemaError::Parse(
814                format!("Expected number, found {:?}", kind),
815                self.current_span(),
816            )),
817            None => Err(SchemaError::Parse(
818                "Expected number, found EOF".to_string(),
819                self.current_span(),
820            )),
821        }
822    }
823
824    // ===== Helper methods =====
825
826    /// Checks if current token matches the given kind.
827    fn check(&self, kind: TokenKind) -> bool {
828        self.peek_kind()
829            .map(|k| std::mem::discriminant(&k) == std::mem::discriminant(&kind))
830            .unwrap_or(false)
831    }
832
833    /// Expects the current token to be of the given kind, advances, returns token.
834    fn expect(&mut self, kind: TokenKind) -> Result<&'a Token> {
835        if self.check(kind.clone()) {
836            Ok(self.advance())
837        } else {
838            Err(SchemaError::Parse(
839                format!("Expected {:?}, found {:?}", kind, self.peek_kind()),
840                self.current_span(),
841            ))
842        }
843    }
844
845    /// Peeks at the current token kind.
846    fn peek_kind(&self) -> Option<TokenKind> {
847        self.tokens.get(self.pos).map(|t| t.kind.clone())
848    }
849
850    /// Advances to the next token, returns current token.
851    fn advance(&mut self) -> &'a Token {
852        let token = &self.tokens[self.pos];
853        if self.pos < self.tokens.len() {
854            self.pos += 1;
855        }
856        token
857    }
858
859    /// Returns the span of the current token.
860    fn current_span(&self) -> Span {
861        self.tokens
862            .get(self.pos)
863            .map(|t| t.span)
864            .unwrap_or_else(|| self.previous_span())
865    }
866
867    /// Returns the span of the previous token.
868    fn previous_span(&self) -> Span {
869        if self.pos > 0 {
870            self.tokens[self.pos - 1].span
871        } else {
872            Span::new(0, 0)
873        }
874    }
875
876    /// Checks if we're at the end of the token stream.
877    fn is_at_end(&self) -> bool {
878        self.pos >= self.tokens.len() || matches!(self.peek_kind(), Some(TokenKind::Eof))
879    }
880
881    /// Skips newline tokens.
882    fn skip_newlines(&mut self) {
883        while matches!(self.peek_kind(), Some(TokenKind::Newline)) {
884            self.advance();
885        }
886    }
887
888    /// Recovers to the next declaration (for error recovery).
889    fn recover_to_next_declaration(&mut self) {
890        while !self.is_at_end() {
891            match self.peek_kind() {
892                Some(TokenKind::Datasource)
893                | Some(TokenKind::Generator)
894                | Some(TokenKind::Model)
895                | Some(TokenKind::Enum)
896                | Some(TokenKind::Type) => break,
897                _ => {
898                    self.advance();
899                }
900            }
901        }
902    }
903}
904
905#[cfg(test)]
906mod tests {
907    use super::*;
908    use crate::lexer::Lexer;
909
910    fn tokenize(input: &str) -> Vec<Token> {
911        let mut lexer = Lexer::new(input);
912        let mut tokens = Vec::new();
913        loop {
914            match lexer.next_token() {
915                Ok(token) => {
916                    if matches!(token.kind, TokenKind::Eof) {
917                        tokens.push(token);
918                        break;
919                    }
920                    tokens.push(token);
921                }
922                Err(e) => panic!("Tokenization failed: {}", e),
923            }
924        }
925        tokens
926    }
927
928    #[test]
929    fn test_parse_empty_schema() {
930        let input = "";
931        let tokens = tokenize(input);
932        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
933        assert_eq!(schema.declarations.len(), 0);
934    }
935
936    #[test]
937    fn test_parse_simple_model() {
938        let input = r#"
939            model User {
940                id Int @id
941            }
942        "#;
943        let tokens = tokenize(input);
944        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
945        assert_eq!(schema.declarations.len(), 1);
946
947        match &schema.declarations[0] {
948            Declaration::Model(model) => {
949                assert_eq!(model.name.value, "User");
950                assert_eq!(model.fields.len(), 1);
951                assert_eq!(model.fields[0].name.value, "id");
952            }
953            _ => panic!("Expected model declaration"),
954        }
955    }
956
957    #[test]
958    fn test_parse_field_types() {
959        let input = r#"
960            model Test {
961                str String
962                num Int
963                big BigInt
964                opt String?
965                arr Int[]
966                dec Decimal(10, 2)
967            }
968        "#;
969        let tokens = tokenize(input);
970        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
971
972        match &schema.declarations[0] {
973            Declaration::Model(model) => {
974                assert_eq!(model.fields.len(), 6);
975                assert!(matches!(model.fields[0].field_type, FieldType::String));
976                assert!(matches!(model.fields[1].field_type, FieldType::Int));
977                assert!(matches!(model.fields[2].field_type, FieldType::BigInt));
978                assert!(model.fields[3].is_optional());
979                assert!(model.fields[4].is_array());
980                assert!(matches!(
981                    model.fields[5].field_type,
982                    FieldType::Decimal {
983                        precision: 10,
984                        scale: 2
985                    }
986                ));
987            }
988            _ => panic!("Expected model"),
989        }
990    }
991
992    #[test]
993    fn test_parse_field_attributes() {
994        let input = r#"
995            model User {
996                id Int @id @default(autoincrement())
997                email String @unique @map("user_email")
998            }
999        "#;
1000        let tokens = tokenize(input);
1001        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
1002
1003        match &schema.declarations[0] {
1004            Declaration::Model(model) => {
1005                assert_eq!(model.fields[0].attributes.len(), 2);
1006                assert!(matches!(model.fields[0].attributes[0], FieldAttribute::Id));
1007                assert!(matches!(
1008                    model.fields[0].attributes[1],
1009                    FieldAttribute::Default(..)
1010                ));
1011
1012                assert_eq!(model.fields[1].attributes.len(), 2);
1013                assert!(matches!(
1014                    model.fields[1].attributes[0],
1015                    FieldAttribute::Unique
1016                ));
1017                assert!(matches!(
1018                    model.fields[1].attributes[1],
1019                    FieldAttribute::Map(_)
1020                ));
1021            }
1022            _ => panic!("Expected model"),
1023        }
1024    }
1025
1026    #[test]
1027    fn test_parse_model_attributes() {
1028        let input = r#"
1029            model User {
1030                id Int
1031                @@map("users")
1032                @@id([id])
1033            }
1034        "#;
1035        let tokens = tokenize(input);
1036        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
1037
1038        match &schema.declarations[0] {
1039            Declaration::Model(model) => {
1040                assert_eq!(model.attributes.len(), 2);
1041                assert!(matches!(model.attributes[0], ModelAttribute::Map(_)));
1042                assert!(matches!(model.attributes[1], ModelAttribute::Id(_)));
1043            }
1044            _ => panic!("Expected model"),
1045        }
1046    }
1047
1048    #[test]
1049    fn test_parse_enum() {
1050        let input = r#"
1051            enum Role {
1052                USER
1053                ADMIN
1054            }
1055        "#;
1056        let tokens = tokenize(input);
1057        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
1058
1059        match &schema.declarations[0] {
1060            Declaration::Enum(enum_decl) => {
1061                assert_eq!(enum_decl.name.value, "Role");
1062                assert_eq!(enum_decl.variants.len(), 2);
1063                assert_eq!(enum_decl.variants[0].name.value, "USER");
1064                assert_eq!(enum_decl.variants[1].name.value, "ADMIN");
1065            }
1066            _ => panic!("Expected enum"),
1067        }
1068    }
1069
1070    #[test]
1071    fn test_parse_datasource() {
1072        let input = r#"
1073            datasource db {
1074                provider = "postgresql"
1075                url = env("DATABASE_URL")
1076            }
1077        "#;
1078        let tokens = tokenize(input);
1079        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
1080
1081        match &schema.declarations[0] {
1082            Declaration::Datasource(ds) => {
1083                assert_eq!(ds.name.value, "db");
1084                assert_eq!(ds.fields.len(), 2);
1085                assert_eq!(ds.provider(), Some("postgresql"));
1086            }
1087            _ => panic!("Expected datasource"),
1088        }
1089    }
1090
1091    #[test]
1092    fn test_parse_generator() {
1093        let input = r#"
1094            generator client {
1095                provider = "nautilus-client-rs"
1096                output = "../generated"
1097            }
1098        "#;
1099        let tokens = tokenize(input);
1100        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
1101
1102        match &schema.declarations[0] {
1103            Declaration::Generator(gen) => {
1104                assert_eq!(gen.name.value, "client");
1105                assert_eq!(gen.fields.len(), 2);
1106            }
1107            _ => panic!("Expected generator"),
1108        }
1109    }
1110
1111    #[test]
1112    fn test_parse_relation() {
1113        let input = r#"
1114            model Post {
1115                userId Int
1116                user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1117            }
1118        "#;
1119        let tokens = tokenize(input);
1120        let schema = Parser::new(&tokens, input).parse_schema().unwrap();
1121
1122        match &schema.declarations[0] {
1123            Declaration::Model(model) => match &model.fields[1].attributes[0] {
1124                FieldAttribute::Relation {
1125                    fields,
1126                    references,
1127                    on_delete,
1128                    ..
1129                } => {
1130                    assert!(fields.is_some());
1131                    assert!(references.is_some());
1132                    assert_eq!(*on_delete, Some(ReferentialAction::Cascade));
1133                }
1134                _ => panic!("Expected relation attribute"),
1135            },
1136            _ => panic!("Expected model"),
1137        }
1138    }
1139}