Add if/match expressions and fix import statement grammar
- Make 'as alias' optional in import_statement
- Add if_expression for if/else as values in @let statements
- Add match_expression for match as values
- Add macro_call support for format!(), vec![], etc.
- Use simple_pattern in let_statement to avoid conflicts with { }
- Reorder primary_expression to prioritize if/match over rust_path
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
ce7162699f
commit
6a0318bcb5
79
grammar.js
79
grammar.js
|
|
@ -41,8 +41,9 @@ module.exports = grammar({
|
||||||
),
|
),
|
||||||
|
|
||||||
// Template imports - supports both quoted "path" and unquoted /path
|
// Template imports - supports both quoted "path" and unquoted /path
|
||||||
|
// The "as alias" part is optional
|
||||||
import_statement: ($) =>
|
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]+/,
|
import_path: ($) => /\/[^\s]+/,
|
||||||
|
|
||||||
|
|
@ -255,8 +256,9 @@ module.exports = grammar({
|
||||||
),
|
),
|
||||||
|
|
||||||
// Let binding: @let name = expression
|
// Let binding: @let name = expression
|
||||||
|
// Use simple_pattern to avoid confusion with if/match expressions containing { }
|
||||||
let_statement: ($) =>
|
let_statement: ($) =>
|
||||||
seq(seq("@", "let"), $.pattern, "=", $.expression),
|
seq(seq("@", "let"), $.simple_pattern, "=", $.expression),
|
||||||
|
|
||||||
if_statement: ($) =>
|
if_statement: ($) =>
|
||||||
seq(
|
seq(
|
||||||
|
|
@ -407,16 +409,87 @@ module.exports = grammar({
|
||||||
|
|
||||||
primary_expression: ($) =>
|
primary_expression: ($) =>
|
||||||
choice(
|
choice(
|
||||||
|
// if/match expressions must come first to match the keywords before rust_path
|
||||||
|
$.if_expression,
|
||||||
|
$.match_expression,
|
||||||
$.literal,
|
$.literal,
|
||||||
$.rust_path,
|
$.macro_call,
|
||||||
$.method_call,
|
$.method_call,
|
||||||
$.field_access,
|
$.field_access,
|
||||||
$.index_access,
|
$.index_access,
|
||||||
$.parenthesized_expression,
|
$.parenthesized_expression,
|
||||||
$.array_literal,
|
$.array_literal,
|
||||||
$.closure_expression,
|
$.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: ($) =>
|
method_call: ($) =>
|
||||||
prec.left(
|
prec.left(
|
||||||
3,
|
3,
|
||||||
|
|
|
||||||
323
src/grammar.json
323
src/grammar.json
|
|
@ -139,12 +139,25 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "CHOICE",
|
||||||
"value": "as"
|
"members": [
|
||||||
},
|
{
|
||||||
{
|
"type": "SEQ",
|
||||||
"type": "SYMBOL",
|
"members": [
|
||||||
"name": "identifier"
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "as"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "identifier"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -1249,7 +1262,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "pattern"
|
"name": "simple_pattern"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
|
|
@ -2087,13 +2100,21 @@
|
||||||
"primary_expression": {
|
"primary_expression": {
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "if_expression"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "match_expression"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "literal"
|
"name": "literal"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "rust_path"
|
"name": "macro_call"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
|
|
@ -2118,9 +2139,292 @@
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "closure_expression"
|
"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": {
|
"method_call": {
|
||||||
"type": "PREC_LEFT",
|
"type": "PREC_LEFT",
|
||||||
"value": 3,
|
"value": 3,
|
||||||
|
|
@ -3367,6 +3671,5 @@
|
||||||
"precedences": [],
|
"precedences": [],
|
||||||
"externals": [],
|
"externals": [],
|
||||||
"inline": [],
|
"inline": [],
|
||||||
"supertypes": [],
|
"supertypes": []
|
||||||
"reserved": {}
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue