[JS IR BE] Refactor namer

This commit is contained in:
Svyatoslav Kuzmich
2019-02-22 15:35:37 +03:00
parent e9cdad1143
commit 0d9218b017
@@ -38,179 +38,182 @@ class SimpleNameGenerator : NameGenerator {
override fun getNameForType(type: IrType, context: JsGenerationContext) =
getNameForDeclaration(type.classifierOrFail.owner as IrDeclarationWithName, context)
private val RESERVED_IDENTIFIERS = setOf(
// keywords
"await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if",
"in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with",
private fun getNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName {
return nameCache.getOrPut(declaration) { getNewNameForDeclaration(declaration, context) }
}
// future reserved words
"class", "const", "enum", "export", "extends", "import", "super",
private fun getNewNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName {
var nameDeclarator: (String) -> JsName = context.currentScope::declareName
// as future reserved words in strict mode
"implements", "interface", "let", "package", "private", "protected", "public", "static", "yield",
val declarationName = declaration.getJsNameOrKotlinName().asString()
// additional reserved words
// "null", "true", "false",
if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) {
return nameDeclarator(declarationName)
}
// disallowed as variable names in strict mode
"eval", "arguments",
if (declaration.isEffectivelyExternal()) {
if (declaration is IrConstructor)
return getNameForDeclaration(declaration.parentAsClass, context)
// global identifiers usually declared in a typical JS interpreter
"NaN", "isNaN", "Infinity", "undefined",
"Error", "Object", "Number",
// "Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON",
// global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc)
// "require", "define", "module", "window", "self",
// the special Kotlin object
"Kotlin"
)
private fun getNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName =
nameCache.getOrPut(declaration) {
var nameDeclarator: (String) -> JsName = context.currentScope::declareName
val nameBuilder = StringBuilder()
val declarationName = declaration.getJsNameOrKotlinName().asString()
if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) {
return@getOrPut nameDeclarator(declarationName)
}
if (declaration.isEffectivelyExternal()) {
if (declaration is IrConstructor)
return@getOrPut getNameForDeclaration(declaration.parentAsClass, context)
if (declaration is IrClass && declaration.parent is IrClass) {
val parentName = getNameForDeclaration(declaration.parentAsClass, context)
if (declaration.isCompanion) {
// External companions are class references
return@getOrPut parentName
}
return@getOrPut context.currentScope.declareFreshName(parentName.ident + "$" + declarationName)
if (declaration is IrClass && declaration.parent is IrClass) {
val parentName = getNameForDeclaration(declaration.parentAsClass, context)
if (declaration.isCompanion) {
// External companions are class references
return parentName
}
return@getOrPut nameDeclarator(declarationName)
return context.currentScope.declareFreshName(parentName.ident + "$" + declarationName)
}
return nameDeclarator(declarationName)
}
val jsName = declaration.getJsName()
if (jsName != null) {
return@getOrPut context.currentScope.declareName(jsName)
}
val jsName = declaration.getJsName()
if (jsName != null) {
return context.currentScope.declareName(jsName)
}
when (declaration) {
is IrValueParameter -> {
if ((context.currentFunction is IrConstructor && declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) ||
declaration == context.currentFunction?.dispatchReceiverParameter
)
nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME)
else if (declaration == context.currentFunction?.extensionReceiverParameter) {
nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
} else {
val declaredName = declarationName
nameBuilder.append(declaredName)
if (declaredName.startsWith("\$")) {
nameBuilder.append('.')
nameBuilder.append(declaration.index)
}
nameDeclarator = context.currentScope::declareFreshName
}
}
is IrField -> {
nameBuilder.append(declarationName)
if (declaration.isTopLevel) {
nameDeclarator = context.staticContext.rootScope::declareFreshName
} else {
val nameBuilder = StringBuilder()
when (declaration) {
is IrValueParameter -> {
if ((context.currentFunction is IrConstructor && declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) ||
declaration == context.currentFunction?.dispatchReceiverParameter
)
nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME)
else if (declaration == context.currentFunction?.extensionReceiverParameter) {
nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
} else {
val declaredName = declarationName
nameBuilder.append(declaredName)
if (declaredName.startsWith("\$")) {
nameBuilder.append('.')
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context))
if (declaration.visibility == Visibilities.PRIVATE) nameDeclarator = context.currentScope::declareFreshName
nameBuilder.append(declaration.index)
}
}
is IrClass -> {
if (declaration.isCompanion) {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context))
nameBuilder.append('.')
}
nameBuilder.append(declarationName)
(declaration.parent as? IrClass)?.let {
nameBuilder.append("$")
nameBuilder.append(getNameForDeclaration(it, context))
}
if (declaration.kind == ClassKind.OBJECT || declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) {
if (declaration.descriptor !is DeserializedClassDescriptor) {
// TODO: temporary workaround for Unit instance
nameDeclarator = context.staticContext.rootScope::declareFreshName
}
val parent = declaration.parent
when (parent) {
is IrDeclarationWithName -> nameBuilder.append(getNameForDeclaration(parent, context))
is IrPackageFragment -> nameBuilder.append(parent.fqName.asString())
}
}
// TODO: remove asap `NameGenerator` is implemented
(declaration.parent as? IrPackageFragment)?.let {
if (declaration.isInline && it.fqName.asString() != "kotlin") {
nameBuilder.append("_FIX")
}
}
}
is IrConstructor -> {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
}
is IrVariable -> {
nameBuilder.append(declaration.name.identifier)
nameDeclarator = context.currentScope::declareFreshName
}
is IrSimpleFunction -> {
}
is IrField -> {
nameBuilder.append(declarationName)
if (declaration.isTopLevel) {
nameDeclarator = context.staticContext.rootScope::declareFreshName
} else {
nameBuilder.append('.')
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context))
if (declaration.visibility == Visibilities.PRIVATE) nameDeclarator = context.currentScope::declareFreshName
}
}
is IrClass -> {
if (declaration.isCompanion) {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context))
nameBuilder.append('.')
}
if (declaration.isStaticMethodOfClass) {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
nameBuilder.append('.')
}
if (declaration.dispatchReceiverParameter == null) {
nameBuilder.append(declarationName)
(declaration.parent as? IrClass)?.let {
nameBuilder.append("$")
nameBuilder.append(getNameForDeclaration(it, context))
}
if (declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) {
if (declaration.descriptor !is DeserializedClassDescriptor) {
// TODO: temporary workaround for Unit instance
nameDeclarator = context.staticContext.rootScope::declareFreshName
}
val parent = declaration.parent
when (parent) {
is IrDeclarationWithName -> nameBuilder.append(getNameForDeclaration(parent, context))
is IrPackageFragment -> nameBuilder.append(parent.fqName.asString())
}
}
nameBuilder.append(declarationName)
// TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters?
declaration.typeParameters.ifNotEmpty {
nameBuilder.append("_\$t")
joinTo(nameBuilder, "") { "_${it.name.asString()}" }
}
declaration.extensionReceiverParameter?.let {
nameBuilder.append("_r$${it.type.asString()}")
}
declaration.valueParameters.ifNotEmpty {
joinTo(nameBuilder, "") { "_${it.type.asString()}" }
}
declaration.returnType.let {
// Return type is only used in signature for inline class types because
// they are binary incompatible with supertypes.
if (it.isInlined()) {
nameBuilder.append("_ret$${it.asString()}")
}
// TODO: remove asap `NameGenerator` is implemented
(declaration.parent as? IrPackageFragment)?.let {
if (declaration.isInline && it.fqName.asString() != "kotlin") {
nameBuilder.append("_FIX")
}
}
}
if (nameBuilder.toString() in RESERVED_IDENTIFIERS) {
nameBuilder.append(0)
is IrConstructor -> {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
}
is IrVariable -> {
nameBuilder.append(declaration.name.identifier)
nameDeclarator = context.currentScope::declareFreshName
}
is IrSimpleFunction -> {
nameDeclarator(sanitizeName(nameBuilder.toString()))
if (declaration.isStaticMethodOfClass) {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
nameBuilder.append('.')
}
if (declaration.dispatchReceiverParameter == null) {
nameDeclarator = context.staticContext.rootScope::declareFreshName
}
nameBuilder.append(declarationName)
// TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters?
declaration.typeParameters.ifNotEmpty {
nameBuilder.append("_\$t")
joinTo(nameBuilder, "") { "_${it.name.asString()}" }
}
declaration.extensionReceiverParameter?.let {
nameBuilder.append("_r$${it.type.asString()}")
}
declaration.valueParameters.ifNotEmpty {
joinTo(nameBuilder, "") { "_${it.type.asString()}" }
}
declaration.returnType.let {
// Return type is only used in signature for inline class types because
// they are binary incompatible with supertypes.
if (it.isInlined()) {
nameBuilder.append("_ret$${it.asString()}")
}
}
}
}
if (nameBuilder.toString() in RESERVED_IDENTIFIERS) {
nameBuilder.append(0)
nameDeclarator = context.currentScope::declareFreshName
}
return nameDeclarator(sanitizeName(nameBuilder.toString()))
}
}
private val RESERVED_IDENTIFIERS = setOf(
// keywords
"await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if",
"in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with",
// future reserved words
"class", "const", "enum", "export", "extends", "import", "super",
// as future reserved words in strict mode
"implements", "interface", "let", "package", "private", "protected", "public", "static", "yield",
// additional reserved words
// "null", "true", "false",
// disallowed as variable names in strict mode
"eval", "arguments",
// global identifiers usually declared in a typical JS interpreter
"NaN", "isNaN", "Infinity", "undefined",
"Error", "Object", "Number",
// "Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON",
// global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc)
// "require", "define", "module", "window", "self",
// the special Kotlin object
"Kotlin"
)
fun sanitizeName(name: String): String {
if (name.isEmpty()) return "_"