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
15pub trait ParserGroup: Database {
17 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 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 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 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 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 #[returns(clone)]
53 diagnostics: Diagnostics<'db, ParserDiagnostic<'db>>,
54 #[returns(copy)]
55 syntax: Maybe<SyntaxNode<'db>>,
56}
57
58#[salsa::tracked(returns(ref))]
60fn file_syntax_data<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> SyntaxData<'db> {
61 let mut diagnostics = DiagnosticsBuilder::default();
62 let syntax = db.file_content(file_id).to_maybe().map(|s| {
63 let green = match file_id.kind(db) {
64 FileKind::Module => Parser::parse_file_green(db, &mut diagnostics, file_id, s).0,
65 FileKind::Expr => Parser::parse_file_expr_green(db, &mut diagnostics, file_id, s).0,
66 FileKind::StatementList => {
67 Parser::parse_file_statement_list_green(db, &mut diagnostics, file_id, s).0
68 }
69 };
70 SyntaxNode::new_canonical_root(db, file_id, green)
76 });
77 SyntaxData::new(db, diagnostics.build(), syntax)
78}
79
80#[salsa::tracked(returns(copy))]
82fn file_syntax<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Maybe<SyntaxNode<'db>> {
83 file_syntax_data(db, file_id).syntax(db)
84}
85
86fn file_module_syntax<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Maybe<SyntaxFile<'db>> {
89 assert_eq!(file_id.kind(db), FileKind::Module, "file_id must be a module");
90 Ok(SyntaxFile::from_syntax_node(db, file_syntax(db, file_id)?))
91}
92
93fn file_expr_syntax<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Maybe<Expr<'db>> {
96 assert_eq!(file_id.kind(db), FileKind::Expr, "file_id must be an expr");
97 Ok(Expr::from_syntax_node(db, file_syntax(db, file_id)?))
98}
99
100fn file_statement_list_syntax<'db>(
104 db: &'db dyn Database,
105 file_id: FileId<'db>,
106) -> Maybe<StatementList<'db>> {
107 assert_eq!(file_id.kind(db), FileKind::StatementList, "file_id must be a statement list");
108 Ok(StatementList::from_syntax_node(db, file_syntax(db, file_id)?))
109}
110
111#[salsa::tracked(returns(ref))]
112fn file_syntax_diagnostics<'db>(
113 db: &'db dyn Database,
114 file_id: FileId<'db>,
115) -> Diagnostics<'db, ParserDiagnostic<'db>> {
116 file_syntax_data(db, file_id).diagnostics(db)
117}