Files
kotlin-fork/libraries/tools/idl2k/src/main/kotlin/idl.kt
T
2015-05-14 09:16:55 +03:00

502 lines
18 KiB
Kotlin

/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idl2k
import org.antlr.v4.runtime.CharStream
import org.antlr.v4.runtime.CommonTokenStream
import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.tree.ParseTree
import org.antlr.v4.runtime.tree.TerminalNode
import org.antlr.webidl.WebIDLBaseVisitor
import org.antlr.webidl.WebIDLLexer
import org.antlr.webidl.WebIDLParser
import org.antlr.webidl.WebIDLParser.*
import java.util.ArrayList
data class ExtendedAttribute(val name: String?, val call: String, val arguments: List<Attribute>)
data class Operation(val name: String, val returnType: String, val parameters: List<Attribute>, val attributes: List<ExtendedAttribute>)
data class Attribute(val name: String, val type: String, val readOnly: Boolean, val defaultValue: String? = null, val vararg: Boolean)
data class Constant(val name: String, val type: String, val value: String?)
enum class DefinitionType {
INTERFACE
TYPEDEF
EXTENSION_INTERFACE
ENUM
DICTIONARY
}
trait Definition
data class TypedefDefinition(val types: String, val namespace: String, val name: String) : Definition
data class InterfaceDefinition(
val name: String,
val namespace: String,
val extendedAttributes: List<ExtendedAttribute>,
val operations: List<Operation>,
val attributes: List<Attribute>,
val superTypes: List<String>,
val constants: List<Constant>,
val dictionary: Boolean = false,
val partial: Boolean,
val callback: Boolean
) : Definition
data class ExtensionInterfaceDefinition(val namespace: String, val name: String, val implements: String) : Definition
data class EnumDefinition(val namespace: String, val name: String) : Definition
class ExtendedAttributeArgumentsParser : WebIDLBaseVisitor<List<Attribute>>() {
private val arguments = ArrayList<Attribute>()
override fun defaultResult(): List<Attribute> = arguments
override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): List<Attribute> {
val attributeVisitor = AttributeVisitor(false)
attributeVisitor.visit(ctx)
val parameter = attributeVisitor.visitChildren(ctx)
arguments.add(parameter)
visitChildren(ctx)
return defaultResult()
}
}
class ExtendedAttributeParser : WebIDLBaseVisitor<ExtendedAttribute>() {
private var name: String? = null
private var call: String = ""
private val arguments = ArrayList<Attribute>()
override fun defaultResult(): ExtendedAttribute = ExtendedAttribute(name, call, arguments)
override fun visitExtendedAttribute(ctx: WebIDLParser.ExtendedAttributeContext): ExtendedAttribute {
call = ctx.children.filterIdentifiers().firstOrNull()?.getText() ?: ""
visitChildren(ctx)
return defaultResult()
}
override fun visitArgumentList(ctx: WebIDLParser.ArgumentListContext): ExtendedAttribute {
arguments.addAll(ExtendedAttributeArgumentsParser().visitChildren(ctx))
return defaultResult()
}
override fun visitIdentifierList(ctx: IdentifierListContext): ExtendedAttribute {
object : WebIDLBaseVisitor<Unit>() {
override fun visitTerminal(node: TerminalNode) {
if (node.getSymbol().getType() == WebIDLLexer.IDENTIFIER_WEBIDL) {
arguments.add(Attribute(node.getText(), "any", true, vararg = false))
}
}
}.visitChildren(ctx)
return defaultResult()
}
override fun visitExtendedAttributeNamePart(ctx: WebIDLParser.ExtendedAttributeNamePartContext): ExtendedAttribute {
name = getName(ctx)
return defaultResult()
}
}
class UnionTypeVisitor : WebIDLBaseVisitor<List<String>>() {
val list = ArrayList<String>()
override fun defaultResult() = list
override fun visitUnionMemberType(ctx: WebIDLParser.UnionMemberTypeContext): List<String> {
list.add(TypeVisitor().visitChildren(ctx))
return list
}
}
class TypeVisitor : WebIDLBaseVisitor<String>() {
private var type = ""
override fun defaultResult() = type
override fun visitNonAnyType(ctx: WebIDLParser.NonAnyTypeContext): String {
type = ctx.getText()
return type
}
override fun visitUnionType(ctx: WebIDLParser.UnionTypeContext): String {
type = "Union<" + UnionTypeVisitor().visitChildren(ctx).joinToString(",") + ">"
return type
}
override fun visitTypeSuffix(ctx: TypeSuffixContext): String {
type += ctx.getText()
return type
}
override fun visitTerminal(node: TerminalNode): String {
type = node.getText()
return type
}
}
class OperationVisitor(val attributes: List<ExtendedAttribute>) : WebIDLBaseVisitor<Operation>() {
private var name: String = ""
private var returnType: String = ""
private val parameters = ArrayList<Attribute>()
private val exts = ArrayList<ExtendedAttribute>()
override fun defaultResult() = Operation(name, returnType, parameters, attributes + exts)
override fun visitOptionalIdentifier(ctx: OptionalIdentifierContext): Operation {
name = ctx.getText()
return defaultResult()
}
override fun visitSpecial(ctx: WebIDLParser.SpecialContext): Operation {
if (ctx.children != null) {
exts.add(ExtendedAttribute(call = ctx.getText(), name = null, arguments = emptyList()))
}
return defaultResult()
}
override fun visitReturnType(ctx: ReturnTypeContext): Operation {
returnType = TypeVisitor().visit(ctx)
return defaultResult()
}
override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): Operation {
val attributeVisitor = AttributeVisitor(false)
attributeVisitor.visit(ctx)
val parameter = attributeVisitor.visitChildren(ctx)
parameters.add(parameter)
return defaultResult()
}
}
class AttributeVisitor(val readOnly: Boolean) : WebIDLBaseVisitor<Attribute>() {
var type: String = ""
var name: String = ""
var defaultValue: String? = null
var vararg: Boolean = false
override fun defaultResult(): Attribute = Attribute(name, type, readOnly, defaultValue, vararg)
override fun visitType(ctx: WebIDLParser.TypeContext): Attribute {
type = TypeVisitor().visit(ctx)
return defaultResult()
}
override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): Attribute {
if (ctx.children?.any { it is TerminalNode && it.getText() == "optional" } ?: false) {
defaultValue = "noImpl"
}
return visitChildren(ctx)
}
override fun visitAttributeRest(ctx: WebIDLParser.AttributeRestContext): Attribute {
try {
name = getName(ctx)
} catch (ignore: Throwable) {
name = ctx.children.filter { it is TerminalNode }.filter { it.getText() != ";" }.last().getText()
}
return defaultResult()
}
override fun visitArgumentName(ctx: WebIDLParser.ArgumentNameContext): Attribute {
try {
name = getName(ctx)
} catch (ignore: Throwable) {
name = ctx.getText()
}
return defaultResult()
}
override fun visitDefaultValue(ctx: WebIDLParser.DefaultValueContext): Attribute {
defaultValue = ctx.getText()
return defaultResult()
}
override fun visitEllipsis(ctx: WebIDLParser.EllipsisContext): Attribute {
vararg = vararg || "..." in ctx.getText()
return defaultResult()
}
}
class ConstantVisitor(val attributes: List<ExtendedAttribute>) : WebIDLBaseVisitor<Constant>() {
var type: String = ""
var name: String = ""
var value: String? = null
override fun defaultResult(): Constant = Constant(name, type, value)
override fun visitConst_(ctx: WebIDLParser.Const_Context): Constant {
name = getName(ctx)
return visitChildren(ctx)
}
override fun visitConstType(ctx: WebIDLParser.ConstTypeContext): Constant {
type = ctx.getText()
return defaultResult()
}
override fun visitConstValue(ctx: WebIDLParser.ConstValueContext): Constant {
value = ctx.getText()
return defaultResult()
}
}
class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val namespace: String, val declarations : MutableList<Definition>) : WebIDLBaseVisitor<Definition>() {
private var type: DefinitionType = DefinitionType.INTERFACE
private var name = ""
private val memberAttributes = ArrayList<ExtendedAttribute>()
private val operations = ArrayList<Operation>()
private val attributes = ArrayList<Attribute>()
private var readOnly: Boolean = false
private val inherited = ArrayList<String>()
private var typedefType: String? = null
private var implements: String? = null
private val constants = ArrayList<Constant>()
private var partial = false
private var callback = false
override fun defaultResult(): Definition = when (type) {
DefinitionType.INTERFACE -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, false, partial, callback)
DefinitionType.DICTIONARY -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, true, partial, callback)
DefinitionType.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "")
DefinitionType.TYPEDEF -> TypedefDefinition(typedefType ?: "", namespace, name)
DefinitionType.ENUM -> EnumDefinition(namespace, name)
}
override fun visitCallbackRestOrInterface(ctx: WebIDLParser.CallbackRestOrInterfaceContext): Definition {
callback = true
return visitChildren(ctx)
}
override fun visitCallbackRest(ctx: WebIDLParser.CallbackRestContext): Definition {
name = getName(ctx)
with(OperationVisitor(memberAttributes.toList())) {
operations.add(visit(ctx))
}
memberAttributes.clear()
return defaultResult()
}
override fun visitModule(ctx: ModuleContext): Definition {
val moduleName = getName(ctx)
val namespace = if (this.namespace.endsWith(moduleName)) this.namespace else this.namespace + "." + moduleName
ModuleVisitor(declarations, namespace).visitChildren(ctx)
return defaultResult()
}
override fun visitInterface_(ctx: Interface_Context): Definition {
name = getName(ctx)
visitChildren(ctx)
return defaultResult()
}
override fun visitPartialInterface(ctx: WebIDLParser.PartialInterfaceContext): Definition {
name = getName(ctx)
partial = true
visitChildren(ctx)
return defaultResult()
}
override fun visitTypedef(ctx: WebIDLParser.TypedefContext): Definition {
if (name != "") {
// TODO temporary workaround for local typedefs
return defaultResult()
}
type = DefinitionType.TYPEDEF
name = getName(ctx)
typedefType = ctx.accept(object : WebIDLBaseVisitor<String>() {
private var foundType = ""
override fun defaultResult(): String = foundType
override fun visitType(ctx: WebIDLParser.TypeContext): String {
foundType = TypeVisitor().visit(ctx)
return defaultResult()
}
})
return defaultResult()
}
override fun visitEnum_(ctx: Enum_Context): Definition {
type = DefinitionType.ENUM
name = getName(ctx)
return defaultResult()
}
override fun visitDictionary(ctx: DictionaryContext): Definition {
type = DefinitionType.DICTIONARY
name = getName(ctx)
return visitChildren(ctx)
}
override fun visitDictionaryMember(ctx: DictionaryMemberContext): Definition {
val name = ctx.children
.filterIdentifiers()
.firstOrNull { it.getText() != "" }
?.getText()
val type = TypeVisitor().visit(ctx.children.first { it is TypeContext })
val defaultValue = object : WebIDLBaseVisitor<String?>() {
private var value: String? = null
override fun defaultResult() = value
override fun visitDefaultValue(ctx2: DefaultValueContext): String? {
value = ctx2.getText()
return value
}
}.visit(ctx)
attributes.add(Attribute(name ?: "", type, false, defaultValue, false))
return defaultResult()
}
override fun visitImplementsStatement(ctx: ImplementsStatementContext): Definition {
val identifiers = ctx.children.filterIdentifiers().map { it.getText() }
if (identifiers.size() >= 2) {
type = DefinitionType.EXTENSION_INTERFACE
name = identifiers[0]
implements = identifiers[1]
visitChildren(ctx)
}
return defaultResult()
}
override fun visitOperation(ctx: OperationContext): Definition {
with(OperationVisitor(memberAttributes.toList())) {
operations.add(visit(ctx))
}
memberAttributes.clear()
return defaultResult()
}
override fun visitInheritance(ctx: WebIDLParser.InheritanceContext): Definition {
if (ctx.children != null) {
inherited.addAll(ctx.children.filterIdentifiers().map {it.getText().trim()}.filter {it != ""})
}
return defaultResult()
}
override fun visitReadOnly(ctx: WebIDLParser.ReadOnlyContext): Definition {
readOnly = true
visitChildren(ctx)
readOnly = false
return defaultResult()
}
override fun visitAttributeRest(ctx: WebIDLParser.AttributeRestContext): Definition {
with(AttributeVisitor(readOnly)) {
visit(ctx)
this@DefinitionVisitor.attributes.add(visitChildren(ctx))
}
return defaultResult()
}
override fun visitConst_(ctx: WebIDLParser.Const_Context): Definition {
constants.add(ConstantVisitor(memberAttributes.toList()).visit(ctx))
memberAttributes.clear()
return defaultResult()
}
override fun visitExtendedAttribute(ctx: ExtendedAttributeContext): Definition {
val att = with(ExtendedAttributeParser()) {
visit(ctx)
}
memberAttributes.add(att)
return defaultResult()
}
}
class ModuleVisitor(val declarations : MutableList<Definition>, var namespace : String = "") : WebIDLBaseVisitor<Unit>() {
val extendedAttributes = ArrayList<ExtendedAttribute>()
override fun visitDefinition(ctx: WebIDLParser.DefinitionContext) {
val declaration = DefinitionVisitor(extendedAttributes.toList(), namespace, declarations).visitChildren(ctx)
extendedAttributes.clear()
declarations.add(declaration)
}
override fun visitExtendedAttribute(ctx: ExtendedAttributeContext?) {
val att = with(ExtendedAttributeParser()) {
visit(ctx)
}
extendedAttributes.add(att)
}
override fun visitNamespaceRest(ctx: NamespaceRestContext) {
this.namespace = ctx.getText()
}
}
private fun List<ParseTree>?.filterIdentifiers(): List<ParseTree> = this?.filter { it is TerminalNode && it.getSymbol().getType() == WebIDLLexer.IDENTIFIER_WEBIDL } ?: emptyList()
private fun getName(ctx: ParserRuleContext) = ctx.children.filterIdentifiers().first().getText()
fun parseIDL(reader: CharStream): Repository {
val ll = WebIDLLexer(reader)
val pp = WebIDLParser(CommonTokenStream(ll))
val idl = pp.webIDL()
val declarations = ArrayList<Definition>()
ModuleVisitor(declarations).visit(idl)
return Repository(
declarations.filterIsInstance<InterfaceDefinition>().filter { it.name.isEmpty().not() }.groupBy { it.name }.mapValues { it.getValue().reduce(::merge) },
declarations.filterIsInstance<TypedefDefinition>().groupBy { it.name }.mapValues { it.getValue().first() },
declarations.filterIsInstance<ExtensionInterfaceDefinition>().groupBy { it.name }.mapValues { it.getValue().map { it.implements } },
declarations.filterIsInstance<EnumDefinition>().groupBy { it.name }.mapValues { it.getValue().reduce { a, b -> a } }
)
}
fun merge(i1: InterfaceDefinition, i2: InterfaceDefinition): InterfaceDefinition {
require(i1.name == i2.name)
return InterfaceDefinition(i1.name,
namespace = if (i1.partial) i2.namespace else i1.namespace,
extendedAttributes = i1.extendedAttributes merge i2.extendedAttributes,
operations = i1.operations merge i2.operations,
attributes = i1.attributes merge i2.attributes,
superTypes = i1.superTypes merge i2.superTypes,
constants = i1.constants merge i2.constants,
dictionary = i1.dictionary || i2.dictionary,
partial = i1.partial && i2.partial,
callback = i1.callback && i2.callback
)
}
fun <T> List<T>.merge(other: List<T>) = (this + other).distinct().toList()