Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic macro support. #7238

Merged
merged 1 commit into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions corelib/src/test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod language_features {
mod const_test;
mod for_test;
mod glob_use_test;
mod macro_test;
mod panics_test;
mod trait_test;
mod while_test;
Expand Down
66 changes: 66 additions & 0 deletions corelib/src/test/language_features/macro_test.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
macro count_idents {
($x:ident) => {
1
};

($x:ident, $y:ident) => {
2
};

($x:ident, $y:ident, $z:ident) => {
3
};

($x:ident $y:ident $z:ident) => {
3
};

($x:ident
| $y:ident
| $z:ident) => {
3
};
}

#[test]
fn test_macro_count_idents() {
assert_eq!(count_idents!(x), 1);
assert_eq!(count_idents!(x, y), 2);
assert_eq!(count_idents!(x, y, z), 3);
assert_eq!(count_idents!(x y z), 3);
assert_eq!(count_idents!(x | y | z), 3);
}

macro add_one {
($x:ident) => {
$x + 1
};
}

#[test]
fn test_macro_add_one() {
let x1 = 1;
let x2 = 2;
let x3 = 3;
assert_eq!(add_one!(x1), 2);
assert_eq!(add_one!(x2), 3);
assert_eq!(add_one!(x3), 4);
}

mod test_assert_eq {
macro assert_eq {
($left:ident, $right:ident) => {
if $left != $right {
panic!("PANIC!");
}
};
}

#[test]
#[should_panic(expected: ("PANIC!",))]
fn test_user_defined_assert_eq() {
let x = 1;
let y = 2;
assert_eq!(x, y);
}
}
55 changes: 54 additions & 1 deletion crates/cairo-lang-defs/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ pub trait DefsGroup:
#[salsa::interned]
fn intern_extern_function(&self, id: ExternFunctionLongId) -> ExternFunctionId;
#[salsa::interned]
fn intern_macro_declaration(&self, id: MacroDeclarationLongId) -> MacroDeclarationId;
#[salsa::interned]
fn intern_param(&self, id: ParamLongId) -> ParamId;
#[salsa::interned]
fn intern_generic_param(&self, id: GenericParamLongId) -> GenericParamId;
Expand Down Expand Up @@ -244,6 +246,21 @@ pub trait DefsGroup:
&self,
extern_function_id: ExternFunctionId,
) -> Maybe<Option<ast::ItemExternFunction>>;
/// Returns the macro declarations in the module.
fn module_macro_declarations(
&self,
module_id: ModuleId,
) -> Maybe<Arc<OrderedHashMap<MacroDeclarationId, ast::ItemMacroDeclaration>>>;
/// Returns the IDs of the macro declarations in the module.
fn module_macro_declarations_ids(
&self,
module_id: ModuleId,
) -> Maybe<Arc<[MacroDeclarationId]>>;
/// Returns the macro declaration by its ID.
fn module_macro_declaration_by_id(
&self,
macro_declaration_id: MacroDeclarationId,
) -> Maybe<Option<ast::ItemMacroDeclaration>>;
fn module_ancestors(&self, module_id: ModuleId) -> OrderedHashSet<ModuleId>;
fn module_generated_file_aux_data(
&self,
Expand Down Expand Up @@ -410,6 +427,7 @@ pub struct ModuleData {
impls: Arc<OrderedHashMap<ImplDefId, ast::ItemImpl>>,
extern_types: Arc<OrderedHashMap<ExternTypeId, ast::ItemExternType>>,
extern_functions: Arc<OrderedHashMap<ExternFunctionId, ast::ItemExternFunction>>,
macro_declarations: Arc<OrderedHashMap<MacroDeclarationId, ast::ItemMacroDeclaration>>,
global_uses: Arc<OrderedHashMap<GlobalUseId, ast::UsePathStar>>,

files: Vec<FileId>,
Expand Down Expand Up @@ -477,6 +495,7 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData
let mut impls = OrderedHashMap::default();
let mut extern_types = OrderedHashMap::default();
let mut extern_functions = OrderedHashMap::default();
let mut macro_declarations = OrderedHashMap::default();
let mut global_uses = OrderedHashMap::default();
let mut aux_data = Vec::new();
let mut files = Vec::new();
Expand Down Expand Up @@ -571,6 +590,13 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData
impl_aliases.insert(item_id, impl_alias);
items.push(ModuleItemId::ImplAlias(item_id));
}
ast::ModuleItem::MacroDeclaration(macro_declaration) => {
let item_id =
MacroDeclarationLongId(module_file_id, macro_declaration.stable_ptr())
.intern(db);
macro_declarations.insert(item_id, macro_declaration);
items.push(ModuleItemId::MacroDeclaration(item_id));
}
ast::ModuleItem::InlineMacro(inline_macro_ast) => plugin_diagnostics.push((
module_file_id,
PluginDiagnostic::error(
Expand All @@ -581,7 +607,6 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData
),
),
)),
ast::ModuleItem::MacroDeclaration(_) => todo!(),
ast::ModuleItem::HeaderDoc(_) => {}
ast::ModuleItem::Missing(_) => {}
}
Expand All @@ -601,6 +626,7 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData
impls: impls.into(),
extern_types: extern_types.into(),
extern_functions: extern_functions.into(),
macro_declarations: macro_declarations.into(),
global_uses: global_uses.into(),
files,
generated_file_aux_data: aux_data,
Expand Down Expand Up @@ -1051,6 +1077,30 @@ pub fn module_extern_type_by_id(
Ok(module_extern_types.get(&extern_type_id).cloned())
}

