Преглед на файлове

[highlightjs] Add struct literal support. (#1370)

This is especially tricky, as there doesn't seem to be support for
indirect recursion, only direct recursion. As a consequence, its
important to have a single recursive pattern that handles all the
balanced delimiters in an expression context.

I've tried to add some comments to help explain this.

I also tried to add something to check that the balanced delimiters
*matched* and re-synchronize if they don't, but that didn't end up
working. I also tried various things to force re-synchronizing more
rapidly in the face of unbalanced delimiters but they all produced
strictly worse highlighting than what I have here. I will try again in
a follow-up commit, but for now this will work well enough for slides.
Chandler Carruth преди 3 години
родител
ревизия
0ed6600615
променени са 2 файла, в които са добавени 23 реда и са изтрити 9 реда
  1. 22 8
      highlighting/highlightjs_carbon_lang.js
  2. 1 1
      highlighting/highlightjs_example.html

+ 22 - 8
highlighting/highlightjs_carbon_lang.js

@@ -9,7 +9,6 @@
  * Category: common, system
  * Website: https://github.com/carbon-language/carbon-lang/
  *
- * TODO: struct literals.
  * TODO: abstract, virtual, impl on methods.
  * TODO: private, protected.
  * TODO: Dedicated package and import highlighting.
@@ -199,20 +198,35 @@ export default function (hljs) {
       keywords: KEYWORDS,
     },
   ];
-  // Use a nesting structure so that we directly track balanced parentheses and
+  const STRUCT_LITERAL_DESIGNATOR = {
+    begin: [/\./, /[a-zA-Z]\w*/, /\s*/, /[:=]/, /\s*/],
+    beginScope: {
+      1: 'punctuation',
+      2: 'symbol',
+      4: 'punctuation',
+    },
+  };
+  // Use a nesting structure so that we directly track balanced delimiters and
   // consume them. This allows patterns below to reliably "end" on closing
   // delimiters without being confused by others in the expression stream.
-  // TODO: Extend this to balanced `[]`s and `{}`s.
+  // Sadly, Highlight.js doesn't support indirect mode recursion so we have to
+  // fuse all the delimited modes into a single one to support arbitrary
+  // recursing. We use callbacks to make sure that the closing delimiters match
+  // the opening ones.
   const PARENTHESIZED_EXPRESSION = {
-    scope: 'carbon-parenthesized-expression',
-    begin: /\(/,
+    scope: 'carbon-delimited-expression',
+    begin: /(\(|\{(?=\s*\.[a-zA-Z]\w*\s*[:=])|\[)/,
     beginScope: 'punctuation',
-    end: /\)/,
+    end: /(\)|\}|\])/,
     endScope: 'punctuation',
     contains: [
       'self',
-      // Tuple literals are comma-separated parenthesized expressions.
+      // Tuple literals and struct literals are comma-separated parenthesized
+      // expressions.
       COMMA_SEPARATOR,
+      // Struct literals include designators. These aren't allowed in tuple
+      // literals, but included here because we fuse into a single recursive mode.
+      STRUCT_LITERAL_DESIGNATOR,
       ...UNPARENTHESIZED_EXPRESSION,
     ],
   };
@@ -274,7 +288,7 @@ export default function (hljs) {
     beginScope: 'punctuation',
     end: /\)/,
     endScope: 'punctuation',
-    contains: ['self', ...UNPARENTHESIZED_PATTERNS],
+    contains: ['self', COMMA_SEPARATOR, ...UNPARENTHESIZED_PATTERNS],
   };
   const PATTERN_SEQUENCE = [
     COMMA_SEPARATOR,

+ 1 - 1
highlighting/highlightjs_example.html

@@ -23,7 +23,7 @@ import Carbon library "Printing";
 fn Partition[T:! Comparable & Movable](s: Slice(T))
       -> i64 {
   var i: i64 = -1;
-  let (x: i64, var y: i64) = (1, 2);
+  let (x: i64, var y: auto) = (1, {.x = {.a = (1, {.k = 42}), .b = 13}, .y = "..."});
 
   for (e: T in s) {
     if (e <= s.Last()) {