From ce7162699fd207d3106121d43d73313cf31d4a7d Mon Sep 17 00:00:00 2001 From: Michael Netshipise Date: Mon, 19 Jan 2026 22:40:55 +0200 Subject: [PATCH] Add high-precedence macro token to prevent @for matching in @format! --- grammar.js | 7 ++++++- queries/highlights.scm | 39 +++++++++++++-------------------------- src/grammar.json | 26 +++++++++++++++++++++----- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/grammar.js b/grammar.js index 55bf150..a3c76ad 100644 --- a/grammar.js +++ b/grammar.js @@ -211,7 +211,12 @@ module.exports = grammar({ template_expression: ($) => choice($.simple_expression, $.complex_expression, $.safe_expression), - simple_expression: ($) => seq("@", $.expression_path), + // High-precedence token to match @identifier before @for/@if etc keywords + simple_expression: ($) => + choice( + token(prec(2, /@[a-zA-Z_][a-zA-Z0-9_]*!/)), // Macro calls: @format! + seq("@", $.expression_path), // Regular expressions: @foo.bar + ), complex_expression: ($) => seq("@", "(", $.expression, ")"), diff --git a/queries/highlights.scm b/queries/highlights.scm index 092a6dc..8a99a21 100644 --- a/queries/highlights.scm +++ b/queries/highlights.scm @@ -8,32 +8,19 @@ (raw_block) @string.special ; Keywords - only in proper syntactic contexts -(use_statement "@" @keyword) -(use_statement "use" @keyword) -(import_statement "@" @keyword) -(import_statement "import" @keyword) -(struct_definition "@" @keyword) -(struct_definition "struct" @keyword) -(enum_definition "@" @keyword) -(enum_definition "enum" @keyword) -(function_definition "@" @keyword) -(function_definition "fn" @keyword) -(let_statement "@" @keyword) -(let_statement "let" @keyword) -(if_statement "@" @keyword) -(if_statement "if" @keyword) -(for_loop "@" @keyword) -(for_loop "for" @keyword) -(match_statement "@" @keyword) -(match_statement "match" @keyword) -(break_statement "@" @keyword) -(break_statement "break" @keyword) -(continue_statement "@" @keyword) -(continue_statement "continue" @keyword) -(attribute_if_statement "@" @keyword) -(attribute_if_statement "if" @keyword) -(attribute_for_loop "@" @keyword) -(attribute_for_loop "for" @keyword) +(use_statement "@use" @keyword) +(import_statement "@import" @keyword) +(struct_definition "@struct" @keyword) +(enum_definition "@enum" @keyword) +(function_definition "@fn" @keyword) +(let_statement "@let" @keyword) +(if_statement "@if" @keyword) +(for_loop "@for" @keyword) +(match_statement "@match" @keyword) +(break_statement "@break" @keyword) +(continue_statement "@continue" @keyword) +(attribute_if_statement "@if" @keyword) +(attribute_for_loop "@for" @keyword) (else_if_branch "else" @keyword) (else_if_branch "if" @keyword) (else_branch "else" @keyword) diff --git a/src/grammar.json b/src/grammar.json index 8a5a59b..cf1ed89 100644 --- a/src/grammar.json +++ b/src/grammar.json @@ -1023,15 +1023,31 @@ ] }, "simple_expression": { - "type": "SEQ", + "type": "CHOICE", "members": [ { - "type": "STRING", - "value": "@" + "type": "TOKEN", + "content": { + "type": "PREC", + "value": 2, + "content": { + "type": "PATTERN", + "value": "@[a-zA-Z_][a-zA-Z0-9_]*!" + } + } }, { - "type": "SYMBOL", - "name": "expression_path" + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "@" + }, + { + "type": "SYMBOL", + "name": "expression_path" + } + ] } ] },