Skip to content

Commit

Permalink
Basic macro support.
Browse files Browse the repository at this point in the history
  • Loading branch information
gilbens-starkware committed Feb 13, 2025
1 parent 6dda66a commit b7fa0c4
Show file tree
Hide file tree
Showing 17 changed files with 587 additions and 41 deletions.
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

0 comments on commit b7fa0c4

Please sign in to comment.