use cairo_lang_macro::{Diagnostic, TokenStream};
use cairo_lang_parser::utils::SimpleParserDatabase;
use cairo_lang_syntax::attribute::structured::{AttributeArgVariant, AttributeStructurize};
use cairo_lang_syntax::node::ast::{Attribute, Member as MemberAst};
use cairo_lang_syntax::node::helpers::QueryAttrs;
use cairo_lang_syntax::node::kind::SyntaxKind::{ExprParenthesized, ItemModule, ItemStruct};
use cairo_lang_syntax::node::{ast, Terminal, TypedSyntaxNode};
use crate::helpers::{DiagnosticsExt, Member};
pub struct DojoParser {}
impl DojoParser {
pub(crate) fn parse_and_find_struct<'a>(
db: &'a SimpleParserDatabase,
token_stream: &'a TokenStream,
) -> Option<ast::ItemStruct> {
let (root_node, _diagnostics) = db.parse_token_stream(token_stream);
for n in root_node.descendants(db) {
if n.kind(db) == ItemStruct {
let struct_ast = ast::ItemStruct::from_syntax_node(db, n);
return Some(struct_ast);
}
}
None
}
pub(crate) fn parse_and_find_module<'a>(
db: &'a SimpleParserDatabase,
token_stream: &'a TokenStream,
) -> Option<ast::ItemModule> {
let (root_node, _diagnostics) = db.parse_token_stream(token_stream);
for n in root_node.descendants(db) {
if n.kind(db) == ItemModule {
let module_ast = ast::ItemModule::from_syntax_node(db, n);
return Some(module_ast);
}
}
None
}
pub(crate) fn parse_inline_args<'a>(
db: &'a SimpleParserDatabase,
token_stream: &'a TokenStream,
) -> Option<ast::ExprParenthesized> {
let (root_node, _diagnostics) = db.parse_token_stream_expr(token_stream);
for n in root_node.descendants(db) {
if n.kind(db) == ExprParenthesized {
return Some(ast::ExprParenthesized::from_syntax_node(db, n));
}
}
None
}
pub(crate) fn parse_members(
db: &SimpleParserDatabase,
members: impl Iterator<Item = MemberAst>,
diagnostics: &mut Vec<Diagnostic>,
) -> Vec<Member> {
let mut parsing_keys = true;
members
.map(|member_ast| {
let is_key = member_ast.has_attr(db, "key");
let member = Member {
name: member_ast.name(db).text(db).to_string(),
ty: member_ast
.type_clause(db)
.ty(db)
.as_syntax_node()
.get_text_without_trivia(db)
.to_string(),
key: is_key,
};
if is_key && !parsing_keys {
diagnostics.push(Diagnostic::error(
"Key members must be defined before non-key members.",
));
}
parsing_keys &= is_key;
member
})
.collect::<Vec<_>>()
}
pub fn extract_derive_attr_names(
db: &SimpleParserDatabase,
diagnostics: &mut Vec<Diagnostic>,
attrs: impl Iterator<Item = Attribute>,
) -> Vec<String> {
attrs
.filter_map(|attr| {
let args = attr.clone().structurize(db).args;
if args.is_empty() {
diagnostics.push_error("Expected args.".into());
None
} else {
Some(args.into_iter().filter_map(|a| {
if let AttributeArgVariant::Unnamed(ast::Expr::Path(path)) = a.variant {
if let Some(ast::PathSegment::Simple(segment)) =
&path.segments(db).elements(db).next()
{
Some(segment.ident(db).text(db).to_string())
} else {
None
}
} else {
None
}
}))
}
})
.flatten()
.collect::<Vec<_>>()
}
}