From eeb6227f898df47dfd1038575e17b3934a0fe8c6 Mon Sep 17 00:00:00 2001 From: Jan Dolinar Date: Tue, 22 Dec 2020 17:00:45 +0100 Subject: [PATCH] kotlin: regex parser --- .../kotlin-destructuring.d/expected.tags | 8 + .../kotlin-destructuring.d/input.kt | 4 + .../kotlin-extensions.d/expected.tags | 3 + .../kotlin-extensions.d/input.kt | 6 + .../kotlin-generics.d/expected.tags | 5 + .../kotlin-generics.d/input.kt | 5 + .../kotlin-multilinestrings.d/expected.tags | 3 + .../kotlin-multilinestrings.d/input.kt | 5 + .../kotlin-quotes.d/expected.tags | 1 + .../parser-kotlin.r/kotlin-quotes.d/input.kt | 15 ++ .../kotlin-strings.d/expected.tags | 2 + .../parser-kotlin.r/kotlin-strings.d/input.kt | 2 + .../kotlin-syntax.d/args.ctags | 1 + .../kotlin-syntax.d/expected.tags | 10 ++ .../parser-kotlin.r/kotlin-syntax.d/input.kt | 20 +++ main/parsers_p.h | 1 + makefiles/optlib2c_input.mak | 1 + optlib/kotlin.c | 165 ++++++++++++++++++ optlib/kotlin.ctags | 91 ++++++++++ win32/ctags_vs2013.vcxproj | 1 + win32/ctags_vs2013.vcxproj.filters | 3 + 21 files changed, 352 insertions(+) create mode 100644 Units/parser-kotlin.r/kotlin-destructuring.d/expected.tags create mode 100644 Units/parser-kotlin.r/kotlin-destructuring.d/input.kt create mode 100644 Units/parser-kotlin.r/kotlin-extensions.d/expected.tags create mode 100644 Units/parser-kotlin.r/kotlin-extensions.d/input.kt create mode 100644 Units/parser-kotlin.r/kotlin-generics.d/expected.tags create mode 100644 Units/parser-kotlin.r/kotlin-generics.d/input.kt create mode 100644 Units/parser-kotlin.r/kotlin-multilinestrings.d/expected.tags create mode 100644 Units/parser-kotlin.r/kotlin-multilinestrings.d/input.kt create mode 100644 Units/parser-kotlin.r/kotlin-quotes.d/expected.tags create mode 100644 Units/parser-kotlin.r/kotlin-quotes.d/input.kt create mode 100644 Units/parser-kotlin.r/kotlin-strings.d/expected.tags create mode 100644 Units/parser-kotlin.r/kotlin-strings.d/input.kt create mode 100644 Units/parser-kotlin.r/kotlin-syntax.d/args.ctags create mode 100644 Units/parser-kotlin.r/kotlin-syntax.d/expected.tags create mode 100644 Units/parser-kotlin.r/kotlin-syntax.d/input.kt create mode 100644 optlib/kotlin.c create mode 100644 optlib/kotlin.ctags diff --git a/Units/parser-kotlin.r/kotlin-destructuring.d/expected.tags b/Units/parser-kotlin.r/kotlin-destructuring.d/expected.tags new file mode 100644 index 0000000000..624342f583 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-destructuring.d/expected.tags @@ -0,0 +1,8 @@ +a input.kt /^val (a, b) = functionReturningPair()$/;" C +b input.kt /^val (a, b) = functionReturningPair()$/;" C +c input.kt /^val (c: Int, d: String) = functionReturningPair()$/;" C +d input.kt /^val (c: Int, d: String) = functionReturningPair()$/;" C +e input.kt /^var (e, f) = functionReturningPair()$/;" v +f input.kt /^var (e, f) = functionReturningPair()$/;" v +g input.kt /^var (g: Int, h: String) = functionReturningPair()$/;" v +h input.kt /^var (g: Int, h: String) = functionReturningPair()$/;" v diff --git a/Units/parser-kotlin.r/kotlin-destructuring.d/input.kt b/Units/parser-kotlin.r/kotlin-destructuring.d/input.kt new file mode 100644 index 0000000000..5642b2ccfb --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-destructuring.d/input.kt @@ -0,0 +1,4 @@ +val (a, b) = functionReturningPair() +val (c: Int, d: String) = functionReturningPair() +var (e, f) = functionReturningPair() +var (g: Int, h: String) = functionReturningPair() diff --git a/Units/parser-kotlin.r/kotlin-extensions.d/expected.tags b/Units/parser-kotlin.r/kotlin-extensions.d/expected.tags new file mode 100644 index 0000000000..7c3c55d82b --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-extensions.d/expected.tags @@ -0,0 +1,3 @@ +A input.kt /^class A$/;" c +test input.kt /^fun A.test() = true$/;" m +value input.kt /^val A.value$/;" C diff --git a/Units/parser-kotlin.r/kotlin-extensions.d/input.kt b/Units/parser-kotlin.r/kotlin-extensions.d/input.kt new file mode 100644 index 0000000000..1276b42f9a --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-extensions.d/input.kt @@ -0,0 +1,6 @@ +class A + +fun A.test() = true + +val A.value + get() = "AAA" diff --git a/Units/parser-kotlin.r/kotlin-generics.d/expected.tags b/Units/parser-kotlin.r/kotlin-generics.d/expected.tags new file mode 100644 index 0000000000..5b07d9c6c6 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-generics.d/expected.tags @@ -0,0 +1,5 @@ +Bar input.kt /^class Bar(val a: T, val b: U): Foo$/;" c +Foo input.kt /^interface Foo {$/;" i +a input.kt /^class Bar(val a: T, val b: U): Foo$/;" C +b input.kt /^class Bar(val a: T, val b: U): Foo$/;" C +genericFunction input.kt /^ fun genericFunction() = 42$/;" m diff --git a/Units/parser-kotlin.r/kotlin-generics.d/input.kt b/Units/parser-kotlin.r/kotlin-generics.d/input.kt new file mode 100644 index 0000000000..8cd7069918 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-generics.d/input.kt @@ -0,0 +1,5 @@ +interface Foo { + fun genericFunction() = 42 +} + +class Bar(val a: T, val b: U): Foo diff --git a/Units/parser-kotlin.r/kotlin-multilinestrings.d/expected.tags b/Units/parser-kotlin.r/kotlin-multilinestrings.d/expected.tags new file mode 100644 index 0000000000..f87a4e299b --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-multilinestrings.d/expected.tags @@ -0,0 +1,3 @@ +used1 input.kt /^var used1 = """var unused1 = 1"""$/;" v +used2 input.kt /^var used2 = """$/;" v +used3 input.kt /^var used3 = """var unused3 = 3""" + """var unused4 = 4"""$/;" v diff --git a/Units/parser-kotlin.r/kotlin-multilinestrings.d/input.kt b/Units/parser-kotlin.r/kotlin-multilinestrings.d/input.kt new file mode 100644 index 0000000000..cdaf8f25de --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-multilinestrings.d/input.kt @@ -0,0 +1,5 @@ +var used1 = """var unused1 = 1""" +var used2 = """ + var unused2 = 2 +""" +var used3 = """var unused3 = 3""" + """var unused4 = 4""" diff --git a/Units/parser-kotlin.r/kotlin-quotes.d/expected.tags b/Units/parser-kotlin.r/kotlin-quotes.d/expected.tags new file mode 100644 index 0000000000..f7d65b14b2 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-quotes.d/expected.tags @@ -0,0 +1 @@ +f input.kt /^\/* comment *\/ var f = 6 \/* another comment *\/$/;" v diff --git a/Units/parser-kotlin.r/kotlin-quotes.d/input.kt b/Units/parser-kotlin.r/kotlin-quotes.d/input.kt new file mode 100644 index 0000000000..e503f386c9 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-quotes.d/input.kt @@ -0,0 +1,15 @@ +// var a = 1 + +/* var b = 2 */ + +/* +var c = 3 +*/ + +/** var d = 4 */ + +/** + * var e = 5 + */ + +/* comment */ var f = 6 /* another comment */ diff --git a/Units/parser-kotlin.r/kotlin-strings.d/expected.tags b/Units/parser-kotlin.r/kotlin-strings.d/expected.tags new file mode 100644 index 0000000000..b47a4444aa --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-strings.d/expected.tags @@ -0,0 +1,2 @@ +used1 input.kt /^var used1 = "var unused1 = 1"$/;" v +used2 input.kt /^var used2 = "\\"var\\" unused2 = 2"$/;" v diff --git a/Units/parser-kotlin.r/kotlin-strings.d/input.kt b/Units/parser-kotlin.r/kotlin-strings.d/input.kt new file mode 100644 index 0000000000..ce25c7b766 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-strings.d/input.kt @@ -0,0 +1,2 @@ +var used1 = "var unused1 = 1" +var used2 = "\"var\" unused2 = 2" diff --git a/Units/parser-kotlin.r/kotlin-syntax.d/args.ctags b/Units/parser-kotlin.r/kotlin-syntax.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-syntax.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-kotlin.r/kotlin-syntax.d/expected.tags b/Units/parser-kotlin.r/kotlin-syntax.d/expected.tags new file mode 100644 index 0000000000..51b7777a75 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-syntax.d/expected.tags @@ -0,0 +1,10 @@ +AbstractWorker input.kt /^interface AbstractWorker {$/;" i +process input.kt /^ abstract fun process(): String$/;" m +Worker input.kt /^class Worker(val name: T): AbstractWorker {$/;" c +name input.kt /^class Worker(val name: T): AbstractWorker {$/;" C +process input.kt /^ override fun process(): String = name.toString()$/;" m +Global input.kt /^object Global {$/;" o +greeting input.kt /^ const val greeting = "Hello"$/;" C +StringWorker input.kt /^typealias StringWorker = Worker$/;" T +main input.kt /^fun main() {$/;" m +result input.kt /^ var result: String = Global.greeting$/;" v diff --git a/Units/parser-kotlin.r/kotlin-syntax.d/input.kt b/Units/parser-kotlin.r/kotlin-syntax.d/input.kt new file mode 100644 index 0000000000..574ac78956 --- /dev/null +++ b/Units/parser-kotlin.r/kotlin-syntax.d/input.kt @@ -0,0 +1,20 @@ +interface AbstractWorker { + abstract fun process(): String +} + +class Worker(val name: T): AbstractWorker { + override fun process(): String = name.toString() +} + +object Global { + const val greeting = "Hello" +} + +typealias StringWorker = Worker + +fun main() { + var result: String = Global.greeting + result = "$result " + StringWorker("World").process() + result += "!" + println(result) +} diff --git a/main/parsers_p.h b/main/parsers_p.h index f202fb0782..f7a348d73d 100644 --- a/main/parsers_p.h +++ b/main/parsers_p.h @@ -97,6 +97,7 @@ JsonParser, \ JuliaParser, \ KconfigParser, \ + KotlinParser, \ LdScriptParser, \ LispParser, \ LiterateHaskellParser, \ diff --git a/makefiles/optlib2c_input.mak b/makefiles/optlib2c_input.mak index 43fdbf324f..bf24faf552 100644 --- a/makefiles/optlib2c_input.mak +++ b/makefiles/optlib2c_input.mak @@ -8,6 +8,7 @@ OPTLIB2C_INPUT = \ optlib/gdbinit.ctags \ optlib/inko.ctags \ optlib/kconfig.ctags \ + optlib/kotlin.ctags \ optlib/man.ctags \ optlib/markdown.ctags \ optlib/meson.ctags \ diff --git a/optlib/kotlin.c b/optlib/kotlin.c new file mode 100644 index 0000000000..45ed97208b --- /dev/null +++ b/optlib/kotlin.c @@ -0,0 +1,165 @@ +/* + * Generated by ./misc/optlib2c from optlib/kotlin.ctags, Don't edit this manually. + */ +#include "general.h" +#include "parse.h" +#include "routines.h" +#include "field.h" +#include "xtag.h" + + +static void initializeKotlinParser (const langType language) +{ + + addLanguageRegexTable (language, "toplevel"); + addLanguageRegexTable (language, "comment"); + addLanguageRegexTable (language, "string"); + addLanguageRegexTable (language, "mlstring"); + addLanguageRegexTable (language, "vals"); + addLanguageRegexTable (language, "vars"); + + addLanguageTagMultiTableRegex (language, "toplevel", + "^/\\*", + "", "", "{tenter=comment}", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^//[^\n]*\n", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^\"\"\"", + "", "", "{tenter=mlstring}", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^\"", + "", "", "{tenter=string}", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^'.{1,2}'", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^val\\s+\\(\\s*", + "", "", "{tenter=vals}", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^var\\s+\\(\\s*", + "", "", "{tenter=vars}", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^class\\s+([[:alnum:]_]+)", + "\\1", "c", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^interface\\s+([[:alnum:]_]+)", + "\\1", "i", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^object\\s+([[:alnum:]_]+)", + "\\1", "o", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^typealias\\s+([[:alnum:]_]+)", + "\\1", "T", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^fun(<.*>)*\\s+([[:alnum:]_]+\\.)*([[:alnum:]_]+)", + "\\3", "m", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^val\\s+([[:alnum:]_]+\\.)*([[:alnum:]_]+)", + "\\2", "C", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^var\\s+([[:alnum:]_]+\\.)*([[:alnum:]_]+)", + "\\2", "v", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^[[:alnum:]]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "toplevel", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "comment", + "^\\*/", + "", "", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "comment", + "^[^*]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "comment", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "string", + "^[^\\\\\"]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "string", + "^\\\\.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "string", + "^\"", + "", "", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "string", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "mlstring", + "^\"\"\"", + "", "", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "mlstring", + "^[^\\\\\"]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "mlstring", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "vals", + "^([[:alnum:]_]+)\\s*(:\\s*[[:alnum:]_]+)*\\s*,*\\s*", + "\\1", "C", "", NULL); + addLanguageTagMultiTableRegex (language, "vals", + "^\\)", + "", "", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "vars", + "^([[:alnum:]_]+)\\s*(:\\s*[[:alnum:]_]+)*\\s*,*\\s*", + "\\1", "v", "", NULL); + addLanguageTagMultiTableRegex (language, "vars", + "^\\)", + "", "", "{tleave}", NULL); +} + +extern parserDefinition* KotlinParser (void) +{ + static const char *const extensions [] = { + "kt", + "kts", + NULL + }; + + static const char *const aliases [] = { + NULL + }; + + static const char *const patterns [] = { + NULL + }; + + static kindDefinition KotlinKindTable [] = { + { + true, 'c', "class", "classes", + }, + { + true, 'o', "object", "objects", + }, + { + true, 'i', "interface", "interfaces", + }, + { + true, 'T', "typealias", "typealiases", + }, + { + true, 'm', "method", "methods", + }, + { + true, 'C', "constant", "constants", + }, + { + true, 'v', "variable", "variables", + }, + }; + + parserDefinition* const def = parserNew ("Kotlin"); + + def->enabled = true; + def->extensions = extensions; + def->patterns = patterns; + def->aliases = aliases; + def->method = METHOD_NOT_CRAFTED|METHOD_REGEX; + def->kindTable = KotlinKindTable; + def->kindCount = ARRAY_SIZE(KotlinKindTable); + def->initialize = initializeKotlinParser; + + return def; +} diff --git a/optlib/kotlin.ctags b/optlib/kotlin.ctags new file mode 100644 index 0000000000..052d48ae67 --- /dev/null +++ b/optlib/kotlin.ctags @@ -0,0 +1,91 @@ +# +# Copyright (c) 2020, Jan DolinĂ¡r +# +# Author: Jan DolinĂ¡r +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. +# + +# Reference documentation for Kotlin language can be found +# at https://kotlinlang.org/docs/reference/, including its +# grammar (https://kotlinlang.org/docs/reference/grammar.html). + +# Known issues: +# - annotations are not handled correctly + +# Regex for Kotlin +--langdef=Kotlin +--map-Kotlin=+.kt +--map-Kotlin=+.kts + +--kinddef-Kotlin=c,class,classes +--kinddef-Kotlin=o,object,objects +--kinddef-Kotlin=i,interface,interfaces +--kinddef-Kotlin=T,typealias,typealiases +--kinddef-Kotlin=m,method,methods +--kinddef-Kotlin=C,constant,constants +--kinddef-Kotlin=v,variable,variables + +--_tabledef-Kotlin=toplevel +--_tabledef-Kotlin=comment +--_tabledef-Kotlin=string +--_tabledef-Kotlin=mlstring +--_tabledef-Kotlin=vals +--_tabledef-Kotlin=vars + +# ignore anything in comment +--_mtable-regex-Kotlin=toplevel/\/\*//{tenter=comment} +--_mtable-regex-Kotlin=toplevel/\/\/[^\n]*\n// +--_mtable-regex-Kotlin=comment/\*\///{tleave} +--_mtable-regex-Kotlin=comment/[^*]+// +--_mtable-regex-Kotlin=comment/.// + +# ignore anything in multiline strings +--_mtable-regex-Kotlin=toplevel/"""//{tenter=mlstring} +--_mtable-regex-Kotlin=mlstring/"""//{tleave} +--_mtable-regex-Kotlin=mlstring/[^\\"]+// +--_mtable-regex-Kotlin=mlstring/.// + +# ignore anything in strings +--_mtable-regex-Kotlin=toplevel/"//{tenter=string} +--_mtable-regex-Kotlin=string/[^\\"]+// +--_mtable-regex-Kotlin=string/\\.// +--_mtable-regex-Kotlin=string/"//{tleave} +--_mtable-regex-Kotlin=string/.// + +# ignore character literals +--_mtable-regex-Kotlin=toplevel/'.{1,2}'// + +# handle destructuring declarations +--_mtable-regex-Kotlin=toplevel/val\s+\(\s*//{tenter=vals} +--_mtable-regex-Kotlin=vals/([[:alnum:]_]+)\s*(:\s*[[:alnum:]_]+)*\s*,*\s*/\1/C/ +--_mtable-regex-Kotlin=vals/\)//{tleave} +--_mtable-regex-Kotlin=toplevel/var\s+\(\s*//{tenter=vars} +--_mtable-regex-Kotlin=vars/([[:alnum:]_]+)\s*(:\s*[[:alnum:]_]+)*\s*,*\s*/\1/v/ +--_mtable-regex-Kotlin=vars/\)//{tleave} + +# parse the language constructs +--_mtable-regex-Kotlin=toplevel/class\s+([[:alnum:]_]+)/\1/c/ +--_mtable-regex-Kotlin=toplevel/interface\s+([[:alnum:]_]+)/\1/i/ +--_mtable-regex-Kotlin=toplevel/object\s+([[:alnum:]_]+)/\1/o/ +--_mtable-regex-Kotlin=toplevel/typealias\s+([[:alnum:]_]+)/\1/T/ +--_mtable-regex-Kotlin=toplevel/fun(<.*>)*\s+([[:alnum:]_]+\.)*([[:alnum:]_]+)/\3/m/ +--_mtable-regex-Kotlin=toplevel/val\s+([[:alnum:]_]+\.)*([[:alnum:]_]+)/\2/C/ +--_mtable-regex-Kotlin=toplevel/var\s+([[:alnum:]_]+\.)*([[:alnum:]_]+)/\2/v/ + +# ignore anything else +--_mtable-regex-Kotlin=toplevel/[[:alnum:]]+// +--_mtable-regex-Kotlin=toplevel/.// diff --git a/win32/ctags_vs2013.vcxproj b/win32/ctags_vs2013.vcxproj index b4b693d313..f7b7c2d846 100644 --- a/win32/ctags_vs2013.vcxproj +++ b/win32/ctags_vs2013.vcxproj @@ -157,6 +157,7 @@ + diff --git a/win32/ctags_vs2013.vcxproj.filters b/win32/ctags_vs2013.vcxproj.filters index cecb2b1cb8..ace672745b 100644 --- a/win32/ctags_vs2013.vcxproj.filters +++ b/win32/ctags_vs2013.vcxproj.filters @@ -207,6 +207,9 @@ Source Files\optlib + + Source Files\optlib + Source Files\optlib