[JS IR BE] Refactor namer
This commit is contained in:
+149
-146
@@ -38,179 +38,182 @@ class SimpleNameGenerator : NameGenerator {
|
|||||||
override fun getNameForType(type: IrType, context: JsGenerationContext) =
|
override fun getNameForType(type: IrType, context: JsGenerationContext) =
|
||||||
getNameForDeclaration(type.classifierOrFail.owner as IrDeclarationWithName, context)
|
getNameForDeclaration(type.classifierOrFail.owner as IrDeclarationWithName, context)
|
||||||
|
|
||||||
private val RESERVED_IDENTIFIERS = setOf(
|
private fun getNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName {
|
||||||
// keywords
|
return nameCache.getOrPut(declaration) { getNewNameForDeclaration(declaration, context) }
|
||||||
"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
|
private fun getNewNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName {
|
||||||
"class", "const", "enum", "export", "extends", "import", "super",
|
var nameDeclarator: (String) -> JsName = context.currentScope::declareName
|
||||||
|
|
||||||
// as future reserved words in strict mode
|
val declarationName = declaration.getJsNameOrKotlinName().asString()
|
||||||
"implements", "interface", "let", "package", "private", "protected", "public", "static", "yield",
|
|
||||||
|
|
||||||
// additional reserved words
|
if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) {
|
||||||
// "null", "true", "false",
|
return nameDeclarator(declarationName)
|
||||||
|
}
|
||||||
|
|
||||||
// disallowed as variable names in strict mode
|
if (declaration.isEffectivelyExternal()) {
|
||||||
"eval", "arguments",
|
if (declaration is IrConstructor)
|
||||||
|
return getNameForDeclaration(declaration.parentAsClass, context)
|
||||||
|
|
||||||
// global identifiers usually declared in a typical JS interpreter
|
if (declaration is IrClass && declaration.parent is IrClass) {
|
||||||
"NaN", "isNaN", "Infinity", "undefined",
|
val parentName = getNameForDeclaration(declaration.parentAsClass, context)
|
||||||
|
if (declaration.isCompanion) {
|
||||||
"Error", "Object", "Number",
|
// External companions are class references
|
||||||
|
return parentName
|
||||||
// "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)
|
|
||||||
}
|
}
|
||||||
return@getOrPut nameDeclarator(declarationName)
|
return context.currentScope.declareFreshName(parentName.ident + "$" + declarationName)
|
||||||
}
|
}
|
||||||
|
return nameDeclarator(declarationName)
|
||||||
|
}
|
||||||
|
|
||||||
val jsName = declaration.getJsName()
|
val jsName = declaration.getJsName()
|
||||||
if (jsName != null) {
|
if (jsName != null) {
|
||||||
return@getOrPut context.currentScope.declareName(jsName)
|
return context.currentScope.declareName(jsName)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (declaration) {
|
val nameBuilder = StringBuilder()
|
||||||
is IrValueParameter -> {
|
when (declaration) {
|
||||||
if ((context.currentFunction is IrConstructor && declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) ||
|
is IrValueParameter -> {
|
||||||
declaration == context.currentFunction?.dispatchReceiverParameter
|
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.IMPLICIT_RECEIVER_NAME)
|
||||||
nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
|
else if (declaration == context.currentFunction?.extensionReceiverParameter) {
|
||||||
} else {
|
nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
|
||||||
val declaredName = declarationName
|
} else {
|
||||||
nameBuilder.append(declaredName)
|
val declaredName = declarationName
|
||||||
if (declaredName.startsWith("\$")) {
|
nameBuilder.append(declaredName)
|
||||||
nameBuilder.append('.')
|
if (declaredName.startsWith("\$")) {
|
||||||
nameBuilder.append(declaration.index)
|
|
||||||
}
|
|
||||||
nameDeclarator = context.currentScope::declareFreshName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is IrField -> {
|
|
||||||
nameBuilder.append(declarationName)
|
|
||||||
if (declaration.isTopLevel) {
|
|
||||||
nameDeclarator = context.staticContext.rootScope::declareFreshName
|
|
||||||
} else {
|
|
||||||
nameBuilder.append('.')
|
nameBuilder.append('.')
|
||||||
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context))
|
nameBuilder.append(declaration.index)
|
||||||
if (declaration.visibility == Visibilities.PRIVATE) nameDeclarator = context.currentScope::declareFreshName
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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
|
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(declarationName)
|
||||||
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
|
|
||||||
nameBuilder.append('.')
|
(declaration.parent as? IrClass)?.let {
|
||||||
}
|
nameBuilder.append("$")
|
||||||
if (declaration.dispatchReceiverParameter == null) {
|
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
|
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: remove asap `NameGenerator` is implemented
|
||||||
// TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters?
|
(declaration.parent as? IrPackageFragment)?.let {
|
||||||
declaration.typeParameters.ifNotEmpty {
|
if (declaration.isInline && it.fqName.asString() != "kotlin") {
|
||||||
nameBuilder.append("_\$t")
|
nameBuilder.append("_FIX")
|
||||||
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()}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
is IrConstructor -> {
|
||||||
if (nameBuilder.toString() in RESERVED_IDENTIFIERS) {
|
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
|
||||||
nameBuilder.append(0)
|
}
|
||||||
|
is IrVariable -> {
|
||||||
|
nameBuilder.append(declaration.name.identifier)
|
||||||
nameDeclarator = context.currentScope::declareFreshName
|
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 {
|
fun sanitizeName(name: String): String {
|
||||||
if (name.isEmpty()) return "_"
|
if (name.isEmpty()) return "_"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user