From 96b9f3dceacecd11fc281f216af530099b61ced5 Mon Sep 17 00:00:00 2001 From: Dean Carmel Date: Sun, 22 Jun 2025 14:21:48 +0300 Subject: [PATCH] add support for unhygenic inline macro expansion --- .../test/language_features/macro_test.cairo | 12 + crates/cairo-lang-parser/src/lexer.rs | 3 + crates/cairo-lang-parser/src/parser.rs | 5 + .../partial_trees/inline_macro | 2 + .../partial_trees/macro_declaration | 3 + .../cairo-lang-semantic/src/expr/compute.rs | 37 +- .../src/expr/test_data/inline_macros | 54 +++ .../src/items/macro_declaration.rs | 13 +- .../src/cairo_spec.rs | 3 + crates/cairo-lang-syntax/src/node/ast.rs | 402 +++++++++++++++++- .../cairo-lang-syntax/src/node/key_fields.rs | 7 + crates/cairo-lang-syntax/src/node/kind.rs | 7 + 12 files changed, 534 insertions(+), 14 deletions(-) diff --git a/corelib/src/test/language_features/macro_test.cairo b/corelib/src/test/language_features/macro_test.cairo index 73a32764d5b..b9b11f4a1c2 100644 --- a/corelib/src/test/language_features/macro_test.cairo +++ b/corelib/src/test/language_features/macro_test.cairo @@ -389,3 +389,15 @@ fn test_defsite_inference() { let z: defsite_inference::A = defsite_inference::use_local_impl_inference!(5); assert_eq!(y.x, z.x); } + +macro define_and_use unhygienic { + () => { + let foo = 123; + }; +} + +#[test] +fn test_define_and_use_unhygienic() { + define_and_use!(); + let _y = foo; +} diff --git a/crates/cairo-lang-parser/src/lexer.rs b/crates/cairo-lang-parser/src/lexer.rs index dfa14275814..7d2db95f221 100644 --- a/crates/cairo-lang-parser/src/lexer.rs +++ b/crates/cairo-lang-parser/src/lexer.rs @@ -214,6 +214,7 @@ impl<'a> Lexer<'a> { "return" => TokenKind::Return, "match" => TokenKind::Match, "macro" => TokenKind::Macro, + "unhygienic" => TokenKind::Unhygienic, "if" => TokenKind::If, "loop" => TokenKind::Loop, "continue" => TokenKind::Continue, @@ -372,6 +373,7 @@ enum TokenKind { False, True, Extern, + Unhygienic, Type, Function, Trait, @@ -463,6 +465,7 @@ fn token_kind_to_terminal_syntax_kind(kind: TokenKind) -> SyntaxKind { TokenKind::False => SyntaxKind::TerminalFalse, TokenKind::True => SyntaxKind::TerminalTrue, TokenKind::Extern => SyntaxKind::TerminalExtern, + TokenKind::Unhygienic => SyntaxKind::TerminalUnhygienic, TokenKind::Type => SyntaxKind::TerminalType, TokenKind::Function => SyntaxKind::TerminalFunction, TokenKind::Trait => SyntaxKind::TerminalTrait, diff --git a/crates/cairo-lang-parser/src/parser.rs b/crates/cairo-lang-parser/src/parser.rs index 319a8863713..a37b4f9490d 100644 --- a/crates/cairo-lang-parser/src/parser.rs +++ b/crates/cairo-lang-parser/src/parser.rs @@ -677,6 +677,10 @@ impl<'a> Parser<'a> { ) -> ItemMacroDeclarationGreen { let macro_kw = self.take::(); let name = self.parse_identifier(); + let unhygienic: OptionTerminalUnhygienicGreen = match self.peek().kind { + SyntaxKind::TerminalUnhygienic => self.take::().into(), + _ => OptionTerminalUnhygienicEmpty::new_green(self.db).into(), + }; let lbrace = self.parse_token::(); let macro_rules = MacroRulesList::new_green( self.db, @@ -689,6 +693,7 @@ impl<'a> Parser<'a> { visibility, macro_kw, name, + unhygienic, lbrace, macro_rules, rbrace, diff --git a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/inline_macro b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/inline_macro index 39e6d8c6fd3..4c6a505bebb 100644 --- a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/inline_macro +++ b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/inline_macro @@ -59,6 +59,7 @@ macro some_macro { │ ├── visibility (kind: VisibilityDefault) [] │ ├── macro_kw (kind: TokenMacro): 'macro' │ ├── name (kind: TokenIdentifier): 'some_macro' + │ ├── unhygienic_kw (kind: OptionTerminalUnhygienicEmpty) [] │ ├── lbrace (kind: TokenLBrace): '{' │ ├── rules (kind: MacroRulesList) │ │ └── child #0 (kind: MacroRule) @@ -167,6 +168,7 @@ fn use_macro() { │ │ ├── visibility (kind: VisibilityDefault) [] │ │ ├── macro_kw (kind: TokenMacro): 'macro' │ │ ├── name (kind: TokenIdentifier): 'some_macro' + │ │ ├── unhygienic_kw (kind: OptionTerminalUnhygienicEmpty) [] │ │ ├── lbrace (kind: TokenLBrace): '{' │ │ ├── rules (kind: MacroRulesList) │ │ │ ├── child #0 (kind: MacroRule) diff --git a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/macro_declaration b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/macro_declaration index a97b1d0e253..e62583c45bc 100644 --- a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/macro_declaration +++ b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/macro_declaration @@ -24,6 +24,7 @@ macro macro_name { │ ├── visibility (kind: VisibilityDefault) [] │ ├── macro_kw (kind: TokenMacro): 'macro' │ ├── name (kind: TokenIdentifier): 'macro_name' + │ ├── unhygienic_kw (kind: OptionTerminalUnhygienicEmpty) [] │ ├── lbrace (kind: TokenLBrace): '{' │ ├── rules (kind: MacroRulesList) │ │ └── child #0 (kind: MacroRule) @@ -80,6 +81,7 @@ macro macro_name { │ ├── visibility (kind: VisibilityDefault) [] │ ├── macro_kw (kind: TokenMacro): 'macro' │ ├── name (kind: TokenIdentifier): 'macro_name' + │ ├── unhygienic_kw (kind: OptionTerminalUnhygienicEmpty) [] │ ├── lbrace (kind: TokenLBrace): '{' │ ├── rules (kind: MacroRulesList) │ │ ├── child #0 (kind: MacroRule) @@ -225,6 +227,7 @@ error: Missing tokens. Expected a macro rule parameter kind. │ ├── visibility (kind: VisibilityDefault) [] │ ├── macro_kw (kind: TokenMacro): 'macro' │ ├── name (kind: TokenIdentifier): 'macro_name' + │ ├── unhygienic_kw (kind: OptionTerminalUnhygienicEmpty) [] │ ├── lbrace (kind: TokenLBrace): '{' │ ├── rules (kind: MacroRulesList) │ │ └── child #0 (kind: MacroRule) diff --git a/crates/cairo-lang-semantic/src/expr/compute.rs b/crates/cairo-lang-semantic/src/expr/compute.rs index 1f727c030dd..175b15b9742 100644 --- a/crates/cairo-lang-semantic/src/expr/compute.rs +++ b/crates/cairo-lang-semantic/src/expr/compute.rs @@ -156,6 +156,7 @@ struct InlineMacroExpansion { pub name: String, pub code_mappings: Vec, pub is_plugin_macro: bool, + pub is_unhygienic: bool, } /// Context for computing the semantic model of expression trees. @@ -529,11 +530,13 @@ fn expand_inline_macro( let mut matcher_ctx = MatcherContext { captures, placeholder_to_rep_id, ..Default::default() }; let expanded_code = expand_macro_rule(ctx.db, rule, &mut matcher_ctx)?; + let is_unhygienic = ctx.db.priv_macro_declaration_data(macro_declaration_id)?.is_unhygienic; Ok(InlineMacroExpansion { content: expanded_code.text, name: macro_name.clone(), code_mappings: expanded_code.code_mappings, is_plugin_macro: false, + is_unhygienic, }) } else if let Some(macro_plugin_id) = ctx.db.crate_inline_macro_plugins(crate_id).get(¯o_name).cloned() @@ -573,6 +576,7 @@ fn expand_inline_macro( name: code.name.to_string(), code_mappings: code.code_mappings, is_plugin_macro: true, + is_unhygienic: false, }) } else { return Err(ctx.diagnostics.report( @@ -591,8 +595,14 @@ fn compute_expr_inline_macro_semantic( ) -> Maybe { let db = ctx.db; let prev_macro_call_data = ctx.resolver.macro_call_data.clone(); - let InlineMacroExpansion { content, name, code_mappings: mappings, is_plugin_macro } = - expand_inline_macro(ctx, syntax)?; + let InlineMacroExpansion { + content, + name, + code_mappings: mappings, + is_plugin_macro, + is_unhygienic, + } = expand_inline_macro(ctx, syntax)?; + if !is_plugin_macro { let user_defined_macro = ctx.resolver.resolve_generic_path( &mut Default::default(), @@ -650,6 +660,8 @@ fn compute_expr_inline_macro_semantic( ); ctx.resolver.set_suppress_modifiers_diagnostics(prev_resolver_modifiers_suppression); result + } else if is_unhygienic { + compute_expr_semantic(ctx, &expr_syntax) } else { ctx.run_in_macro_subscope( |ctx| compute_expr_semantic(ctx, &expr_syntax), @@ -659,7 +671,6 @@ fn compute_expr_inline_macro_semantic( ctx.resolver.macro_call_data = prev_macro_call_data; Ok(expr.expr) } - /// Expands an inline macro used in statement position, computes its semantic model, and extends /// `statements` with it. fn expand_macro_for_statement( @@ -669,8 +680,13 @@ fn expand_macro_for_statement( statements: &mut Vec, ) -> Maybe<()> { let prev_macro_call_data = ctx.resolver.macro_call_data.clone(); - let InlineMacroExpansion { content, name, code_mappings: mappings, is_plugin_macro } = - expand_inline_macro(ctx, syntax)?; + let InlineMacroExpansion { + content, + name, + code_mappings: mappings, + is_plugin_macro, + is_unhygienic, + } = expand_inline_macro(ctx, syntax)?; let new_file_long_id = FileLongId::Virtual(VirtualFile { parent: Some(syntax.stable_ptr(ctx.db).untyped().file_id(ctx.db)), name: name.clone().into(), @@ -709,6 +725,17 @@ fn expand_macro_for_statement( ctx.resolver.set_suppress_modifiers_diagnostics(prev_resolver_modifiers_suppression); ctx.resolver.macro_call_data = prev_macro_call_data; result + } else if is_unhygienic { + let mut ids = compute_statement_list_semantic(ctx, parsed_statements.clone()); + if let Some(tail_expr) = tail { + let expr = compute_expr_semantic(ctx, &tail_expr); + ids.push(ctx.arenas.statements.alloc(semantic::Statement::Expr( + semantic::StatementExpr { expr: expr.id, stable_ptr: statement_stable_ptr }, + ))); + } + statements.extend(ids); + ctx.resolver.macro_call_data = prev_macro_call_data; + Ok(()) } else { let result = ctx.run_in_macro_subscope( |ctx| { diff --git a/crates/cairo-lang-semantic/src/expr/test_data/inline_macros b/crates/cairo-lang-semantic/src/expr/test_data/inline_macros index 5fa5ddbb3a9..fecfe080264 100644 --- a/crates/cairo-lang-semantic/src/expr/test_data/inline_macros +++ b/crates/cairo-lang-semantic/src/expr/test_data/inline_macros @@ -1480,3 +1480,57 @@ error: Parser error in macro-expanded code: Skipped tokens. Expected: end of exp _^ | let b = 2; |__________________^ + +//! > ========================================================================== + +//! > Test: Variable defined in unhygienic macro is visible outside. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: false) + +//! > function +fn foo() { + define_var_unhygienic!(); + let _x = a; +} + +//! > function_name +foo + +//! > module_code +macro define_var_unhygienic unhygienic { + () => { + let a = 42; + }; +} + +//! > expected_diagnostics + +//! > ========================================================================== + +//! > Test: Variable defined in hygienic macro is not visible outside. + +//! > test_runner_name +test_function_diagnostics(expect_diagnostics: true) + +//! > function +fn foo() { + define_var_hygienic!(); + let _x = _a; +} + +//! > function_name +foo + +//! > module_code +macro define_var_hygienic { + () => { + let _a = 42; + }; +} + +//! > expected_diagnostics +error[E0006]: Identifier not found. + --> lib.cairo:8:14 + let _x = _a; + ^^ diff --git a/crates/cairo-lang-semantic/src/items/macro_declaration.rs b/crates/cairo-lang-semantic/src/items/macro_declaration.rs index bf4586209fe..4f3e9c0fc38 100644 --- a/crates/cairo-lang-semantic/src/items/macro_declaration.rs +++ b/crates/cairo-lang-semantic/src/items/macro_declaration.rs @@ -68,6 +68,7 @@ pub struct MacroDeclarationData { attributes: Vec, diagnostics: Diagnostics, resolver_data: Arc, + pub is_unhygienic: bool, } /// The semantic data for a single macro rule in a macro declaration. @@ -121,6 +122,10 @@ pub fn priv_macro_declaration_data( ); } + let is_unhygienic = matches!( + macro_declaration_syntax.unhygienic_kw(syntax_db), + ast::OptionTerminalUnhygienic::TerminalUnhygienic(_) + ); let attributes = macro_declaration_syntax.attributes(syntax_db).structurize(syntax_db); let inference_id = InferenceId::LookupItemDeclaration(LookupItemId::ModuleItem( ModuleItemId::MacroDeclaration(macro_declaration_id), @@ -174,7 +179,13 @@ pub fn priv_macro_declaration_data( rules.push(MacroRuleData { pattern, expansion }); } let resolver_data = Arc::new(resolver.data); - Ok(MacroDeclarationData { diagnostics: diagnostics.build(), attributes, resolver_data, rules }) + Ok(MacroDeclarationData { + diagnostics: diagnostics.build(), + attributes, + resolver_data, + rules, + is_unhygienic, + }) } /// Helper function to extract pattern elements from a WrappedMacro. diff --git a/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs b/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs index 30cca4ebcc6..ee9d2222650 100644 --- a/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs +++ b/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs @@ -900,10 +900,12 @@ pub fn get_spec() -> Vec { .node("visibility", "Visibility") .node("macro_kw", "TerminalMacro") .key_node("name", "TerminalIdentifier") + .node("unhygienic_kw", "OptionTerminalUnhygienic") .node("lbrace", "TerminalLBrace") .node("rules", "MacroRulesList") .node("rbrace", "TerminalRBrace") ) + .add_option("TerminalUnhygienic") .add_list("MacroRulesList", "MacroRule") .add_struct(StructBuilder::new("MacroRule") .node("lhs", "WrappedMacro") @@ -1022,6 +1024,7 @@ pub fn get_spec() -> Vec { .add_keyword_token_and_terminal("Implicits") .add_keyword_token_and_terminal("Let") .add_keyword_token_and_terminal("Macro") + .add_keyword_token_and_terminal("Unhygienic") .add_keyword_token_and_terminal("Match") .add_keyword_token_and_terminal("Module") .add_keyword_token_and_terminal("Mut") diff --git a/crates/cairo-lang-syntax/src/node/ast.rs b/crates/cairo-lang-syntax/src/node/ast.rs index 9fe02bddf2d..3808fe6f638 100644 --- a/crates/cairo-lang-syntax/src/node/ast.rs +++ b/crates/cairo-lang-syntax/src/node/ast.rs @@ -22378,21 +22378,31 @@ impl ItemMacroDeclaration { pub const INDEX_VISIBILITY: usize = 1; pub const INDEX_MACRO_KW: usize = 2; pub const INDEX_NAME: usize = 3; - pub const INDEX_LBRACE: usize = 4; - pub const INDEX_RULES: usize = 5; - pub const INDEX_RBRACE: usize = 6; + pub const INDEX_UNHYGIENIC_KW: usize = 4; + pub const INDEX_LBRACE: usize = 5; + pub const INDEX_RULES: usize = 6; + pub const INDEX_RBRACE: usize = 7; pub fn new_green( db: &dyn SyntaxGroup, attributes: AttributeListGreen, visibility: VisibilityGreen, macro_kw: TerminalMacroGreen, name: TerminalIdentifierGreen, + unhygienic_kw: OptionTerminalUnhygienicGreen, lbrace: TerminalLBraceGreen, rules: MacroRulesListGreen, rbrace: TerminalRBraceGreen, ) -> ItemMacroDeclarationGreen { - let children: Vec = - vec![attributes.0, visibility.0, macro_kw.0, name.0, lbrace.0, rules.0, rbrace.0]; + let children: Vec = vec![ + attributes.0, + visibility.0, + macro_kw.0, + name.0, + unhygienic_kw.0, + lbrace.0, + rules.0, + rbrace.0, + ]; let width = children.iter().copied().map(|id| id.lookup_intern(db).width()).sum(); ItemMacroDeclarationGreen( Arc::new(GreenNode { @@ -22416,14 +22426,17 @@ impl ItemMacroDeclaration { pub fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier { TerminalIdentifier::from_syntax_node(db, self.children[3]) } + pub fn unhygienic_kw(&self, db: &dyn SyntaxGroup) -> OptionTerminalUnhygienic { + OptionTerminalUnhygienic::from_syntax_node(db, self.children[4]) + } pub fn lbrace(&self, db: &dyn SyntaxGroup) -> TerminalLBrace { - TerminalLBrace::from_syntax_node(db, self.children[4]) + TerminalLBrace::from_syntax_node(db, self.children[5]) } pub fn rules(&self, db: &dyn SyntaxGroup) -> MacroRulesList { - MacroRulesList::from_syntax_node(db, self.children[5]) + MacroRulesList::from_syntax_node(db, self.children[6]) } pub fn rbrace(&self, db: &dyn SyntaxGroup) -> TerminalRBrace { - TerminalRBrace::from_syntax_node(db, self.children[6]) + TerminalRBrace::from_syntax_node(db, self.children[7]) } } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -22468,6 +22481,7 @@ impl TypedSyntaxNode for ItemMacroDeclaration { Visibility::missing(db).0, TerminalMacro::missing(db).0, TerminalIdentifier::missing(db).0, + OptionTerminalUnhygienic::missing(db).0, TerminalLBrace::missing(db).0, MacroRulesList::missing(db).0, TerminalRBrace::missing(db).0, @@ -22505,6 +22519,176 @@ impl TypedSyntaxNode for ItemMacroDeclaration { } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub enum OptionTerminalUnhygienic { + Empty(OptionTerminalUnhygienicEmpty), + TerminalUnhygienic(TerminalUnhygienic), +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct OptionTerminalUnhygienicPtr(pub SyntaxStablePtrId); +impl TypedStablePtr for OptionTerminalUnhygienicPtr { + type SyntaxNode = OptionTerminalUnhygienic; + fn untyped(&self) -> SyntaxStablePtrId { + self.0 + } + fn lookup(&self, db: &dyn SyntaxGroup) -> OptionTerminalUnhygienic { + OptionTerminalUnhygienic::from_syntax_node(db, self.0.lookup(db)) + } +} +impl From for SyntaxStablePtrId { + fn from(ptr: OptionTerminalUnhygienicPtr) -> Self { + ptr.untyped() + } +} +impl From for OptionTerminalUnhygienicPtr { + fn from(value: OptionTerminalUnhygienicEmptyPtr) -> Self { + Self(value.0) + } +} +impl From for OptionTerminalUnhygienicPtr { + fn from(value: TerminalUnhygienicPtr) -> Self { + Self(value.0) + } +} +impl From for OptionTerminalUnhygienicGreen { + fn from(value: OptionTerminalUnhygienicEmptyGreen) -> Self { + Self(value.0) + } +} +impl From for OptionTerminalUnhygienicGreen { + fn from(value: TerminalUnhygienicGreen) -> Self { + Self(value.0) + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct OptionTerminalUnhygienicGreen(pub GreenId); +impl TypedSyntaxNode for OptionTerminalUnhygienic { + const OPTIONAL_KIND: Option = None; + type StablePtr = OptionTerminalUnhygienicPtr; + type Green = OptionTerminalUnhygienicGreen; + fn missing(db: &dyn SyntaxGroup) -> Self::Green { + panic!("No missing variant."); + } + fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self { + let kind = node.kind(db); + match kind { + SyntaxKind::OptionTerminalUnhygienicEmpty => OptionTerminalUnhygienic::Empty( + OptionTerminalUnhygienicEmpty::from_syntax_node(db, node), + ), + SyntaxKind::TerminalUnhygienic => OptionTerminalUnhygienic::TerminalUnhygienic( + TerminalUnhygienic::from_syntax_node(db, node), + ), + _ => panic!( + "Unexpected syntax kind {:?} when constructing {}.", + kind, "OptionTerminalUnhygienic" + ), + } + } + fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option { + let kind = node.kind(db); + match kind { + SyntaxKind::OptionTerminalUnhygienicEmpty => Some(OptionTerminalUnhygienic::Empty( + OptionTerminalUnhygienicEmpty::from_syntax_node(db, node), + )), + SyntaxKind::TerminalUnhygienic => Some(OptionTerminalUnhygienic::TerminalUnhygienic( + TerminalUnhygienic::from_syntax_node(db, node), + )), + _ => None, + } + } + fn as_syntax_node(&self) -> SyntaxNode { + match self { + OptionTerminalUnhygienic::Empty(x) => x.as_syntax_node(), + OptionTerminalUnhygienic::TerminalUnhygienic(x) => x.as_syntax_node(), + } + } + fn stable_ptr(&self, db: &dyn SyntaxGroup) -> Self::StablePtr { + OptionTerminalUnhygienicPtr(self.as_syntax_node().lookup_intern(db).stable_ptr) + } +} +impl OptionTerminalUnhygienic { + /// Checks if a kind of a variant of [OptionTerminalUnhygienic]. + pub fn is_variant(kind: SyntaxKind) -> bool { + matches!(kind, SyntaxKind::OptionTerminalUnhygienicEmpty | SyntaxKind::TerminalUnhygienic) + } +} +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct OptionTerminalUnhygienicEmpty { + node: SyntaxNode, + children: Arc<[SyntaxNode]>, +} +impl OptionTerminalUnhygienicEmpty { + pub fn new_green(db: &dyn SyntaxGroup) -> OptionTerminalUnhygienicEmptyGreen { + let children: Vec = vec![]; + let width = children.iter().copied().map(|id| id.lookup_intern(db).width()).sum(); + OptionTerminalUnhygienicEmptyGreen( + Arc::new(GreenNode { + kind: SyntaxKind::OptionTerminalUnhygienicEmpty, + details: GreenNodeDetails::Node { children, width }, + }) + .intern(db), + ) + } +} +impl OptionTerminalUnhygienicEmpty {} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct OptionTerminalUnhygienicEmptyPtr(pub SyntaxStablePtrId); +impl OptionTerminalUnhygienicEmptyPtr {} +impl TypedStablePtr for OptionTerminalUnhygienicEmptyPtr { + type SyntaxNode = OptionTerminalUnhygienicEmpty; + fn untyped(&self) -> SyntaxStablePtrId { + self.0 + } + fn lookup(&self, db: &dyn SyntaxGroup) -> OptionTerminalUnhygienicEmpty { + OptionTerminalUnhygienicEmpty::from_syntax_node(db, self.0.lookup(db)) + } +} +impl From for SyntaxStablePtrId { + fn from(ptr: OptionTerminalUnhygienicEmptyPtr) -> Self { + ptr.untyped() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct OptionTerminalUnhygienicEmptyGreen(pub GreenId); +impl TypedSyntaxNode for OptionTerminalUnhygienicEmpty { + const OPTIONAL_KIND: Option = Some(SyntaxKind::OptionTerminalUnhygienicEmpty); + type StablePtr = OptionTerminalUnhygienicEmptyPtr; + type Green = OptionTerminalUnhygienicEmptyGreen; + fn missing(db: &dyn SyntaxGroup) -> Self::Green { + OptionTerminalUnhygienicEmptyGreen( + Arc::new(GreenNode { + kind: SyntaxKind::OptionTerminalUnhygienicEmpty, + details: GreenNodeDetails::Node { children: vec![], width: TextWidth::default() }, + }) + .intern(db), + ) + } + fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self { + let kind = node.kind(db); + assert_eq!( + kind, + SyntaxKind::OptionTerminalUnhygienicEmpty, + "Unexpected SyntaxKind {:?}. Expected {:?}.", + kind, + SyntaxKind::OptionTerminalUnhygienicEmpty + ); + Self { children: node.get_children(db), node } + } + fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option { + let kind = node.kind(db); + if kind == SyntaxKind::OptionTerminalUnhygienicEmpty { + Some(Self::from_syntax_node(db, node)) + } else { + None + } + } + fn as_syntax_node(&self) -> SyntaxNode { + self.node + } + fn stable_ptr(&self, db: &dyn SyntaxGroup) -> Self::StablePtr { + OptionTerminalUnhygienicEmptyPtr(self.node.stable_ptr(db)) + } +} +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct MacroRulesList(ElementList); impl Deref for MacroRulesList { type Target = ElementList; @@ -28421,6 +28605,189 @@ impl TypedSyntaxNode for TerminalMacro { } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct TokenUnhygienic { + node: SyntaxNode, +} +impl Token for TokenUnhygienic { + fn new_green(db: &dyn SyntaxGroup, text: SmolStr) -> Self::Green { + TokenUnhygienicGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TokenUnhygienic, + details: GreenNodeDetails::Token(text), + }) + .intern(db), + ) + } + fn text(&self, db: &dyn SyntaxGroup) -> SmolStr { + extract_matches!( + &self.node.lookup_intern(db).green.lookup_intern(db).details, + GreenNodeDetails::Token + ) + .clone() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TokenUnhygienicPtr(pub SyntaxStablePtrId); +impl TypedStablePtr for TokenUnhygienicPtr { + type SyntaxNode = TokenUnhygienic; + fn untyped(&self) -> SyntaxStablePtrId { + self.0 + } + fn lookup(&self, db: &dyn SyntaxGroup) -> TokenUnhygienic { + TokenUnhygienic::from_syntax_node(db, self.0.lookup(db)) + } +} +impl From for SyntaxStablePtrId { + fn from(ptr: TokenUnhygienicPtr) -> Self { + ptr.untyped() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TokenUnhygienicGreen(pub GreenId); +impl TokenUnhygienicGreen { + pub fn text(&self, db: &dyn SyntaxGroup) -> SmolStr { + extract_matches!(&self.0.lookup_intern(db).details, GreenNodeDetails::Token).clone() + } +} +impl TypedSyntaxNode for TokenUnhygienic { + const OPTIONAL_KIND: Option = Some(SyntaxKind::TokenUnhygienic); + type StablePtr = TokenUnhygienicPtr; + type Green = TokenUnhygienicGreen; + fn missing(db: &dyn SyntaxGroup) -> Self::Green { + TokenUnhygienicGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TokenMissing, + details: GreenNodeDetails::Token("".into()), + }) + .intern(db), + ) + } + fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self { + match node.lookup_intern(db).green.lookup_intern(db).details { + GreenNodeDetails::Token(_) => Self { node }, + GreenNodeDetails::Node { .. } => { + panic!("Expected a token {:?}, not an internal node", SyntaxKind::TokenUnhygienic) + } + } + } + fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option { + match node.lookup_intern(db).green.lookup_intern(db).details { + GreenNodeDetails::Token(_) => Some(Self { node }), + GreenNodeDetails::Node { .. } => None, + } + } + fn as_syntax_node(&self) -> SyntaxNode { + self.node + } + fn stable_ptr(&self, db: &dyn SyntaxGroup) -> Self::StablePtr { + TokenUnhygienicPtr(self.node.stable_ptr(db)) + } +} +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct TerminalUnhygienic { + node: SyntaxNode, + children: Arc<[SyntaxNode]>, +} +impl Terminal for TerminalUnhygienic { + const KIND: SyntaxKind = SyntaxKind::TerminalUnhygienic; + type TokenType = TokenUnhygienic; + fn new_green( + db: &dyn SyntaxGroup, + leading_trivia: TriviaGreen, + token: <::TokenType as TypedSyntaxNode>::Green, + trailing_trivia: TriviaGreen, + ) -> Self::Green { + let children: Vec = vec![leading_trivia.0, token.0, trailing_trivia.0]; + let width = children.iter().copied().map(|id| id.lookup_intern(db).width()).sum(); + TerminalUnhygienicGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TerminalUnhygienic, + details: GreenNodeDetails::Node { children, width }, + }) + .intern(db), + ) + } + fn text(&self, db: &dyn SyntaxGroup) -> SmolStr { + self.token(db).text(db) + } +} +impl TerminalUnhygienic { + pub fn leading_trivia(&self, db: &dyn SyntaxGroup) -> Trivia { + Trivia::from_syntax_node(db, self.children[0]) + } + pub fn token(&self, db: &dyn SyntaxGroup) -> TokenUnhygienic { + TokenUnhygienic::from_syntax_node(db, self.children[1]) + } + pub fn trailing_trivia(&self, db: &dyn SyntaxGroup) -> Trivia { + Trivia::from_syntax_node(db, self.children[2]) + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TerminalUnhygienicPtr(pub SyntaxStablePtrId); +impl TerminalUnhygienicPtr {} +impl TypedStablePtr for TerminalUnhygienicPtr { + type SyntaxNode = TerminalUnhygienic; + fn untyped(&self) -> SyntaxStablePtrId { + self.0 + } + fn lookup(&self, db: &dyn SyntaxGroup) -> TerminalUnhygienic { + TerminalUnhygienic::from_syntax_node(db, self.0.lookup(db)) + } +} +impl From for SyntaxStablePtrId { + fn from(ptr: TerminalUnhygienicPtr) -> Self { + ptr.untyped() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TerminalUnhygienicGreen(pub GreenId); +impl TypedSyntaxNode for TerminalUnhygienic { + const OPTIONAL_KIND: Option = Some(SyntaxKind::TerminalUnhygienic); + type StablePtr = TerminalUnhygienicPtr; + type Green = TerminalUnhygienicGreen; + fn missing(db: &dyn SyntaxGroup) -> Self::Green { + TerminalUnhygienicGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TerminalUnhygienic, + details: GreenNodeDetails::Node { + children: vec![ + Trivia::missing(db).0, + TokenUnhygienic::missing(db).0, + Trivia::missing(db).0, + ], + width: TextWidth::default(), + }, + }) + .intern(db), + ) + } + fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self { + let kind = node.kind(db); + assert_eq!( + kind, + SyntaxKind::TerminalUnhygienic, + "Unexpected SyntaxKind {:?}. Expected {:?}.", + kind, + SyntaxKind::TerminalUnhygienic + ); + Self { children: node.get_children(db), node } + } + fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option { + let kind = node.kind(db); + if kind == SyntaxKind::TerminalUnhygienic { + Some(Self::from_syntax_node(db, node)) + } else { + None + } + } + fn as_syntax_node(&self) -> SyntaxNode { + self.node + } + fn stable_ptr(&self, db: &dyn SyntaxGroup) -> Self::StablePtr { + TerminalUnhygienicPtr(self.node.stable_ptr(db)) + } +} +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct TokenMatch { node: SyntaxNode, } @@ -40329,6 +40696,7 @@ pub enum TokenNode { TerminalImplicits(TerminalImplicits), TerminalLet(TerminalLet), TerminalMacro(TerminalMacro), + TerminalUnhygienic(TerminalUnhygienic), TerminalMatch(TerminalMatch), TerminalModule(TerminalModule), TerminalMut(TerminalMut), @@ -40503,6 +40871,11 @@ impl From for TokenNodePtr { Self(value.0) } } +impl From for TokenNodePtr { + fn from(value: TerminalUnhygienicPtr) -> Self { + Self(value.0) + } +} impl From for TokenNodePtr { fn from(value: TerminalMatchPtr) -> Self { Self(value.0) @@ -40908,6 +41281,11 @@ impl From for TokenNodeGreen { Self(value.0) } } +impl From for TokenNodeGreen { + fn from(value: TerminalUnhygienicGreen) -> Self { + Self(value.0) + } +} impl From for TokenNodeGreen { fn from(value: TerminalMatchGreen) -> Self { Self(value.0) @@ -41283,6 +41661,9 @@ impl TypedSyntaxNode for TokenNode { SyntaxKind::TerminalMacro => { TokenNode::TerminalMacro(TerminalMacro::from_syntax_node(db, node)) } + SyntaxKind::TerminalUnhygienic => { + TokenNode::TerminalUnhygienic(TerminalUnhygienic::from_syntax_node(db, node)) + } SyntaxKind::TerminalMatch => { TokenNode::TerminalMatch(TerminalMatch::from_syntax_node(db, node)) } @@ -41516,6 +41897,9 @@ impl TypedSyntaxNode for TokenNode { SyntaxKind::TerminalMacro => { Some(TokenNode::TerminalMacro(TerminalMacro::from_syntax_node(db, node))) } + SyntaxKind::TerminalUnhygienic => { + Some(TokenNode::TerminalUnhygienic(TerminalUnhygienic::from_syntax_node(db, node))) + } SyntaxKind::TerminalMatch => { Some(TokenNode::TerminalMatch(TerminalMatch::from_syntax_node(db, node))) } @@ -41726,6 +42110,7 @@ impl TypedSyntaxNode for TokenNode { TokenNode::TerminalImplicits(x) => x.as_syntax_node(), TokenNode::TerminalLet(x) => x.as_syntax_node(), TokenNode::TerminalMacro(x) => x.as_syntax_node(), + TokenNode::TerminalUnhygienic(x) => x.as_syntax_node(), TokenNode::TerminalMatch(x) => x.as_syntax_node(), TokenNode::TerminalModule(x) => x.as_syntax_node(), TokenNode::TerminalMut(x) => x.as_syntax_node(), @@ -41818,6 +42203,7 @@ impl TokenNode { | SyntaxKind::TerminalImplicits | SyntaxKind::TerminalLet | SyntaxKind::TerminalMacro + | SyntaxKind::TerminalUnhygienic | SyntaxKind::TerminalMatch | SyntaxKind::TerminalModule | SyntaxKind::TerminalMut diff --git a/crates/cairo-lang-syntax/src/node/key_fields.rs b/crates/cairo-lang-syntax/src/node/key_fields.rs index 46f72430ba6..772c5605cb6 100644 --- a/crates/cairo-lang-syntax/src/node/key_fields.rs +++ b/crates/cairo-lang-syntax/src/node/key_fields.rs @@ -451,6 +451,9 @@ pub fn get_key_fields(kind: SyntaxKind, children: &[GreenId]) -> Vec { SyntaxKind::ItemMacroDeclaration => { vec![/* name */ children[3]] } + SyntaxKind::OptionTerminalUnhygienicEmpty => { + vec![] + } SyntaxKind::MacroRulesList => vec![], SyntaxKind::MacroRule => { vec![] @@ -580,6 +583,10 @@ pub fn get_key_fields(kind: SyntaxKind, children: &[GreenId]) -> Vec { SyntaxKind::TerminalMacro => { vec![] } + SyntaxKind::TokenUnhygienic => vec![], + SyntaxKind::TerminalUnhygienic => { + vec![] + } SyntaxKind::TokenMatch => vec![], SyntaxKind::TerminalMatch => { vec![] diff --git a/crates/cairo-lang-syntax/src/node/kind.rs b/crates/cairo-lang-syntax/src/node/kind.rs index 8fc3edd875a..7b688b4699f 100644 --- a/crates/cairo-lang-syntax/src/node/kind.rs +++ b/crates/cairo-lang-syntax/src/node/kind.rs @@ -168,6 +168,7 @@ pub enum SyntaxKind { ExprInlineMacro, ItemInlineMacro, ItemMacroDeclaration, + OptionTerminalUnhygienicEmpty, MacroRulesList, MacroRule, ParamKind, @@ -225,6 +226,8 @@ pub enum SyntaxKind { TerminalLet, TokenMacro, TerminalMacro, + TokenUnhygienic, + TerminalUnhygienic, TokenMatch, TerminalMatch, TokenModule, @@ -381,6 +384,7 @@ impl SyntaxKind { | SyntaxKind::TokenImplicits | SyntaxKind::TokenLet | SyntaxKind::TokenMacro + | SyntaxKind::TokenUnhygienic | SyntaxKind::TokenMatch | SyntaxKind::TokenModule | SyntaxKind::TokenMut @@ -474,6 +478,7 @@ impl SyntaxKind { | SyntaxKind::TerminalImplicits | SyntaxKind::TerminalLet | SyntaxKind::TerminalMacro + | SyntaxKind::TerminalUnhygienic | SyntaxKind::TerminalMatch | SyntaxKind::TerminalModule | SyntaxKind::TerminalMut @@ -556,6 +561,7 @@ impl SyntaxKind { | SyntaxKind::TokenImplicits | SyntaxKind::TokenLet | SyntaxKind::TokenMacro + | SyntaxKind::TokenUnhygienic | SyntaxKind::TokenMatch | SyntaxKind::TokenModule | SyntaxKind::TokenMut @@ -591,6 +597,7 @@ impl SyntaxKind { | SyntaxKind::TerminalImplicits | SyntaxKind::TerminalLet | SyntaxKind::TerminalMacro + | SyntaxKind::TerminalUnhygienic | SyntaxKind::TerminalMatch | SyntaxKind::TerminalModule | SyntaxKind::TerminalMut