Repository: alecthomas/chroma
Pull request #392 (2020-08-21 15:41:23)

Kotlin improvements around string interpolation, escaping, and generics
Hi,

I did a few improvements on the kotlin lexer. Each commit describes what it does but the main changes are:

* Detect string interpolation and escaping
```kotlin
"My value is $something and 1 + 2 is ${ 1 + 2}"
"I can do new lines\n"
```

* Better detect generics

  * now the reified keyword is properly detected. Before it was just considered Text

```kotlin
class Holder <in A, out B, C: TUpper>

fun <T : Comparable<T>> sort(list: List<T>)  // woohoo! nested generics work

inline fun <reified T>  generic(t: T)
```

And added a few more tests to verify the functionality around my changes.


Patch:
diff --git a/lexers/k/kotlin.go b/lexers/k/kotlin.go
index 3e90af7..17cdfa6 100644
--- a/lexers/k/kotlin.go
+++ b/lexers/k/kotlin.go
@@ -28,29 +28,67 @@ var Kotlin = internal.Register(MustNewLexer(
 			{`%=|&&|\*=|\+\+|\+=|--|-=|->|\.\.|\/=|::|<=|==|>=|!!|!=|\|\||\?[:.]`, Operator, nil},
 			{`[~!%^&*()+=|\[\]:;,.<>\/?-]`, Punctuation, nil},
 			{`[{}]`, Punctuation, nil},
-			{`"""[^"]*"""`, LiteralString, nil},
-			{`"(\\\\|\\"|[^"\n])*["\n]`, LiteralString, nil},
+			{`"""`, LiteralString, Push("rawstring")},
+			{`"`, LiteralStringDouble, Push("string")},
+			{`(')(\\u[0-9a-fA-F]{4})(')`, ByGroups(LiteralStringChar, LiteralStringEscape, LiteralStringChar), nil},
 			{`'\\.'|'[^\\]'`, LiteralStringChar, nil},
 			{`0[xX][0-9a-fA-F]+[Uu]?[Ll]?|[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)?[fF]?[Uu]?[Ll]?`, LiteralNumber, nil},
 			{`(companion)(\s+)(object)`, ByGroups(Keyword, Text, Keyword), nil},
 			{`(class|interface|object)(\s+)`, ByGroups(Keyword, Text), Push("class")},
 			{`(package|import)(\s+)`, ByGroups(Keyword, Text), Push("package")},
 			{`(val|var)(\s+)`, ByGroups(Keyword, Text), Push("property")},
-			{`(fun)(\s+)(<[^>]*>\s+)?`, ByGroups(Keyword, Text, Text), Push("function")},
+			{`(fun)(\s+)`, ByGroups(Keyword, Text), Push("function")},
 			{`(abstract|actual|annotation|as|as\?|break|by|catch|class|companion|const|constructor|continue|crossinline|data|delegate|do|dynamic|else|enum|expect|external|false|field|file|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|it|lateinit|noinline|null|object|open|operator|out|override|package|param|private|property|protected|public|receiver|reified|return|sealed|set|setparam|super|suspend|tailrec|this|throw|true|try|typealias|typeof|val|var|vararg|when|where|while)\b`, Keyword, nil},
-			{"(@?[" + kotlinIdentifier + "]*`)", Name, nil},
+			{`@[` + kotlinIdentifier + `]+`, NameDecorator, nil},
+			{`[` + kotlinIdentifier + `]+`, Name, nil},
 		},
 		"package": {
 			{`\S+`, NameNamespace, Pop(1)},
 		},
 		"class": {
-			{"(@?[" + kotlinIdentifier + "]*`)", NameClass, Pop(1)},
+			// \x60 is the back tick character (`)
+			{`\x60[^\x60]+?\x60`, NameClass, Pop(1)},
+			{`[` + kotlinIdentifier + `]+`, NameClass, Pop(1)},
 		},
 		"property": {
-			{"(@?[" + kotlinIdentifier + " ]*`)", NameProperty, Pop(1)},
+			{`\x60[^\x60]+?\x60`, NameProperty, Pop(1)},
+			{`[` + kotlinIdentifier + `]+`, NameProperty, Pop(1)},
+		},
+		"generics-specification": {
+			{`<`, Punctuation, Push("generics-specification")}, // required for generics inside generics e.g. <T : List<Int> >
+			{`>`, Punctuation, Pop(1)},
+			{`[,:*?]`, Punctuation, nil},
+			{`(in|out|reified)`, Keyword, nil},
+			{`\x60[^\x60]+?\x60`, NameClass, nil},
+			{`[` + kotlinIdentifier + `]+`, NameClass, nil},
+			{`\s+`, Text, nil},
 		},
 		"function": {
-			{"(@?[" + kotlinIdentifier + " ]*`)", NameFunction, Pop(1)},
+			{`<`, Punctuation, Push("generics-specification")},
+			{`\x60[^\x60]+?\x60`, NameFunction, Pop(1)},
+			{`[` + kotlinIdentifier + `]+`, NameFunction, Pop(1)},
+			{`\s+`, Text, nil},
+		},
+		"rawstring": {
+			// raw strings don't allow character escaping
+			{`"""`, LiteralString, Pop(1)},
+			{`(?:[^$"]+|\"{1,2}[^"])+`, LiteralString, nil},
+			Include("string-interpol"),
+			// remaining dollar signs are just a string
+			{`\$`, LiteralString, nil},
+		},
+		"string": {
+			{`\\[tbnr'"\\\$]`, LiteralStringEscape, nil},
+			{`\\u[0-9a-fA-F]{4}`, LiteralStringEscape, nil},
+			{`"`, LiteralStringDouble, Pop(1)},
+			Include("string-interpol"),
+			{`[^\n\\"$]+`, LiteralStringDouble, nil},
+			// remaining dollar signs are just a string
+			{`\$`, LiteralStringDouble, nil},
+		},
+		"string-interpol": {
+			{`\$[` + kotlinIdentifier + `]+`, LiteralStringInterpol, nil},
+			{`\${[^}\n]*}`, LiteralStringInterpol, nil},
 		},
 	},
 ))


