diff --git a/utils/textmate/README.md b/utils/textmate/README.md
index 6d67f11343ff..bf37ae6c8883 100644
--- a/utils/textmate/README.md
+++ b/utils/textmate/README.md
@@ -49,9 +49,11 @@ utils/textmate/render_sample.py utils/textmate/Samples/*.carbon
```
The colors are a palette built for this grammar rather than an editor's theme.
-Each family of related scopes gets one color, and bold and italic distinguish
-the scopes within a family, so every scope the grammar emits renders differently
-and a change to what the grammar scopes is visible in the image. Unscoped text
+Each family of related scopes gets one color, and bold, italic, and underline
+distinguish the scopes within a family. Every scope the grammar picks from
+context renders differently, so a change to what the grammar scopes is visible
+in the image. Scopes that follow from the spelling alone, such as a bracket's
+shape, can share a rendering, since the text already shows them. Unscoped text
is dimmer than any scope's color, so text the grammar misses stands out. A scope
-with no entry of its own takes its family's color and style, so give a new scope
-an entry to keep every scope distinct.
+with no entry of its own takes its family's color and style, so give a new
+context-dependent scope an entry of its own.
diff --git a/utils/textmate/Samples/choices.svg b/utils/textmate/Samples/choices.svg
index bfdc725f5f3c..f80db658477f 100644
--- a/utils/textmate/Samples/choices.svg
+++ b/utils/textmate/Samples/choices.svg
@@ -5,9 +5,9 @@
2 // Exceptions. See /LICENSE for license information.
3 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
-5 choice SomeChoice(T: type) {
-6 Val1,
-7 Val2(a: i32, b: array(T, 5), t: T),
-8 Val3
-9 }
+5 choice SomeChoice(T: type) {
+6 Val1,
+7 Val2(a: i32, b: array(T, 5), t: T),
+8 Val3
+9 }
diff --git a/utils/textmate/Samples/comments.carbon b/utils/textmate/Samples/comments.carbon
index e089e9cc197b..bc2295b69dba 100644
--- a/utils/textmate/Samples/comments.carbon
+++ b/utils/textmate/Samples/comments.carbon
@@ -8,6 +8,8 @@
//@dump-sem-ir-begin
//@dump-sem-ir-end
//@include-in-dumps
+ //@include-in-dumps
+//@dump-sem-ir-begin with trailing text is an ordinary comment
//@dump-sem-ir-
//no whitespace after double slash
/* invalid comment pattern. */
diff --git a/utils/textmate/Samples/comments.svg b/utils/textmate/Samples/comments.svg
index 5929b28e802f..272c9fda15f2 100644
--- a/utils/textmate/Samples/comments.svg
+++ b/utils/textmate/Samples/comments.svg
@@ -1,4 +1,4 @@
-
diff --git a/utils/textmate/Samples/functions_variables.carbon b/utils/textmate/Samples/functions_variables.carbon
index 1054a90b015a..c180c26e1b81 100644
--- a/utils/textmate/Samples/functions_variables.carbon
+++ b/utils/textmate/Samples/functions_variables.carbon
@@ -28,6 +28,7 @@ generic a: T = b;
a: A in some_list;
var a: T;
let b: T;
+let unused c: T = d;
binding: T;
generic binding: T;
var
@@ -50,3 +51,17 @@ r#class
r#if
r#i32
var r#var: i32 = r#class;
+
+// --- member access through a pointer
+
+p->field;
+p->Method(a);
+p->0;
+(*p).field;
+t.0.1;
+q.value()->size();
+
+// --- builtin function definitions
+
+fn Add(a: i32, b: i32) -> i32 = "int.sadd";
+fn Bits(n: IntLiteral) -> type = "int.make_type_signed";
diff --git a/utils/textmate/Samples/functions_variables.svg b/utils/textmate/Samples/functions_variables.svg
index f17f1a65c3b7..3732439c78ed 100644
--- a/utils/textmate/Samples/functions_variables.svg
+++ b/utils/textmate/Samples/functions_variables.svg
@@ -1,56 +1,71 @@
-
+
1 // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2 // Exceptions. See /LICENSE for license information.
3 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
- 5 fn F;
- 6 fn F1();
- 7 fn Func(a: i32, b: A);
- 8 fn Generic[T: type, U: I](a: T, b: U) -> U;
- 9 fn Lambda(a: i32) -> i32 => return a + 5;
+ 5 fn F;
+ 6 fn F1();
+ 7 fn Func(a: i32, b: A);
+ 8 fn Generic[T: type, U: I](a: T, b: U) -> U;
+ 9 fn Lambda(a: i32) -> i32 => return a + 5;
10 fn
11
-12 MultiLine[
-13 A: type,
-14 B: C1,
-15 C: C2
-16 ](a: A(B, C),
-17 b: B,
-18 c: i32);
-19 fn Invalid#+?Name();
-20 x.(I.F)();
+12 MultiLine[
+13 A: type,
+14 B: C1,
+15 C: C2
+16 ](a: A(B, C),
+17 b: B,
+18 c: i32);
+19 fn Invalid#+?Name();
+20 x.(I.F)();
21
-22 a: A;
-23 a: A = (b as A);
-24 a: i32;
-25 a: array(A, 5);
-26 generic a: type;
-27 generic a: T = b;
-28 a: A in some_list;
+22 a: A;
+23 a: A = (b as A);
+24 a: i32;
+25 a: array(A, 5);
+26 generic a: type;
+27 generic a: T = b;
+28 a: A in some_list;
29 var a: T;
-30 let b: T;
-31 binding: T;
-32 generic binding: T;
-33 var
-34 multiline: T;
-35
-36 fn F(ref a: A, const ref b: B);
-37 fn F() -> T;
-38 fn F() -> T.U { return val; }
-39 fn F() -> i32 => return val;
-40
-41 // --- lambdas and positional parameters
-42
-43 var explicit: auto = fn (x: i32) -> i32 { return x + 1; };
-44 var expression: auto = fn (x: i32) => x + 1;
-45 var positional: auto = fn { Print($0, $1, $42); };
-46
-47 // --- raw identifiers
-48
-49 r#class
-50 r#if
-51 r#i32
-52 var r#var: i32 = r#class;
+30 let b: T;
+31 let unused c: T = d;
+32 binding: T;
+33 generic binding: T;
+34 var
+35 multiline: T;
+36
+37 fn F(ref a: A, const ref b: B);
+38 fn F() -> T;
+39 fn F() -> T.U { return val; }
+40 fn F() -> i32 => return val;
+41
+42 // --- lambdas and positional parameters
+43
+44 var explicit: auto = fn (x: i32) -> i32 { return x + 1; };
+45 var expression: auto = fn (x: i32) => x + 1;
+46 var positional: auto = fn { Print($0, $1, $42); };
+47
+48 // --- raw identifiers
+49
+50 r#class
+51 r#if
+52 r#i32
+53 var r#var: i32 = r#class;
+54
+55 // --- member access through a pointer
+56
+57 p->field;
+58 p->Method(a);
+59 p->0;
+60 (*p).field;
+61 t.0.1;
+62 q.value()->size();
+63
+64 // --- builtin function definitions
+65
+66 fn Add(a: i32, b: i32) -> i32 = "int.sadd";
+67 fn Bits(n: IntLiteral) -> type = "int.make_type_signed";
diff --git a/utils/textmate/Samples/interop.svg b/utils/textmate/Samples/interop.svg
index 99238f7277f1..c9ebd87e530e 100644
--- a/utils/textmate/Samples/interop.svg
+++ b/utils/textmate/Samples/interop.svg
@@ -9,25 +9,25 @@
6 // grammar highlights them as C++; these renderings come from the Carbon grammar
7 // alone, so that content shows plain.
8
- 9 package Sample library "interop";
+ 9 package Sample library "interop";
10
-11 import Cpp library "<cstdio>";
-12 import Cpp library "<string_view>";
+11 import Cpp library "<cstdio>";
+12 import Cpp library "<string_view>";
13
-14 import Cpp inline '''c++
+14 import Cpp inline '''c++
15 int FromImport() { return 1; }
16 ''';
17
-18 import Cpp inline "int OneLiner() { return 2; }";
+18 import Cpp inline "int OneLiner() { return 2; }";
19
20 inline Cpp '''
21 int FromBlock() { return 3; }
22 ''';
23
-24 fn Uses() {
-25 var value: Cpp.int = 1 as Cpp.int;
-26 var widened: Cpp.size_t = value as Cpp.size_t;
-27 var back: i32 = value unsafe as i32;
-28 Cpp.printf("%d\n", value);
-29 }
+24 fn Uses() {
+25 var value: Cpp.int = 1 as Cpp.int;
+26 var widened: Cpp.size_t = value as Cpp.size_t;
+27 var back: i32 = value unsafe as i32;
+28 Cpp.printf("%d\n", value);
+29 }
diff --git a/utils/textmate/Samples/keywords.svg b/utils/textmate/Samples/keywords.svg
index b5827092c65a..ff4de3982413 100644
--- a/utils/textmate/Samples/keywords.svg
+++ b/utils/textmate/Samples/keywords.svg
@@ -8,8 +8,8 @@
5 // --- operators
6
7 >>= <=> <<= ->? &= ^= := :? == => != >= >> <= <> << <- -= -> -- %= |= += ++ /=
- 8 *= ~= & @ ^ : = ! > < - % . | + ? / * ~ \
- 9 and as impls in like not or typeof where
+ 8 *= ~= & @ ^ : = ! > < - % . | + ? / * ~ \
+ 9 and as impls in like not or typeof where
10
11 // --- special-keywords
12
@@ -18,7 +18,7 @@
15
16 // --- introducer-keywords
17
-18 adapt alias choice class constraint fn import inline interface let library
+18 adapt alias choice class constraint fn import inline interface let library
19 match_first namespace observe require var
20 base
21 export
@@ -31,7 +31,7 @@
28 private protected ref runtime static template unsafe unused val virtual
29 base class
30 default
-31 export import
+31 export import
32 impl fn
33 impl library
34 impl package
@@ -40,8 +40,8 @@
37
38 destroy each expand forall form friend
39 fn destroy
-40 ...expand
-41 .base
+40 ...expand
+41 .base
42
43 // --- self-keywords
44
diff --git a/utils/textmate/Samples/literals.carbon b/utils/textmate/Samples/literals.carbon
index 382f52b7b63d..447f7a4ab889 100644
--- a/utils/textmate/Samples/literals.carbon
+++ b/utils/textmate/Samples/literals.carbon
@@ -14,6 +14,12 @@
'''py
Block literal with a file type indicator.
'''
+'''sql // A trailing comment on the introducer line.
+ SELECT 1;
+'''
+''' // A comment with no file type indicator.
+ Text.
+'''
#"a raw \n literal, where \#n is the escape"#
##"nested "# stays inside, and \##n is the escape"##
@@ -27,6 +33,7 @@
'a' '\n' '\0' '\u{1F600}'
'\x70'
+"\x4F is an escape, \x4f is not"
''
'abcde'
diff --git a/utils/textmate/Samples/literals.svg b/utils/textmate/Samples/literals.svg
index 8dbfcbe77eab..5ecfdbe91a41 100644
--- a/utils/textmate/Samples/literals.svg
+++ b/utils/textmate/Samples/literals.svg
@@ -1,4 +1,4 @@
-
+
1 // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
@@ -17,56 +17,63 @@
14 '''py
15 Block literal with a file type indicator.
16 '''
-17
-18 #"a raw \n literal, where \#n is the escape"#
-19 ##"nested "# stays inside, and \##n is the escape"##
-20 #'''
-21 A raw block literal.
-22 '''#
+17 '''sql // A trailing comment on the introducer line.
+18 SELECT 1;
+19 '''
+20 ''' // A comment with no file type indicator.
+21 Text.
+22 '''
23
-24 "unterminated
-25
-26 // --- characters
-27
-28 'a' '\n' '\0' '\u{1F600}'
-29 '\x70'
-30 ''
-31 'abcde'
-32
-33 // --- true-false
-34
-35 true false
-36
-37 // --- type-literals
-38
-39 array auto bool char str type
-40 i8 i16 i32 i64 i128 i10
-41 u8 u16 u32 u64 u128 u11
-42 f8 f16 f32 f64 f128 f12
+24 #"a raw \n literal, where \#n is the escape"#
+25 ##"nested "# stays inside, and \##n is the escape"##
+26 #'''
+27 A raw block literal.
+28 '''#
+29
+30 "unterminated
+31
+32 // --- characters
+33
+34 'a' '\n' '\0' '\u{1F600}'
+35 '\x70'
+36 "\x4F is an escape, \x4f is not"
+37 ''
+38 'abcde'
+39
+40 // --- true-false
+41
+42 true false
43
-44 // --- numbers
+44 // --- type-literals
45
-46 12345 6789 00012345
-47
-48 1234.56789
-49 0.875
-50 0.3e5
-51 1e5
-52 .123
-53 .1e3
+46 array auto bool char str type
+47 i8 i16 i32 i64 i128 i10
+48 u8 u16 u32 u64 u128 u11
+49 f8 f16 f32 f64 f128 f12
+50
+51 // --- numbers
+52
+53 12345 6789 00012345
54
-55 0o755
-56 0o_17
-57 0o8
-58
-59 0b1011_0010
-60 0b_010
-61 0b2345
-62 0B011
-63
-64 0x2AE5
-65 0x_F109
-66 0xD8_E2.5F_7Bp8
-67 0xabcdef.abcdef
-68 0XA85CE
+55 1234.56789
+56 0.875
+57 0.3e5
+58 1e5
+59 .123
+60 .1e3
+61
+62 0o755
+63 0o_17
+64 0o8
+65
+66 0b1011_0010
+67 0b_010
+68 0b2345
+69 0B011
+70
+71 0x2AE5
+72 0x_F109
+73 0xD8_E2.5F_7Bp8
+74 0xabcdef.abcdef
+75 0XA85CE
diff --git a/utils/textmate/Samples/main.svg b/utils/textmate/Samples/main.svg
index a536895d7ead..d3534c9d1092 100644
--- a/utils/textmate/Samples/main.svg
+++ b/utils/textmate/Samples/main.svg
@@ -9,42 +9,42 @@
6
7 package Carbon;
8
- 9 interface HasValueParam(T: type, V: T) {
-10 fn Go(self) -> T;
-11 }
+ 9 interface HasValueParam(T: type, V: T) {
+10 fn Go(self) -> T;
+11 }
12
-13 impl () as HasValueParam(i32, 5) {
-14 fn Go(self) -> i32 { return 42; }
-15 }
+13 impl () as HasValueParam(i32, 5) {
+14 fn Go(self) -> i32 { return 42; }
+15 }
16
-17 class Point {
-18 fn Origin() -> Self {
-19 return {.x = 0, .y = 0};
-20 }
+17 class Point {
+18 fn Origin() -> Self {
+19 return {.x = 0, .y = 0};
+20 }
21
22 var x: i32;
23 var y: i32;
-24 }
+24 }
25
-26 fn Procedure() -> i32 {
+26 fn Procedure() -> i32 {
27 returned var zoop: i32 = 0;
-28 while (DoSomeJob()) {
+28 while (DoSomeJob()) {
29 zoop += 1;
-30 }
+30 }
31
32 return var;
-33 }
+33 }
34
-35 fn Main() -> i32 {
+35 fn Main() -> i32 {
36 let str = "Hello world";
-37 let hex = 0xABCDEF1234567890;
-38 let bin = 0b0000111001010010;
+37 let hex = 0xABCDEF1234567890;
+38 let bin = 0b0000111001010010;
39 let dec = 123456789012345678;
40
-41 let big: Core.Int(1024) = 1234;
-42 let aaa: auto = "Carbon";
-43 let view: str = "Carbon";
+41 let big: Core.Int(1024) = 1234;
+42 let aaa: auto = "Carbon";
+43 let view: str = "Carbon";
44
-45 return Procedure();
-46 }
+45 return Procedure();
+46 }
diff --git a/utils/textmate/Samples/types.carbon b/utils/textmate/Samples/types.carbon
index d2e46b08042a..b5def909c003 100644
--- a/utils/textmate/Samples/types.carbon
+++ b/utils/textmate/Samples/types.carbon
@@ -30,6 +30,7 @@ interface I;
impl C as (I(A, B, C.(D.E(F, G)).H)) {}
impl C as I where .A = (B where .Self = {}) {}
impl C as I where .A = {} and .B = C {}
+impl forall [T: I where .A = i32] T as J where .B = T.A {}
impl Self as I;
impl as I;
@@ -39,3 +40,40 @@ constraint Constraint {
require impls I;
extern require impls I;
}
+
+namespace N;
+
+class N.C1 {
+ fn N.C1.Make() -> Self;
+}
+alias N.A = N.C1;
+fn N.C1.Other();
+class Outer(T: type).Inner(U: type) {}
+fn Outer(T: type).Inner(U: type).F[self: Self](x: T) -> U;
+fn N.Base(N.T).Member() {}
+interface N.I2;
+constraint N.C2 {}
+
+class C6 {
+ fn destroy(ref self);
+}
+fn C6.destroy(ref self) {}
+
+var p: C6* = &c6;
+var q: typeof(p) = p;
+var r: typeof(Make(p, (q))).Pointee = *p;
+
+// --- the same names in type and expression positions
+
+var o: Optional(Slice(i32)) = Optional(Slice(i32)).None();
+let origin: Point = Point.Origin();
+let t: type = Point;
+var c: Core.Int(64) = x as Core.Int(64);
+var v: Cpp.std.vector(i32) = Make(i32, Vector(Point));
+var s: {.x: i32, .y: Point} = {.x = 1, .y = p};
+var tup: (i32, Point) = (1, p);
+fn Pick[T: Hashable & Eq where .Key = i32](t: T) -> T.Key;
+fn Iter() -> Vector(T).Iterator;
+if (T == Point and x impls Hashable) {}
+alias lower = i32;
+var l: lower = a * b;
diff --git a/utils/textmate/Samples/types.svg b/utils/textmate/Samples/types.svg
index bb2c9c1e38bc..ba77584ddde7 100644
--- a/utils/textmate/Samples/types.svg
+++ b/utils/textmate/Samples/types.svg
@@ -1,45 +1,83 @@
-
+
1 // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2 // Exceptions. See /LICENSE for license information.
3 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
- 5 class C1;
- 6 class C2(T1: type, T2: C1) {}
- 7 class C3 {
- 8 extend base: C1;
- 9 }
+ 5 class C1;
+ 6 class C2(T1: type, T2: C1) {}
+ 7 class C3 {
+ 8 extend base: C1;
+ 9 }
10 class
-11 (C4(
-12 (T1: type),
-13 T2:
-14 (A.(B(E, F(G)).C)
-15 .D))) ;
+11 (C4(
+12 (T1: type),
+13 T2:
+14 (A.(B(E, F(G)).C)
+15 .D))) ;
16
-17 class C5 {
-18 impl as I;
-19 extend impl as I;
-20 }
+17 class C5 {
+18 impl as I;
+19 extend impl as I;
+20 }
21
-22 alias a1 = C1;
+22 alias a1 = C1;
23 alias a2 = i32;
24
25 adapt SomeClass;
-26 adapt {.a: SomeClass, .b: i32};
+26 adapt {.a: SomeClass, .b: i32};
27 adapt i32;
28
29 interface I;
-30 impl C as (I(A, B, C.(D.E(F, G)).H)) {}
-31 impl C as I where .A = (B where .Self = {}) {}
-32 impl C as I where .A = {} and .B = C {}
-33 impl Self as I;
-34 impl as I;
-35
-36 constraint Constraint {
-37 require T impls I;
-38 require Self impls I;
-39 require impls I;
-40 extern require impls I;
-41 }
+30 impl C as (I(A, B, C.(D.E(F, G)).H)) {}
+31 impl C as I where .A = (B where .Self = {}) {}
+32 impl C as I where .A = {} and .B = C {}
+33 impl forall [T: I where .A = i32] T as J where .B = T.A {}
+34 impl Self as I;
+35 impl as I;
+36
+37 constraint Constraint {
+38 require T impls I;
+39 require Self impls I;
+40 require impls I;
+41 extern require impls I;
+42 }
+43
+44 namespace N;
+45
+46 class N.C1 {
+47 fn N.C1.Make() -> Self;
+48 }
+49 alias N.A = N.C1;
+50 fn N.C1.Other();
+51 class Outer(T: type).Inner(U: type) {}
+52 fn Outer(T: type).Inner(U: type).F[self: Self](x: T) -> U;
+53 fn N.Base(N.T).Member() {}
+54 interface N.I2;
+55 constraint N.C2 {}
+56
+57 class C6 {
+58 fn destroy(ref self);
+59 }
+60 fn C6.destroy(ref self) {}
+61
+62 var p: C6* = &c6;
+63 var q: typeof(p) = p;
+64 var r: typeof(Make(p, (q))).Pointee = *p;
+65
+66 // --- the same names in type and expression positions
+67
+68 var o: Optional(Slice(i32)) = Optional(Slice(i32)).None();
+69 let origin: Point = Point.Origin();
+70 let t: type = Point;
+71 var c: Core.Int(64) = x as Core.Int(64);
+72 var v: Cpp.std.vector(i32) = Make(i32, Vector(Point));
+73 var s: {.x: i32, .y: Point} = {.x = 1, .y = p};
+74 var tup: (i32, Point) = (1, p);
+75 fn Pick[T: Hashable & Eq where .Key = i32](t: T) -> T.Key;
+76 fn Iter() -> Vector(T).Iterator;
+77 if (T == Point and x impls Hashable) {}
+78 alias lower = i32;
+79 var l: lower = a * b;
diff --git a/utils/textmate/Syntaxes/carbon.tmLanguage b/utils/textmate/Syntaxes/carbon.tmLanguage
index f68fa1fbbec8..ab1ea0fd5658 100644
--- a/utils/textmate/Syntaxes/carbon.tmLanguage
+++ b/utils/textmate/Syntaxes/carbon.tmLanguage
@@ -39,10 +39,26 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
include
#strings
+
+ include
+ #builtin-functions
+
+
+ include
+ #choice-definitions
+
include
#declarations
+
+ include
+ #inheritance
+
+
+ include
+ #type-annotation
+
include
#keywords
@@ -70,6 +86,376 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
repository
+ bindings
+
+ patterns
+
+
+ captures
+
+ 1
+
+ name
+ punctuation.definition.raw-identifier.carbon
+
+ 2
+
+ name
+ variable.parameter.carbon
+
+
+ comment
+ Parameter bindings (`name: Type` when not preceded by `let` or `var`), with `variable.parameter` nested inside `variable.other`.
+ match
+ (?<!\.)(?<!->)\b(r#)?([A-Za-z_][A-Za-z0-9_]*)(?=\s*:(?![=!?]))
+ name
+ variable.other.carbon
+
+
+
+ builtin-functions
+
+ patterns
+
+
+ begin
+ \b(fn)\b(?=[^"/;]*=\s*")
+ beginCaptures
+
+ 1
+
+ name
+ storage.type.carbon
+
+
+ comment
+ A builtin function declaration (`fn ... = "..."`), scoping the string contents as `support.function.builtin`.
+ end
+ (?=;)|$
+ patterns
+
+
+ captures
+
+ 1
+
+ name
+ keyword.operator.carbon
+
+ 2
+
+ name
+ string.quoted.double.carbon
+
+ 3
+
+ name
+ punctuation.definition.string.begin.carbon
+
+ 4
+
+ name
+ support.function.builtin.carbon
+
+ 5
+
+ name
+ punctuation.definition.string.end.carbon
+
+
+ match
+ (=)\s*((")([^"\\\n]*)("))
+
+
+ include
+ #declarations
+
+
+ include
+ #comments
+
+
+ include
+ #strings
+
+
+ include
+ #type-annotation
+
+
+ include
+ #keywords
+
+
+ include
+ #literals
+
+
+ include
+ #numbers
+
+
+ include
+ #operators
+
+
+ include
+ #identifiers
+
+
+ include
+ #punctuation
+
+
+
+
+
+ choice-definitions
+
+ patterns
+
+
+ begin
+ \b(choice)\b
+ beginCaptures
+
+ 1
+
+ name
+ storage.type.carbon
+
+
+ comment
+ A `choice` declaration, scoping names in its body as enum members and closing immediately if there is no body.
+ end
+ (?<=\})|(?=[^\s({])
+ patterns
+
+
+ begin
+ (?<=\bchoice)\s+(?=(?:r#)?[A-Za-z_])
+ end
+ ((?:r#)?[A-Za-z_][A-Za-z0-9_]*)\b(?!\s*(?:\[[^\[\]]*\]\s*)?(?:\([^()]*(?:\([^()]*(?:\([^()]*\)[^()]*)*\)[^()]*)*\)\s*)?\.)|(?=[^\sA-Za-z_])|$
+ endCaptures
+
+ 1
+
+ name
+ entity.name.type.carbon
+
+
+ patterns
+
+
+ include
+ #declared-name-qualifier
+
+
+
+
+ include
+ #comments
+
+
+ begin
+ \(
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ comment
+ Choice parameters.
+ end
+ (\))|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ patterns
+
+
+ include
+ #choice-parameters
+
+
+
+
+ begin
+ \{
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.block.begin.bracket.curly.carbon
+
+
+ comment
+ Choice body.
+ end
+ (\})|(?=[;=])
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.block.end.bracket.curly.carbon
+
+
+ patterns
+
+
+ include
+ #comments
+
+
+ begin
+ \(
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ comment
+ Alternative parameters.
+ end
+ (\))|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ patterns
+
+
+ include
+ #choice-parameters
+
+
+
+
+ begin
+ \[
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.brackets.begin.bracket.square.carbon
+
+
+ comment
+ Invalid implicit parameter list on an alternative, matched so its contents are not scoped as enum members.
+ end
+ (\])|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.brackets.end.bracket.square.carbon
+
+
+ patterns
+
+
+ include
+ #choice-parameters
+
+
+
+
+ include
+ #keywords
+
+
+ include
+ #literals
+
+
+ match
+ \b(?:r#)?[A-Za-z_][A-Za-z0-9_]*\b
+ name
+ variable.other.enummember.carbon
+
+
+ include
+ #numbers
+
+
+ include
+ #operators
+
+
+ include
+ #punctuation
+
+
+
+
+
+
+
+ choice-parameters
+
+ patterns
+
+
+ include
+ #comments
+
+
+ include
+ #strings
+
+
+ include
+ #inheritance
+
+
+ include
+ #type-annotation
+
+
+ include
+ #keywords
+
+
+ include
+ #literals
+
+
+ include
+ #numbers
+
+
+ include
+ #operators
+
+
+ include
+ #identifiers
+
+
+ include
+ #punctuation
+
+
+
comments
patterns
@@ -80,20 +466,23 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
1
name
- punctuation.definition.comment.carbon
+ comment.line.double-slash.carbon
2
+
+ name
+ punctuation.definition.comment.carbon
+
+ 3
name
keyword.other.directive.carbon
comment
- Toolchain directives, which are comments the driver acts on.
+ Toolchain directives. The comment scope sits on a capture rather than on the rule, to leave the leading indentation outside it.
match
- (//)(@(?:dump-sem-ir-(?:begin|end)|include-in-dumps))\b.*$
- name
- comment.line.double-slash.carbon
+ ^\s*((//)(@(?:dump-sem-ir-(?:begin|end)|include-in-dumps)))$
captures
@@ -117,13 +506,13 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
begin
- \b(?:(import)\s+(Cpp)\s+(inline)|(inline)\s+(Cpp))\s*(''')([^\s'\"#]*)
+ \b(?:(import)\s+(Cpp)\s+(inline)|(inline)\s+(Cpp))\s*(''')([^\s'\"#]*)(?:[ \t]*((//)(?:[ \t][^\n]*)?)$)?
beginCaptures
1
name
- storage.type.carbon
+ keyword.control.import.carbon
2
@@ -155,6 +544,16 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
name
entity.name.tag.language.carbon
+ 8
+
+ name
+ comment.line.double-slash.carbon
+
+ 9
+
+ name
+ punctuation.definition.comment.carbon
+
comment
Inline C++, block form.
@@ -172,7 +571,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
2
name
- punctuation.terminator.carbon
+ punctuation.terminator.statement.carbon
patterns
@@ -191,7 +590,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
1
name
- storage.type.carbon
+ keyword.control.import.carbon
2
@@ -235,7 +634,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
2
name
- punctuation.terminator.carbon
+ punctuation.terminator.statement.carbon
patterns
@@ -253,23 +652,78 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
patterns
- captures
+ begin
+ (?<=\bfn)\s+(?=(?:r#)?[A-Za-z_])
+ comment
+ The name a function declaration declares, after any qualifiers, or the `destroy` keyword.
+ end
+ (?:(destroy)|((?:r#)?[A-Za-z_][A-Za-z0-9_]*))\b(?!\s*(?:\[[^\[\]]*\]\s*)?(?:\([^()]*(?:\([^()]*(?:\([^()]*\)[^()]*)*\)[^()]*)*\)\s*)?\.)|(?=[^\sA-Za-z_])|$
+ endCaptures
1
name
- storage.type.carbon
+ keyword.other.carbon
2
name
- entity.name.function.carbon
+ entity.name.function.definition.carbon
+ patterns
+
+
+ include
+ #declared-name-qualifier
+
+
+
+
+ begin
+ (?<=\bclass)\s+(?=(?:r#)?[A-Za-z_])
comment
- Function declarations, including lambdas with a name. `destroy` is a keyword naming a destructor, not a name.
- match
- \b(fn)\s+(?!destroy\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)
+ The name a class declaration declares, given `entity.name.type.class` for themes that color classes apart from other types.
+ end
+ ((?:r#)?[A-Za-z_][A-Za-z0-9_]*)\b(?!\s*(?:\[[^\[\]]*\]\s*)?(?:\([^()]*(?:\([^()]*(?:\([^()]*\)[^()]*)*\)[^()]*)*\)\s*)?\.)|(?=[^\sA-Za-z_])|$
+ endCaptures
+
+ 1
+
+ name
+ entity.name.type.class.carbon
+
+
+ patterns
+
+
+ include
+ #declared-name-qualifier
+
+
+
+
+ begin
+ (?:(?<=\balias)|(?<=\bconstraint)|(?<=\binterface))\s+(?=(?:r#)?[A-Za-z_])
+ comment
+ The name the other nominal type declarations declare.
+ end
+ ((?:r#)?[A-Za-z_][A-Za-z0-9_]*)\b(?!\s*(?:\[[^\[\]]*\]\s*)?(?:\([^()]*(?:\([^()]*(?:\([^()]*\)[^()]*)*\)[^()]*)*\)\s*)?\.)|(?=[^\sA-Za-z_])|$
+ endCaptures
+
+ 1
+
+ name
+ entity.name.type.carbon
+
+
+ patterns
+
+
+ include
+ #declared-name-qualifier
+
+
captures
@@ -282,13 +736,69 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
2
name
- entity.name.type.carbon
+ storage.modifier.carbon
+
+ 3
+
+ name
+ punctuation.definition.raw-identifier.carbon
+
+ 4
+
+ name
+ variable.other.constant.carbon
comment
- Nominal type declarations.
+ `let` and `var` bindings, with optional modifiers before the name. `_` and `self` are left to `#literals`.
match
- \b(alias|choice|class|constraint|interface)\s+((?:r#)?[A-Za-z_][A-Za-z0-9_]*)
+ \b(let)\s+((?:(?:generic|ref|template|unused|var)\s+)*)(?!_\s*:)(r#)?([A-Za-z_][A-Za-z0-9_]*)(?=\s*:(?![=!?]))
+
+
+ captures
+
+ 1
+
+ name
+ storage.type.carbon
+
+ 2
+
+ name
+ storage.modifier.carbon
+
+ 3
+
+ name
+ punctuation.definition.raw-identifier.carbon
+
+ 4
+
+ name
+ variable.other.carbon
+
+
+ match
+ \b(var)\s+((?:(?:generic|ref|template|unused)\s+)*)(?!(?:_|self)\s*:)(r#)?([A-Za-z_][A-Za-z0-9_]*)(?=\s*:(?![=!?]))
+
+
+ captures
+
+ 1
+
+ name
+ keyword.control.import.carbon
+
+ 2
+
+ name
+ entity.name.namespace.carbon
+
+
+ comment
+ Package, namespace, and import names, excluding keywords (`library`, `inline`) and `Core` and `Cpp`.
+ match
+ \b(import)\s+(?!(?:library|inline|Core|Cpp)\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)
captures
@@ -304,10 +814,125 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
entity.name.namespace.carbon
- comment
- Package, namespace, and import names. `library` and `inline` are keywords that may follow `import`, not names.
match
- \b(package|namespace|import)\s+(?!(?:library|inline)\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)
+ \b(package|namespace)\s+(?!(?:library|Core|Cpp)\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)
+
+
+ captures
+
+ 1
+
+ name
+ storage.type.carbon
+
+ 2
+
+ name
+ string.quoted.double.carbon
+
+ 3
+
+ name
+ punctuation.definition.string.begin.carbon
+
+ 4
+
+ name
+ entity.name.namespace.library.carbon
+
+ 5
+
+ name
+ punctuation.definition.string.end.carbon
+
+
+ comment
+ A library name, written as a string, with `entity.name.namespace.library` nested inside the string scope.
+ match
+ \b(library)\s+((")((?:\\.|[^"\\\n])*)("))
+
+
+
+ declared-name-qualifier
+
+ patterns
+
+
+ begin
+ (((?:r#)?[A-Za-z_][A-Za-z0-9_]*))\b(?=\s*(?:\[[^\[\]]*\]\s*)?(?:\([^()]*(?:\([^()]*(?:\([^()]*\)[^()]*)*\)[^()]*)*\)\s*)?\.)
+ beginCaptures
+
+ 1
+
+ name
+ entity.name.type.carbon
+
+ 2
+
+ name
+ entity.name.scope-resolution.carbon
+
+
+ comment
+ One qualifier on a declared name, such as `N.` or `Base(T: type).`, matched when followed by `.` after any parameter lists. `entity.name.scope-resolution` is nested inside `entity.name.type` so themes without a scope-resolution rule fall back to the type color.
+ end
+ (\.)
+ endCaptures
+
+ 1
+
+ name
+ punctuation.separator.dot-access.carbon
+
+
+ patterns
+
+
+ include
+ #type-body
+
+
+
+
+
+ expression-parens
+
+ patterns
+
+
+ begin
+ \(
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ comment
+ Parentheses nested in an expression that sits inside a type, so that only the matching `)` ends the expression.
+ end
+ (\))|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ patterns
+
+
+ include
+ #expression-parens
+
+
+ include
+ $self
+
+
@@ -316,23 +941,8 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
patterns
- captures
-
- 1
-
- name
- punctuation.definition.raw-identifier.carbon
-
- 2
-
- name
- entity.name.type.carbon
-
-
- comment
- Raw identifiers, which suppress keyword meaning.
- match
- \b(r#)([A-Z][A-Za-z0-9_]*)
+ include
+ #bindings
captures
@@ -342,54 +952,309 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
name
punctuation.definition.raw-identifier.carbon
- 2
-
- name
- variable.other.carbon
-
+ comment
+ Raw identifiers.
match
- \b(r#)([a-z_][A-Za-z0-9_]*)
+ \b(r#)([A-Za-z_][A-Za-z0-9_]*)
+ name
+ variable.other.carbon
comment
- An identifier applied to an argument list is a call.
+ Member function call.
+ match
+ (?:(?<=\.)|(?<=\->))[A-Za-z_][A-Za-z0-9_]*(?=\s*\()
+ name
+ entity.name.function.member.carbon
+
+
+ comment
+ Member access via `.` or `->`.
+ match
+ (?:(?<=\.)|(?<=\->))[A-Za-z_][A-Za-z0-9_]*\b
+ name
+ variable.other.property.carbon
+
+
+ comment
+ Function call.
match
\b[A-Za-z_][A-Za-z0-9_]*(?=\s*\()
name
- entity.name.function.carbon
+ entity.name.function.call.carbon
- comment
- UpperCamel names a type.
match
- \b[A-Z][A-Za-z0-9_]*\b
- name
- entity.name.type.carbon
-
-
- comment
- lower_snake names a value.
- match
- \b[a-z_][A-Za-z0-9_]*\b
+ \b[A-Za-z_][A-Za-z0-9_]*\b
name
variable.other.carbon
+ impls-clause
+
+ patterns
+
+
+ begin
+ \b(impls)\b
+ beginCaptures
+
+ 1
+
+ name
+ keyword.operator.expression.impls.carbon
+
+
+ end
+ (?=[,;={}\)\]]|[-+/%!<>|^~?@\\]|//|\b(?:in|and|or|not|as|impls)\b|$)
+ name
+ meta.inheritance-clause.carbon
+ patterns
+
+
+ include
+ #inheritance-body
+
+
+
+
+
+ inheritance
+
+ patterns
+
+
+ begin
+ \b(impl)\b(?!\s*(?:adapt|alias|base|choice|class|constraint|export|fn|impl|import|interface|let|library|match_first|namespace|observe|package|require|var)\b)
+ beginCaptures
+
+ 1
+
+ name
+ storage.type.carbon
+
+
+ comment
+ An `impl` declaration (when `impl` does not precede another declaration keyword), scoping the type before `as` with `#type-body` and the interface after `as` with `#inheritance-body`.
+ end
+ (?=[;{]|$)
+ name
+ meta.type.annotation.carbon
+ patterns
+
+
+ begin
+ \b(as)\b
+ beginCaptures
+
+ 1
+
+ name
+ keyword.operator.expression.as.carbon
+
+
+ end
+ (?=[,;={}\)\]]|[-+/%!<>|^~?@\\]|//|\b(?:in|and|or|not|as|impls)\b|$)
+ name
+ meta.inheritance-clause.carbon
+ patterns
+
+
+ include
+ #inheritance-body
+
+
+
+
+ include
+ #type-body
+
+
+
+
+ begin
+ (?<!\.)\b(base)\s*(:)(?![=!?])
+ beginCaptures
+
+ 1
+
+ name
+ storage.type.carbon
+
+ 2
+
+ name
+ keyword.operator.type.annotation.carbon
+
+
+ comment
+ A `base:` declaration, excluding `.base` member access and `base class`.
+ end
+ (?=[,;={}\)\]]|[-+/%!<>|^~?@\\]|//|\b(?:in|and|or|not|as|impls)\b|$)
+ name
+ meta.inheritance-clause.carbon
+ patterns
+
+
+ include
+ #inheritance-body
+
+
+
+
+ include
+ #impls-clause
+
+
+
+ inheritance-body
+
+ patterns
+
+
+ begin
+ (?<=[A-Za-z0-9_\]])\(
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ comment
+ Only the interface itself is scoped as `entity.other.inherited-class`; its argument list switches to expression scoping.
+ end
+ (\))|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ patterns
+
+
+ include
+ #expression-parens
+
+
+ include
+ $self
+
+
+
+
+ begin
+ \(
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ comment
+ Grouping parentheses around an interface name stay in `#inheritance-body`.
+ end
+ (\))|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ patterns
+
+
+ include
+ #inheritance-body
+
+
+
+
+ begin
+ \b(where)\b
+ beginCaptures
+
+ 1
+
+ name
+ keyword.other.where.carbon
+
+
+ comment
+ A `where` clause switches to expression scoping and ends at a `)` or `]` it did not open.
+ end
+ (?=[;{}\)\]]|$)
+ patterns
+
+
+ include
+ #expression-parens
+
+
+ include
+ $self
+
+
+
+
+ include
+ #keywords
+
+
+ include
+ #literals
+
+
+ comment
+ The final identifier of the interface or base class name; any preceding qualifiers fall through to `#type-body`.
+ match
+ \b(?:r#)?[A-Za-z_][A-Za-z0-9_]*\b(?!\s*\.)
+ name
+ entity.other.inherited-class.carbon
+
+
+ include
+ #type-body
+
+
+
keywords
patterns
+ comment
+ `.base` member access, matched before `base` as an introducer.
match
- \b(adapt|alias|choice|class|constraint|fn|import|inline|interface|let|library|match_first|namespace|observe|require|var)\b
+ (?<=\.)\b(base)\b
+ name
+ keyword.other.base.carbon
+
+
+ match
+ \b(import)\b
+ name
+ keyword.control.import.carbon
+
+
+ match
+ \b(adapt|alias|choice|class|constraint|fn|inline|interface|let|library|match_first|namespace|observe|require|var)\b
name
storage.type.carbon
comment
- `base` introduces a base class declaration unless it modifies one.
+ `base` as an introducer (not `base class`).
match
\b(base)\b(?!\s*class\b)
name
@@ -403,13 +1268,13 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \b(impl)\b(?!\s*(fn|library|package)\b)
+ \b(impl)\b(?!\s*(adapt|alias|base|choice|class|constraint|export|fn|impl|import|interface|let|library|match_first|namespace|observe|package|require|var)\b)
name
storage.type.carbon
comment
- `package` is an introducer unless it begins a qualified name.
+ `package` as an introducer (not `package.`).
match
\b(package)\b(?!\.)
name
@@ -423,7 +1288,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
comment
- `default` is a declaration modifier unless it opens a match arm.
+ `default` as a modifier (not `default =>`).
match
\b(default)\b(?!\s*=>)
name
@@ -443,7 +1308,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \b(impl)\b(?=\s*(fn|library|package)\b)
+ \b(impl)\b(?=\s*(adapt|alias|base|choice|class|constraint|export|fn|impl|import|interface|let|library|match_first|namespace|observe|package|require|var)\b)
name
storage.modifier.carbon
@@ -455,7 +1320,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
comment
- `default` is a match arm here, and a declaration modifier elsewhere.
+ `default` in a `match` clause.
match
\b(default)\b(?=\s*=>)
name
@@ -463,21 +1328,57 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \b(and|as|impls|in|like|not|or|typeof|where)\b
+ \b(and|or)\b
name
keyword.control.carbon
match
- \b(destroy|each|expand|forall|form|friend)\b
+ \b(not)\b
name
- keyword.other.carbon
+ keyword.operator.expression.not.carbon
comment
- `.base` names the base class subobject.
+ Fallback when not matched by `#type-annotation` or `#inheritance`.
match
- (?<=\.)\b(base)\b
+ \b(as)\b
+ name
+ keyword.operator.expression.as.carbon
+
+
+ match
+ \b(impls)\b
+ name
+ keyword.operator.expression.impls.carbon
+
+
+ match
+ \b(in)\b
+ name
+ keyword.operator.expression.in.carbon
+
+
+ match
+ \b(like)\b
+ name
+ keyword.operator.expression.like.carbon
+
+
+ match
+ \b(typeof)\b
+ name
+ keyword.operator.expression.typeof.carbon
+
+
+ match
+ \b(where)\b
+ name
+ keyword.other.where.carbon
+
+
+ match
+ \b(destroy|each|expand|forall|form|friend)\b
name
keyword.other.carbon
@@ -503,7 +1404,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
comment
- Language-provided package roots.
+ Built-in package names.
match
\b(Core|Cpp)\b
name
@@ -511,7 +1412,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
comment
- `package` as a qualified-name root names the current package.
+ `package` as a qualifier.
match
\b(package)\b(?=\.)
name
@@ -525,17 +1426,23 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \b(array|auto|bool|char|str|type)\b
+ \b(array|auto|type)\b
name
support.type.builtin.carbon
+
+ match
+ \b(bool|char|str)\b
+ name
+ support.type.primitive.carbon
+
comment
- Integer and float type literals. The lexer accepts any width, so this must not be restricted to the common ones.
+ Integer and floating-point type literals.
match
\b[iuf][1-9][0-9]*\b
name
- support.type.builtin.carbon
+ support.type.primitive.carbon
@@ -544,26 +1451,72 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
patterns
+ captures
+
+ 1
+
+ name
+ keyword.other.unit.hexadecimal.carbon
+
+
+ comment
+ Each numeric rule matches a full alphanumeric word starting with a digit so a malformed suffix is not split into an identifier. Real literals exclude a leading `.` or `->` so tuple access like `t.0.1` is not matched as a real.
match
- \b0x[_0-9A-Fa-f]*(?:\.[_0-9A-Fa-f]*)?(?:[pP][-+]?[0-9]+)?
+ (?<!\.)(?<!->)\b(0x)[_0-9A-Za-z]*\.[0-9A-Za-z][_0-9A-Za-z]*(?:(?<=[a-z])[-+][0-9A-Za-z][_0-9A-Za-z]*)?
name
constant.numeric.hex.carbon
+ captures
+
+ 1
+
+ name
+ keyword.other.unit.hexadecimal.carbon
+
+
match
- \b0o[_0-7]*
+ \b(0x)[_0-9A-Za-z]*
+ name
+ constant.numeric.hex.carbon
+
+
+ captures
+
+ 1
+
+ name
+ keyword.other.unit.octal.carbon
+
+
+ match
+ \b(0o)[_0-9A-Za-z]*
name
constant.numeric.octal.carbon
+ captures
+
+ 1
+
+ name
+ keyword.other.unit.binary.carbon
+
+
match
- \b0b[_01]*
+ \b(0b)[_0-9A-Za-z]*
name
constant.numeric.binary.carbon
match
- \b[0-9][_0-9]*(?:\.[_0-9]+)?(?:[eE][-+]?[0-9]+)?
+ (?<!\.)(?<!->)\b[0-9][_0-9A-Za-z]*\.[0-9A-Za-z][_0-9A-Za-z]*(?:(?<=[a-z])[-+][0-9A-Za-z][_0-9A-Za-z]*)?
+ name
+ constant.numeric.decimal.carbon
+
+
+ match
+ \b[0-9][_0-9A-Za-z]*
name
constant.numeric.decimal.carbon
@@ -583,7 +1536,51 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- (\->\?|>>=|<=>|<<=|\&=|\^=|:=|:\?|==|=>|!=|>=|>>|<=|<>|<<|<\-|\-=|\->|\-\-|%=|\|=|\+=|\+\+|/=|\*=|\~=|\&|@|\^|:|=|!|>|<|\-|%|\.|\||\+|\?|/|\*|\~|\\)
+ :!
+ name
+ keyword.operator.type.annotation.symbolic.carbon
+
+
+ match
+ :\?
+ name
+ keyword.operator.type.annotation.form.carbon
+
+
+ match
+ :(?![=!?])
+ name
+ keyword.operator.type.annotation.carbon
+
+
+ comment
+ `->` directly after an operand is pointer member access rather than a return type arrow.
+ match
+ (?<=[A-Za-z0-9_)\]}])\->(?!\?)
+ name
+ punctuation.separator.pointer-access.carbon
+
+
+ match
+ \->\?
+ name
+ keyword.operator.function-result.form.carbon
+
+
+ match
+ \->(?!\?)
+ name
+ keyword.operator.function-result.carbon
+
+
+ match
+ =>
+ name
+ keyword.operator.arrow.fat.carbon
+
+
+ match
+ <=>|<<=|>>=|==|!=|<=|>=|<<|>>|\+\+|--|\+=|-=|\*=|/=|%=|&=|\|=|\^=|~=|:=|<-|<>|[-+*/%&|^~!<>=@?\\]
name
keyword.operator.carbon
@@ -593,17 +1590,59 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
patterns
+
+ match
+ \(
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ match
+ \)
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ match
+ \{
+ name
+ punctuation.section.block.begin.bracket.curly.carbon
+
+
+ match
+ \}
+ name
+ punctuation.section.block.end.bracket.curly.carbon
+
+
+ match
+ \[
+ name
+ punctuation.section.brackets.begin.bracket.square.carbon
+
+
+ match
+ \]
+ name
+ punctuation.section.brackets.end.bracket.square.carbon
+
+
+ match
+ \.
+ name
+ punctuation.separator.dot-access.carbon
+
match
,
name
- punctuation.separator.carbon
+ punctuation.separator.comma.carbon
match
;
name
- punctuation.terminator.carbon
+ punctuation.terminator.statement.carbon
@@ -613,7 +1652,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \\(?:[tnr0'\"\\]|x[0-9A-Fa-f]{2}|u\{[0-9A-Fa-f]+\})
+ \\(?:[tnr0'\"\\]|x[0-9A-F]{2}|u\{[0-9A-F]+\})
name
constant.character.escape.carbon
@@ -625,7 +1664,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \\#(?:[tnr0'\"\\]|x[0-9A-Fa-f]{2}|u\{[0-9A-Fa-f]+\})
+ \\#(?:[tnr0'\"\\]|x[0-9A-F]{2}|u\{[0-9A-F]+\})
name
constant.character.escape.carbon
@@ -637,7 +1676,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \\##(?:[tnr0'\"\\]|x[0-9A-Fa-f]{2}|u\{[0-9A-Fa-f]+\})
+ \\##(?:[tnr0'\"\\]|x[0-9A-F]{2}|u\{[0-9A-F]+\})
name
constant.character.escape.carbon
@@ -649,7 +1688,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
match
- \\#{3,}(?:[tnr0'\"\\]|x[0-9A-Fa-f]{2}|u\{[0-9A-Fa-f]+\})
+ \\#{3,}(?:[tnr0'\"\\]|x[0-9A-F]{2}|u\{[0-9A-F]+\})
name
constant.character.escape.carbon
@@ -661,7 +1700,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
begin
- (#{3,})(''')([^\s'\"#]*)
+ (#{3,})(''')([^\s'\"#]*)(?:[ \t]*((//)(?:[ \t][^\n]*)?)$)?
beginCaptures
1
@@ -679,6 +1718,16 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
name
entity.name.tag.language.carbon
+ 4
+
+ name
+ comment.line.double-slash.carbon
+
+ 5
+
+ name
+ punctuation.definition.comment.carbon
+
comment
Block string literal, with an optional file type indicator, raw at `###` level.
@@ -704,7 +1753,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
begin
- (##)(''')([^\s'\"#]*)
+ (##)(''')([^\s'\"#]*)(?:[ \t]*((//)(?:[ \t][^\n]*)?)$)?
beginCaptures
1
@@ -722,6 +1771,16 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
name
entity.name.tag.language.carbon
+ 4
+
+ name
+ comment.line.double-slash.carbon
+
+ 5
+
+ name
+ punctuation.definition.comment.carbon
+
comment
Block string literal, with an optional file type indicator, raw at `##` level.
@@ -747,7 +1806,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
begin
- (#)(''')([^\s'\"#]*)
+ (#)(''')([^\s'\"#]*)(?:[ \t]*((//)(?:[ \t][^\n]*)?)$)?
beginCaptures
1
@@ -765,6 +1824,16 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
name
entity.name.tag.language.carbon
+ 4
+
+ name
+ comment.line.double-slash.carbon
+
+ 5
+
+ name
+ punctuation.definition.comment.carbon
+
comment
Block string literal, with an optional file type indicator, raw at `#` level.
@@ -790,7 +1859,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
begin
- (''')([^\s'\"#]*)
+ (''')([^\s'\"#]*)(?:[ \t]*((//)(?:[ \t][^\n]*)?)$)?
beginCaptures
1
@@ -803,6 +1872,16 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
name
entity.name.tag.language.carbon
+ 3
+
+ name
+ comment.line.double-slash.carbon
+
+ 4
+
+ name
+ punctuation.definition.comment.carbon
+
comment
Block string literal, with an optional file type indicator.
@@ -828,7 +1907,7 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
begin
- (""")([^\s'\"#]*)
+ (""")([^\s'\"#]*)(?:[ \t]*((//)(?:[ \t][^\n]*)?)$)?
beginCaptures
1
@@ -841,6 +1920,16 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
name
entity.name.tag.language.carbon
+ 3
+
+ name
+ comment.line.double-slash.carbon
+
+ 4
+
+ name
+ punctuation.definition.comment.carbon
+
comment
A `"""` block is always an error, but highlighting it as a block string keeps the rest of the file readable.
@@ -1046,6 +2135,285 @@ THIS FILE IS AUTOGENERATED FROM carbon.tmLanguage.json. DO NOT EDIT.
+ type-annotation
+
+ patterns
+
+
+ begin
+ (:!)|(:\?)|(:(?![=!?]))|((?<![A-Za-z0-9_)\]}])\->\?)|((?<![A-Za-z0-9_)\]}])\->(?!\?))|\b(as)\b|\b(adapt)\b|\b(require)\b
+ beginCaptures
+
+ 1
+
+ name
+ keyword.operator.type.annotation.symbolic.carbon
+
+ 2
+
+ name
+ keyword.operator.type.annotation.form.carbon
+
+ 3
+
+ name
+ keyword.operator.type.annotation.carbon
+
+ 4
+
+ name
+ keyword.operator.function-result.form.carbon
+
+ 5
+
+ name
+ keyword.operator.function-result.carbon
+
+ 6
+
+ name
+ keyword.operator.expression.as.carbon
+
+ 7
+
+ name
+ storage.type.carbon
+
+ 8
+
+ name
+ storage.type.carbon
+
+
+ comment
+ A type expression, from the token that introduces it to the first token that cannot continue one.
+ end
+ (?=[,;={}\)\]]|[-+/%!<>|^~?@\\]|//|\b(?:in|and|or|not|as|impls)\b|$)
+ name
+ meta.type.annotation.carbon
+ patterns
+
+
+ include
+ #type-body
+
+
+
+
+
+ type-body
+
+ patterns
+
+
+ begin
+ \(
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ comment
+ Argument and grouping parentheses, which nest rather than ending the type.
+ end
+ (\))|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ patterns
+
+
+ include
+ #type-body
+
+
+
+
+ begin
+ \[
+ beginCaptures
+
+ 0
+
+ name
+ punctuation.section.brackets.begin.bracket.square.carbon
+
+
+ end
+ (\])|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.brackets.end.bracket.square.carbon
+
+
+ patterns
+
+
+ include
+ #type-body
+
+
+
+
+ begin
+ \bwhere\b
+ beginCaptures
+
+ 0
+
+ name
+ keyword.other.where.carbon
+
+
+ comment
+ A `where` clause switches to expression scoping so `=` does not end the enclosing type as an initializer, and ends at a `)` or `]` it did not open.
+ end
+ (?=[;{}\)\]]|$)
+ patterns
+
+
+ include
+ #expression-parens
+
+
+ include
+ $self
+
+
+
+
+ include
+ #impls-clause
+
+
+ include
+ #comments
+
+
+ include
+ #strings
+
+
+ begin
+ \b(typeof)\s*(\()
+ beginCaptures
+
+ 1
+
+ name
+ keyword.operator.expression.typeof.carbon
+
+ 2
+
+ name
+ punctuation.section.parens.begin.bracket.round.carbon
+
+
+ comment
+ `typeof` takes an expression operand, switching out of `#type-body`.
+ end
+ (\))|$
+ endCaptures
+
+ 1
+
+ name
+ punctuation.section.parens.end.bracket.round.carbon
+
+
+ patterns
+
+
+ include
+ #expression-parens
+
+
+ include
+ $self
+
+
+
+
+ include
+ #keywords
+
+
+ include
+ #literals
+
+
+ include
+ #numbers
+
+
+ comment
+ Pointer `*`, written directly after the pointee type.
+ match
+ (?<=[A-Za-z0-9_)\]*])\*(?!=)
+ name
+ keyword.operator.type.pointer.carbon
+
+
+ include
+ #operators
+
+
+ include
+ #bindings
+
+
+ captures
+
+ 1
+
+ name
+ entity.name.scope-resolution.carbon
+
+
+ comment
+ A qualifier in a type, which `#declared-name-qualifier` scopes the same way on a declared name.
+ match
+ (?:(?<=[A-Za-z0-9_)\]]\.)|(?<!\.))\b((?:r#)?[A-Za-z_][A-Za-z0-9_]*)\b(?=\s*(?:\[[^\[\]]*\]\s*)?(?:\([^()]*(?:\([^()]*(?:\([^()]*\)[^()]*)*\)[^()]*)*\)\s*)?\.)
+ name
+ entity.name.type.carbon
+
+
+ captures
+
+ 1
+
+ name
+ punctuation.definition.raw-identifier.carbon
+
+
+ comment
+ Unqualified names and qualified member names in a type context. A `.` with no preceding qualifier (such as a struct field `.x`) is left to `#identifiers`.
+ match
+ (?:(?<=[A-Za-z0-9_)\]]\.)|(?<!\.))\b(r#)?[A-Za-z_][A-Za-z0-9_]*\b
+ name
+ entity.name.type.carbon
+
+
+ include
+ #identifiers
+
+
+ include
+ #punctuation
+
+
+
scopeName
source.carbon
diff --git a/utils/textmate/render_sample.py b/utils/textmate/render_sample.py
index e815365fd63a..cdb79be58814 100755
--- a/utils/textmate/render_sample.py
+++ b/utils/textmate/render_sample.py
@@ -36,10 +36,12 @@ _GRAMMAR_PATH = (
)
# A theme built for this grammar rather than taken from an editor. Each family
-# of related scopes gets one color, and bold and italic distinguish the scopes
-# within a family, so every scope the grammar emits renders differently and a
-# change to what it scopes is visible in the rendering. A scope with no entry of
-# its own takes its family's. The colors are Catppuccin Mocha's.
+# of related scopes gets one color, and bold, italic, and underline distinguish
+# the scopes within a family. Every scope the grammar picks from context renders
+# differently, so a change to what it scopes is visible in the rendering. Scopes
+# that follow from the spelling alone, such as a bracket's shape, can share a
+# rendering, since the text already shows them. A scope with no entry of its own
+# takes its family's. The colors are Catppuccin Mocha's.
_COLORS = {
"comment": "#7f849c",
"punctuation.definition.comment": "#7f849c",
@@ -53,10 +55,17 @@ _COLORS = {
"entity.name.type": "#f9e2af",
"support.type": "#f9e2af",
"support.class": "#f9e2af",
+ "entity.other.inherited-class": "#f9e2af",
"entity.name.namespace": "#f5e0dc",
+ "entity.name.scope-resolution": "#f5e0dc",
"entity.name.tag": "#f5e0dc",
"entity.name.function": "#89b4fa",
+ "support.function": "#89b4fa",
"variable": "#cdd6f4",
+ # Members of something else: a field or other member read through `.` or
+ # `->`, and a choice's alternatives.
+ "variable.other.property": "#eba0ac",
+ "variable.other.enummember": "#eba0ac",
"string": "#a6e3a1",
"constant.character.escape": "#f5c2e7",
"constant.numeric": "#fab387",
@@ -76,14 +85,25 @@ _STYLES = {
"storage.modifier": "italic",
"constant.language": "bold",
"keyword.other": "italic",
+ "keyword.operator.type.pointer": "bold",
"punctuation.terminator": "bold",
"punctuation.definition.string": "italic",
"punctuation.definition.raw-identifier": "bold italic",
"support.type": "italic",
"support.class": "bold",
+ "entity.name.type.class": "bold italic",
+ "entity.other.inherited-class": "underline",
+ "entity.name.namespace.library": "bold",
+ "entity.name.scope-resolution": "bold italic",
"entity.name.tag": "italic",
+ "entity.name.function.definition": "bold",
+ "entity.name.function.member": "italic",
+ "support.function": "bold italic",
"variable.parameter": "italic",
"variable.language": "bold",
+ "variable.other.constant": "bold italic",
+ "variable.other.property": "italic",
+ "variable.other.enummember": "bold",
"string.quoted.single": "italic",
"string.quoted.triple": "bold",
"constant.character.escape": "",
diff --git a/utils/textmate/tmlanguage.py b/utils/textmate/tmlanguage.py
index 3cdcfe5657cc..6b6649032c33 100644
--- a/utils/textmate/tmlanguage.py
+++ b/utils/textmate/tmlanguage.py
@@ -234,30 +234,42 @@ def _append_capture_tokens(
group's text takes on top of `scopes`; group `"0"` is the whole match. The
tokens tile the match with no gaps: text not covered by a listed group is
still appended, under `scopes` alone.
+
+ Groups nest, so the scopes do too: text inside `((//)(@x))` carries the
+ scope of group 1 and then the scope of whichever of 2 and 3 covers it.
+ Enclosing groups have the lower number, which is what puts them lower in
+ the stack.
"""
if not captures:
_append_token(tokens, linenum, match.start(), match.end(), scopes)
return
- pos = match.start()
+ spans = []
for group in range((match.re.groups or 0) + 1):
spec = captures.get(str(group))
- # Skip a group the grammar does not name, one that did not
- # participate in the match (`start` is then -1), and one that lies
- # behind text already appended, since tokens come out in order.
- if spec is None or match.start(group) < pos:
+ start, end = match.span(group)
+ # Skip a group the grammar does not name, one that did not participate
+ # in the match, whose `start` is then -1, and one that matched empty.
+ if spec is None or start < 0 or start == end:
continue
- if match.start(group) == match.end(group):
- continue
- _append_token(tokens, linenum, pos, match.start(group), scopes)
+ spans.append((start, end, spec["name"]))
+ edges = sorted(
+ {match.start(), match.end()}.union(
+ point for start, end, _ in spans for point in (start, end)
+ )
+ )
+ for start, end in zip(edges, edges[1:]):
_append_token(
tokens,
linenum,
- match.start(group),
- match.end(group),
- scopes + [spec["name"]],
+ start,
+ end,
+ scopes
+ + [
+ name
+ for span_start, span_end, name in spans
+ if span_start <= start and end <= span_end
+ ],
)
- pos = match.end(group)
- _append_token(tokens, linenum, pos, match.end(), scopes)
def _push_scope(
diff --git a/utils/vscode/carbon.tmLanguage.json b/utils/vscode/carbon.tmLanguage.json
index 6b1ff9918ccd..2d58b7ed493d 100644
--- a/utils/vscode/carbon.tmLanguage.json
+++ b/utils/vscode/carbon.tmLanguage.json
@@ -10,7 +10,11 @@
{ "include": "#comments" },
{ "include": "#cpp-inline" },
{ "include": "#strings" },
+ { "include": "#builtin-functions" },
+ { "include": "#choice-definitions" },
{ "include": "#declarations" },
+ { "include": "#inheritance" },
+ { "include": "#type-annotation" },
{ "include": "#keywords" },
{ "include": "#literals" },
{ "include": "#numbers" },
@@ -22,12 +26,12 @@
"comments": {
"patterns": [
{
- "comment": "Toolchain directives, which are comments the driver acts on.",
- "name": "comment.line.double-slash.carbon",
- "match": "(//)(@(?:dump-sem-ir-(?:begin|end)|include-in-dumps))\\b.*$",
+ "comment": "Toolchain directives. The comment scope sits on a capture rather than on the rule, to leave the leading indentation outside it.",
+ "match": "^\\s*((//)(@(?:dump-sem-ir-(?:begin|end)|include-in-dumps)))$",
"captures": {
- "1": { "name": "punctuation.definition.comment.carbon" },
- "2": { "name": "keyword.other.directive.carbon" }
+ "1": { "name": "comment.line.double-slash.carbon" },
+ "2": { "name": "punctuation.definition.comment.carbon" },
+ "3": { "name": "keyword.other.directive.carbon" }
}
},
{
@@ -43,20 +47,22 @@
"patterns": [
{
"comment": "Inline C++, block form.",
- "begin": "\\b(?:(import)\\s+(Cpp)\\s+(inline)|(inline)\\s+(Cpp))\\s*(''')([^\\s'\\\"#]*)",
+ "begin": "\\b(?:(import)\\s+(Cpp)\\s+(inline)|(inline)\\s+(Cpp))\\s*(''')([^\\s'\\\"#]*)(?:[ \\t]*((//)(?:[ \\t][^\\n]*)?)$)?",
"end": "(''')\\s*(;)?",
"beginCaptures": {
- "1": { "name": "storage.type.carbon" },
+ "1": { "name": "keyword.control.import.carbon" },
"2": { "name": "support.class.carbon" },
"3": { "name": "storage.type.carbon" },
"4": { "name": "storage.type.carbon" },
"5": { "name": "support.class.carbon" },
"6": { "name": "punctuation.definition.string.begin.carbon" },
- "7": { "name": "entity.name.tag.language.carbon" }
+ "7": { "name": "entity.name.tag.language.carbon" },
+ "8": { "name": "comment.line.double-slash.carbon" },
+ "9": { "name": "punctuation.definition.comment.carbon" }
},
"endCaptures": {
"1": { "name": "punctuation.definition.string.end.carbon" },
- "2": { "name": "punctuation.terminator.carbon" }
+ "2": { "name": "punctuation.terminator.statement.carbon" }
},
"contentName": "meta.embedded.block.cpp",
"patterns": [{ "include": "source.cpp" }]
@@ -66,7 +72,7 @@
"begin": "\\b(?:(import)\\s+(Cpp)\\s+(inline)|(inline)\\s+(Cpp))\\s*(\")",
"end": "(\")\\s*(;)?",
"beginCaptures": {
- "1": { "name": "storage.type.carbon" },
+ "1": { "name": "keyword.control.import.carbon" },
"2": { "name": "support.class.carbon" },
"3": { "name": "storage.type.carbon" },
"4": { "name": "storage.type.carbon" },
@@ -75,7 +81,7 @@
},
"endCaptures": {
"1": { "name": "punctuation.definition.string.end.carbon" },
- "2": { "name": "punctuation.terminator.carbon" }
+ "2": { "name": "punctuation.terminator.statement.carbon" }
},
"contentName": "meta.embedded.inline.cpp",
"patterns": [{ "include": "source.cpp" }]
@@ -87,12 +93,14 @@
{
"comment": "Block string literal, with an optional file type indicator, raw at `###` level.",
"name": "string.quoted.triple.carbon",
- "begin": "(#{3,})(''')([^\\s'\\\"#]*)",
+ "begin": "(#{3,})(''')([^\\s'\\\"#]*)(?:[ \\t]*((//)(?:[ \\t][^\\n]*)?)$)?",
"end": "(''')\\1",
"beginCaptures": {
"1": { "name": "punctuation.definition.string.begin.carbon" },
"2": { "name": "punctuation.definition.string.begin.carbon" },
- "3": { "name": "entity.name.tag.language.carbon" }
+ "3": { "name": "entity.name.tag.language.carbon" },
+ "4": { "name": "comment.line.double-slash.carbon" },
+ "5": { "name": "punctuation.definition.comment.carbon" }
},
"endCaptures": {
"1": { "name": "punctuation.definition.string.end.carbon" }
@@ -102,12 +110,14 @@
{
"comment": "Block string literal, with an optional file type indicator, raw at `##` level.",
"name": "string.quoted.triple.carbon",
- "begin": "(##)(''')([^\\s'\\\"#]*)",
+ "begin": "(##)(''')([^\\s'\\\"#]*)(?:[ \\t]*((//)(?:[ \\t][^\\n]*)?)$)?",
"end": "('''##)",
"beginCaptures": {
"1": { "name": "punctuation.definition.string.begin.carbon" },
"2": { "name": "punctuation.definition.string.begin.carbon" },
- "3": { "name": "entity.name.tag.language.carbon" }
+ "3": { "name": "entity.name.tag.language.carbon" },
+ "4": { "name": "comment.line.double-slash.carbon" },
+ "5": { "name": "punctuation.definition.comment.carbon" }
},
"endCaptures": {
"1": { "name": "punctuation.definition.string.end.carbon" }
@@ -117,12 +127,14 @@
{
"comment": "Block string literal, with an optional file type indicator, raw at `#` level.",
"name": "string.quoted.triple.carbon",
- "begin": "(#)(''')([^\\s'\\\"#]*)",
+ "begin": "(#)(''')([^\\s'\\\"#]*)(?:[ \\t]*((//)(?:[ \\t][^\\n]*)?)$)?",
"end": "('''#)",
"beginCaptures": {
"1": { "name": "punctuation.definition.string.begin.carbon" },
"2": { "name": "punctuation.definition.string.begin.carbon" },
- "3": { "name": "entity.name.tag.language.carbon" }
+ "3": { "name": "entity.name.tag.language.carbon" },
+ "4": { "name": "comment.line.double-slash.carbon" },
+ "5": { "name": "punctuation.definition.comment.carbon" }
},
"endCaptures": {
"1": { "name": "punctuation.definition.string.end.carbon" }
@@ -132,11 +144,13 @@
{
"comment": "Block string literal, with an optional file type indicator.",
"name": "string.quoted.triple.carbon",
- "begin": "(''')([^\\s'\\\"#]*)",
+ "begin": "(''')([^\\s'\\\"#]*)(?:[ \\t]*((//)(?:[ \\t][^\\n]*)?)$)?",
"end": "(''')",
"beginCaptures": {
"1": { "name": "punctuation.definition.string.begin.carbon" },
- "2": { "name": "entity.name.tag.language.carbon" }
+ "2": { "name": "entity.name.tag.language.carbon" },
+ "3": { "name": "comment.line.double-slash.carbon" },
+ "4": { "name": "punctuation.definition.comment.carbon" }
},
"endCaptures": {
"1": { "name": "punctuation.definition.string.end.carbon" }
@@ -146,11 +160,13 @@
{
"comment": "A `\"\"\"` block is always an error, but highlighting it as a block string keeps the rest of the file readable.",
"name": "string.quoted.triple.carbon",
- "begin": "(\"\"\")([^\\s'\\\"#]*)",
+ "begin": "(\"\"\")([^\\s'\\\"#]*)(?:[ \\t]*((//)(?:[ \\t][^\\n]*)?)$)?",
"end": "(\"\"\")",
"beginCaptures": {
"1": { "name": "punctuation.definition.string.begin.carbon" },
- "2": { "name": "entity.name.tag.language.carbon" }
+ "2": { "name": "entity.name.tag.language.carbon" },
+ "3": { "name": "comment.line.double-slash.carbon" },
+ "4": { "name": "punctuation.definition.comment.carbon" }
},
"endCaptures": {
"1": { "name": "punctuation.definition.string.end.carbon" }
@@ -231,7 +247,7 @@
"patterns": [
{
"name": "constant.character.escape.carbon",
- "match": "\\\\(?:[tnr0'\\\"\\\\]|x[0-9A-Fa-f]{2}|u\\{[0-9A-Fa-f]+\\})"
+ "match": "\\\\(?:[tnr0'\\\"\\\\]|x[0-9A-F]{2}|u\\{[0-9A-F]+\\})"
}
]
},
@@ -239,7 +255,7 @@
"patterns": [
{
"name": "constant.character.escape.carbon",
- "match": "\\\\#(?:[tnr0'\\\"\\\\]|x[0-9A-Fa-f]{2}|u\\{[0-9A-Fa-f]+\\})"
+ "match": "\\\\#(?:[tnr0'\\\"\\\\]|x[0-9A-F]{2}|u\\{[0-9A-F]+\\})"
}
]
},
@@ -247,7 +263,7 @@
"patterns": [
{
"name": "constant.character.escape.carbon",
- "match": "\\\\##(?:[tnr0'\\\"\\\\]|x[0-9A-Fa-f]{2}|u\\{[0-9A-Fa-f]+\\})"
+ "match": "\\\\##(?:[tnr0'\\\"\\\\]|x[0-9A-F]{2}|u\\{[0-9A-F]+\\})"
}
]
},
@@ -255,46 +271,383 @@
"patterns": [
{
"name": "constant.character.escape.carbon",
- "match": "\\\\#{3,}(?:[tnr0'\\\"\\\\]|x[0-9A-Fa-f]{2}|u\\{[0-9A-Fa-f]+\\})"
+ "match": "\\\\#{3,}(?:[tnr0'\\\"\\\\]|x[0-9A-F]{2}|u\\{[0-9A-F]+\\})"
+ }
+ ]
+ },
+ "builtin-functions": {
+ "patterns": [
+ {
+ "comment": "A builtin function declaration (`fn ... = \"...\"`), scoping the string contents as `support.function.builtin`.",
+ "begin": "\\b(fn)\\b(?=[^\"/;]*=\\s*\")",
+ "beginCaptures": {
+ "1": { "name": "storage.type.carbon" }
+ },
+ "end": "(?=;)|$",
+ "patterns": [
+ {
+ "match": "(=)\\s*((\")([^\"\\\\\\n]*)(\"))",
+ "captures": {
+ "1": { "name": "keyword.operator.carbon" },
+ "2": { "name": "string.quoted.double.carbon" },
+ "3": { "name": "punctuation.definition.string.begin.carbon" },
+ "4": { "name": "support.function.builtin.carbon" },
+ "5": { "name": "punctuation.definition.string.end.carbon" }
+ }
+ },
+ { "include": "#declarations" },
+ { "include": "#comments" },
+ { "include": "#strings" },
+ { "include": "#type-annotation" },
+ { "include": "#keywords" },
+ { "include": "#literals" },
+ { "include": "#numbers" },
+ { "include": "#operators" },
+ { "include": "#identifiers" },
+ { "include": "#punctuation" }
+ ]
}
]
},
"declarations": {
"patterns": [
{
- "comment": "Function declarations, including lambdas with a name. `destroy` is a keyword naming a destructor, not a name.",
- "match": "\\b(fn)\\s+(?!destroy\\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)",
+ "comment": "The name a function declaration declares, after any qualifiers, or the `destroy` keyword.",
+ "begin": "(?<=\\bfn)\\s+(?=(?:r#)?[A-Za-z_])",
+ "end": "(?:(destroy)|((?:r#)?[A-Za-z_][A-Za-z0-9_]*))\\b(?!\\s*(?:\\[[^\\[\\]]*\\]\\s*)?(?:\\([^()]*(?:\\([^()]*(?:\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*)?\\.)|(?=[^\\sA-Za-z_])|$",
+ "endCaptures": {
+ "1": { "name": "keyword.other.carbon" },
+ "2": { "name": "entity.name.function.definition.carbon" }
+ },
+ "patterns": [{ "include": "#declared-name-qualifier" }]
+ },
+ {
+ "comment": "The name a class declaration declares, given `entity.name.type.class` for themes that color classes apart from other types.",
+ "begin": "(?<=\\bclass)\\s+(?=(?:r#)?[A-Za-z_])",
+ "end": "((?:r#)?[A-Za-z_][A-Za-z0-9_]*)\\b(?!\\s*(?:\\[[^\\[\\]]*\\]\\s*)?(?:\\([^()]*(?:\\([^()]*(?:\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*)?\\.)|(?=[^\\sA-Za-z_])|$",
+ "endCaptures": {
+ "1": { "name": "entity.name.type.class.carbon" }
+ },
+ "patterns": [{ "include": "#declared-name-qualifier" }]
+ },
+ {
+ "comment": "The name the other nominal type declarations declare.",
+ "begin": "(?:(?<=\\balias)|(?<=\\bconstraint)|(?<=\\binterface))\\s+(?=(?:r#)?[A-Za-z_])",
+ "end": "((?:r#)?[A-Za-z_][A-Za-z0-9_]*)\\b(?!\\s*(?:\\[[^\\[\\]]*\\]\\s*)?(?:\\([^()]*(?:\\([^()]*(?:\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*)?\\.)|(?=[^\\sA-Za-z_])|$",
+ "endCaptures": {
+ "1": { "name": "entity.name.type.carbon" }
+ },
+ "patterns": [{ "include": "#declared-name-qualifier" }]
+ },
+ {
+ "comment": "`let` and `var` bindings, with optional modifiers before the name. `_` and `self` are left to `#literals`.",
+ "match": "\\b(let)\\s+((?:(?:generic|ref|template|unused|var)\\s+)*)(?!_\\s*:)(r#)?([A-Za-z_][A-Za-z0-9_]*)(?=\\s*:(?![=!?]))",
"captures": {
"1": { "name": "storage.type.carbon" },
- "2": { "name": "entity.name.function.carbon" }
+ "2": { "name": "storage.modifier.carbon" },
+ "3": { "name": "punctuation.definition.raw-identifier.carbon" },
+ "4": { "name": "variable.other.constant.carbon" }
}
},
{
- "comment": "Nominal type declarations.",
- "match": "\\b(alias|choice|class|constraint|interface)\\s+((?:r#)?[A-Za-z_][A-Za-z0-9_]*)",
+ "match": "\\b(var)\\s+((?:(?:generic|ref|template|unused)\\s+)*)(?!(?:_|self)\\s*:)(r#)?([A-Za-z_][A-Za-z0-9_]*)(?=\\s*:(?![=!?]))",
"captures": {
"1": { "name": "storage.type.carbon" },
- "2": { "name": "entity.name.type.carbon" }
+ "2": { "name": "storage.modifier.carbon" },
+ "3": { "name": "punctuation.definition.raw-identifier.carbon" },
+ "4": { "name": "variable.other.carbon" }
}
},
{
- "comment": "Package, namespace, and import names. `library` and `inline` are keywords that may follow `import`, not names.",
- "match": "\\b(package|namespace|import)\\s+(?!(?:library|inline)\\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)",
+ "comment": "Package, namespace, and import names, excluding keywords (`library`, `inline`) and `Core` and `Cpp`.",
+ "match": "\\b(import)\\s+(?!(?:library|inline|Core|Cpp)\\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)",
+ "captures": {
+ "1": { "name": "keyword.control.import.carbon" },
+ "2": { "name": "entity.name.namespace.carbon" }
+ }
+ },
+ {
+ "match": "\\b(package|namespace)\\s+(?!(?:library|Core|Cpp)\\b)((?:r#)?[A-Za-z_][A-Za-z0-9_]*)",
"captures": {
"1": { "name": "storage.type.carbon" },
"2": { "name": "entity.name.namespace.carbon" }
}
+ },
+ {
+ "comment": "A library name, written as a string, with `entity.name.namespace.library` nested inside the string scope.",
+ "match": "\\b(library)\\s+((\")((?:\\\\.|[^\"\\\\\\n])*)(\"))",
+ "captures": {
+ "1": { "name": "storage.type.carbon" },
+ "2": { "name": "string.quoted.double.carbon" },
+ "3": { "name": "punctuation.definition.string.begin.carbon" },
+ "4": { "name": "entity.name.namespace.library.carbon" },
+ "5": { "name": "punctuation.definition.string.end.carbon" }
+ }
}
]
},
+ "declared-name-qualifier": {
+ "patterns": [
+ {
+ "comment": "One qualifier on a declared name, such as `N.` or `Base(T: type).`, matched when followed by `.` after any parameter lists. `entity.name.scope-resolution` is nested inside `entity.name.type` so themes without a scope-resolution rule fall back to the type color.",
+ "begin": "(((?:r#)?[A-Za-z_][A-Za-z0-9_]*))\\b(?=\\s*(?:\\[[^\\[\\]]*\\]\\s*)?(?:\\([^()]*(?:\\([^()]*(?:\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*)?\\.)",
+ "beginCaptures": {
+ "1": { "name": "entity.name.type.carbon" },
+ "2": { "name": "entity.name.scope-resolution.carbon" }
+ },
+ "end": "(\\.)",
+ "endCaptures": {
+ "1": { "name": "punctuation.separator.dot-access.carbon" }
+ },
+ "patterns": [{ "include": "#type-body" }]
+ }
+ ]
+ },
+ "type-annotation": {
+ "patterns": [
+ {
+ "comment": "A type expression, from the token that introduces it to the first token that cannot continue one.",
+ "name": "meta.type.annotation.carbon",
+ "begin": "(:!)|(:\\?)|(:(?![=!?]))|((?\\?)|((?(?!\\?))|\\b(as)\\b|\\b(adapt)\\b|\\b(require)\\b",
+ "beginCaptures": {
+ "1": { "name": "keyword.operator.type.annotation.symbolic.carbon" },
+ "2": { "name": "keyword.operator.type.annotation.form.carbon" },
+ "3": { "name": "keyword.operator.type.annotation.carbon" },
+ "4": { "name": "keyword.operator.function-result.form.carbon" },
+ "5": { "name": "keyword.operator.function-result.carbon" },
+ "6": { "name": "keyword.operator.expression.as.carbon" },
+ "7": { "name": "storage.type.carbon" },
+ "8": { "name": "storage.type.carbon" }
+ },
+ "end": "(?=[,;={}\\)\\]]|[-+/%!<>|^~?@\\\\]|//|\\b(?:in|and|or|not|as|impls)\\b|$)",
+ "patterns": [{ "include": "#type-body" }]
+ }
+ ]
+ },
+ "type-body": {
+ "patterns": [
+ {
+ "comment": "Argument and grouping parentheses, which nest rather than ending the type.",
+ "begin": "\\(",
+ "end": "(\\))|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.parens.end.bracket.round.carbon"
+ }
+ },
+ "patterns": [{ "include": "#type-body" }]
+ },
+ {
+ "begin": "\\[",
+ "end": "(\\])|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.brackets.begin.bracket.square.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.brackets.end.bracket.square.carbon"
+ }
+ },
+ "patterns": [{ "include": "#type-body" }]
+ },
+ {
+ "comment": "A `where` clause switches to expression scoping so `=` does not end the enclosing type as an initializer, and ends at a `)` or `]` it did not open.",
+ "begin": "\\bwhere\\b",
+ "beginCaptures": {
+ "0": { "name": "keyword.other.where.carbon" }
+ },
+ "end": "(?=[;{}\\)\\]]|$)",
+ "patterns": [
+ { "include": "#expression-parens" },
+ { "include": "$self" }
+ ]
+ },
+ { "include": "#impls-clause" },
+ { "include": "#comments" },
+ { "include": "#strings" },
+ {
+ "comment": "`typeof` takes an expression operand, switching out of `#type-body`.",
+ "begin": "\\b(typeof)\\s*(\\()",
+ "end": "(\\))|$",
+ "beginCaptures": {
+ "1": { "name": "keyword.operator.expression.typeof.carbon" },
+ "2": {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.parens.end.bracket.round.carbon"
+ }
+ },
+ "patterns": [
+ { "include": "#expression-parens" },
+ { "include": "$self" }
+ ]
+ },
+ { "include": "#keywords" },
+ { "include": "#literals" },
+ { "include": "#numbers" },
+ {
+ "comment": "Pointer `*`, written directly after the pointee type.",
+ "name": "keyword.operator.type.pointer.carbon",
+ "match": "(?<=[A-Za-z0-9_)\\]*])\\*(?!=)"
+ },
+ { "include": "#operators" },
+ { "include": "#bindings" },
+ {
+ "comment": "A qualifier in a type, which `#declared-name-qualifier` scopes the same way on a declared name.",
+ "name": "entity.name.type.carbon",
+ "match": "(?:(?<=[A-Za-z0-9_)\\]]\\.)|(?|^~?@\\\\]|//|\\b(?:in|and|or|not|as|impls)\\b|$)",
+ "patterns": [{ "include": "#inheritance-body" }]
+ },
+ { "include": "#type-body" }
+ ],
+ "name": "meta.type.annotation.carbon"
+ },
+ {
+ "comment": "A `base:` declaration, excluding `.base` member access and `base class`.",
+ "name": "meta.inheritance-clause.carbon",
+ "begin": "(?|^~?@\\\\]|//|\\b(?:in|and|or|not|as|impls)\\b|$)",
+ "patterns": [{ "include": "#inheritance-body" }]
+ },
+ { "include": "#impls-clause" }
+ ]
+ },
+ "impls-clause": {
+ "patterns": [
+ {
+ "name": "meta.inheritance-clause.carbon",
+ "begin": "\\b(impls)\\b",
+ "beginCaptures": {
+ "1": { "name": "keyword.operator.expression.impls.carbon" }
+ },
+ "end": "(?=[,;={}\\)\\]]|[-+/%!<>|^~?@\\\\]|//|\\b(?:in|and|or|not|as|impls)\\b|$)",
+ "patterns": [{ "include": "#inheritance-body" }]
+ }
+ ]
+ },
+ "inheritance-body": {
+ "patterns": [
+ {
+ "comment": "Only the interface itself is scoped as `entity.other.inherited-class`; its argument list switches to expression scoping.",
+ "begin": "(?<=[A-Za-z0-9_\\]])\\(",
+ "end": "(\\))|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.parens.end.bracket.round.carbon"
+ }
+ },
+ "patterns": [
+ { "include": "#expression-parens" },
+ { "include": "$self" }
+ ]
+ },
+ {
+ "comment": "Grouping parentheses around an interface name stay in `#inheritance-body`.",
+ "begin": "\\(",
+ "end": "(\\))|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.parens.end.bracket.round.carbon"
+ }
+ },
+ "patterns": [{ "include": "#inheritance-body" }]
+ },
+ {
+ "comment": "A `where` clause switches to expression scoping and ends at a `)` or `]` it did not open.",
+ "begin": "\\b(where)\\b",
+ "beginCaptures": {
+ "1": { "name": "keyword.other.where.carbon" }
+ },
+ "end": "(?=[;{}\\)\\]]|$)",
+ "patterns": [
+ { "include": "#expression-parens" },
+ { "include": "$self" }
+ ]
+ },
+ { "include": "#keywords" },
+ { "include": "#literals" },
+ {
+ "comment": "The final identifier of the interface or base class name; any preceding qualifiers fall through to `#type-body`.",
+ "name": "entity.other.inherited-class.carbon",
+ "match": "\\b(?:r#)?[A-Za-z_][A-Za-z0-9_]*\\b(?!\\s*\\.)"
+ },
+ { "include": "#type-body" }
+ ]
+ },
"keywords": {
"patterns": [
{
- "name": "storage.type.carbon",
- "match": "\\b(adapt|alias|choice|class|constraint|fn|import|inline|interface|let|library|match_first|namespace|observe|require|var)\\b"
+ "comment": "`.base` member access, matched before `base` as an introducer.",
+ "name": "keyword.other.base.carbon",
+ "match": "(?<=\\.)\\b(base)\\b"
},
{
- "comment": "`base` introduces a base class declaration unless it modifies one.",
+ "name": "keyword.control.import.carbon",
+ "match": "\\b(import)\\b"
+ },
+ {
+ "name": "storage.type.carbon",
+ "match": "\\b(adapt|alias|choice|class|constraint|fn|inline|interface|let|library|match_first|namespace|observe|require|var)\\b"
+ },
+ {
+ "comment": "`base` as an introducer (not `base class`).",
"name": "storage.type.carbon",
"match": "\\b(base)\\b(?!\\s*class\\b)"
},
@@ -304,10 +657,10 @@
},
{
"name": "storage.type.carbon",
- "match": "\\b(impl)\\b(?!\\s*(fn|library|package)\\b)"
+ "match": "\\b(impl)\\b(?!\\s*(adapt|alias|base|choice|class|constraint|export|fn|impl|import|interface|let|library|match_first|namespace|observe|package|require|var)\\b)"
},
{
- "comment": "`package` is an introducer unless it begins a qualified name.",
+ "comment": "`package` as an introducer (not `package.`).",
"name": "storage.type.carbon",
"match": "\\b(package)\\b(?!\\.)"
},
@@ -316,7 +669,7 @@
"match": "\\b(abstract|const|eval|extend|extern|final|generic|musteval|override|partial|private|protected|ref|runtime|static|template|unsafe|unused|val|virtual)\\b"
},
{
- "comment": "`default` is a declaration modifier unless it opens a match arm.",
+ "comment": "`default` as a modifier (not `default =>`).",
"name": "storage.modifier.carbon",
"match": "\\b(default)\\b(?!\\s*=>)"
},
@@ -330,29 +683,50 @@
},
{
"name": "storage.modifier.carbon",
- "match": "\\b(impl)\\b(?=\\s*(fn|library|package)\\b)"
+ "match": "\\b(impl)\\b(?=\\s*(adapt|alias|base|choice|class|constraint|export|fn|impl|import|interface|let|library|match_first|namespace|observe|package|require|var)\\b)"
},
{
"name": "keyword.control.carbon",
"match": "\\b(break|case|continue|else|for|if|match|return|returned|then|while)\\b"
},
{
- "comment": "`default` is a match arm here, and a declaration modifier elsewhere.",
+ "comment": "`default` in a `match` clause.",
"name": "keyword.control.carbon",
"match": "\\b(default)\\b(?=\\s*=>)"
},
{
"name": "keyword.control.carbon",
- "match": "\\b(and|as|impls|in|like|not|or|typeof|where)\\b"
+ "match": "\\b(and|or)\\b"
},
+ {
+ "name": "keyword.operator.expression.not.carbon",
+ "match": "\\b(not)\\b"
+ },
+ {
+ "comment": "Fallback when not matched by `#type-annotation` or `#inheritance`.",
+ "name": "keyword.operator.expression.as.carbon",
+ "match": "\\b(as)\\b"
+ },
+ {
+ "name": "keyword.operator.expression.impls.carbon",
+ "match": "\\b(impls)\\b"
+ },
+ {
+ "name": "keyword.operator.expression.in.carbon",
+ "match": "\\b(in)\\b"
+ },
+ {
+ "name": "keyword.operator.expression.like.carbon",
+ "match": "\\b(like)\\b"
+ },
+ {
+ "name": "keyword.operator.expression.typeof.carbon",
+ "match": "\\b(typeof)\\b"
+ },
+ { "name": "keyword.other.where.carbon", "match": "\\b(where)\\b" },
{
"name": "keyword.other.carbon",
"match": "\\b(destroy|each|expand|forall|form|friend)\\b"
- },
- {
- "comment": "`.base` names the base class subobject.",
- "name": "keyword.other.carbon",
- "match": "(?<=\\.)\\b(base)\\b"
}
]
},
@@ -365,23 +739,27 @@
"match": "\\b(_)\\b"
},
{
- "comment": "Language-provided package roots.",
+ "comment": "Built-in package names.",
"name": "support.class.carbon",
"match": "\\b(Core|Cpp)\\b"
},
{
- "comment": "`package` as a qualified-name root names the current package.",
+ "comment": "`package` as a qualifier.",
"name": "variable.language.carbon",
"match": "\\b(package)\\b(?=\\.)"
},
{ "name": "constant.language.carbon", "match": "\\b(true|false)\\b" },
{
"name": "support.type.builtin.carbon",
- "match": "\\b(array|auto|bool|char|str|type)\\b"
+ "match": "\\b(array|auto|type)\\b"
},
{
- "comment": "Integer and float type literals. The lexer accepts any width, so this must not be restricted to the common ones.",
- "name": "support.type.builtin.carbon",
+ "name": "support.type.primitive.carbon",
+ "match": "\\b(bool|char|str)\\b"
+ },
+ {
+ "comment": "Integer and floating-point type literals.",
+ "name": "support.type.primitive.carbon",
"match": "\\b[iuf][1-9][0-9]*\\b"
}
]
@@ -389,14 +767,41 @@
"numbers": {
"patterns": [
{
+ "comment": "Each numeric rule matches a full alphanumeric word starting with a digit so a malformed suffix is not split into an identifier. Real literals exclude a leading `.` or `->` so tuple access like `t.0.1` is not matched as a real.",
"name": "constant.numeric.hex.carbon",
- "match": "\\b0x[_0-9A-Fa-f]*(?:\\.[_0-9A-Fa-f]*)?(?:[pP][-+]?[0-9]+)?"
+ "match": "(?)\\b(0x)[_0-9A-Za-z]*\\.[0-9A-Za-z][_0-9A-Za-z]*(?:(?<=[a-z])[-+][0-9A-Za-z][_0-9A-Za-z]*)?",
+ "captures": {
+ "1": { "name": "keyword.other.unit.hexadecimal.carbon" }
+ }
+ },
+ {
+ "name": "constant.numeric.hex.carbon",
+ "match": "\\b(0x)[_0-9A-Za-z]*",
+ "captures": {
+ "1": { "name": "keyword.other.unit.hexadecimal.carbon" }
+ }
+ },
+ {
+ "name": "constant.numeric.octal.carbon",
+ "match": "\\b(0o)[_0-9A-Za-z]*",
+ "captures": {
+ "1": { "name": "keyword.other.unit.octal.carbon" }
+ }
+ },
+ {
+ "name": "constant.numeric.binary.carbon",
+ "match": "\\b(0b)[_0-9A-Za-z]*",
+ "captures": {
+ "1": { "name": "keyword.other.unit.binary.carbon" }
+ }
},
- { "name": "constant.numeric.octal.carbon", "match": "\\b0o[_0-7]*" },
- { "name": "constant.numeric.binary.carbon", "match": "\\b0b[_01]*" },
{
"name": "constant.numeric.decimal.carbon",
- "match": "\\b[0-9][_0-9]*(?:\\.[_0-9]+)?(?:[eE][-+]?[0-9]+)?"
+ "match": "(?)\\b[0-9][_0-9A-Za-z]*\\.[0-9A-Za-z][_0-9A-Za-z]*(?:(?<=[a-z])[-+][0-9A-Za-z][_0-9A-Za-z]*)?"
+ },
+ {
+ "name": "constant.numeric.decimal.carbon",
+ "match": "\\b[0-9][_0-9A-Za-z]*"
},
{
"comment": "Positional parameter, as used in lambdas.",
@@ -407,50 +812,247 @@
},
"operators": {
"patterns": [
+ {
+ "name": "keyword.operator.type.annotation.symbolic.carbon",
+ "match": ":!"
+ },
+ {
+ "name": "keyword.operator.type.annotation.form.carbon",
+ "match": ":\\?"
+ },
+ {
+ "name": "keyword.operator.type.annotation.carbon",
+ "match": ":(?![=!?])"
+ },
+ {
+ "comment": "`->` directly after an operand is pointer member access rather than a return type arrow.",
+ "name": "punctuation.separator.pointer-access.carbon",
+ "match": "(?<=[A-Za-z0-9_)\\]}])\\->(?!\\?)"
+ },
+ {
+ "name": "keyword.operator.function-result.form.carbon",
+ "match": "\\->\\?"
+ },
+ {
+ "name": "keyword.operator.function-result.carbon",
+ "match": "\\->(?!\\?)"
+ },
+ { "name": "keyword.operator.arrow.fat.carbon", "match": "=>" },
{
"name": "keyword.operator.carbon",
- "match": "(\\->\\?|>>=|<=>|<<=|\\&=|\\^=|:=|:\\?|==|=>|!=|>=|>>|<=|<>|<<|<\\-|\\-=|\\->|\\-\\-|%=|\\|=|\\+=|\\+\\+|/=|\\*=|\\~=|\\&|@|\\^|:|=|!|>|<|\\-|%|\\.|\\||\\+|\\?|/|\\*|\\~|\\\\)"
+ "match": "<=>|<<=|>>=|==|!=|<=|>=|<<|>>|\\+\\+|--|\\+=|-=|\\*=|/=|%=|&=|\\|=|\\^=|~=|:=|<-|<>|[-+*/%&|^~!<>=@?\\\\]"
}
]
},
"identifiers": {
"patterns": [
+ { "include": "#bindings" },
{
- "comment": "Raw identifiers, which suppress keyword meaning.",
- "match": "\\b(r#)([A-Z][A-Za-z0-9_]*)",
+ "comment": "Raw identifiers.",
+ "name": "variable.other.carbon",
+ "match": "\\b(r#)([A-Za-z_][A-Za-z0-9_]*)",
"captures": {
- "1": { "name": "punctuation.definition.raw-identifier.carbon" },
- "2": { "name": "entity.name.type.carbon" }
+ "1": { "name": "punctuation.definition.raw-identifier.carbon" }
}
},
{
- "match": "\\b(r#)([a-z_][A-Za-z0-9_]*)",
- "captures": {
- "1": { "name": "punctuation.definition.raw-identifier.carbon" },
- "2": { "name": "variable.other.carbon" }
- }
+ "comment": "Member function call.",
+ "name": "entity.name.function.member.carbon",
+ "match": "(?:(?<=\\.)|(?<=\\->))[A-Za-z_][A-Za-z0-9_]*(?=\\s*\\()"
},
{
- "comment": "An identifier applied to an argument list is a call.",
- "name": "entity.name.function.carbon",
+ "comment": "Member access via `.` or `->`.",
+ "name": "variable.other.property.carbon",
+ "match": "(?:(?<=\\.)|(?<=\\->))[A-Za-z_][A-Za-z0-9_]*\\b"
+ },
+ {
+ "comment": "Function call.",
+ "name": "entity.name.function.call.carbon",
"match": "\\b[A-Za-z_][A-Za-z0-9_]*(?=\\s*\\()"
},
{
- "comment": "UpperCamel names a type.",
- "name": "entity.name.type.carbon",
- "match": "\\b[A-Z][A-Za-z0-9_]*\\b"
- },
- {
- "comment": "lower_snake names a value.",
"name": "variable.other.carbon",
- "match": "\\b[a-z_][A-Za-z0-9_]*\\b"
+ "match": "\\b[A-Za-z_][A-Za-z0-9_]*\\b"
}
]
},
"punctuation": {
"patterns": [
- { "name": "punctuation.separator.carbon", "match": "," },
- { "name": "punctuation.terminator.carbon", "match": ";" }
+ {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon",
+ "match": "\\("
+ },
+ {
+ "name": "punctuation.section.parens.end.bracket.round.carbon",
+ "match": "\\)"
+ },
+ {
+ "name": "punctuation.section.block.begin.bracket.curly.carbon",
+ "match": "\\{"
+ },
+ {
+ "name": "punctuation.section.block.end.bracket.curly.carbon",
+ "match": "\\}"
+ },
+ {
+ "name": "punctuation.section.brackets.begin.bracket.square.carbon",
+ "match": "\\["
+ },
+ {
+ "name": "punctuation.section.brackets.end.bracket.square.carbon",
+ "match": "\\]"
+ },
+ { "name": "punctuation.separator.dot-access.carbon", "match": "\\." },
+ { "name": "punctuation.separator.comma.carbon", "match": "," },
+ { "name": "punctuation.terminator.statement.carbon", "match": ";" }
+ ]
+ },
+ "choice-definitions": {
+ "patterns": [
+ {
+ "comment": "A `choice` declaration, scoping names in its body as enum members and closing immediately if there is no body.",
+ "begin": "\\b(choice)\\b",
+ "beginCaptures": {
+ "1": { "name": "storage.type.carbon" }
+ },
+ "end": "(?<=\\})|(?=[^\\s({])",
+ "patterns": [
+ {
+ "begin": "(?<=\\bchoice)\\s+(?=(?:r#)?[A-Za-z_])",
+ "end": "((?:r#)?[A-Za-z_][A-Za-z0-9_]*)\\b(?!\\s*(?:\\[[^\\[\\]]*\\]\\s*)?(?:\\([^()]*(?:\\([^()]*(?:\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*)?\\.)|(?=[^\\sA-Za-z_])|$",
+ "endCaptures": {
+ "1": { "name": "entity.name.type.carbon" }
+ },
+ "patterns": [{ "include": "#declared-name-qualifier" }]
+ },
+ { "include": "#comments" },
+ {
+ "comment": "Choice parameters.",
+ "begin": "\\(",
+ "end": "(\\))|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.parens.end.bracket.round.carbon"
+ }
+ },
+ "patterns": [{ "include": "#choice-parameters" }]
+ },
+ {
+ "comment": "Choice body.",
+ "begin": "\\{",
+ "end": "(\\})|(?=[;=])",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.block.begin.bracket.curly.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.block.end.bracket.curly.carbon"
+ }
+ },
+ "patterns": [
+ { "include": "#comments" },
+ {
+ "comment": "Alternative parameters.",
+ "begin": "\\(",
+ "end": "(\\))|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.parens.end.bracket.round.carbon"
+ }
+ },
+ "patterns": [{ "include": "#choice-parameters" }]
+ },
+ {
+ "comment": "Invalid implicit parameter list on an alternative, matched so its contents are not scoped as enum members.",
+ "begin": "\\[",
+ "end": "(\\])|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.brackets.begin.bracket.square.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.brackets.end.bracket.square.carbon"
+ }
+ },
+ "patterns": [{ "include": "#choice-parameters" }]
+ },
+ { "include": "#keywords" },
+ { "include": "#literals" },
+ {
+ "name": "variable.other.enummember.carbon",
+ "match": "\\b(?:r#)?[A-Za-z_][A-Za-z0-9_]*\\b"
+ },
+ { "include": "#numbers" },
+ { "include": "#operators" },
+ { "include": "#punctuation" }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "choice-parameters": {
+ "patterns": [
+ { "include": "#comments" },
+ { "include": "#strings" },
+ { "include": "#inheritance" },
+ { "include": "#type-annotation" },
+ { "include": "#keywords" },
+ { "include": "#literals" },
+ { "include": "#numbers" },
+ { "include": "#operators" },
+ { "include": "#identifiers" },
+ { "include": "#punctuation" }
+ ]
+ },
+ "bindings": {
+ "patterns": [
+ {
+ "comment": "Parameter bindings (`name: Type` when not preceded by `let` or `var`), with `variable.parameter` nested inside `variable.other`.",
+ "name": "variable.other.carbon",
+ "match": "(?)\\b(r#)?([A-Za-z_][A-Za-z0-9_]*)(?=\\s*:(?![=!?]))",
+ "captures": {
+ "1": { "name": "punctuation.definition.raw-identifier.carbon" },
+ "2": { "name": "variable.parameter.carbon" }
+ }
+ }
+ ]
+ },
+ "expression-parens": {
+ "patterns": [
+ {
+ "comment": "Parentheses nested in an expression that sits inside a type, so that only the matching `)` ends the expression.",
+ "begin": "\\(",
+ "end": "(\\))|$",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.parens.begin.bracket.round.carbon"
+ }
+ },
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.section.parens.end.bracket.round.carbon"
+ }
+ },
+ "patterns": [
+ { "include": "#expression-parens" },
+ { "include": "$self" }
+ ]
+ }
]
}
}