From 6d7dd58f7072622e90fa5db2f1f4e398707b7fc8 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Fri, 30 Mar 2018 13:58:12 +0300 Subject: [PATCH] Separated idl2k frontend and backend invocations. --- .../tools/idl2k/src/main/kotlin/build.kt | 129 ++++++++++++++++ .../tools/idl2k/src/main/kotlin/generator.kt | 31 ++++ libraries/tools/idl2k/src/main/kotlin/main.kt | 139 +----------------- 3 files changed, 165 insertions(+), 134 deletions(-) create mode 100644 libraries/tools/idl2k/src/main/kotlin/build.kt create mode 100644 libraries/tools/idl2k/src/main/kotlin/generator.kt diff --git a/libraries/tools/idl2k/src/main/kotlin/build.kt b/libraries/tools/idl2k/src/main/kotlin/build.kt new file mode 100644 index 00000000000..967f6b86c9e --- /dev/null +++ b/libraries/tools/idl2k/src/main/kotlin/build.kt @@ -0,0 +1,129 @@ +package org.jetbrains.idl2k + +import org.antlr.v4.runtime.ANTLRFileStream +import kotlin.collections.HashSet +import java.io.File +import java.io.IOException +import java.net.URL +import java.util.ArrayList +import java.util.LinkedHashMap + + +class BuildWebIdl(val mdnCacheFile: File, val srcDir: File) { + val repositoryPre = loadPreliminaryRepository() + + fun loadPreliminaryRepository(): Repository { + if (!srcDir.exists()) { + System.err?.println("Directory ${srcDir.absolutePath} doesn't exist") + System.exit(1) + } + + return srcDir.walkTopDown().filter { it.isDirectory || it.extension == "idl" }.asSequence().filter { it.isFile }.toList().sortedBy { it.absolutePath }.fold(Repository(emptyMap(), emptyMap(), emptyMap(), emptyMap())) { acc, e -> + System.err.flush() + System.err.println("Parsing ${e.absolutePath}") + val fileRepository = parseIDL(ANTLRFileStream(e.absolutePath, "UTF-8")) + + Repository( + interfaces = acc.interfaces.mergeReduce(fileRepository.interfaces, ::merge), + typeDefs = acc.typeDefs + fileRepository.typeDefs, + externals = acc.externals.merge(fileRepository.externals), + enums = acc.enums + fileRepository.enums + ) + } + } + + init { + println("Prepare...") + } + + val repository = repositoryPre.copy(typeDefs = repositoryPre.typeDefs.mapValues { it.value.copy(mapType(repositoryPre, it.value.types)) }) + + val definitions = mapDefinitions(repository, repository.interfaces.values).map { + if (it.name in relocations) { + // we need this to get interfaces listed in the relocations in valid package + // to keep compatibility with DOM Java API + it.copy(namespace = relocations[it.name]!!) + } else { + it + } + } + val unions = generateUnions(definitions, repository.typeDefs.values) + + init { + implementInterfaces(definitions) + } + + val allPackages = (definitions.asSequence().map { it.namespace } + repository.enums.values.map { it.namespace }).distinct().sorted() + + val mdnCache by lazy { updateMdnCache() } + + fun updateMdnCache(): MDNDocumentationCache { + println("Processing MDN") + + val oldMdnCache = if (mdnCacheFile.canRead()) MDNDocumentationCache.read(mdnCacheFile) else MDNDocumentationCache.Empty + val newMdnCacheExisting = HashSet(oldMdnCache.existing) + val newMdnCacheNonExisting = HashSet(oldMdnCache.nonExisting) + + for (iface in definitions) { + val url = "https://developer.mozilla.org/en/docs/Web/API/${iface.name}" + val addUrl = when (oldMdnCache.checkInCache(url)) { + true -> true + false -> false + else -> try { + val text = URL(url).openStream().reader().use { it.readText() } + text.contains(iface.name, ignoreCase = true) + } catch (ignore: IOException) { + false + } + } + + if (addUrl) + newMdnCacheExisting.add(url) + else + newMdnCacheNonExisting.add(url) + } + + val mdnCache = MDNDocumentationCache(newMdnCacheExisting, newMdnCacheNonExisting) + MDNDocumentationCache.writeTo(mdnCache, mdnCacheFile) + + return mdnCache + } +} + + +internal fun Map>.reduceValues(reduce: (V, V) -> V = { a, b -> b }): Map = mapValues { it.value.reduce(reduce) } + +internal fun Map.mergeReduce(other: Map, reduce: (V, V) -> V = { a, b -> b }): Map { + val result = LinkedHashMap(this.size + other.size) + result.putAll(this) + other.forEach { e -> + val existing = result[e.key] + + if (existing == null) { + result[e.key] = e.value + } + else { + result[e.key] = reduce(e.value, existing) + } + } + + return result +} + +internal fun Map>.merge(other: Map>): Map> { + val result = LinkedHashMap>(size + other.size) + this.forEach { + result[it.key] = ArrayList(it.value) + } + other.forEach { + val list = result[it.key] + if (list == null) { + result[it.key] = ArrayList(it.value) + } + else { + list.addAll(it.value) + } + } + + return result +} \ No newline at end of file diff --git a/libraries/tools/idl2k/src/main/kotlin/generator.kt b/libraries/tools/idl2k/src/main/kotlin/generator.kt new file mode 100644 index 00000000000..6e9bb7a15da --- /dev/null +++ b/libraries/tools/idl2k/src/main/kotlin/generator.kt @@ -0,0 +1,31 @@ +package org.jetbrains.idl2k + +import java.io.File + +fun BuildWebIdl.jsGenerator(outDir: File, copyrightNotice: String) { + + outDir.deleteRecursively() + outDir.mkdirs() + + allPackages.forEach { pkg -> + File(outDir, pkg + ".kt").bufferedWriter().use { w -> + println("Generating for package $pkg...") + w.appendln(copyrightNotice) + w.appendln("// NOTE: THIS FILE IS AUTO-GENERATED, DO NOT EDIT!") + w.appendln("// See libraries/tools/idl2k for details") + + w.appendln() + w.appendln("@file:Suppress(\"NESTED_CLASS_IN_EXTERNAL_INTERFACE\")") + w.appendln("package $pkg") + w.appendln() + + w.appendln("import kotlin.js.*") + allPackages.filter { it != pkg }.forEach { import -> + w.appendln("import $import.*") + } + w.appendln() + + w.render(pkg, definitions, unions, repository.enums.values.toList(), mdnCache) + } + } +} \ No newline at end of file diff --git a/libraries/tools/idl2k/src/main/kotlin/main.kt b/libraries/tools/idl2k/src/main/kotlin/main.kt index 932b9025fb0..64c5648e397 100644 --- a/libraries/tools/idl2k/src/main/kotlin/main.kt +++ b/libraries/tools/idl2k/src/main/kotlin/main.kt @@ -1,144 +1,15 @@ package org.jetbrains.idl2k -import org.antlr.v4.runtime.ANTLRFileStream import org.jetbrains.idl2k.util.readCopyrightNoticeFromProfile import java.io.* -import java.net.* -import java.util.* -import kotlin.collections.HashSet fun main(args: Array) { - val mdnCacheFile = File("target/mdn-cache.txt") - val outDir = File("../../stdlib/js/src/org.w3c") - val srcDir = File("../../stdlib/js/idl") - if (!srcDir.exists()) { - System.err?.println("Directory ${srcDir.absolutePath} doesn't exist") - System.exit(1) - return - } - - val copyrightNotice = readCopyrightNoticeFromProfile(File("../../../.idea/copyright/apache.xml")) - - val repositoryPre = srcDir.walkTopDown().filter { it.isDirectory || it.extension == "idl" }.asSequence().filter { it.isFile }.toList().sortedBy { it.absolutePath }.fold(Repository(emptyMap(), emptyMap(), emptyMap(), emptyMap())) { acc, e -> - System.err.flush() - System.err.println("Parsing ${e.absolutePath}") - val fileRepository = parseIDL(ANTLRFileStream(e.absolutePath, "UTF-8")) - - Repository( - interfaces = acc.interfaces.mergeReduce(fileRepository.interfaces, ::merge), - typeDefs = acc.typeDefs + fileRepository.typeDefs, - externals = acc.externals.merge(fileRepository.externals), - enums = acc.enums + fileRepository.enums - ) - } - - println("Prepare...") - - val repository = repositoryPre.copy(typeDefs = repositoryPre.typeDefs.mapValues { it.value.copy(mapType(repositoryPre, it.value.types)) }) - - val definitions = mapDefinitions(repository, repository.interfaces.values).map { - if (it.name in relocations) { - // we need this to get interfaces listed in the relocations in valid package - // to keep compatibility with DOM Java API - it.copy(namespace = relocations[it.name]!!) - } else { - it - } - } - val unions = generateUnions(definitions, repository.typeDefs.values) - val allPackages = (definitions.asSequence().map { it.namespace } + repository.enums.values.map { it.namespace }).distinct().sorted() - implementInterfaces(definitions) - - outDir.deleteRecursively() - outDir.mkdirs() - - println("Processing MDN") - val oldMdnCache = if (mdnCacheFile.canRead()) MDNDocumentationCache.read(mdnCacheFile) else MDNDocumentationCache.Empty - val newMdnCacheExisting = HashSet(oldMdnCache.existing) - val newMdnCacheNonExisting = HashSet(oldMdnCache.nonExisting) - - for (iface in definitions) { - val url = "https://developer.mozilla.org/en/docs/Web/API/${iface.name}" - val addUrl = when (oldMdnCache.checkInCache(url)) { - true -> true - false -> false - else -> try { - val text = URL(url).openStream().reader().use { it.readText() } - text.contains(iface.name, ignoreCase = true) - } catch (ignore: IOException) { - false - } - } - - if (addUrl) - newMdnCacheExisting.add(url) - else - newMdnCacheNonExisting.add(url) - } - - val mdnCache = MDNDocumentationCache(newMdnCacheExisting, newMdnCacheNonExisting) - MDNDocumentationCache.writeTo(mdnCache, mdnCacheFile) + val webIdl = BuildWebIdl( + mdnCacheFile = File("target/mdn-cache.txt"), + srcDir = File("../../stdlib/js/idl")) println("Generating...") - allPackages.forEach { pkg -> - File(outDir, pkg + ".kt").bufferedWriter().use { w -> - println("Generating for package $pkg...") - - w.appendln(copyrightNotice) - - w.appendln("// NOTE: THIS FILE IS AUTO-GENERATED, DO NOT EDIT!") - w.appendln("// See libraries/tools/idl2k for details") - - w.appendln() - w.appendln("@file:Suppress(\"NESTED_CLASS_IN_EXTERNAL_INTERFACE\")") - w.appendln("package $pkg") - w.appendln() - - w.appendln("import kotlin.js.*") - allPackages.filter { it != pkg }.forEach { import -> - w.appendln("import $import.*") - } - w.appendln() - - w.render(pkg, definitions, unions, repository.enums.values.toList(), mdnCache) - } - } + val copyrightNotice = readCopyrightNoticeFromProfile(File("../../../.idea/copyright/apache.xml")) + webIdl.jsGenerator(File("../../stdlib/js/src/org.w3c"), copyrightNotice) } - -internal fun Map>.reduceValues(reduce: (V, V) -> V = { a, b -> b }): Map = mapValues { it.value.reduce(reduce) } - -internal fun Map.mergeReduce(other: Map, reduce: (V, V) -> V = { a, b -> b }): Map { - val result = LinkedHashMap(this.size + other.size) - result.putAll(this) - other.forEach { e -> - val existing = result[e.key] - - if (existing == null) { - result[e.key] = e.value - } - else { - result[e.key] = reduce(e.value, existing) - } - } - - return result -} - -internal fun Map>.merge(other: Map>): Map> { - val result = LinkedHashMap>(size + other.size) - this.forEach { - result[it.key] = ArrayList(it.value) - } - other.forEach { - val list = result[it.key] - if (list == null) { - result[it.key] = ArrayList(it.value) - } - else { - list.addAll(it.value) - } - } - - return result -} \ No newline at end of file