Test patch:
diff --git a/lexers/testdata/kotlin.actual b/lexers/testdata/kotlin.actual
index e28a03a..68e05af 100644
--- a/lexers/testdata/kotlin.actual
+++ b/lexers/testdata/kotlin.actual
@@ -21,6 +21,23 @@ fun nullable2(nullable: String?): Int = nullable?.length ?: run {
     1 + 2
 }
 
+val rawStringWithQuotes = """
+Hello "example" ${1 + 2}
+And now { Just the braces }
+Escapes here don't work so this is just text \t \n \u1234 $ \$
+"""
+
+fun returnsSomething(): Int {
+    return "".length
+}
+
+fun returnsSomethingElse(): Int = "\\\n".length
+
+val character = '"'
+val escapedCharacter = '\"'
+// escaping a double quote character inside a character is optional
+val stringWithSingleQuote = "'"
+
 typealias MySecretAlias<A, B> = (A, B) -> Unit
 
 val impl : MySecretAlias<Int, Int> = { a, _ -> Unit }
@@ -66,6 +83,42 @@ fun moreOperators(arg: Any?) {
     	println(arg === Unit)
 }
 
+@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
+        AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
+@Retention(AnnotationRetention.SOURCE)
+annotation class Annotated
+
+@Annotated class A {
+    @Annotated fun a(
+        @Annotated param: Int
+    ) {
+
+        @Annotated val y = 0
+
+    }
+}
+
+open class TUpper
+fun <T: TUpper, R: Any?> generic() = 123
+
+class Holder <in A, out B, C: TUpper>
+
+class Holder2  <T>
+
+var holder1: Holder<Int, String, *>? = null
+
+class Some(
+    val holder2: Holder<Int, String, *>? = null
+) {
+    var holder3: Holder<Int, String, *>? = null
+    fun example() {
+        var holder4: Holder<Int, String, *>? = null
+    }
+}
+fun <T : Comparable<T>> sort(list: List<T>) {
+    
+}
+
 class X {
     companion object {
     }
diff --git a/lexers/testdata/kotlin.expected b/lexers/testdata/kotlin.expected
index f562eee..bf1caaf 100644
--- a/lexers/testdata/kotlin.expected
+++ b/lexers/testdata/kotlin.expected
@@ -27,14 +27,12 @@
   {"type":"Text","value":"\n    "},
   {"type":"Keyword","value":"val"},
   {"type":"Text","value":" "},
-  {"type":"Error","value":"` + \""},
-  {"type":"NameProperty","value":"with"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"spaces"},
-  {"type":"LiteralString","value":"\" + ` = \""},
-  {"type":"Name","value":"hello"},
-  {"type":"LiteralString","value":"\"\n"},
-  {"type":"Text","value":"    "},
+  {"type":"NameProperty","value":"` + \"with spaces\" + `"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringDouble","value":"\"hello\""},
+  {"type":"Text","value":"\n    "},
   {"type":"Keyword","value":"val"},
   {"type":"Text","value":" "},
   {"type":"NameProperty","value":"multiline"},
@@ -130,6 +128,73 @@
   {"type":"Text","value":"\n"},
   {"type":"Punctuation","value":"}"},
   {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"val"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"rawStringWithQuotes"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralString","value":"\"\"\"\nHello \"example\" "},
+  {"type":"LiteralStringInterpol","value":"${1 + 2}"},
+  {"type":"LiteralString","value":"\nAnd now { Just the braces }\nEscapes here don't work so this is just text \\t \\n \\u1234 $ \\$\n\"\"\""},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"fun"},
+  {"type":"Text","value":" "},
+  {"type":"NameFunction","value":"returnsSomething"},
+  {"type":"Punctuation","value":"():"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Int"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"return"},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringDouble","value":"\"\""},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"length"},
+  {"type":"Text","value":"\n"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"fun"},
+  {"type":"Text","value":" "},
+  {"type":"NameFunction","value":"returnsSomethingElse"},
+  {"type":"Punctuation","value":"():"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Int"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringDouble","value":"\""},
+  {"type":"LiteralStringEscape","value":"\\\\\\n"},
+  {"type":"LiteralStringDouble","value":"\""},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"length"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"val"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"character"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringChar","value":"'\"'"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"val"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"escapedCharacter"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringChar","value":"'\\\"'"},
+  {"type":"Text","value":"\n"},
+  {"type":"CommentSingle","value":"// escaping a double quote character inside a character is optional\n"},
+  {"type":"Keyword","value":"val"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"stringWithSingleQuote"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringDouble","value":"\"'\""},
+  {"type":"Text","value":"\n\n"},
   {"type":"Keyword","value":"typealias"},
   {"type":"Text","value":" "},
   {"type":"Name","value":"MySecretAlias"},
