diff --git a/components.js b/components.js index 7a221fc78a..5bfd705636 100644 --- a/components.js +++ b/components.js @@ -266,6 +266,11 @@ var components = { "title": "Keyman", "owner": "mcdurdin" }, + "kotlin": { + "title": "Kotlin", + "require": "clike", + "owner": "Golmote" + }, "latex": { "title": "LaTeX", "owner": "japborst" diff --git a/components/prism-kotlin.js b/components/prism-kotlin.js new file mode 100644 index 0000000000..e473c2fbf8 --- /dev/null +++ b/components/prism-kotlin.js @@ -0,0 +1,68 @@ +(function (Prism) { + Prism.languages.kotlin = Prism.languages.extend('clike', { + 'keyword': { + // The lookbehind prevents wrong highlighting of e.g. kotlin.properties.get + pattern: /(^|[^.])\b(?:abstract|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|else|enum|final|finally|for|fun|get|if|import|in|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|out|override|package|private|protected|public|reified|return|sealed|set|super|tailrec|this|throw|to|try|val|var|when|where|while)\b/, + lookbehind: true + }, + 'function': [ + /\w+(?=\s*\()/, + { + pattern: /(\.)\w+(?=\s*\{)/, + lookbehind: true + } + ], + 'number': /\b(?:0[bx][\da-fA-F]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?[fFL]?)\b/, + 'operator': /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/ + }); + + delete Prism.languages.kotlin["class-name"]; + + Prism.languages.insertBefore('kotlin', 'string', { + 'raw-string': { + pattern: /(["'])\1\1[\s\S]*?\1{3}/, + alias: 'string' + // See interpolation below + } + }); + Prism.languages.insertBefore('kotlin', 'keyword', { + 'annotation': { + pattern: /\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/, + alias: 'builtin' + } + }); + Prism.languages.insertBefore('kotlin', 'function', { + 'label': { + pattern: /\w+@|@\w+/, + alias: 'symbol' + } + }); + + var interpolation = [ + { + pattern: /\$\{[^}]+\}/, + inside: { + delimiter: { + pattern: /^\$\{|\}$/, + alias: 'variable' + }, + rest: Prism.util.clone(Prism.languages.kotlin) + } + }, + { + pattern: /\$\w+/, + alias: 'variable' + } + ]; + + Prism.languages.kotlin['string'] = { + pattern: Prism.languages.kotlin['string'], + inside: { + interpolation: interpolation + } + }; + Prism.languages.kotlin['raw-string'].inside = { + interpolation: interpolation + }; + +}(Prism)); \ No newline at end of file diff --git a/components/prism-kotlin.min.js b/components/prism-kotlin.min.js new file mode 100644 index 0000000000..dce90b6446 --- /dev/null +++ b/components/prism-kotlin.min.js @@ -0,0 +1 @@ +!function(n){n.languages.kotlin=n.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|else|enum|final|finally|for|fun|get|if|import|in|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|out|override|package|private|protected|public|reified|return|sealed|set|super|tailrec|this|throw|to|try|val|var|when|where|while)\b/,lookbehind:!0},"function":[/\w+(?=\s*\()/,{pattern:/(\.)\w+(?=\s*\{)/,lookbehind:!0}],number:/\b(?:0[bx][\da-fA-F]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete n.languages.kotlin["class-name"],n.languages.insertBefore("kotlin","string",{"raw-string":{pattern:/(["'])\1\1[\s\S]*?\1{3}/,alias:"string"}}),n.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),n.languages.insertBefore("kotlin","function",{label:{pattern:/\w+@|@\w+/,alias:"symbol"}});var e=[{pattern:/\$\{[^}]+\}/,inside:{delimiter:{pattern:/^\$\{|\}$/,alias:"variable"},rest:n.util.clone(n.languages.kotlin)}},{pattern:/\$\w+/,alias:"variable"}];n.languages.kotlin.string={pattern:n.languages.kotlin.string,inside:{interpolation:e}},n.languages.kotlin["raw-string"].inside={interpolation:e}}(Prism); \ No newline at end of file diff --git a/examples/prism-kotlin.html b/examples/prism-kotlin.html new file mode 100644 index 0000000000..c996624187 --- /dev/null +++ b/examples/prism-kotlin.html @@ -0,0 +1,147 @@ +
To use this language, use the class "language-kotlin".
+ +123
+123L
+0x0F
+0b00001011
+123.5
+123.5e10
+123.5f
+123.5F
+
+'2'
+'\uFF00'
+'\''
+
+"foo $bar \"baz"
+"""
+foo ${40 + 2}
+baz${bar()}
+"""
+
+loop@ for (i in 1..100) {
+ for (j in 1..100) {
+ if (...)
+ break@loop
+ }
+}
+
+public class MyTest {
+ lateinit var subject: TestSubject
+
+ @SetUp fun setup() {
+ subject = TestSubject()
+ }
+
+ @Test fun test() {
+ subject.method() // dereference directly
+ }
+}
+
+package com.example.html
+
+interface Element {
+ fun render(builder: StringBuilder, indent: String)
+
+ override fun toString(): String {
+ val builder = StringBuilder()
+ render(builder, "")
+ return builder.toString()
+ }
+}
+
+class TextElement(val text: String): Element {
+ override fun render(builder: StringBuilder, indent: String) {
+ builder.append("$indent$text\n")
+ }
+}
+
+abstract class Tag(val name: String): Element {
+ val children = arrayListOf<Element>()
+ val attributes = hashMapOf<String, String>()
+
+ protected fun initTag<T: Element>(tag: T, init: T.() -> Unit): T {
+ tag.init()
+ children.add(tag)
+ return tag
+ }
+
+ override fun render(builder: StringBuilder, indent: String) {
+ builder.append("$indent<$name${renderAttributes()}>\n")
+ for (c in children) {
+ c.render(builder, indent + " ")
+ }
+ builder.append("$indent</$name>\n")
+ }
+
+ private fun renderAttributes(): String? {
+ val builder = StringBuilder()
+ for (a in attributes.keySet()) {
+ builder.append(" $a=\"${attributes[a]}\"")
+ }
+ return builder.toString()
+ }
+}
+
+abstract class TagWithText(name: String): Tag(name) {
+ operator fun String.plus() {
+ children.add(TextElement(this))
+ }
+}
+
+class HTML(): TagWithText("html") {
+ fun head(init: Head.() -> Unit) = initTag(Head(), init)
+
+ fun body(init: Body.() -> Unit) = initTag(Body(), init)
+}
+
+class Head(): TagWithText("head") {
+ fun title(init: Title.() -> Unit) = initTag(Title(), init)
+}
+
+class Title(): TagWithText("title")
+
+abstract class BodyTag(name: String): TagWithText(name) {
+ fun b(init: B.() -> Unit) = initTag(B(), init)
+ fun p(init: P.() -> Unit) = initTag(P(), init)
+ fun h1(init: H1.() -> Unit) = initTag(H1(), init)
+ fun a(href: String, init: A.() -> Unit) {
+ val a = initTag(A(), init)
+ a.href = href
+ }
+}
+
+class Body(): BodyTag("body")
+
+class B(): BodyTag("b")
+class P(): BodyTag("p")
+class H1(): BodyTag("h1")
+class A(): BodyTag("a") {
+ public var href: String
+ get() = attributes["href"]!!
+ set(value) {
+ attributes["href"] = value
+ }
+}
+
+fun html(init: HTML.() -> Unit): HTML {
+ val html = HTML()
+ html.init()
+ return html
+}
+
+There are certain edge cases where Prism will fail. + There are always such cases in every regex-based syntax highlighter. + However, Prism dares to be open and honest about them. + If a failure is listed here, it doesn’t mean it will never be fixed. This is more of a “known bugs” list, just with a certain type of bug. +
+ +"foo /* bar */";
\ No newline at end of file
diff --git a/plugins/autoloader/prism-autoloader.js b/plugins/autoloader/prism-autoloader.js
index 0d04b72bc4..68a981ce7a 100644
--- a/plugins/autoloader/prism-autoloader.js
+++ b/plugins/autoloader/prism-autoloader.js
@@ -4,7 +4,7 @@
}
// The dependencies map is built automatically with gulp
- var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","fsharp":"clike","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","haxe":"clike","jade":"javascript","java":"clike","less":"css","markdown":"markup","nginx":"clike","objectivec":"c","parser":"markup","php":"clike","php-extras":"php","processing":"clike","qore":"clike","jsx":["markup","javascript"],"ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","wiki":"markup"}/*]*/;
+ var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","fsharp":"clike","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","haxe":"clike","jade":"javascript","java":"clike","kotlin":"clike","less":"css","markdown":"markup","nginx":"clike","objectivec":"c","parser":"markup","php":"clike","php-extras":"php","processing":"clike","qore":"clike","jsx":["markup","javascript"],"ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","wiki":"markup"}/*]*/;
var lang_data = {};
diff --git a/plugins/autoloader/prism-autoloader.min.js b/plugins/autoloader/prism-autoloader.min.js
index ef40ff60e6..3dffdf1e72 100644
--- a/plugins/autoloader/prism-autoloader.min.js
+++ b/plugins/autoloader/prism-autoloader.min.js
@@ -1 +1 @@
-!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",fsharp:"clike",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",haxe:"clike",jade:"javascript",java:"clike",less:"css",markdown:"markup",nginx:"clike",objectivec:"c",parser:"markup",php:"clike","php-extras":"php",processing:"clike",qore:"clike",jsx:["markup","javascript"],ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",wiki:"markup"},c={},a=Prism.plugins.autoloader={languages_path:"components/",use_minified:!0},s=function(e,c,a){var s=document.createElement("script");s.src=e,s.async=!0,s.onload=function(){document.body.removeChild(s),c&&c()},s.onerror=function(){document.body.removeChild(s),a&&a()},document.body.appendChild(s)},r=function(e){return a.languages_path+"prism-"+e+(a.use_minified?".min":"")+".js"},n=function(e,a){var s=c[e];s||(s=c[e]={});var r=a.getAttribute("data-dependencies");!r&&a.parentNode&&"pre"===a.parentNode.tagName.toLowerCase()&&(r=a.parentNode.getAttribute("data-dependencies")),r=r?r.split(/\s*,\s*/g):[],i(r,function(){t(e,function(){Prism.highlightElement(a)})})},i=function(e,c,a){"string"==typeof e&&(e=[e]);var s=0,r=e.length,n=function(){r>s?t(e[s],function(){s++,n()},function(){a&&a(e[s])}):s===r&&c&&c(e)};n()},t=function(a,n,t){var u=function(){var e=!1;a.indexOf("!")>=0&&(e=!0,a=a.replace("!",""));var i=c[a];if(i||(i=c[a]={}),n&&(i.success_callbacks||(i.success_callbacks=[]),i.success_callbacks.push(n)),t&&(i.error_callbacks||(i.error_callbacks=[]),i.error_callbacks.push(t)),!e&&Prism.languages[a])l(a);else if(!e&&i.error)o(a);else if(e||!i.loading){i.loading=!0;var u=r(a);s(u,function(){i.loading=!1,l(a)},function(){i.loading=!1,i.error=!0,o(a)})}},p=e[a];p&&p.length?i(p,u):u()},l=function(e){c[e]&&c[e].success_callbacks&&c[e].success_callbacks.length&&c[e].success_callbacks.forEach(function(c){c(e)})},o=function(e){c[e]&&c[e].error_callbacks&&c[e].error_callbacks.length&&c[e].error_callbacks.forEach(function(c){c(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&n(e.language,e.element)})}}();
\ No newline at end of file
+!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",fsharp:"clike",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",haxe:"clike",jade:"javascript",java:"clike",kotlin:"clike",less:"css",markdown:"markup",nginx:"clike",objectivec:"c",parser:"markup",php:"clike","php-extras":"php",processing:"clike",qore:"clike",jsx:["markup","javascript"],ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",wiki:"markup"},c={},a=Prism.plugins.autoloader={languages_path:"components/",use_minified:!0},s=function(e,c,a){var s=document.createElement("script");s.src=e,s.async=!0,s.onload=function(){document.body.removeChild(s),c&&c()},s.onerror=function(){document.body.removeChild(s),a&&a()},document.body.appendChild(s)},r=function(e){return a.languages_path+"prism-"+e+(a.use_minified?".min":"")+".js"},n=function(e,a){var s=c[e];s||(s=c[e]={});var r=a.getAttribute("data-dependencies");!r&&a.parentNode&&"pre"===a.parentNode.tagName.toLowerCase()&&(r=a.parentNode.getAttribute("data-dependencies")),r=r?r.split(/\s*,\s*/g):[],i(r,function(){t(e,function(){Prism.highlightElement(a)})})},i=function(e,c,a){"string"==typeof e&&(e=[e]);var s=0,r=e.length,n=function(){r>s?t(e[s],function(){s++,n()},function(){a&&a(e[s])}):s===r&&c&&c(e)};n()},t=function(a,n,t){var u=function(){var e=!1;a.indexOf("!")>=0&&(e=!0,a=a.replace("!",""));var i=c[a];if(i||(i=c[a]={}),n&&(i.success_callbacks||(i.success_callbacks=[]),i.success_callbacks.push(n)),t&&(i.error_callbacks||(i.error_callbacks=[]),i.error_callbacks.push(t)),!e&&Prism.languages[a])l(a);else if(!e&&i.error)o(a);else if(e||!i.loading){i.loading=!0;var u=r(a);s(u,function(){i.loading=!1,l(a)},function(){i.loading=!1,i.error=!0,o(a)})}},p=e[a];p&&p.length?i(p,u):u()},l=function(e){c[e]&&c[e].success_callbacks&&c[e].success_callbacks.length&&c[e].success_callbacks.forEach(function(c){c(e)})},o=function(e){c[e]&&c[e].error_callbacks&&c[e].error_callbacks.length&&c[e].error_callbacks.forEach(function(c){c(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&n(e.language,e.element)})}}();
\ No newline at end of file
diff --git a/tests/languages/kotlin/annotation_feature.test b/tests/languages/kotlin/annotation_feature.test
new file mode 100644
index 0000000000..05c138556d
--- /dev/null
+++ b/tests/languages/kotlin/annotation_feature.test
@@ -0,0 +1,21 @@
+@Deprecated(SUBSYSTEM_DEPRECATED)
+@SetUp
+@Suppress
+@field:Ann
+@file:JvmName
+@set:[Inject VisibleForTesting]
+
+----------------------------------------------------
+
+[
+ ["annotation", "@Deprecated"], ["punctuation", "("], "SUBSYSTEM_DEPRECATED", ["punctuation", ")"],
+ ["annotation", "@SetUp"],
+ ["annotation", "@Suppress"],
+ ["annotation", "@field:Ann"],
+ ["annotation", "@file:JvmName"],
+ ["annotation", "@set:[Inject VisibleForTesting]"]
+]
+
+----------------------------------------------------
+
+Checks for annotations.
\ No newline at end of file
diff --git a/tests/languages/kotlin/function_feature.test b/tests/languages/kotlin/function_feature.test
new file mode 100644
index 0000000000..8bfd2b2261
--- /dev/null
+++ b/tests/languages/kotlin/function_feature.test
@@ -0,0 +1,16 @@
+foo()
+foo_Bar_42()
+list.filter {}
+
+----------------------------------------------------
+
+[
+ ["function", "foo"], ["punctuation", "("], ["punctuation", ")"],
+ ["function", "foo_Bar_42"], ["punctuation", "("], ["punctuation", ")"],
+ "\r\nlist", ["punctuation", "."],
+ ["function", "filter"], ["punctuation", "{"], ["punctuation", "}"]
+]
+
+----------------------------------------------------
+
+Checks for functions.
\ No newline at end of file
diff --git a/tests/languages/kotlin/interpolation_feature.test b/tests/languages/kotlin/interpolation_feature.test
new file mode 100644
index 0000000000..0ee8299bf0
--- /dev/null
+++ b/tests/languages/kotlin/interpolation_feature.test
@@ -0,0 +1,46 @@
+"$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/keyword_feature.test b/tests/languages/kotlin/keyword_feature.test
new file mode 100644
index 0000000000..d8ace30581
--- /dev/null
+++ b/tests/languages/kotlin/keyword_feature.test
@@ -0,0 +1,121 @@
+abstract
+annotation
+as
+break
+by
+catch
+class
+companion
+const
+constructor
+continue
+crossinline
+data
+do
+else
+enum
+final
+finally
+for
+fun
+get
+if
+import
+in
+init
+inline
+inner
+interface
+internal
+is
+lateinit
+noinline
+null
+object
+open
+out
+override
+package
+private
+protected
+public
+reified
+return
+sealed
+set
+super
+tailrec
+this
+throw
+to
+try
+val
+var
+when
+where
+while
+
+----------------------------------------------------
+
+[
+ ["keyword", "abstract"],
+ ["keyword", "annotation"],
+ ["keyword", "as"],
+ ["keyword", "break"],
+ ["keyword", "by"],
+ ["keyword", "catch"],
+ ["keyword", "class"],
+ ["keyword", "companion"],
+ ["keyword", "const"],
+ ["keyword", "constructor"],
+ ["keyword", "continue"],
+ ["keyword", "crossinline"],
+ ["keyword", "data"],
+ ["keyword", "do"],
+ ["keyword", "else"],
+ ["keyword", "enum"],
+ ["keyword", "final"],
+ ["keyword", "finally"],
+ ["keyword", "for"],
+ ["keyword", "fun"],
+ ["keyword", "get"],
+ ["keyword", "if"],
+ ["keyword", "import"],
+ ["keyword", "in"],
+ ["keyword", "init"],
+ ["keyword", "inline"],
+ ["keyword", "inner"],
+ ["keyword", "interface"],
+ ["keyword", "internal"],
+ ["keyword", "is"],
+ ["keyword", "lateinit"],
+ ["keyword", "noinline"],
+ ["keyword", "null"],
+ ["keyword", "object"],
+ ["keyword", "open"],
+ ["keyword", "out"],
+ ["keyword", "override"],
+ ["keyword", "package"],
+ ["keyword", "private"],
+ ["keyword", "protected"],
+ ["keyword", "public"],
+ ["keyword", "reified"],
+ ["keyword", "return"],
+ ["keyword", "sealed"],
+ ["keyword", "set"],
+ ["keyword", "super"],
+ ["keyword", "tailrec"],
+ ["keyword", "this"],
+ ["keyword", "throw"],
+ ["keyword", "to"],
+ ["keyword", "try"],
+ ["keyword", "val"],
+ ["keyword", "var"],
+ ["keyword", "when"],
+ ["keyword", "where"],
+ ["keyword", "while"]
+]
+
+----------------------------------------------------
+
+Checks for keywords.
\ No newline at end of file
diff --git a/tests/languages/kotlin/label_feature.test b/tests/languages/kotlin/label_feature.test
new file mode 100644
index 0000000000..fa6226603a
--- /dev/null
+++ b/tests/languages/kotlin/label_feature.test
@@ -0,0 +1,15 @@
+loop@
+break@loop
+return@forEach
+
+----------------------------------------------------
+
+[
+ ["label", "loop@"],
+ ["keyword", "break"], ["label", "@loop"],
+ ["keyword", "return"], ["label", "@forEach"]
+]
+
+----------------------------------------------------
+
+Checks for labels.
\ No newline at end of file
diff --git a/tests/languages/kotlin/number_feature.test b/tests/languages/kotlin/number_feature.test
new file mode 100644
index 0000000000..df21736c63
--- /dev/null
+++ b/tests/languages/kotlin/number_feature.test
@@ -0,0 +1,29 @@
+123
+123L
+0x0F
+0b00001011
+123.5
+123.5e10
+123.5e-10
+123.5e+10
+123.5f
+123.5F
+
+----------------------------------------------------
+
+[
+ ["number", "123"],
+ ["number", "123L"],
+ ["number", "0x0F"],
+ ["number", "0b00001011"],
+ ["number", "123.5"],
+ ["number", "123.5e10"],
+ ["number", "123.5e-10"],
+ ["number", "123.5e+10"],
+ ["number", "123.5f"],
+ ["number", "123.5F"]
+]
+
+----------------------------------------------------
+
+Checks for numbers.
\ No newline at end of file
diff --git a/tests/languages/kotlin/operator_feature.test b/tests/languages/kotlin/operator_feature.test
new file mode 100644
index 0000000000..12f0cae315
--- /dev/null
+++ b/tests/languages/kotlin/operator_feature.test
@@ -0,0 +1,31 @@
++ ++ +=
+- -- -= ->
+= == ===
+! !! != !==
+/ /= * *=
+% %=
+< <= > >=
+? ?: : ::
+.. && ||
+and inv or
+shl shr ushr xor
+
+----------------------------------------------------
+
+[
+ ["operator", "+"], ["operator", "++"], ["operator", "+="],
+ ["operator", "-"], ["operator", "--"], ["operator", "-="], ["operator", "->"],
+ ["operator", "="], ["operator", "=="], ["operator", "==="],
+ ["operator", "!"], ["operator", "!!"], ["operator", "!="], ["operator", "!=="],
+ ["operator", "/"], ["operator", "/="], ["operator", "*"], ["operator", "*="],
+ ["operator", "%"], ["operator", "%="],
+ ["operator", "<"], ["operator", "<="], ["operator", ">"], ["operator", ">="],
+ ["operator", "?"], ["operator", "?:"], ["operator", ":"], ["operator", "::"],
+ ["operator", ".."], ["operator", "&&"], ["operator", "||"],
+ ["operator", "and"], ["operator", "inv"], ["operator", "or"],
+ ["operator", "shl"], ["operator", "shr"], ["operator", "ushr"], ["operator", "xor"]
+]
+
+----------------------------------------------------
+
+Checks for operators.
\ No newline at end of file
diff --git a/tests/languages/kotlin/raw-string_feature.test b/tests/languages/kotlin/raw-string_feature.test
new file mode 100644
index 0000000000..5a5ca3309b
--- /dev/null
+++ b/tests/languages/kotlin/raw-string_feature.test
@@ -0,0 +1,18 @@
+""""""
+"""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