Skip to content

Commit

Permalink
Change macro matcher syntax to include the params.
Browse files Browse the repository at this point in the history
  • Loading branch information
gilbens-starkware committed Jan 28, 2025
1 parent cb8bb62 commit 2c20f0f
Show file tree
Hide file tree
Showing 7 changed files with 814 additions and 39 deletions.
3 changes: 2 additions & 1 deletion crates/cairo-lang-formatter/src/node_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ impl SyntaxNodeFormat for SyntaxNode {
true
}
SyntaxKind::TokenColon
if grandparent_kind(db, self) == Some(SyntaxKind::ArgClauseFieldInitShorthand) =>
if grandparent_kind(db, self) == Some(SyntaxKind::ArgClauseFieldInitShorthand)
|| grandparent_kind(db, self) == Some(SyntaxKind::MacroRuleParam) =>
{
true
}
Expand Down
76 changes: 68 additions & 8 deletions crates/cairo-lang-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,18 +602,78 @@ impl<'a> Parser<'a> {
/// Returns a GreenId of a node with a MacroRule kind or TryParseFailure if a macro rule can't
/// be parsed.
fn try_parse_macro_rule(&mut self) -> TryParseResult<MacroRuleGreen> {
let macro_matcher = match self.peek().kind {
SyntaxKind::TerminalLParen => self
.expect_wrapped_macro_rule_elements::<TerminalLParen, TerminalRParen, _, _>(
ParenthesizedMacroMatcher::new_green,
)
.into(),
SyntaxKind::TerminalLBrace => self
.expect_wrapped_macro_rule_elements::<TerminalLBrace, TerminalRBrace, _, _>(
BracedMacroMatcher::new_green,
)
.into(),
SyntaxKind::TerminalLBrack => self
.expect_wrapped_macro_rule_elements::<TerminalLBrack, TerminalRBrack, _, _>(
BracketedMacroMatcher::new_green,
)
.into(),
_ => return Err(TryParseFailure::SkipToken),
};
let arrow = self.parse_token::<TerminalMatchArrow>();
let macro_body = self.parse_block_with_placeholders();
let semicolon = self.parse_token::<TerminalSemicolon>();
Ok(MacroRule::new_green(self.db, macro_matcher, arrow, macro_body, semicolon))
}

/// Assumes the current token is LTerminal.
/// Expected pattern: `[LTerminal](<MacroRuleElement>)*[RTerminal]`
/// Gets `new_green` a green id node builder for the list of the requested type, applies it to
/// the parsed list and returns the result.
fn expect_wrapped_macro_rule_elements<
LTerminal: syntax::node::Terminal,
RTerminal: syntax::node::Terminal,
ListGreen,
NewGreen: Fn(
&dyn SyntaxGroup,
LTerminal::Green,
MacroRuleElementsGreen,
RTerminal::Green,
) -> ListGreen,
>(
&mut self,
new_green: NewGreen,
) -> ListGreen {
let l_term = self.take::<LTerminal>();
let exprs: Vec<MacroRuleElementGreen> = self.parse_list(
Self::try_parse_macro_rule_element,
is_of_kind!(rparen, rbrace, rbrack),
"macro rule element",
);
let r_term: <RTerminal as TypedSyntaxNode>::Green = self.parse_token::<RTerminal>();
new_green(self.db, l_term, MacroRuleElements::new_green(self.db, exprs), r_term)
}

/// Returns a GreenId of a node with a MacroRuleElement kind or TryParseFailure if a macro rule
/// element can't be parsed.
/// Expected pattern: Either any token or a matcher of the pattern $ident:kind.
fn try_parse_macro_rule_element(&mut self) -> TryParseResult<MacroRuleElementGreen> {
match self.peek().kind {
SyntaxKind::TerminalLParen => {
let lhs = self.parse_token_tree_node();
let arrow = self.parse_token::<TerminalMatchArrow>();
let rhs = self.parse_block_with_placeholders();
let semicolon = self.parse_token::<TerminalSemicolon>();
Ok(MacroRule::new_green(self.db, lhs, arrow, rhs, semicolon))
SyntaxKind::TerminalDollar => {
let dollar = self.take::<TerminalDollar>();
let ident = self.parse_identifier();
let colon = self.parse_token::<TerminalColon>();
let kind = self.parse_token::<TerminalIdentifier>();
Ok(MacroRuleParam::new_green(self.db, dollar, ident, colon, kind).into())
}
_ => Err(TryParseFailure::SkipToken),
// TODO(Gil): Handle these cases using a tree structure similar to the one used for
// token trees.
SyntaxKind::TerminalRParen
| SyntaxKind::TerminalRBrace
| SyntaxKind::TerminalRBrack => Err(TryParseFailure::SkipToken),
_ => Ok(self.parse_token_tree_leaf().into()),
}
}

/// Returns a GreenId of a node with a UsePath kind or TryParseFailure if can't parse a UsePath.
fn try_parse_use_path(&mut self) -> TryParseResult<UsePathGreen> {
if !matches!(self.peek().kind, SyntaxKind::TerminalLBrace | SyntaxKind::TerminalIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ macro macro_name {
│ ├── lbrace (kind: TokenLBrace): '{'
│ ├── rules (kind: MacroRulesList)
│ │ └── child #0 (kind: MacroRule)
│ │ ├── lhs (kind: TokenTreeNode)
│ │ │ └── subtree (kind: ParenthesizedTokenTree)
│ │ │ ├── lparen (kind: TokenLParen): '('
│ │ │ ├── tokens (kind: TokenList) []
│ │ │ └── rparen (kind: TokenRParen): ')'
│ │ ├── lhs (kind: ParenthesizedMacroMatcher)
│ │ │ ├── lparen (kind: TokenLParen): '('
│ │ │ ├── elements (kind: MacroRuleElements) []
│ │ │ └── rparen (kind: TokenRParen): ')'
│ │ ├── fat_arrow (kind: TokenMatchArrow): '=>'
│ │ ├── rhs (kind: ExprBlock)
│ │ │ ├── lbrace (kind: TokenLBrace): '{'
Expand Down Expand Up @@ -63,7 +62,7 @@ macro macro_name {
2 + $placeholder
};

($x: ident) => {
($x:ident x + y) => {
2 + $x
};
}
Expand All @@ -85,11 +84,10 @@ macro macro_name {
│ ├── lbrace (kind: TokenLBrace): '{'
│ ├── rules (kind: MacroRulesList)
│ │ ├── child #0 (kind: MacroRule)
│ │ │ ├── lhs (kind: TokenTreeNode)
│ │ │ │ └── subtree (kind: ParenthesizedTokenTree)
│ │ │ │ ├── lparen (kind: TokenLParen): '('
│ │ │ │ ├── tokens (kind: TokenList) []
│ │ │ │ └── rparen (kind: TokenRParen): ')'
│ │ │ ├── lhs (kind: ParenthesizedMacroMatcher)
│ │ │ │ ├── lparen (kind: TokenLParen): '('
│ │ │ │ ├── elements (kind: MacroRuleElements) []
│ │ │ │ └── rparen (kind: TokenRParen): ')'
│ │ │ ├── fat_arrow (kind: TokenMatchArrow): '=>'
│ │ │ ├── rhs (kind: ExprBlock)
│ │ │ │ ├── lbrace (kind: TokenLBrace): '{'
Expand All @@ -106,19 +104,21 @@ macro macro_name {
│ │ │ │ └── rbrace (kind: TokenRBrace): '}'
│ │ │ └── semicolon (kind: TokenSemicolon): ';'
│ │ └── child #1 (kind: MacroRule)
│ │ ├── lhs (kind: TokenTreeNode)
│ │ │ └── subtree (kind: ParenthesizedTokenTree)
│ │ │ ├── lparen (kind: TokenLParen): '('
│ │ │ ├── tokens (kind: TokenList)
│ │ │ │ ├── child #0 (kind: TokenTreeLeaf)
│ │ │ │ │ └── leaf (kind: TokenDollar): '$'
│ │ │ │ ├── child #1 (kind: TokenTreeLeaf)
│ │ │ │ │ └── leaf (kind: TokenIdentifier): 'x'
│ │ │ │ ├── child #2 (kind: TokenTreeLeaf)
│ │ │ │ │ └── leaf (kind: TokenColon): ':'
│ │ │ │ └── child #3 (kind: TokenTreeLeaf)
│ │ │ │ └── leaf (kind: TokenIdentifier): 'ident'
│ │ │ └── rparen (kind: TokenRParen): ')'
│ │ ├── lhs (kind: ParenthesizedMacroMatcher)
│ │ │ ├── lparen (kind: TokenLParen): '('
│ │ │ ├── elements (kind: MacroRuleElements)
│ │ │ │ ├── child #0 (kind: MacroRuleParam)
│ │ │ │ │ ├── dollar (kind: TokenDollar): '$'
│ │ │ │ │ ├── name (kind: TokenIdentifier): 'x'
│ │ │ │ │ ├── colon (kind: TokenColon): ':'
│ │ │ │ │ └── kind (kind: TokenIdentifier): 'ident'
│ │ │ │ ├── child #1 (kind: TokenTreeLeaf)
│ │ │ │ │ └── leaf (kind: TokenIdentifier): 'x'
│ │ │ │ ├── child #2 (kind: TokenTreeLeaf)
│ │ │ │ │ └── leaf (kind: TokenPlus): '+'
│ │ │ │ └── child #3 (kind: TokenTreeLeaf)
│ │ │ │ └── leaf (kind: TokenIdentifier): 'y'
│ │ │ └── rparen (kind: TokenRParen): ')'
│ │ ├── fat_arrow (kind: TokenMatchArrow): '=>'
│ │ ├── rhs (kind: ExprBlock)
│ │ │ ├── lbrace (kind: TokenLBrace): '{'
Expand Down
33 changes: 31 additions & 2 deletions crates/cairo-lang-syntax-codegen/src/cairo_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,12 +851,41 @@ pub fn get_spec() -> Vec<Node> {
)
.add_list("MacroRulesList", "MacroRule")
.add_struct(StructBuilder::new("MacroRule")
.node("lhs", "TokenTreeNode")
.node("lhs", "MacroMatcher")
.node("fat_arrow", "TerminalMatchArrow")
.node("rhs", "ExprBlock")
.node("semicolon", "TerminalSemicolon")
)
// TODO
.add_struct(StructBuilder::new("MacroRuleParam")
.node("dollar", "TerminalDollar")
.node("name", "TerminalIdentifier")
.node("colon", "TerminalColon")
.node("kind", "TerminalIdentifier"))
.add_enum(EnumBuilder::new("MacroRuleElement")
.node_with_explicit_kind("Token", "TokenTreeLeaf")
.node_with_explicit_kind("Param", "MacroRuleParam")
)
.add_enum(EnumBuilder::new("MacroMatcher")
.node_with_explicit_kind("Parenthesized", "ParenthesizedMacroMatcher")
.node_with_explicit_kind("Braced", "BracedMacroMatcher")
.node_with_explicit_kind("Bracketed", "BracketedMacroMatcher")
)
.add_struct(StructBuilder::new("ParenthesizedMacroMatcher")
.node("lparen", "TerminalLParen")
.node("elements", "MacroRuleElements")
.node("rparen", "TerminalRParen")
)
.add_struct(StructBuilder::new("BracedMacroMatcher")
.node("lbrace", "TerminalLBrace")
.node("elements", "MacroRuleElements")
.node("rbrace", "TerminalRBrace")
)
.add_struct(StructBuilder::new("BracketedMacroMatcher")
.node("lbrack", "TerminalLBrack")
.node("elements", "MacroRuleElements")
.node("rbrack", "TerminalRBrack")
)
.add_list("MacroRuleElements", "MacroRuleElement")
.add_struct(StructBuilder::new("LegacyExprInlineMacro")
.node("path", "ExprPath")
.node("bang", "TerminalNot")
Expand Down
Loading

0 comments on commit 2c20f0f

Please sign in to comment.