From 563cd73ea232e2100fea9233956c1564d6dc5214 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 5 Dec 2021 14:48:00 +0100 Subject: [PATCH] Kotlin: Added `char` token and improved string interpolation (#3225) --- components/prism-kotlin.js | 70 +++++++---- components/prism-kotlin.min.js | 2 +- tests/languages/kotlin/char_feature.test | 11 ++ .../kotlin/interpolation_feature.test | 46 ------- .../languages/kotlin/raw-string_feature.test | 18 --- tests/languages/kotlin/string_feature.test | 113 ++++++++++++++++++ 6 files changed, 170 insertions(+), 90 deletions(-) create mode 100644 tests/languages/kotlin/char_feature.test delete mode 100644 tests/languages/kotlin/interpolation_feature.test delete mode 100644 tests/languages/kotlin/raw-string_feature.test create mode 100644 tests/languages/kotlin/string_feature.test diff --git a/components/prism-kotlin.js b/components/prism-kotlin.js index 00dfbe867b..3b45dcbf57 100644 --- a/components/prism-kotlin.js +++ b/components/prism-kotlin.js @@ -22,19 +22,60 @@ delete Prism.languages.kotlin['class-name']; + var interpolationInside = { + 'interpolation-punctuation': { + pattern: /^\$\{?|\}$/, + alias: 'punctuation' + }, + 'expression': { + pattern: /[\s\S]+/, + inside: Prism.languages.kotlin + } + }; + Prism.languages.insertBefore('kotlin', 'string', { - 'raw-string': { - pattern: /("""|''')[\s\S]*?\1/, - alias: 'string' - // See interpolation below + // https://kotlinlang.org/spec/expressions.html#string-interpolation-expressions + 'string-literal': [ + { + pattern: /"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/, + alias: 'multiline', + inside: { + 'interpolation': { + pattern: /\$(?:[a-z_]\w*|\{[^{}]*\})/i, + inside: interpolationInside + }, + 'string': /[\s\S]+/ + } + }, + { + pattern: /"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/, + alias: 'singleline', + inside: { + 'interpolation': { + pattern: /((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i, + lookbehind: true, + inside: interpolationInside + }, + 'string': /[\s\S]+/ + } + } + ], + 'char': { + // https://kotlinlang.org/spec/expressions.html#character-literals + pattern: /'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/, + greedy: true } }); + + delete Prism.languages.kotlin['string']; + Prism.languages.insertBefore('kotlin', 'keyword', { 'annotation': { pattern: /\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/, alias: 'builtin' } }); + Prism.languages.insertBefore('kotlin', 'function', { 'label': { pattern: /\b\w+@|@\w+\b/, @@ -42,27 +83,6 @@ } }); - var interpolation = [ - { - pattern: /\$\{[^}]+\}/, - inside: { - 'delimiter': { - pattern: /^\$\{|\}$/, - alias: 'variable' - }, - rest: Prism.languages.kotlin - } - }, - { - pattern: /\$\w+/, - alias: 'variable' - } - ]; - - Prism.languages.kotlin['string'].inside = Prism.languages.kotlin['raw-string'].inside = { - interpolation: interpolation - }; - Prism.languages.kt = Prism.languages.kotlin; Prism.languages.kts = Prism.languages.kotlin; }(Prism)); diff --git a/components/prism-kotlin.min.js b/components/prism-kotlin.min.js index 9cb698a542..78a9057188 100644 --- a/components/prism-kotlin.min.js +++ b/components/prism-kotlin.min.js @@ -1 +1 @@ -!function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"],e.languages.insertBefore("kotlin","string",{"raw-string":{pattern:/("""|''')[\s\S]*?\1/,alias:"string"}}),e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}});var n=[{pattern:/\$\{[^}]+\}/,inside:{delimiter:{pattern:/^\$\{|\}$/,alias:"variable"},rest:e.languages.kotlin}},{pattern:/\$\w+/,alias:"variable"}];e.languages.kotlin.string.inside=e.languages.kotlin["raw-string"].inside={interpolation:n},e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(Prism); \ No newline at end of file +!function(n){n.languages.kotlin=n.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete n.languages.kotlin["class-name"];var e={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:n.languages.kotlin}};n.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:e},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:e},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete n.languages.kotlin.string,n.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),n.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),n.languages.kt=n.languages.kotlin,n.languages.kts=n.languages.kotlin}(Prism); \ No newline at end of file diff --git a/tests/languages/kotlin/char_feature.test b/tests/languages/kotlin/char_feature.test new file mode 100644 index 0000000000..8f59a658da --- /dev/null +++ b/tests/languages/kotlin/char_feature.test @@ -0,0 +1,11 @@ +'a' +'\n' +'\uFFFF' + +---------------------------------------------------- + +[ + ["char", "'a'"], + ["char", "'\\n'"], + ["char", "'\\uFFFF'"] +] diff --git a/tests/languages/kotlin/interpolation_feature.test b/tests/languages/kotlin/interpolation_feature.test deleted file mode 100644 index 44ec667d62..0000000000 --- a/tests/languages/kotlin/interpolation_feature.test +++ /dev/null @@ -1,46 +0,0 @@ -"$foo ${bar} ${'$'} ${foobar()}" -""" -$foo ${bar} -${'$'} ${foobar()} -""" - ----------------------------------------------------- - -[ - ["string", [ - "\"", - ["interpolation", "$foo"], - ["interpolation", [ - ["delimiter", "${"], "bar", ["delimiter", "}"] - ]], - ["interpolation", [ - ["delimiter", "${"], ["string", ["'$'"]], ["delimiter", "}"] - ]], - ["interpolation", [ - ["delimiter", "${"], - ["function", "foobar"], ["punctuation", "("], ["punctuation", ")"], - ["delimiter", "}"] - ]], - "\"" - ]], - ["raw-string", [ - "\"\"\"\r\n", - ["interpolation", "$foo"], - ["interpolation", [ - ["delimiter", "${"], "bar", ["delimiter", "}"] - ]], - ["interpolation", [ - ["delimiter", "${"], ["string", ["'$'"]], ["delimiter", "}"] - ]], - ["interpolation", [ - ["delimiter", "${"], - ["function", "foobar"], ["punctuation", "("], ["punctuation", ")"], - ["delimiter", "}"] - ]], - "\r\n\"\"\"" - ]] -] - ----------------------------------------------------- - -Checks for string interpolation. \ No newline at end of file diff --git a/tests/languages/kotlin/raw-string_feature.test b/tests/languages/kotlin/raw-string_feature.test deleted file mode 100644 index 5a5ca3309b..0000000000 --- a/tests/languages/kotlin/raw-string_feature.test +++ /dev/null @@ -1,18 +0,0 @@ -"""""" -"""Foo "bar"" baz""" -""" -"Foo" -bar -""" - ----------------------------------------------------- - -[ - ["raw-string", ["\"\"\"\"\"\""]], - ["raw-string", ["\"\"\"Foo \"bar\"\" baz\"\"\""]], - ["raw-string", ["\"\"\"\r\n\"Foo\"\r\nbar\r\n\"\"\""]] -] - ----------------------------------------------------- - -Checks for raw strings. \ No newline at end of file diff --git a/tests/languages/kotlin/string_feature.test b/tests/languages/kotlin/string_feature.test new file mode 100644 index 0000000000..921f51e5b8 --- /dev/null +++ b/tests/languages/kotlin/string_feature.test @@ -0,0 +1,113 @@ +"" +"foo" +"\"\"" + +"""""" +"""Foo "bar"" baz""" +""" +"Foo" +bar +""" + +// interpolation + +"$foo ${bar} ${'$'} ${foobar()}" +""" +$foo ${bar} +${'$'} ${foobar()} +""" + +---------------------------------------------------- + +[ + ["string-literal", [ + ["string", "\"\""] + ]], + ["string-literal", [ + ["string", "\"foo\""] + ]], + ["string-literal", [ + ["string", "\"\\\"\\\"\""] + ]], + + ["string-literal", [ + ["string", "\"\"\"\"\"\""] + ]], + ["string-literal", [ + ["string", "\"\"\"Foo \"bar\"\" baz\"\"\""] + ]], + ["string-literal", [ + ["string", "\"\"\"\r\n\"Foo\"\r\nbar\r\n\"\"\""] + ]], + + ["comment", "// interpolation"], + + ["string-literal", [ + ["string", "\""], + ["interpolation", [ + ["interpolation-punctuation", "$"], + ["expression", ["foo"]] + ]], + ["string", " "], + ["interpolation", [ + ["interpolation-punctuation", "${"], + ["expression", ["bar"]], + ["interpolation-punctuation", "}"] + ]], + ["string", " "], + ["interpolation", [ + ["interpolation-punctuation", "${"], + ["expression", [ + ["char", "'$'"] + ]], + ["interpolation-punctuation", "}"] + ]], + ["string", " "], + ["interpolation", [ + ["interpolation-punctuation", "${"], + ["expression", [ + ["function", "foobar"], + ["punctuation", "("], + ["punctuation", ")"] + ]], + ["interpolation-punctuation", "}"] + ]], + ["string", "\""] + ]], + ["string-literal", [ + ["string", "\"\"\"\r\n"], + ["interpolation", [ + ["interpolation-punctuation", "$"], + ["expression", ["foo"]] + ]], + ["string", " "], + ["interpolation", [ + ["interpolation-punctuation", "${"], + ["expression", ["bar"]], + ["interpolation-punctuation", "}"] + ]], + ["string", "\r\n"], + ["interpolation", [ + ["interpolation-punctuation", "${"], + ["expression", [ + ["char", "'$'"] + ]], + ["interpolation-punctuation", "}"] + ]], + ["string", " "], + ["interpolation", [ + ["interpolation-punctuation", "${"], + ["expression", [ + ["function", "foobar"], + ["punctuation", "("], + ["punctuation", ")"] + ]], + ["interpolation-punctuation", "}"] + ]], + ["string", "\r\n\"\"\""] + ]] +] + +---------------------------------------------------- + +Checks for raw strings.