Skip to main content

cairo_lang_parser/
db.rs

1use cairo_lang_diagnostics::{Diagnostics, DiagnosticsBuilder, Maybe, ToMaybe};
2use cairo_lang_filesystem::db::FilesGroup;
3use cairo_lang_filesystem::ids::{FileId, FileKind};
4use cairo_lang_syntax::node::ast::{Expr, StatementList, SyntaxFile};
5use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
6use salsa::Database;
7
8use crate::diagnostic::ParserDiagnostic;
9use crate::parser::Parser;
10
11#[cfg(test)]
12#[path = "db_test.rs"]
13mod db_test;
14
15/// Interface of the parser database.
16pub trait ParserGroup: Database {
17    /// Parses a file and returns its AST as a root SyntaxNode.
18    fn file_syntax<'db>(&'db self, file_id: FileId<'db>) -> Maybe<SyntaxNode<'db>> {
19        file_syntax(self.as_dyn_database(), file_id)
20    }
21
22    /// Parses a file and returns its AST as a root SyntaxFile.
23    fn file_module_syntax<'db>(&'db self, file_id: FileId<'db>) -> Maybe<SyntaxFile<'db>> {
24        file_module_syntax(self.as_dyn_database(), file_id)
25    }
26    /// Parses a file and returns its AST as an expression. Only used for inline macros expanded
27    /// code.
28    fn file_expr_syntax<'db>(&'db self, file_id: FileId<'db>) -> Maybe<Expr<'db>> {
29        file_expr_syntax(self.as_dyn_database(), file_id)
30    }
31    /// Parses a file and returns its AST as a list of statements. Only used for inline macros
32    /// expanded code.
33    fn file_statement_list_syntax<'db>(
34        &'db self,
35        file_id: FileId<'db>,
36    ) -> Maybe<StatementList<'db>> {
37        file_statement_list_syntax(self.as_dyn_database(), file_id)
38    }
39    /// Returns the parser diagnostics for this file.
40    fn file_syntax_diagnostics<'db>(
41        &'db self,
42        file_id: FileId<'db>,
43    ) -> &'db Diagnostics<'db, ParserDiagnostic<'db>> {
44        file_syntax_diagnostics(self.as_dyn_database(), file_id)
45    }
46}
47
48impl<T: Database + ?Sized> ParserGroup for T {}
49
50#[salsa::tracked]
51struct SyntaxData<'db> {
52    diagnostics: Diagnostics<'db, ParserDiagnostic<'db>>,
53    syntax: Maybe<SyntaxNode<'db>>,
54}
55
56/// Parses a file and returns the result and the generated [ParserDiagnostic].
57#[salsa::tracked(returns(ref))]
58fn file_syntax_data<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> SyntaxData<'db> {
59    let mut diagnostics = DiagnosticsBuilder::default();
60    let syntax = db.file_content(file_id).to_maybe().map(|s| match file_id.kind(db) {
61        FileKind::Module => Parser::parse_file(db, &mut diagnostics, file_id, s).as_syntax_node(),
62        FileKind::Expr => {
63            Parser::parse_file_expr(db, &mut diagnostics, file_id, s).as_syntax_node()
64        }
65        FileKind::StatementList => {
66            Parser::parse_file_statement_list(db, &mut diagnostics, file_id, s).as_syntax_node()
67        }
68    });
69    SyntaxData::new(db, diagnostics.build(), syntax)
70}
71
72/// Parses a file and returns its SyntaxNode.
73#[salsa::tracked]
74fn file_syntax<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Maybe<SyntaxNode<'db>> {
75    file_syntax_data(db, file_id).syntax(db)
76}
77
78/// Parses a file and returns its AST as a root SyntaxFile.
79/// Requires `file_id.kind()` to be `FileKind::Module`.
80fn file_module_syntax<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Maybe<SyntaxFile<'db>> {
81    assert_eq!(file_id.kind(db), FileKind::Module, "file_id must be a module");
82    Ok(SyntaxFile::from_syntax_node(db, file_syntax(db, file_id)?))
83}
84
85/// Parses a file and returns its AST as an expression. Only used for inline macros expanded code.
86/// Requires `file_id.kind()` to be `FileKind::Expr`.
87fn file_expr_syntax<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Maybe<Expr<'db>> {
88    assert_eq!(file_id.kind(db), FileKind::Expr, "file_id must be an expr");
89    Ok(Expr::from_syntax_node(db, file_syntax(db, file_id)?))
90}
91
92/// Parses a file and returns its AST as a list of statements. Only used for inline macros
93/// expanded code.
94/// Requires `file_id.kind()` to be `FileKind::StatementList`.
95fn file_statement_list_syntax<'db>(
96    db: &'db dyn Database,
97    file_id: FileId<'db>,
98) -> Maybe<StatementList<'db>> {
99    assert_eq!(file_id.kind(db), FileKind::StatementList, "file_id must be a statement list");
100    Ok(StatementList::from_syntax_node(db, file_syntax(db, file_id)?))
101}
102
103#[salsa::tracked(returns(ref))]
104fn file_syntax_diagnostics<'db>(
105    db: &'db dyn Database,
106    file_id: FileId<'db>,
107) -> Diagnostics<'db, ParserDiagnostic<'db>> {
108    file_syntax_data(db, file_id).diagnostics(db)
109}