/// Returns all the macro declarations of the given module.
pub fn module_macro_declarations(
db: &dyn DefsGroup,
module_id: ModuleId,
) -> Maybe<Arc<OrderedHashMap<MacroDeclarationId, ast::ItemMacroDeclaration>>> {
Ok(db.priv_module_data(module_id)?.macro_declarations)
}
/// Returns all the ids of the macro declarations of the given module.
pub fn module_macro_declarations_ids(
db: &dyn DefsGroup,
module_id: ModuleId,
) -> Maybe<Arc<[MacroDeclarationId]>> {
Ok(db.module_macro_declarations(module_id)?.keys().copied().collect_vec().into())
}
/// Returns the macro declaration of the given id.
pub fn module_macro_declaration_by_id(
db: &dyn DefsGroup,
macro_declaration_id: MacroDeclarationId,
) -> Maybe<Option<ast::ItemMacroDeclaration>> {
let module_macro_declarations =
db.module_macro_declarations(macro_declaration_id.module_file_id(db.upcast()).0)?;
Ok(module_macro_declarations.get(&macro_declaration_id).cloned())
}

/// Returns all the extern_functions of the given module.
pub fn module_extern_functions(
db: &dyn DefsGroup,
Expand Down Expand Up @@ -1144,5 +1194,8 @@ fn module_item_name_stable_ptr(
ModuleItemId::ExternFunction(id) => {
data.extern_functions[id].declaration(db).name(db).stable_ptr().untyped()
}
ModuleItemId::MacroDeclaration(id) => {
data.macro_declarations[id].name(db).stable_ptr().untyped()
}
})
}
12 changes: 11 additions & 1 deletion crates/cairo-lang-defs/src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ define_language_element_id_as_enum! {
Impl(ImplDefId),
ExternType(ExternTypeId),
ExternFunction(ExternFunctionId),
MacroDeclaration(MacroDeclarationId),
}
}
define_top_level_language_element_id!(
Expand Down Expand Up @@ -381,6 +382,14 @@ define_top_level_language_element_id!(
intern_free_function
);

define_top_level_language_element_id!(
MacroDeclarationId,
MacroDeclarationLongId,
ast::ItemMacroDeclaration,
lookup_intern_macro_declaration,
intern_macro_declaration
);

impl UnstableSalsaId for FreeFunctionId {
fn get_internal_id(&self) -> &salsa::InternId {
&self.0
Expand Down Expand Up @@ -1058,7 +1067,8 @@ impl OptionFrom<ModuleItemId> for GenericTypeId {
| ModuleItemId::FreeFunction(_)
| ModuleItemId::Trait(_)
| ModuleItemId::Impl(_)
| ModuleItemId::ExternFunction(_) => None,
| ModuleItemId::ExternFunction(_)
| ModuleItemId::MacroDeclaration(_) => None,
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/cairo-lang-doc/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ impl ToDocumentableItemId<DocumentableItemId> for ResolvedGenericItem {
ResolvedGenericItem::Impl(id) => Some(DocumentableItemId::LookupItem(
LookupItemId::ModuleItem(ModuleItemId::Impl(id)),
)),
ResolvedGenericItem::Macro(id) => Some(DocumentableItemId::LookupItem(
LookupItemId::ModuleItem(ModuleItemId::MacroDeclaration(id)),
)),
ResolvedGenericItem::GenericType(GenericTypeId::Extern(id)) => {
Some(DocumentableItemId::LookupItem(LookupItemId::ModuleItem(
ModuleItemId::ExternType(id),
Expand Down
1 change: 1 addition & 0 deletions crates/cairo-lang-lowering/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ fn module_lowering_diagnostics(
}
ModuleItemId::ExternType(_) => {}
ModuleItemId::ExternFunction(_) => {}
ModuleItemId::MacroDeclaration(_) => {}
}
}
Ok(diagnostics.build())
Expand Down
38 changes: 34 additions & 4 deletions crates/cairo-lang-semantic/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use cairo_lang_defs::ids::{
ConstantId, EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, FunctionTitleId,
FunctionWithBodyId, GenericParamId, GenericTypeId, GlobalUseId, ImplAliasId, ImplConstantDefId,
ImplDefId, ImplFunctionId, ImplImplDefId, ImplItemId, ImplTypeDefId, LanguageElementId,
LookupItemId, ModuleFileId, ModuleId, ModuleItemId, ModuleTypeAliasId, StructId,
TraitConstantId, TraitFunctionId, TraitId, TraitImplId, TraitItemId, TraitTypeId, UseId,
VariantId,
LookupItemId, MacroDeclarationId, ModuleFileId, ModuleId, ModuleItemId, ModuleTypeAliasId,
StructId, TraitConstantId, TraitFunctionId, TraitId, TraitImplId, TraitItemId, TraitTypeId,
UseId, VariantId,
};
use cairo_lang_diagnostics::{Diagnostics, DiagnosticsBuilder, Maybe};
use cairo_lang_filesystem::db::{AsFilesGroupMut, FilesGroup};
Expand All @@ -31,6 +31,7 @@ use crate::items::generics::{GenericParam, GenericParamData, GenericParamsData};
use crate::items::imp::{
ImplId, ImplImplId, ImplLookupContext, ImplicitImplImplData, UninferredImpl,
};
use crate::items::macro_declaration::{MacroDeclarationData, MacroRuleData};
use crate::items::module::{ModuleItemInfo, ModuleSemanticData};
use crate::items::trt::{
ConcreteTraitGenericFunctionId, ConcreteTraitId, TraitItemConstantData, TraitItemImplData,
Expand Down Expand Up @@ -1446,7 +1447,32 @@ pub trait SemanticGroup:
&self,
generic_function_id: GenericFunctionId,
) -> Maybe<OrderedHashMap<TypeId, TypeId>>;

// Macro Declaration.
// =================
/// Private query to compute data about a macro declaration.
#[salsa::invoke(items::macro_declaration::priv_macro_declaration_data)]
fn priv_macro_declaration_data(
&self,
macro_id: MacroDeclarationId,
) -> Maybe<MacroDeclarationData>;
/// Returns the semantic diagnostics of a macro declaration.
#[salsa::invoke(items::macro_declaration::macro_declaration_diagnostics)]
fn macro_declaration_diagnostics(
&self,
macro_id: MacroDeclarationId,
) -> Diagnostics<SemanticDiagnostic>;
/// Returns the resolver data of a macro declaration.
#[salsa::invoke(items::macro_declaration::macro_declaration_resolver_data)]
fn macro_declaration_resolver_data(
&self,
macro_id: MacroDeclarationId,
) -> Maybe<Arc<ResolverData>>;
/// Returns the attributes of a macro declaration.
#[salsa::invoke(items::macro_declaration::macro_declaration_attributes)]
fn macro_declaration_attributes(&self, macro_id: MacroDeclarationId) -> Maybe<Vec<Attribute>>;
/// Returns the rules semantic data of a macro declaration.
#[salsa::invoke(items::macro_declaration::macro_declaration_rules)]
fn macro_declaration_rules(&self, macro_id: MacroDeclarationId) -> Maybe<Vec<MacroRuleData>>;
// Generic type.
// =============
/// Returns the generic params of a generic type.
Expand Down Expand Up @@ -1723,6 +1749,9 @@ fn module_semantic_diagnostics(
ModuleItemId::ImplAlias(type_alias) => {
diagnostics.extend(db.impl_alias_semantic_diagnostics(*type_alias));
}
ModuleItemId::MacroDeclaration(macro_declaration) => {
diagnostics.extend(db.macro_declaration_diagnostics(*macro_declaration));
}
}
}
for global_use in db.module_global_uses(module_id)?.keys() {
Expand Down Expand Up @@ -1855,6 +1884,7 @@ pub fn get_resolver_data_options(
ModuleItemId::ExternFunction(id) => {
vec![db.extern_function_declaration_resolver_data(id)]
}
ModuleItemId::MacroDeclaration(id) => vec![db.macro_declaration_resolver_data(id)],
},
LookupItemId::TraitItem(id) => match id {
cairo_lang_defs::ids::TraitItemId::Function(id) => {
Expand Down
11 changes: 11 additions & 0 deletions crates/cairo-lang-semantic/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ impl DiagnosticEntry for SemanticDiagnostic {
NotFoundItemType::Type => "Type not found.".into(),
NotFoundItemType::Trait => "Trait not found.".into(),
NotFoundItemType::Impl => "Impl not found.".into(),
NotFoundItemType::Macro => "Macro not found.".into(),
},
SemanticDiagnosticKind::AmbiguousPath(module_items) => {
format!(
Expand Down Expand Up @@ -905,6 +906,9 @@ impl DiagnosticEntry for SemanticDiagnostic {
SemanticDiagnosticKind::InlineMacroFailed(macro_name) => {
format!("Inline macro `{}` failed.", macro_name)
}
SemanticDiagnosticKind::InlineMacroNoMatchingRule(macro_name) => {
format!("No matching rule found in inline macro `{}`.", macro_name)
}
SemanticDiagnosticKind::UnknownGenericParam(name) => {
format!("Unknown generic parameter `{}`.", name)
}
Expand Down Expand Up @@ -1421,6 +1425,7 @@ pub enum SemanticDiagnosticKind {
UnknownStatementAttribute,
InlineMacroNotFound(SmolStr),
InlineMacroFailed(SmolStr),
InlineMacroNoMatchingRule(SmolStr),
UnknownGenericParam(SmolStr),
PositionalGenericAfterNamed,
GenericArgDuplicate(SmolStr),
Expand Down Expand Up @@ -1490,13 +1495,15 @@ impl SemanticDiagnosticKind {
}
}

// TODO(Gil): It seems to have the same functionality as ElementKind, maybe we can merge them.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum NotFoundItemType {
Identifier,
Function,
Type,
Trait,
Impl,
Macro,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
Expand All @@ -1515,6 +1522,7 @@ pub enum ElementKind {
Variant,
Trait,
Impl,
Macro,
}
impl From<&ResolvedConcreteItem> for ElementKind {
fn from(val: &ResolvedConcreteItem) -> Self {
Expand All @@ -1528,6 +1536,7 @@ impl From<&ResolvedConcreteItem> for ElementKind {
ElementKind::Trait
}
ResolvedConcreteItem::Impl(_) => ElementKind::Impl,
ResolvedConcreteItem::Macro(_) => ElementKind::Macro,
}
}
}
Expand All @@ -1546,6 +1555,7 @@ impl From<&ResolvedGenericItem> for ElementKind {
ElementKind::Impl
}
ResolvedGenericItem::Variable(_) => ElementKind::Variable,
ResolvedGenericItem::Macro(_) => ElementKind::Macro,
}
}
}
Expand All @@ -1560,6 +1570,7 @@ impl Display for ElementKind {
ElementKind::Variant => "variant",
ElementKind::Trait => "trait",
ElementKind::Impl => "impl",
ElementKind::Macro => "macro",
};
write!(f, "{res}")
}
Expand Down
Loading
Loading