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