diff --git a/grammars/csharp.tmLanguage b/grammars/csharp.tmLanguage
index 3906d58..ff466bb 100644
--- a/grammars/csharp.tmLanguage
+++ b/grammars/csharp.tmLanguage
@@ -173,6 +173,10 @@
include
#property-declaration
+
+ include
+ #fixed-size-buffer-declaration
+
include
#field-declaration
@@ -1692,6 +1696,60 @@
+ fixed-size-buffer-declaration
+
+ begin
+ (?x)
+\b(fixed)\b\s+
+(?<type_name>
+ (?:
+ (?:(?<identifier>@?[_[:alpha:]][_[:alnum:]]*)\s*\:\:\s*)? # alias-qualification
+ (?<name_and_type_args> # identifier + type arguments (if any)
+ \g<identifier>\s*
+ (?<type_args>\s*<(?:[^<>]|\g<type_args>)+>\s*)?
+ )
+ (?:\s*\.\s*\g<name_and_type_args>)* # Are there any more names being dotted into?
+ )
+)\s+
+(\g<identifier>)\s* # buffer name
+(?=\[)
+ beginCaptures
+
+ 1
+
+ name
+ storage.modifier.fixed.cs
+
+ 2
+
+ patterns
+
+
+ include
+ #type
+
+
+
+ 6
+
+ name
+ entity.name.variable.field.cs
+
+
+ end
+ (?=;)
+ patterns
+
+
+ include
+ #bracketed-argument-list
+
+
+ include
+ #comment
+
+
+
field-declaration
begin
diff --git a/grammars/csharp.tmLanguage.cson b/grammars/csharp.tmLanguage.cson
index 0fb74a7..77892d1 100644
--- a/grammars/csharp.tmLanguage.cson
+++ b/grammars/csharp.tmLanguage.cson
@@ -117,6 +117,9 @@ repository:
{
include: "#property-declaration"
}
+ {
+ include: "#fixed-size-buffer-declaration"
+ }
{
include: "#field-declaration"
}
@@ -1060,6 +1063,43 @@ repository:
include: "#generic-constraints"
}
]
+ "fixed-size-buffer-declaration":
+ begin: '''
+ (?x)
+ \\b(fixed)\\b\\s+
+ (?
+ (?:
+ (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification
+ (? # identifier + type arguments (if any)
+ \\g\\s*
+ (?\\s*<(?:[^<>]|\\g)+>\\s*)?
+ )
+ (?:\\s*\\.\\s*\\g)* # Are there any more names being dotted into?
+ )
+ )\\s+
+ (\\g)\\s* # buffer name
+ (?=\\[)
+ '''
+ beginCaptures:
+ "1":
+ name: "storage.modifier.fixed.cs"
+ "2":
+ patterns: [
+ {
+ include: "#type"
+ }
+ ]
+ "6":
+ name: "entity.name.variable.field.cs"
+ end: "(?=;)"
+ patterns: [
+ {
+ include: "#bracketed-argument-list"
+ }
+ {
+ include: "#comment"
+ }
+ ]
"field-declaration":
begin: '''
(?x)
diff --git a/src/csharp.tmLanguage.yml b/src/csharp.tmLanguage.yml
index 4576f37..d12bc44 100644
--- a/src/csharp.tmLanguage.yml
+++ b/src/csharp.tmLanguage.yml
@@ -54,6 +54,7 @@ repository:
- include: '#type-declarations'
- include: '#constructor-declaration'
- include: '#property-declaration'
+ - include: '#fixed-size-buffer-declaration'
- include: '#field-declaration'
- include: '#event-declaration'
- include: '#indexer-declaration'
@@ -543,6 +544,36 @@ repository:
- include: '#punctuation-comma'
- include: '#generic-constraints'
+ fixed-size-buffer-declaration:
+ begin: |-
+ (?x)
+ \b(fixed)\b\s+
+ (?
+ (?:
+ (?:(?@?[_[:alpha:]][_[:alnum:]]*)\s*\:\:\s*)? # alias-qualification
+ (? # identifier + type arguments (if any)
+ \g\s*
+ (?\s*<(?:[^<>]|\g)+>\s*)?
+ )
+ (?:\s*\.\s*\g)* # Are there any more names being dotted into?
+ )
+ )\s+
+ (\g)\s* # buffer name
+ (?=\[)
+ beginCaptures:
+ '1': { name: storage.modifier.fixed.cs }
+ '2':
+ patterns:
+ - include: '#type'
+ # '3': ? is a sub-expression. It's final value is not considered.
+ # '4': ? is a sub-expression. It's final value is not considered.
+ # '5': ? is a sub-expression. It's final value is not considered.
+ '6': { name: entity.name.variable.field.cs }
+ end: (?=;)
+ patterns:
+ - include: '#bracketed-argument-list'
+ - include: '#comment'
+
field-declaration:
begin: |-
(?x)
diff --git a/test/field.tests.ts b/test/field.tests.ts
index 795133f..771c367 100644
--- a/test/field.tests.ts
+++ b/test/field.tests.ts
@@ -395,5 +395,71 @@ class C
Token.Punctuation.CloseBrace
]);
});
+
+ it("fixed-size buffer declaration", async () => {
+ const input = Input.InStruct(`public fixed byte Buffer[30];`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Public,
+ Token.Keyword.Modifier.Fixed,
+ Token.PrimitiveType.Byte,
+ Token.Identifier.FieldName("Buffer"),
+ Token.Punctuation.OpenBracket,
+ Token.Literal.Numeric.Decimal("30"),
+ Token.Punctuation.CloseBracket,
+ Token.Punctuation.Semicolon
+ ]);
+ });
+
+ it("fixed-size buffer with unsafe modifier", async () => {
+ const input = Input.InStruct(`public unsafe fixed byte Buffer[30];`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Modifier.Public,
+ Token.Keyword.Modifier.Unsafe,
+ Token.Keyword.Modifier.Fixed,
+ Token.PrimitiveType.Byte,
+ Token.Identifier.FieldName("Buffer"),
+ Token.Punctuation.OpenBracket,
+ Token.Literal.Numeric.Decimal("30"),
+ Token.Punctuation.CloseBracket,
+ Token.Punctuation.Semicolon
+ ]);
+ });
+
+ it("fixed-size buffer with const reference", async () => {
+ const input = `
+struct C
+{
+ public const int length = 30;
+ public unsafe fixed byte Buffer[length];
+}`;
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.Keyword.Definition.Struct,
+ Token.Identifier.StructName("C"),
+ Token.Punctuation.OpenBrace,
+ Token.Keyword.Modifier.Public,
+ Token.Keyword.Modifier.Const,
+ Token.PrimitiveType.Int,
+ Token.Identifier.FieldName("length"),
+ Token.Operator.Assignment,
+ Token.Literal.Numeric.Decimal("30"),
+ Token.Punctuation.Semicolon,
+ Token.Keyword.Modifier.Public,
+ Token.Keyword.Modifier.Unsafe,
+ Token.Keyword.Modifier.Fixed,
+ Token.PrimitiveType.Byte,
+ Token.Identifier.FieldName("Buffer"),
+ Token.Punctuation.OpenBracket,
+ Token.Variable.ReadWrite("length"),
+ Token.Punctuation.CloseBracket,
+ Token.Punctuation.Semicolon,
+ Token.Punctuation.CloseBrace
+ ]);
+ });
});
});
diff --git a/test/utils/tokenize.ts b/test/utils/tokenize.ts
index e6cde77..8acf3a2 100644
--- a/test/utils/tokenize.ts
+++ b/test/utils/tokenize.ts
@@ -341,6 +341,7 @@ export namespace Token {
export const Explicit = createToken('explicit', 'storage.modifier.explicit.cs');
export const Extern = createToken('extern', 'storage.modifier.extern.cs');
export const File = createToken('file', 'storage.modifier.file.cs');
+ export const Fixed = createToken('fixed', 'storage.modifier.fixed.cs');
export const Implicit = createToken('implicit', 'storage.modifier.implicit.cs');
export const In = createToken('in', 'storage.modifier.in.cs');
export const Internal = createToken('internal', 'storage.modifier.internal.cs');