diff --git a/grammars/csharp.tmLanguage b/grammars/csharp.tmLanguage
index 6b6a385..9d66b73 100644
--- a/grammars/csharp.tmLanguage
+++ b/grammars/csharp.tmLanguage
@@ -4799,9 +4799,12 @@
begin
(?x)
(?:
- (?:(\bref)\s+(?:(\breadonly)\s+)?)?(\bvar\b)| # ref local
+ (?:(\bscoped)\s+(?:(\bref)\s+)?)? # scoped local
+ (?:(\bref)\s+(?:(\breadonly)\s+)?)? # ref local
+ (\bvar\b)|
(?<type_name>
(?:
+ (?:scoped\s+(?:ref\s+)?)? # scoped local
(?:ref\s+(?:readonly\s+)?)? # ref local
(?:
(?:(?<identifier>@?[_[:alpha:]][_[:alnum:]]*)\s*\:\:\s*)? # alias-qualification
@@ -4832,19 +4835,29 @@
1
name
- storage.modifier.ref.cs
+ storage.modifier.scoped.cs
2
name
- storage.modifier.readonly.cs
+ storage.modifier.ref.cs
3
name
- storage.type.var.cs
+ storage.modifier.ref.cs
4
+
+ name
+ storage.modifier.readonly.cs
+
+ 5
+
+ name
+ storage.type.var.cs
+
+ 6
patterns
@@ -4854,7 +4867,7 @@
- 9
+ 11
name
entity.name.variable.local.cs
@@ -7284,7 +7297,7 @@
match
(?x)
-(?:(?:\b(ref|params|out|in|this)\b)\s+)?
+(?:(?:\b(scoped|ref|params|out|in|this)\b)\s+)?
(?<type_name>
(?:
(?:ref\s+)? # ref return
@@ -8204,6 +8217,10 @@
include
#comment
+
+ include
+ #scoped-modifier
+
include
#ref-modifier
@@ -8242,6 +8259,13 @@
+ scoped-modifier
+
+ name
+ storage.modifier.scoped.cs
+ match
+ \bscoped\b
+
ref-modifier
name
diff --git a/grammars/csharp.tmLanguage.cson b/grammars/csharp.tmLanguage.cson
index 3f09e3e..86263bf 100644
--- a/grammars/csharp.tmLanguage.cson
+++ b/grammars/csharp.tmLanguage.cson
@@ -2931,9 +2931,12 @@ repository:
begin: '''
(?x)
(?:
- (?:(\\bref)\\s+(?:(\\breadonly)\\s+)?)?(\\bvar\\b)| # ref local
+ (?:(\\bscoped)\\s+(?:(\\bref)\\s+)?)? # scoped local
+ (?:(\\bref)\\s+(?:(\\breadonly)\\s+)?)? # ref local
+ (\\bvar\\b)|
(?
(?:
+ (?:scoped\\s+(?:ref\\s+)?)? # scoped local
(?:ref\\s+(?:readonly\\s+)?)? # ref local
(?:
(?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification
@@ -2962,18 +2965,22 @@ repository:
'''
beginCaptures:
"1":
- name: "storage.modifier.ref.cs"
+ name: "storage.modifier.scoped.cs"
"2":
- name: "storage.modifier.readonly.cs"
+ name: "storage.modifier.ref.cs"
"3":
- name: "storage.type.var.cs"
+ name: "storage.modifier.ref.cs"
"4":
+ name: "storage.modifier.readonly.cs"
+ "5":
+ name: "storage.type.var.cs"
+ "6":
patterns: [
{
include: "#type"
}
]
- "9":
+ "11":
name: "entity.name.variable.local.cs"
end: "(?=[;)}])"
patterns: [
@@ -4393,7 +4400,7 @@ repository:
parameter:
match: '''
(?x)
- (?:(?:\\b(ref|params|out|in|this)\\b)\\s+)?
+ (?:(?:\\b(scoped|ref|params|out|in|this)\\b)\\s+)?
(?
(?:
(?:ref\\s+)? # ref return
@@ -4961,6 +4968,9 @@ repository:
{
include: "#comment"
}
+ {
+ include: "#scoped-modifier"
+ }
{
include: "#ref-modifier"
}
@@ -4989,6 +4999,9 @@ repository:
include: "#type-pointer-suffix"
}
]
+ "scoped-modifier":
+ name: "storage.modifier.scoped.cs"
+ match: "\\bscoped\\b"
"ref-modifier":
name: "storage.modifier.ref.cs"
match: "\\bref\\b"
diff --git a/src/csharp.tmLanguage.yml b/src/csharp.tmLanguage.yml
index 360b7d2..d99b878 100644
--- a/src/csharp.tmLanguage.yml
+++ b/src/csharp.tmLanguage.yml
@@ -1739,9 +1739,12 @@ repository:
begin: |-
(?x)
(?:
- (?:(\bref)\s+(?:(\breadonly)\s+)?)?(\bvar\b)| # ref local
+ (?:(\bscoped)\s+(?:(\bref)\s+)?)? # scoped local
+ (?:(\bref)\s+(?:(\breadonly)\s+)?)? # ref local
+ (\bvar\b)|
(?
(?:
+ (?:scoped\s+(?:ref\s+)?)? # scoped local
(?:ref\s+(?:readonly\s+)?)? # ref local
(?:
(?:(?@?[_[:alpha:]][_[:alnum:]]*)\s*\:\:\s*)? # alias-qualification
@@ -1768,17 +1771,19 @@ repository:
(?!=>)
(?=,|;|=|\))
beginCaptures:
- 1: { name: storage.modifier.ref.cs }
- 2: { name: storage.modifier.readonly.cs }
- 3: { name: storage.type.var.cs }
- 4:
+ 1: { name: storage.modifier.scoped.cs }
+ 2: { name: storage.modifier.ref.cs }
+ 3: { name: storage.modifier.ref.cs }
+ 4: { name: storage.modifier.readonly.cs }
+ 5: { name: storage.type.var.cs }
+ 6:
patterns:
- include: '#type'
- # 5: ? is a sub-expression. It's final value is not considered.
- # 6: ? is a sub-expression. It's final value is not considered.
- # 7: ? is a sub-expression. It's final value is not considered.
- # 8: ? is a sub-expression. It's final value is not considered.
- 9: { name: entity.name.variable.local.cs }
+ # 7: ? is a sub-expression. It's final value is not considered.
+ # 8: ? is a sub-expression. It's final value is not considered.
+ # 9: ? is a sub-expression. It's final value is not considered.
+ # 10: ? is a sub-expression. It's final value is not considered.
+ 11: { name: entity.name.variable.local.cs }
end: (?=[;)}])
patterns:
- name: entity.name.variable.local.cs
@@ -2829,7 +2834,7 @@ repository:
parameter:
match: |-
(?x)
- (?:(?:\b(ref|params|out|in|this)\b)\s+)?
+ (?:(?:\b(scoped|ref|params|out|in|this)\b)\s+)?
(?
(?:
(?:ref\s+)? # ref return
@@ -3226,6 +3231,7 @@ repository:
type:
patterns:
- include: '#comment'
+ - include: '#scoped-modifier'
- include: '#ref-modifier'
- include: '#readonly-modifier'
- include: '#tuple-type'
@@ -3236,6 +3242,10 @@ repository:
- include: '#type-nullable-suffix'
- include: '#type-pointer-suffix'
+ scoped-modifier:
+ name: storage.modifier.scoped.cs
+ match: \bscoped\b
+
ref-modifier:
name: storage.modifier.ref.cs
match: \bref\b
diff --git a/test/local.tests.ts b/test/local.tests.ts
index 9b342c4..4077bf3 100644
--- a/test/local.tests.ts
+++ b/test/local.tests.ts
@@ -96,6 +96,79 @@ describe("Locals", () => {
]);
});
+ it("scoped local", async () => {
+ const input = Input.InMethod(`scoped Span x = stackalloc int[42];`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Scoped,
+ Token.Type("Span"),
+ Token.Punctuation.TypeParameter.Begin,
+ Token.PrimitiveType.Int,
+ Token.Punctuation.TypeParameter.End,
+ Token.Identifier.LocalName("x"),
+ Token.Operator.Assignment,
+ Token.Operator.Expression.StackAlloc,
+ Token.PrimitiveType.Int,
+ Token.Punctuation.OpenBracket,
+ Token.Literal.Numeric.Decimal("42"),
+ Token.Punctuation.CloseBracket,
+ Token.Punctuation.Semicolon
+ ]);
+ });
+
+ it("scoped local var", async () => {
+ const input = Input.InMethod(`scoped var x = y;`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Scoped,
+ Token.Keyword.Definition.Var,
+ Token.Identifier.LocalName("x"),
+ Token.Operator.Assignment,
+ Token.Variable.ReadWrite("y"),
+ Token.Punctuation.Semicolon
+ ]);
+ });
+
+ it("scoped ref local", async () => {
+ const input = Input.InMethod(`scoped ref Span x = stackalloc int[42];`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Scoped,
+ Token.Keyword.Modifier.Ref,
+ Token.Type("Span"),
+ Token.Punctuation.TypeParameter.Begin,
+ Token.PrimitiveType.Int,
+ Token.Punctuation.TypeParameter.End,
+ Token.Identifier.LocalName("x"),
+ Token.Operator.Assignment,
+ Token.Operator.Expression.StackAlloc,
+ Token.PrimitiveType.Int,
+ Token.Punctuation.OpenBracket,
+ Token.Literal.Numeric.Decimal("42"),
+ Token.Punctuation.CloseBracket,
+ Token.Punctuation.Semicolon
+ ]);
+ });
+
+ it("scoped ref local var", async () => {
+ const input = Input.InMethod(`scoped ref var x = ref y;`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Scoped,
+ Token.Keyword.Modifier.Ref,
+ Token.Keyword.Definition.Var,
+ Token.Identifier.LocalName("x"),
+ Token.Operator.Assignment,
+ Token.Keyword.Modifier.Ref,
+ Token.Variable.ReadWrite("y"),
+ Token.Punctuation.Semicolon
+ ]);
+ });
+
it("ref local", async () => {
const input = Input.InMethod(`ref int x;`);
const tokens = await tokenize(input);
diff --git a/test/method.tests.ts b/test/method.tests.ts
index ad90879..edaba0b 100644
--- a/test/method.tests.ts
+++ b/test/method.tests.ts
@@ -796,6 +796,67 @@ public void LinearRegression(double[,] samples, double[] standardDeviations, int
]);
});
+ it("ref parameter in parameter list", async () => {
+ const input = Input.InClass(`
+public static Span CreateSpan(ref T reference, int length) {}
+`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Public,
+ Token.Keyword.Modifier.Static,
+ Token.Type("Span"),
+ Token.Punctuation.TypeParameter.Begin,
+ Token.Type("T"),
+ Token.Punctuation.TypeParameter.End,
+ Token.Identifier.MethodName("CreateSpan"),
+ Token.Punctuation.TypeParameter.Begin,
+ Token.Identifier.TypeParameterName("T"),
+ Token.Punctuation.TypeParameter.End,
+ Token.Punctuation.OpenParen,
+ Token.Keyword.Modifier.Ref,
+ Token.Type("T"),
+ Token.Identifier.ParameterName("reference"),
+ Token.Punctuation.Comma,
+ Token.PrimitiveType.Int,
+ Token.Identifier.ParameterName("length"),
+ Token.Punctuation.CloseParen,
+ Token.Punctuation.OpenBrace,
+ Token.Punctuation.CloseBrace
+ ]);
+ });
+
+ it("scoped ref parameter in parameter list (#306)", async () => {
+ const input = Input.InClass(`
+public static Span CreateSpan(scoped ref T reference, int length) {}
+`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Public,
+ Token.Keyword.Modifier.Static,
+ Token.Type("Span"),
+ Token.Punctuation.TypeParameter.Begin,
+ Token.Type("T"),
+ Token.Punctuation.TypeParameter.End,
+ Token.Identifier.MethodName("CreateSpan"),
+ Token.Punctuation.TypeParameter.Begin,
+ Token.Identifier.TypeParameterName("T"),
+ Token.Punctuation.TypeParameter.End,
+ Token.Punctuation.OpenParen,
+ Token.Keyword.Modifier.Scoped,
+ Token.Keyword.Modifier.Ref,
+ Token.Type("T"),
+ Token.Identifier.ParameterName("reference"),
+ Token.Punctuation.Comma,
+ Token.PrimitiveType.Int,
+ Token.Identifier.ParameterName("length"),
+ Token.Punctuation.CloseParen,
+ Token.Punctuation.OpenBrace,
+ Token.Punctuation.CloseBrace
+ ]);
+ });
+
it("expression body and type constraint (issue #74)", async () => {
const input = Input.InClass(`
T id1(T a) => a;
diff --git a/test/utils/tokenize.ts b/test/utils/tokenize.ts
index 71f950d..e032e35 100644
--- a/test/utils/tokenize.ts
+++ b/test/utils/tokenize.ts
@@ -355,6 +355,7 @@ export namespace Token {
export const ReadOnly = createToken('readonly', 'storage.modifier.readonly.cs');
export const Ref = createToken('ref', 'storage.modifier.ref.cs');
export const Required = createToken('required', 'storage.modifier.required.cs');
+ export const Scoped = createToken('scoped', 'storage.modifier.scoped.cs');
export const Sealed = createToken('sealed', 'storage.modifier.sealed.cs');
export const Static = createToken('static', 'storage.modifier.static.cs');
export const This = createToken('this', 'storage.modifier.this.cs');