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::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:
19    SyntaxGroup + Upcast<dyn SyntaxGroup> + FilesGroup + Upcast<dyn FilesGroup>
20{
21    /// Should only be used internally.
22    /// Parses a file and returns the result and the generated [ParserDiagnostic].
23    fn priv_file_syntax_data(&self, file_id: FileId) -> SyntaxData;
24    /// Parses a file and returns its SyntaxNode.
25    fn file_syntax(&self, file_id: FileId) -> Maybe<SyntaxNode>;
26    /// Parses a file and returns its AST as a root SyntaxFile.
27    fn file_module_syntax(&self, file_id: FileId) -> Maybe<SyntaxFile>;
28    /// Parses a file and returns its AST as an expression. Only used for inline macros expanded
29    /// code.
30    fn file_expr_syntax(&self, file_id: FileId) -> Maybe<Expr>;
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(&self, file_id: FileId) -> Maybe<StatementList>;
34    /// Returns the parser diagnostics for this file.
35    fn file_syntax_diagnostics(&self, file_id: FileId) -> Diagnostics<ParserDiagnostic>;
36}
37
38#[derive(Clone, PartialEq, Eq, Debug)]
39pub struct SyntaxData {
40    diagnostics: Diagnostics<ParserDiagnostic>,
41    syntax: Maybe<SyntaxNode>,
42}
43
44pub fn priv_file_syntax_data(db: &dyn ParserGroup, file_id: FileId) -> SyntaxData {
45    let mut diagnostics = DiagnosticsBuilder::default();
46    let syntax = db.file_content(file_id).to_maybe().map(|s| match file_id.kind(db) {
47        FileKind::Module => Parser::parse_file(db, &mut diagnostics, file_id, &s).as_syntax_node(),
48        FileKind::Expr => {
49            Parser::parse_file_expr(db, &mut diagnostics, file_id, &s).as_syntax_node()
50        }
51        FileKind::StatementList => {
52            Parser::parse_file_statement_list(db, &mut diagnostics, file_id, &s).as_syntax_node()
53        }
54    });
55    SyntaxData { diagnostics: diagnostics.build(), syntax }
56}
57
58pub fn file_syntax(db: &dyn ParserGroup, file_id: FileId) -> Maybe<SyntaxNode> {
59    db.priv_file_syntax_data(file_id).syntax
60}
61
62pub fn file_module_syntax(db: &dyn ParserGroup, file_id: FileId) -> Maybe<SyntaxFile> {
63    assert_eq!(file_id.kind(db), FileKind::Module, "file_id must be a module");
64    Ok(SyntaxFile::from_syntax_node(db, db.file_syntax(file_id)?))
65}
66
67pub fn file_expr_syntax(db: &dyn ParserGroup, file_id: FileId) -> Maybe<Expr> {
68    assert_eq!(file_id.kind(db), FileKind::Expr, "file_id must be an expr");
69    Ok(Expr::from_syntax_node(db, db.file_syntax(file_id)?))
70}
71
72pub fn file_statement_list_syntax(db: &dyn ParserGroup, file_id: FileId) -> Maybe<StatementList> {
73    assert_eq!(file_id.kind(db), FileKind::StatementList, "file_id must be a for a statement list");
74    Ok(StatementList::from_syntax_node(db, db.file_syntax(file_id)?))
75}
76
77pub fn file_syntax_diagnostics(
78    db: &dyn ParserGroup,
79    file_id: FileId,
80) -> Diagnostics<ParserDiagnostic> {
81    db.priv_file_syntax_data(file_id).diagnostics
82}