@@ -214,7 +279,13 @@
   {"type":"Text","value":"\n    "},
   {"type":"Name","value":"println"},
   {"type":"Punctuation","value":"("},
-  {"type":"LiteralString","value":"\"This is an example a = $a and the sum is ${a + b} ${ A.foo() }\""},
+  {"type":"LiteralStringDouble","value":"\"This is an example a = "},
+  {"type":"LiteralStringInterpol","value":"$a"},
+  {"type":"LiteralStringDouble","value":" and the sum is "},
+  {"type":"LiteralStringInterpol","value":"${a + b}"},
+  {"type":"LiteralStringDouble","value":" "},
+  {"type":"LiteralStringInterpol","value":"${ A.foo() }"},
+  {"type":"LiteralStringDouble","value":"\""},
   {"type":"Punctuation","value":")"},
   {"type":"Text","value":"\n    "},
   {"type":"Name","value":"println"},
@@ -415,6 +486,260 @@
   {"type":"Text","value":"\n"},
   {"type":"Punctuation","value":"}"},
   {"type":"Text","value":"\n\n"},
+  {"type":"NameDecorator","value":"@Target"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"AnnotationTarget"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"CLASS"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"AnnotationTarget"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"FUNCTION"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":"\n        "},
+  {"type":"Name","value":"AnnotationTarget"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"VALUE_PARAMETER"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"AnnotationTarget"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"EXPRESSION"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n"},
+  {"type":"NameDecorator","value":"@Retention"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"AnnotationRetention"},
+  {"type":"Punctuation","value":"."},
+  {"type":"Name","value":"SOURCE"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"annotation"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"Annotated"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"NameDecorator","value":"@Annotated"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"A"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n    "},
+  {"type":"NameDecorator","value":"@Annotated"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"fun"},
+  {"type":"Text","value":" "},
+  {"type":"NameFunction","value":"a"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Text","value":"\n        "},
+  {"type":"NameDecorator","value":"@Annotated"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"param"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Int"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n\n        "},
+  {"type":"NameDecorator","value":"@Annotated"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"val"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"y"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumber","value":"0"},
+  {"type":"Text","value":"\n\n    "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"open"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"TUpper"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"fun"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameClass","value":"T"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"TUpper"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"R"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"Any"},
+  {"type":"Punctuation","value":"?\u003e"},
+  {"type":"Text","value":" "},
+  {"type":"NameFunction","value":"generic"},
+  {"type":"Punctuation","value":"()"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumber","value":"123"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"Holder"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Keyword","value":"in"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"A"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"out"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"B"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"C"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"TUpper"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"Holder2"},
+  {"type":"Text","value":"  "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Name","value":"T"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"holder1"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Holder"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Name","value":"Int"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"String"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"*\u003e?"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"null"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"Some"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"val"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"holder2"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Holder"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Name","value":"Int"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"String"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"*\u003e?"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"null"},
+  {"type":"Text","value":"\n"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"holder3"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Holder"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Name","value":"Int"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"String"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"*\u003e?"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"null"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"fun"},
+  {"type":"Text","value":" "},
+  {"type":"NameFunction","value":"example"},
+  {"type":"Punctuation","value":"()"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"NameProperty","value":"holder4"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Holder"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Name","value":"Int"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"String"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"*\u003e?"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"null"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"fun"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameClass","value":"T"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"Comparable"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameClass","value":"T"},
+  {"type":"Punctuation","value":"\u003e\u003e"},
+  {"type":"Text","value":" "},
+  {"type":"NameFunction","value":"sort"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"list"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"List"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Name","value":"T"},
+  {"type":"Punctuation","value":"\u003e)"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n    \n"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n\n"},
   {"type":"Keyword","value":"class"},
   {"type":"Text","value":" "},
   {"type":"NameClass","value":"X"},
@@ -434,7 +759,13 @@
   {"type":"Keyword","value":"inline"},
   {"type":"Text","value":" "},
   {"type":"Keyword","value":"fun"},
-  {"type":"Text","value":" \u003creified T\u003e  "},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"Keyword","value":"reified"},
+  {"type":"Text","value":" "},
+  {"type":"NameClass","value":"T"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":"  "},
   {"type":"NameFunction","value":"generic"},
   {"type":"Punctuation","value":"("},
   {"type":"Name","value":"t"},