Separated idl2k frontend and backend invocations.
This commit is contained in:
committed by
Sergey Mashkov
parent
6b777356e8
commit
6d7dd58f70
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user