Separated idl2k frontend and backend invocations.

This commit is contained in:
Alexander Gorshenev
2018-03-30 13:58:12 +03:00
committed by Sergey Mashkov
parent 6b777356e8
commit 6d7dd58f70
3 changed files with 165 additions and 134 deletions
@@ -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 <K, V> Map<K, List<V>>.reduceValues(reduce: (V, V) -> V = { a, b -> b }): Map<K, V> = mapValues { it.value.reduce(reduce) }
internal fun <K, V> Map<K, V>.mergeReduce(other: Map<K, V>, reduce: (V, V) -> V = { a, b -> b }): Map<K, V> {
val result = LinkedHashMap<K, V>(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 <K, V> Map<K, List<V>>.merge(other: Map<K, List<V>>): Map<K, List<V>> {
val result = LinkedHashMap<K, MutableList<V>>(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
}
@@ -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)
}
}
}
+5 -134
View File
@@ -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<String>) {
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 <K, V> Map<K, List<V>>.reduceValues(reduce: (V, V) -> V = { a, b -> b }): Map<K, V> = mapValues { it.value.reduce(reduce) }
internal fun <K, V> Map<K, V>.mergeReduce(other: Map<K, V>, reduce: (V, V) -> V = { a, b -> b }): Map<K, V> {
val result = LinkedHashMap<K, V>(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 <K, V> Map<K, List<V>>.merge(other: Map<K, List<V>>): Map<K, List<V>> {
val result = LinkedHashMap<K, MutableList<V>>(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
}