diff --git a/grammars/csharp.tmLanguage b/grammars/csharp.tmLanguage index 3906d58..81ce2a8 100644 --- a/grammars/csharp.tmLanguage +++ b/grammars/csharp.tmLanguage @@ -4878,6 +4878,10 @@ include #local-tuple-var-deconstruction + + include + #local-tuple-declaration-deconstruction + local-variable-declaration @@ -5176,6 +5180,26 @@ + local-tuple-declaration-deconstruction + + match + (?x) # e.g. (int x, var y) = GetPoint(); +(?<tuple>\((?:[^\(\)]|\g<tuple>)+\))\s* +(?!=>|==)(?==) + captures + + 1 + + patterns + + + include + #tuple-declaration-deconstruction-element-list + + + + + tuple-deconstruction-assignment match diff --git a/grammars/csharp.tmLanguage.cson b/grammars/csharp.tmLanguage.cson index 0fb74a7..650104c 100644 --- a/grammars/csharp.tmLanguage.cson +++ b/grammars/csharp.tmLanguage.cson @@ -2984,6 +2984,9 @@ repository: { include: "#local-tuple-var-deconstruction" } + { + include: "#local-tuple-declaration-deconstruction" + } ] "local-variable-declaration": begin: ''' @@ -3196,6 +3199,19 @@ repository: include: "#variable-initializer" } ] + "local-tuple-declaration-deconstruction": + match: ''' + (?x) # e.g. (int x, var y) = GetPoint(); + (?\\((?:[^\\(\\)]|\\g)+\\))\\s* + (?!=>|==)(?==) + ''' + captures: + "1": + patterns: [ + { + include: "#tuple-declaration-deconstruction-element-list" + } + ] "tuple-deconstruction-assignment": match: ''' (?x) diff --git a/src/csharp.tmLanguage.yml b/src/csharp.tmLanguage.yml index 4576f37..6dd0cf9 100644 --- a/src/csharp.tmLanguage.yml +++ b/src/csharp.tmLanguage.yml @@ -1770,6 +1770,7 @@ repository: - include: '#local-variable-declaration' - include: '#local-function-declaration' - include: '#local-tuple-var-deconstruction' + - include: '#local-tuple-declaration-deconstruction' local-variable-declaration: begin: |- @@ -1930,6 +1931,16 @@ repository: - include: '#comment' - include: '#variable-initializer' + local-tuple-declaration-deconstruction: + match: |- + (?x) # e.g. (int x, var y) = GetPoint(); + (?\((?:[^\(\)]|\g)+\))\s* + (?!=>|==)(?==) + captures: + '1': + patterns: + - include: '#tuple-declaration-deconstruction-element-list' + tuple-deconstruction-assignment: match: |- (?x) diff --git a/test/tuple.tests.ts b/test/tuple.tests.ts index f18c8df..7f37a42 100644 --- a/test/tuple.tests.ts +++ b/test/tuple.tests.ts @@ -423,5 +423,115 @@ describe("Tuples", () => { Token.Punctuation.CloseBrace ]); }); + + it("Deconstruct with mixed type and var (int _, var _)", async () => { + const input = Input.InMethod(`(int _, var _) = (1, 2);`); + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.OpenParen, + Token.PrimitiveType.Int, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.Comma, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.CloseParen, + Token.Operator.Assignment, + Token.Punctuation.OpenParen, + Token.Literal.Numeric.Decimal("1"), + Token.Punctuation.Comma, + Token.Literal.Numeric.Decimal("2"), + Token.Punctuation.CloseParen, + Token.Punctuation.Semicolon + ]); + }); + + it("Deconstruct with all vars and discards (var _, var _, var _)", async () => { + const input = Input.InMethod(`(var _, var _, var _) = ('a', 'b', 'c');`); + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.OpenParen, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.Comma, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.Comma, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.CloseParen, + Token.Operator.Assignment, + Token.Punctuation.OpenParen, + Token.Punctuation.Char.Begin, + Token.Literal.Char("a"), + Token.Punctuation.Char.End, + Token.Punctuation.Comma, + Token.Punctuation.Char.Begin, + Token.Literal.Char("b"), + Token.Punctuation.Char.End, + Token.Punctuation.Comma, + Token.Punctuation.Char.Begin, + Token.Literal.Char("c"), + Token.Punctuation.Char.End, + Token.Punctuation.CloseParen, + Token.Punctuation.Semicolon + ]); + }); + + it("Deconstruct with mixed type and var at top level (int _, var _)", async () => { + const input = Input.FromText(`(int _, var _) = (1, 2);`); + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.OpenParen, + Token.PrimitiveType.Int, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.Comma, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.CloseParen, + Token.Operator.Assignment, + Token.Punctuation.OpenParen, + Token.Literal.Numeric.Decimal("1"), + Token.Punctuation.Comma, + Token.Literal.Numeric.Decimal("2"), + Token.Punctuation.CloseParen, + Token.Punctuation.Semicolon + ]); + }); + + it("Deconstruct with all vars and discards at top level (var _, var _, var _)", async () => { + const input = Input.FromText(`(var _, var _, var _) = ('a', 'b', 'c');`); + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.OpenParen, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.Comma, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.Comma, + Token.Keyword.Definition.Var, + Token.Identifier.TupleElementName("_"), + Token.Punctuation.CloseParen, + Token.Operator.Assignment, + Token.Punctuation.OpenParen, + Token.Punctuation.Char.Begin, + Token.Literal.Char("a"), + Token.Punctuation.Char.End, + Token.Punctuation.Comma, + Token.Punctuation.Char.Begin, + Token.Literal.Char("b"), + Token.Punctuation.Char.End, + Token.Punctuation.Comma, + Token.Punctuation.Char.Begin, + Token.Literal.Char("c"), + Token.Punctuation.Char.End, + Token.Punctuation.CloseParen, + Token.Punctuation.Semicolon + ]); + }); }); });