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