Skip to main content

nounsql_core/
parser.rs

1use crate::ast::*;
2use crate::diag::Diagnostic;
3use crate::lexer::{Tok, Token, lex};
4use crate::span::{Span, Spanned};
5
6pub fn parse(src: &str) -> (Document, Vec<Diagnostic>) {
7    let (tokens, mut diags) = lex(src);
8    let mut parser = Parser {
9        tokens,
10        pos: 0,
11        diags: Vec::new(),
12    };
13    let doc = parser.document();
14    diags.append(&mut parser.diags);
15    (doc, diags)
16}
17
18/// 文の解析に失敗したことを表す。行末まで読み飛ばして回復する。
19struct Bail;
20type PResult<T> = Result<T, Bail>;
21
22const ATTR_KEYS: &[&str] = &["type", "null", "default", "on_update", "comment"];
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24enum BlockKind {
25    Table,
26    Mixin,
27}
28
29const RELATION_KEYS: &[&str] = &["fk", "alias", "via", "comment"];
30const VALUE_FNS: &[&str] = &["noun", "singular", "plural"];
31
32struct Parser {
33    tokens: Vec<Token>,
34    pos: usize,
35    diags: Vec<Diagnostic>,
36}
37
38impl Parser {
39    // ---------- トークン操作 ----------
40
41    fn peek(&self) -> &Tok {
42        &self.tokens[self.pos].value
43    }
44
45    fn peek_at(&self, n: usize) -> &Tok {
46        let i = (self.pos + n).min(self.tokens.len() - 1);
47        &self.tokens[i].value
48    }
49
50    fn span(&self) -> Span {
51        self.tokens[self.pos].span
52    }
53
54    fn prev_span(&self) -> Span {
55        self.tokens[self.pos.saturating_sub(1)].span
56    }
57
58    fn bump(&mut self) -> Token {
59        let tok = self.tokens[self.pos].clone();
60        if self.pos + 1 < self.tokens.len() {
61            self.pos += 1;
62        }
63        tok
64    }
65
66    fn at(&self, tok: &Tok) -> bool {
67        self.peek() == tok
68    }
69
70    fn eat(&mut self, tok: &Tok) -> bool {
71        if self.at(tok) {
72            self.bump();
73            true
74        } else {
75            false
76        }
77    }
78
79    fn at_keyword(&self, kw: &str) -> bool {
80        matches!(self.peek(), Tok::Ident(s) if s == kw)
81    }
82
83    fn error(&mut self, span: Span, msg: impl Into<String>) -> Bail {
84        self.diags.push(Diagnostic::error(span, msg));
85        Bail
86    }
87
88    fn expect(&mut self, tok: Tok) -> PResult<Span> {
89        if self.at(&tok) {
90            Ok(self.bump().span)
91        } else {
92            let span = self.span();
93            let found = self.peek().describe();
94            Err(self.error(span, format!("{} が必要。{} が来た", tok.describe(), found)))
95        }
96    }
97
98    fn expect_ident(&mut self, what: &str) -> PResult<Name> {
99        match self.peek().clone() {
100            Tok::Ident(name) => {
101                let span = self.bump().span;
102                Ok(Spanned::new(name, span))
103            }
104            other => {
105                let span = self.span();
106                Err(self.error(span, format!("{what} が必要。{} が来た", other.describe())))
107            }
108        }
109    }
110
111    fn expect_string(&mut self, what: &str) -> PResult<Spanned<String>> {
112        match self.peek().clone() {
113            Tok::Str(s) => {
114                let span = self.bump().span;
115                Ok(Spanned::new(s, span))
116            }
117            other => {
118                let span = self.span();
119                Err(self.error(span, format!("{what} が必要。{} が来た", other.describe())))
120            }
121        }
122    }
123
124    fn skip_newlines(&mut self) {
125        while self.at(&Tok::Newline) {
126            self.bump();
127        }
128    }
129
130    /// 行末まで読み飛ばす。1行1文なので、これで次の文から再開できる。
131    fn recover_line(&mut self) {
132        while !matches!(self.peek(), Tok::Newline | Tok::Eof | Tok::RBrace) {
133            self.bump();
134        }
135    }
136
137    /// 対応する `}` まで読み飛ばす。
138    fn recover_block(&mut self) {
139        let mut depth = 0usize;
140        loop {
141            match self.peek() {
142                Tok::Eof => return,
143                Tok::LBrace => depth += 1,
144                Tok::RBrace => {
145                    self.bump();
146                    if depth == 0 {
147                        return;
148                    }
149                    depth -= 1;
150                    continue;
151                }
152                _ => {}
153            }
154            self.bump();
155        }
156    }
157
158    /// 文の終わり(改行 / `}` / EOF)を要求する。
159    fn end_of_statement(&mut self) -> PResult<()> {
160        match self.peek() {
161            Tok::Newline | Tok::Eof | Tok::RBrace => Ok(()),
162            other => {
163                let span = self.span();
164                let found = other.describe();
165                Err(self.error(span, format!("1行1文。行末が必要だが {found} が来た")))
166            }
167        }
168    }
169
170    // ---------- トップレベル ----------
171
172    fn document(&mut self) -> Document {
173        let mut doc = Document::default();
174        loop {
175            self.skip_newlines();
176            if self.at(&Tok::Eof) {
177                break;
178            }
179            if self.item(&mut doc).is_err() {
180                self.recover_line();
181            }
182        }
183        doc
184    }
185
186    fn item(&mut self, doc: &mut Document) -> PResult<()> {
187        let Tok::Ident(kw) = self.peek().clone() else {
188            let span = self.span();
189            let found = self.peek().describe();
190            return Err(self.error(span, format!("トップレベルに書けない: {found}")));
191        };
192        match kw.as_str() {
193            "naming" | "constraints" => {
194                let block = self.config_block()?;
195                let slot = if kw == "naming" {
196                    &mut doc.naming
197                } else {
198                    &mut doc.constraints
199                };
200                if let Some(prev) = slot {
201                    let span = block.name.span;
202                    let prev_span = prev.name.span;
203                    self.diags.push(
204                        Diagnostic::error(span, format!("`{kw}` ブロックが重複している"))
205                            .with_label(prev_span, "最初の定義"),
206                    );
207                } else {
208                    *slot = Some(block);
209                }
210                Ok(())
211            }
212            "nouns" => {
213                let block = self.nouns_block()?;
214                if let Some(prev) = &doc.nouns {
215                    let prev_span = prev.span;
216                    self.diags.push(
217                        Diagnostic::error(block.span, "`nouns` ブロックが重複している")
218                            .with_label(prev_span, "最初の定義"),
219                    );
220                } else {
221                    doc.nouns = Some(block);
222                }
223                Ok(())
224            }
225            "mixin" => {
226                let m = self.mixin_block()?;
227                doc.mixins.push(m);
228                Ok(())
229            }
230            "table" => {
231                let t = self.table_block()?;
232                doc.tables.push(t);
233                Ok(())
234            }
235            "blueprint" => {
236                let b = self.blueprint_block()?;
237                doc.blueprints.push(b);
238                Ok(())
239            }
240            "associate" | "apply_blueprint" => {
241                let m = self.macro_call()?;
242                doc.macros.push(m);
243                self.end_of_statement()
244            }
245            other => {
246                let span = self.span();
247                Err(self.error(span, format!("トップレベルに書けないキーワード `{other}`")))
248            }
249        }
250    }
251
252    // ---------- 設定ブロック ----------
253
254    fn config_block(&mut self) -> PResult<ConfigBlock> {
255        let name = self.expect_ident("ブロック名")?;
256        let start = name.span;
257        if self.expect(Tok::LBrace).is_err() {
258            self.recover_block();
259            return Err(Bail);
260        }
261        let mut entries = Vec::new();
262        loop {
263            self.skip_newlines();
264            if self.at(&Tok::RBrace) || self.at(&Tok::Eof) {
265                break;
266            }
267            match self.assign() {
268                Ok(a) => {
269                    entries.push(a);
270                    if self.end_of_statement().is_err() {
271                        self.recover_line();
272                    }
273                }
274                Err(Bail) => self.recover_line(),
275            }
276        }
277        let end = self.expect(Tok::RBrace).unwrap_or(self.prev_span());
278        Ok(ConfigBlock {
279            name,
280            entries,
281            span: start.join(end),
282        })
283    }
284
285    fn assign(&mut self) -> PResult<Assign> {
286        let key = self.expect_ident("設定キー")?;
287        self.expect(Tok::Eq)?;
288        let value = self.value()?;
289        Ok(Assign { key, value })
290    }
291
292    fn nouns_block(&mut self) -> PResult<NounsBlock> {
293        let start = self.expect_ident("`nouns`")?.span;
294        if self.expect(Tok::LBrace).is_err() {
295            self.recover_block();
296            return Err(Bail);
297        }
298        let mut entries = Vec::new();
299        loop {
300            self.skip_newlines();
301            if self.at(&Tok::RBrace) || self.at(&Tok::Eof) {
302                break;
303            }
304            match self.noun_entry() {
305                Ok(e) => {
306                    entries.push(e);
307                    if self.end_of_statement().is_err() {
308                        self.recover_line();
309                    }
310                }
311                Err(Bail) => self.recover_line(),
312            }
313        }
314        let end = self.expect(Tok::RBrace).unwrap_or(self.prev_span());
315        Ok(NounsBlock {
316            entries,
317            span: start.join(end),
318        })
319    }
320
321    fn noun_entry(&mut self) -> PResult<Noun> {
322        let singular = self.expect_ident("単数形")?;
323        let plural = self.expect_ident("複数形")?;
324        let comment = match self.peek() {
325            Tok::Str(_) => Some(self.expect_string("コメント")?),
326            _ => None,
327        };
328        Ok(Noun {
329            singular,
330            plural,
331            comment,
332        })
333    }
334
335    // ---------- mixin / table ----------
336
337    fn mixin_block(&mut self) -> PResult<Mixin> {
338        let start = self.expect_ident("`mixin`")?.span;
339        let name = self.expect_ident("mixin名")?;
340        let (members, end) = self.member_block(BlockKind::Mixin)?;
341        Ok(Mixin {
342            name,
343            members,
344            span: start.join(end),
345        })
346    }
347
348    fn table_block(&mut self) -> PResult<Table> {
349        let start = self.expect_ident("`table`")?.span;
350        let name = self.expect_ident("テーブル名")?;
351        let (members, end) = self.member_block(BlockKind::Table)?;
352        Ok(Table {
353            name,
354            members,
355            span: start.join(end),
356        })
357    }
358
359    fn member_block(&mut self, kind: BlockKind) -> PResult<(Vec<Spanned<Member>>, Span)> {
360        if self.expect(Tok::LBrace).is_err() {
361            self.recover_block();
362            return Err(Bail);
363        }
364        let mut members = Vec::new();
365        loop {
366            self.skip_newlines();
367            if self.at(&Tok::RBrace) || self.at(&Tok::Eof) {
368                break;
369            }
370            let start = self.span();
371            match self.member(kind) {
372                Ok(m) => {
373                    let span = start.join(self.prev_span());
374                    members.push(Spanned::new(m, span));
375                    if self.end_of_statement().is_err() {
376                        self.recover_line();
377                    }
378                }
379                Err(Bail) => self.recover_line(),
380            }
381        }
382        let end = self.expect(Tok::RBrace).unwrap_or(self.prev_span());
383        Ok((members, end))
384    }
385
386    fn member(&mut self, kind: BlockKind) -> PResult<Member> {
387        let Tok::Ident(kw) = self.peek().clone() else {
388            let span = self.span();
389            let found = self.peek().describe();
390            return Err(self.error(span, format!("宣言文が必要。{found} が来た")));
391        };
392        match kw.as_str() {
393            "comment" => {
394                self.bump();
395                let text = self.expect_string("コメント(文字列)")?;
396                if kind != BlockKind::Table {
397                    self.diags.push(Diagnostic::error(
398                        text.span,
399                        "`comment` は `table` にしか書けない",
400                    ));
401                }
402                Ok(Member::Comment(text))
403            }
404            "column" => {
405                self.bump();
406                let name = self.expect_ident("カラム名")?;
407                let attrs = self.attrs()?;
408                Ok(Member::Column(Column { name, attrs }))
409            }
410            "pk" => {
411                self.bump();
412                Ok(Member::Pk(self.name_list("列名")?))
413            }
414            "index" => {
415                self.bump();
416                let columns = self.name_list("列名")?;
417                let unique = if self.at_keyword("unique") {
418                    self.bump();
419                    true
420                } else {
421                    false
422                };
423                Ok(Member::Index(Index { columns, unique }))
424            }
425            "use" => {
426                self.bump();
427                Ok(Member::Use(self.expect_ident("mixin名")?))
428            }
429            "override" => {
430                self.bump();
431                let name = self.expect_ident("カラム名")?;
432                let attrs = self.attrs()?;
433                if attrs.is_empty() {
434                    let span = name.span;
435                    return Err(self.error(span, "`override` には属性が1つ以上必要"));
436                }
437                Ok(Member::Override(Override { name, attrs }))
438            }
439            "except" => {
440                self.bump();
441                if self.at_keyword("index") {
442                    self.bump();
443                    Ok(Member::ExceptIndex(self.name_list("列名")?))
444                } else {
445                    Ok(Member::Except(self.name_list("カラム名")?))
446                }
447            }
448            "belongs_to" => self.relation(RelationKind::BelongsTo),
449            "unique_belongs_to" => self.relation(RelationKind::UniqueBelongsTo),
450            "has_many" => self.relation(RelationKind::HasMany),
451            "has_one" => self.relation(RelationKind::HasOne),
452            other => {
453                let span = self.span();
454                Err(self.error(span, format!("宣言文にならないキーワード `{other}`")))
455            }
456        }
457    }
458
459    fn relation(&mut self, kind: RelationKind) -> PResult<Member> {
460        self.bump();
461        let target = self.expect_ident("参照先の語")?;
462        let mut rel = Relation {
463            kind,
464            target,
465            fk: None,
466            alias: None,
467            via: None,
468            comment: None,
469        };
470        while let Tok::Ident(key) = self.peek().clone() {
471            if *self.peek_at(1) != Tok::Eq {
472                break;
473            }
474            let key_span = self.span();
475            self.bump();
476            self.bump();
477            if !RELATION_KEYS.contains(&key.as_str()) {
478                self.diags.push(Diagnostic::error(
479                    key_span,
480                    format!(
481                        "`{}` に書けない属性キー `{key}`。使えるのは {}",
482                        kind.keyword(),
483                        RELATION_KEYS.join(" / ")
484                    ),
485                ));
486            }
487            let duplicated = match key.as_str() {
488                "alias" => {
489                    let value = self.value()?;
490                    rel.alias.replace(value).is_some()
491                }
492                "fk" => {
493                    let value = self.expect_string("列名(文字列)")?;
494                    rel.fk.replace(value).is_some()
495                }
496                "comment" => {
497                    let value = self.expect_string("コメント(文字列)")?;
498                    rel.comment.replace(value).is_some()
499                }
500                _ => {
501                    let value = self.expect_string("列名(文字列)")?;
502                    rel.via.replace(value).is_some()
503                }
504            };
505            if duplicated {
506                self.diags.push(Diagnostic::error(
507                    key_span,
508                    format!("`{key}` が重複している"),
509                ));
510            }
511        }
512        if rel.fk.is_some() && !kind.owns_fk() {
513            let span = rel.fk.as_ref().map(|f| f.span).unwrap_or(rel.target.span);
514            self.diags.push(Diagnostic::error(
515                span,
516                format!("`{}` に `fk=` は書けない", kind.keyword()),
517            ));
518        }
519        if rel.via.is_some() && kind.owns_fk() {
520            let span = rel.via.as_ref().map(|v| v.span).unwrap_or(rel.target.span);
521            self.diags.push(Diagnostic::error(
522                span,
523                format!("`{}` に `via=` は書けない", kind.keyword()),
524            ));
525        }
526        if rel.comment.is_some() && !kind.owns_fk() {
527            let span = rel
528                .comment
529                .as_ref()
530                .map(|c| c.span)
531                .unwrap_or(rel.target.span);
532            self.diags.push(Diagnostic::error(
533                span,
534                format!(
535                    "`{}` は列を作らないので `comment=` は書けない",
536                    kind.keyword()
537                ),
538            ));
539        }
540        Ok(Member::Relation(rel))
541    }
542
543    fn attrs(&mut self) -> PResult<Vec<Attr>> {
544        let mut attrs = Vec::new();
545        while let Tok::Ident(key) = self.peek().clone() {
546            if *self.peek_at(1) != Tok::Eq {
547                break;
548            }
549            let key_span = self.span();
550            self.bump();
551            self.bump();
552            if !ATTR_KEYS.contains(&key.as_str()) {
553                self.diags.push(Diagnostic::error(
554                    key_span,
555                    format!(
556                        "知らない属性キー `{key}`。使えるのは {}",
557                        ATTR_KEYS.join(" / ")
558                    ),
559                ));
560            }
561            let value = self.value()?;
562            attrs.push(Attr {
563                key: Spanned::new(key, key_span),
564                value,
565            });
566        }
567        Ok(attrs)
568    }
569
570    /// `名前` または `[名前, ...]`
571    fn name_list(&mut self, what: &str) -> PResult<Vec<Name>> {
572        if self.eat(&Tok::LBracket) {
573            let mut names = Vec::new();
574            loop {
575                if self.at(&Tok::RBracket) {
576                    break;
577                }
578                names.push(self.expect_ident(what)?);
579                if !self.eat(&Tok::Comma) {
580                    break;
581                }
582            }
583            self.expect(Tok::RBracket)?;
584            if names.is_empty() {
585                let span = self.prev_span();
586                return Err(self.error(span, format!("{what} が空")));
587            }
588            Ok(names)
589        } else {
590            Ok(vec![self.expect_ident(what)?])
591        }
592    }
593
594    // ---------- blueprint ----------
595
596    fn blueprint_block(&mut self) -> PResult<Blueprint> {
597        let start = self.expect_ident("`blueprint`")?.span;
598        let name = self.expect_ident("blueprint名")?;
599        let mut params = Vec::new();
600        while matches!(self.peek(), Tok::Ident(_)) {
601            params.push(self.expect_ident("引数名")?);
602        }
603
604        if self.expect(Tok::LBrace).is_err() {
605            self.recover_block();
606            return Err(Bail);
607        }
608        let mut items = Vec::new();
609        loop {
610            self.skip_newlines();
611            if self.at(&Tok::RBrace) || self.at(&Tok::Eof) {
612                break;
613            }
614            if self.at_keyword("let") {
615                match self.let_stmt() {
616                    Ok(l) => {
617                        items.push(BlueprintItem::Let(l));
618                        if self.end_of_statement().is_err() {
619                            self.recover_line();
620                        }
621                    }
622                    Err(Bail) => self.recover_line(),
623                }
624            } else if self.at_keyword("table") {
625                match self.table_block() {
626                    Ok(t) => items.push(BlueprintItem::Table(t)),
627                    Err(Bail) => self.recover_line(),
628                }
629            } else {
630                let span = self.span();
631                let found = self.peek().describe();
632                self.diags.push(Diagnostic::error(
633                    span,
634                    format!("blueprint 内に書けるのは `let` と `table` のみ。{found} が来た"),
635                ));
636                self.recover_line();
637            }
638        }
639        let end = self.expect(Tok::RBrace).unwrap_or(self.prev_span());
640        Ok(Blueprint {
641            name,
642            params,
643            items,
644            span: start.join(end),
645        })
646    }
647
648    fn let_stmt(&mut self) -> PResult<Let> {
649        self.expect_ident("`let`")?;
650        let name = self.expect_ident("束縛名")?;
651        self.expect(Tok::Eq)?;
652        let value = self.value()?;
653        Ok(Let { name, value })
654    }
655
656    // ---------- マクロ ----------
657
658    fn macro_call(&mut self) -> PResult<MacroCall> {
659        let name = self.expect_ident("マクロ名")?;
660        let start = name.span;
661        self.expect(Tok::LParen)?;
662        let mut args = Vec::new();
663        let mut table_name = None;
664        let mut comment = None;
665        loop {
666            if self.at(&Tok::RParen) {
667                break;
668            }
669            // `キー=値` は名前付き、それ以外は位置引数。
670            if matches!(self.peek(), Tok::Ident(_)) && *self.peek_at(1) == Tok::Eq {
671                let key = self.expect_ident("キー")?;
672                self.expect(Tok::Eq)?;
673                let duplicated = match key.value.as_str() {
674                    "name" => table_name.replace(self.value()?).is_some(),
675                    "comment" => comment
676                        .replace(self.expect_string("コメント(文字列)")?)
677                        .is_some(),
678                    other => {
679                        self.diags.push(Diagnostic::error(
680                            key.span,
681                            format!("知らないキー `{other}`。使えるのは name / comment"),
682                        ));
683                        self.value()?;
684                        false
685                    }
686                };
687                if duplicated {
688                    self.diags.push(Diagnostic::error(
689                        key.span,
690                        format!("`{}` が重複している", key.value),
691                    ));
692                }
693            } else {
694                args.push(self.expect_ident("引数")?);
695            }
696            if !self.eat(&Tok::Comma) {
697                break;
698            }
699        }
700        let end = self.expect(Tok::RParen)?;
701        Ok(MacroCall {
702            name,
703            args,
704            table_name,
705            comment,
706            span: start.join(end),
707        })
708    }
709
710    // ---------- 値 ----------
711
712    fn value(&mut self) -> PResult<Spanned<Value>> {
713        let start = self.span();
714        match self.peek().clone() {
715            Tok::Str(s) => {
716                let span = self.bump().span;
717                Ok(Spanned::new(Value::Str(s), span))
718            }
719            Tok::Num(n) => {
720                let span = self.bump().span;
721                Ok(Spanned::new(Value::Num(n), span))
722            }
723            Tok::Eval(body) => {
724                let span = self.bump().span;
725                Ok(Spanned::new(Value::Eval(body), span))
726            }
727            Tok::LBracket => {
728                let items = self.value_list()?;
729                let span = start.join(self.prev_span());
730                Ok(Spanned::new(Value::List(items), span))
731            }
732            Tok::Ident(name) => {
733                if *self.peek_at(1) == Tok::LParen {
734                    let call_name = self.expect_ident("関数名")?;
735                    if !VALUE_FNS.contains(&name.as_str()) {
736                        self.diags.push(Diagnostic::error(
737                            call_name.span,
738                            format!(
739                                "値の位置で使える関数は {} のみ。`{name}` は使えない",
740                                VALUE_FNS.join(" / ")
741                            ),
742                        ));
743                    }
744                    self.expect(Tok::LParen)?;
745                    let mut args = Vec::new();
746                    loop {
747                        if self.at(&Tok::RParen) {
748                            break;
749                        }
750                        args.push(self.value()?);
751                        if !self.eat(&Tok::Comma) {
752                            break;
753                        }
754                    }
755                    let end = self.expect(Tok::RParen)?;
756                    Ok(Spanned::new(
757                        Value::Call {
758                            name: call_name,
759                            args,
760                        },
761                        start.join(end),
762                    ))
763                } else {
764                    let span = self.bump().span;
765                    Ok(Spanned::new(Value::Ident(name), span))
766                }
767            }
768            other => {
769                let span = self.span();
770                let found = other.describe();
771                Err(self.error(span, format!("値が必要。{found} が来た")))
772            }
773        }
774    }
775
776    /// リストは要素の途中で改行できる。
777    fn value_list(&mut self) -> PResult<Vec<Name>> {
778        self.expect(Tok::LBracket)?;
779        let mut items = Vec::new();
780        loop {
781            self.skip_newlines();
782            if self.at(&Tok::RBracket) || self.at(&Tok::Eof) {
783                break;
784            }
785            items.push(self.expect_ident("リスト要素")?);
786            self.skip_newlines();
787            if !self.eat(&Tok::Comma) {
788                break;
789            }
790        }
791        self.skip_newlines();
792        self.expect(Tok::RBracket)?;
793        Ok(items)
794    }
795}