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, SyntaxFile};
5use cairo_lang_syntax::node::db::SyntaxGroup;
6use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
7use cairo_lang_utils::Upcast;
8
9use crate::diagnostic::ParserDiagnostic;
10use crate::parser::Parser;
11
12#[cfg(test)]
13#[path = "db_test.rs"]
14mod db_test;
15
16// Salsa database interface.
17#[salsa::query_group(ParserDatabase)]
18pub trait ParserGroup: SyntaxGroup + Upcast<dyn SyntaxGroup> + FilesGroup {
19    /// Should only be used internally.
20    /// Parses a file and returns the result and the generated [ParserDiagnostic].
21    fn priv_file_syntax_data(&self, file_id: FileId) -> SyntaxData;
22    /// Parses a file and returns its SyntaxNode.
23    fn file_syntax(&self, file_id: FileId) -> Maybe<SyntaxNode>;
24    /// Parses a file and returns its AST as a root SyntaxFile.
25    fn file_module_syntax(&self, file_id: FileId) -> Maybe<SyntaxFile>;
26    /// Parses a file and returns its AST as an expression.
27    fn file_expr_syntax(&self, file_id: FileId) -> Maybe<Expr>;
28    /// Returns the parser diagnostics for this file.
29    fn file_syntax_diagnostics(&self, file_id: FileId) -> Diagnostics<ParserDiagnostic>;
30}
31
32#[derive(Clone, PartialEq, Eq, Debug)]
33pub struct SyntaxData {
34    diagnostics: Diagnostics<ParserDiagnostic>,
35    syntax: Maybe<SyntaxNode>,
36}
37
38pub fn priv_file_syntax_data(db: &dyn ParserGroup, file_id: FileId) -> SyntaxData {
39    let mut diagnostics = DiagnosticsBuilder::default();
40    let syntax = db.file_content(file_id).to_maybe().map(|s| match file_id.kind(db.upcast()) {
41        FileKind::Module => {
42            Parser::parse_file(db.upcast(), &mut diagnostics, file_id, &s).as_syntax_node()
43        }
44        FileKind::Expr => {
45            Parser::parse_file_expr(db.upcast(), &mut diagnostics, file_id, &s).as_syntax_node()
46        }
47    });
48    SyntaxData { diagnostics: diagnostics.build(), syntax }
49}
50
51pub fn file_syntax(db: &dyn ParserGroup, file_id: FileId) -> Maybe<SyntaxNode> {
52    db.priv_file_syntax_data(file_id).syntax
53}
54
55pub fn file_module_syntax(db: &dyn ParserGroup, file_id: FileId) -> Maybe<SyntaxFile> {
56    assert_eq!(file_id.kind(db.upcast()), FileKind::Module, "file_id must be a module");
57    Ok(SyntaxFile::from_syntax_node(db.upcast(), db.file_syntax(file_id)?))
58}
59
60pub fn file_expr_syntax(db: &dyn ParserGroup, file_id: FileId) -> Maybe<Expr> {
61    assert_eq!(file_id.kind(db.upcast()), FileKind::Expr, "file_id must be a module");
62    Ok(Expr::from_syntax_node(db.upcast(), db.file_syntax(file_id)?))
63}
64
65pub fn file_syntax_diagnostics(
66    db: &dyn ParserGroup,
67    file_id: FileId,
68) -> Diagnostics<ParserDiagnostic> {
69    db.priv_file_syntax_data(file_id).diagnostics
70}