diff --git a/grammar.js b/grammar.js index a3c76ad..2273fd1 100644 --- a/grammar.js +++ b/grammar.js @@ -41,8 +41,9 @@ module.exports = grammar({ ), // Template imports - supports both quoted "path" and unquoted /path + // The "as alias" part is optional import_statement: ($) => - seq(seq("@", "import"), choice($.string_literal, $.import_path), "as", $.identifier), + seq(seq("@", "import"), choice($.string_literal, $.import_path), optional(seq("as", $.identifier))), import_path: ($) => /\/[^\s]+/, @@ -255,8 +256,9 @@ module.exports = grammar({ ), // Let binding: @let name = expression + // Use simple_pattern to avoid confusion with if/match expressions containing { } let_statement: ($) => - seq(seq("@", "let"), $.pattern, "=", $.expression), + seq(seq("@", "let"), $.simple_pattern, "=", $.expression), if_statement: ($) => seq( @@ -407,16 +409,87 @@ module.exports = grammar({ primary_expression: ($) => choice( + // if/match expressions must come first to match the keywords before rust_path + $.if_expression, + $.match_expression, $.literal, - $.rust_path, + $.macro_call, $.method_call, $.field_access, $.index_access, $.parenthesized_expression, $.array_literal, $.closure_expression, + // rust_path last as fallback for identifiers + $.rust_path, ), + // If expression (returns a value): if cond { expr } else { expr } + if_expression: ($) => + prec.right( + 10, + seq( + "if", + $.expression, + "{", + $.expression, + "}", + "else", + choice( + $.if_expression, + seq("{", $.expression, "}"), + ), + ), + ), + + // Match expression (returns a value): match expr { pat => expr, ... } + match_expression: ($) => + prec.right( + 10, + seq( + "match", + $.expression, + "{", + repeat($.expression_match_arm), + "}", + ), + ), + + expression_match_arm: ($) => + seq( + $.pattern, + optional(seq("if", $.expression)), + "=>", + $.expression, + optional(","), + ), + + // Rust macro calls: format!(), vec![], println!(), etc. + macro_call: ($) => + prec( + 5, + seq( + $.identifier, + "!", + choice( + seq("(", optional($.macro_args), ")"), + seq("[", optional($.macro_args), "]"), + seq("{", optional($.macro_args), "}"), + ), + ), + ), + + // Macro arguments + macro_args: ($) => + seq( + $.macro_arg, + repeat(seq(",", $.macro_arg)), + optional(","), + ), + + // Macro argument - just use expression + macro_arg: ($) => $.expression, + method_call: ($) => prec.left( 3, diff --git a/src/grammar.json b/src/grammar.json index cf1ed89..2ff14eb 100644 --- a/src/grammar.json +++ b/src/grammar.json @@ -139,12 +139,25 @@ ] }, { - "type": "STRING", - "value": "as" - }, - { - "type": "SYMBOL", - "name": "identifier" + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "as" + }, + { + "type": "SYMBOL", + "name": "identifier" + } + ] + }, + { + "type": "BLANK" + } + ] } ] }, @@ -1249,7 +1262,7 @@ }, { "type": "SYMBOL", - "name": "pattern" + "name": "simple_pattern" }, { "type": "STRING", @@ -2087,13 +2100,21 @@ "primary_expression": { "type": "CHOICE", "members": [ + { + "type": "SYMBOL", + "name": "if_expression" + }, + { + "type": "SYMBOL", + "name": "match_expression" + }, { "type": "SYMBOL", "name": "literal" }, { "type": "SYMBOL", - "name": "rust_path" + "name": "macro_call" }, { "type": "SYMBOL", @@ -2118,9 +2139,292 @@ { "type": "SYMBOL", "name": "closure_expression" + }, + { + "type": "SYMBOL", + "name": "rust_path" } ] }, + "if_expression": { + "type": "PREC_RIGHT", + "value": 10, + "content": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "if" + }, + { + "type": "SYMBOL", + "name": "expression" + }, + { + "type": "STRING", + "value": "{" + }, + { + "type": "SYMBOL", + "name": "expression" + }, + { + "type": "STRING", + "value": "}" + }, + { + "type": "STRING", + "value": "else" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "if_expression" + }, + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "{" + }, + { + "type": "SYMBOL", + "name": "expression" + }, + { + "type": "STRING", + "value": "}" + } + ] + } + ] + } + ] + } + }, + "match_expression": { + "type": "PREC_RIGHT", + "value": 10, + "content": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "match" + }, + { + "type": "SYMBOL", + "name": "expression" + }, + { + "type": "STRING", + "value": "{" + }, + { + "type": "REPEAT", + "content": { + "type": "SYMBOL", + "name": "expression_match_arm" + } + }, + { + "type": "STRING", + "value": "}" + } + ] + } + }, + "expression_match_arm": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "pattern" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "if" + }, + { + "type": "SYMBOL", + "name": "expression" + } + ] + }, + { + "type": "BLANK" + } + ] + }, + { + "type": "STRING", + "value": "=>" + }, + { + "type": "SYMBOL", + "name": "expression" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "STRING", + "value": "," + }, + { + "type": "BLANK" + } + ] + } + ] + }, + "macro_call": { + "type": "PREC", + "value": 5, + "content": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "identifier" + }, + { + "type": "STRING", + "value": "!" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "(" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "macro_args" + }, + { + "type": "BLANK" + } + ] + }, + { + "type": "STRING", + "value": ")" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "[" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "macro_args" + }, + { + "type": "BLANK" + } + ] + }, + { + "type": "STRING", + "value": "]" + } + ] + }, + { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "{" + }, + { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "macro_args" + }, + { + "type": "BLANK" + } + ] + }, + { + "type": "STRING", + "value": "}" + } + ] + } + ] + } + ] + } + }, + "macro_args": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "macro_arg" + }, + { + "type": "REPEAT", + "content": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "," + }, + { + "type": "SYMBOL", + "name": "macro_arg" + } + ] + } + }, + { + "type": "CHOICE", + "members": [ + { + "type": "STRING", + "value": "," + }, + { + "type": "BLANK" + } + ] + } + ] + }, + "macro_arg": { + "type": "SYMBOL", + "name": "expression" + }, "method_call": { "type": "PREC_LEFT", "value": 3, @@ -3367,6 +3671,5 @@ "precedences": [], "externals": [], "inline": [], - "supertypes": [], - "reserved": {} -} \ No newline at end of file + "supertypes": [] +}