Skip to content

Support property parameters in constructors #308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.jetbrains.dukat.astModel

interface CallableParameterModel {
import org.jetbrains.dukat.astCommon.Entity

interface CallableParameterModel : Entity {
val name: String?
val type: TypeModel
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.jetbrains.dukat.astModel

data class ConstructorModel(
val parameters: List<ParameterModel>,
val parameters: List<CallableParameterModel>,
val typeParameters: List<TypeParameterModel>
) : MemberModel
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.jetbrains.dukat.astModel

import org.jetbrains.dukat.astModel.modifiers.VisibilityModifierModel
import org.jetbrains.dukat.astModel.statements.StatementModel

data class PropertyParameterModel(
override val name: String,
override val type: TypeModel,
val initializer: StatementModel?,
val visibilityModifier: VisibilityModifierModel
): CallableParameterModel

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// [test] withPropertyDeclaration.kt
// [test] constructorWithPropertyDeclaration.kt
@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS", "EXTERNAL_DELEGATION")

import kotlin.js.*
Expand All @@ -16,11 +16,6 @@ import org.w3c.performance.*
import org.w3c.workers.*
import org.w3c.xhr.*

external open class Foo(x: Any) {
open var x: Any
}
open class Foo(var x: Any)

external open class Bar(n: Number, a: Any) {
open var n: Number
open var a: Any
}
open class Bar(var n: Number, var a: Any)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class Foo {
constructor(public x) {

}
}

export class Bar {
constructor(public n: number, public a) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ private class DescriptorTranslator(val context: DescriptorContext) {
SourceElement.NO_SOURCE
)
constructorDescriptor.initialize(
translateParameters(constructorModel.parameters, constructorDescriptor),
translateParameters(constructorModel.parameters.filterIsInstance<ParameterModel>(), constructorDescriptor),
visibility
)
constructorDescriptor.returnType = LazyWrappedType(LockBasedStorageManager.NO_LOCKS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import org.jetbrains.dukat.tsmodel.ConstructorDeclaration
import org.jetbrains.dukat.tsmodel.FunctionDeclaration
import org.jetbrains.dukat.tsmodel.MemberDeclaration
import org.jetbrains.dukat.tsmodel.ModifierDeclaration
import org.jetbrains.dukat.tsmodel.ParameterDeclaration
import org.jetbrains.dukat.tsmodel.PropertyDeclaration
import org.jetbrains.dukat.tsmodel.types.TypeDeclaration

fun ConstructorDeclaration.addTo(owner: ClassConstraint) {
owner.constructorConstraint = FunctionDeclaration(
name = "",
parameters = parameters,
parameters = parameters.filterIsInstance<ParameterDeclaration>(),
type = TypeDeclaration(
value = IdentifierEntity("Unit"),
params = emptyList()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
package org.jetbrains.dukat.model.commonLowerings

import org.jetbrains.dukat.astModel.CallableParameterModel
import org.jetbrains.dukat.astModel.FunctionTypeModel
import org.jetbrains.dukat.astModel.LambdaParameterModel
import org.jetbrains.dukat.astModel.MemberModel
import org.jetbrains.dukat.astModel.ModuleModel
import org.jetbrains.dukat.astModel.ParameterModel
import org.jetbrains.dukat.astModel.PropertyParameterModel
import org.jetbrains.dukat.astModel.TypeModel
import org.jetbrains.dukat.astModel.TypeParameterModel
import org.jetbrains.dukat.astModel.TypeValueModel
import org.jetbrains.dukat.astModel.statements.BlockStatementModel
import org.jetbrains.dukat.astModel.statements.StatementModel
import org.jetbrains.dukat.ownerContext.NodeOwner
import org.jetbrains.dukat.ownerContext.OwnerContext

interface ModelWithOwnerLowering : TopLevelModelLowering {
fun lowerFunctionTypeModel(ownerContext: NodeOwner<FunctionTypeModel>): FunctionTypeModel
fun lowerLambdaParameterModel(ownerContext: NodeOwner<LambdaParameterModel>): LambdaParameterModel
fun lowerParameterModel(ownerContext: NodeOwner<ParameterModel>): ParameterModel
fun lowerPropertyParameterModel(ownerContext: NodeOwner<PropertyParameterModel>): PropertyParameterModel
fun lowerMemberModel(ownerContext: NodeOwner<MemberModel>, parentModule: ModuleModel): MemberModel?

fun lowerCallableParameterModel(ownerContext: NodeOwner<CallableParameterModel>): CallableParameterModel {
return when (val declaration = ownerContext.node) {
is ParameterModel -> lowerParameterModel(NodeOwner(declaration, ownerContext))
is LambdaParameterModel -> lowerLambdaParameterModel(NodeOwner(declaration, ownerContext))
is PropertyParameterModel -> lowerPropertyParameterModel(NodeOwner(declaration, ownerContext))
else -> declaration
}
}

fun lowerTypeParameterModel(ownerContext: NodeOwner<TypeParameterModel>): TypeParameterModel {
val typeParameterModel = ownerContext.node
return typeParameterModel.copy(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jetbrains.dukat.model.commonLowerings

import org.jetbrains.dukat.astModel.CallableParameterModel
import org.jetbrains.dukat.astModel.ClassLikeModel
import org.jetbrains.dukat.astModel.ClassModel
import org.jetbrains.dukat.astModel.ConstructorModel
Expand All @@ -17,6 +18,7 @@ import org.jetbrains.dukat.astModel.PropertyModel
import org.jetbrains.dukat.astModel.TypeAliasModel
import org.jetbrains.dukat.astModel.VariableModel
import org.jetbrains.dukat.astModel.LambdaParameterModel
import org.jetbrains.dukat.astModel.PropertyParameterModel
import org.jetbrains.dukat.astModel.expressions.AsExpressionModel
import org.jetbrains.dukat.astModel.expressions.BinaryExpressionModel
import org.jetbrains.dukat.astModel.expressions.CallExpressionModel
Expand Down Expand Up @@ -113,6 +115,11 @@ interface ModelWithOwnerTypeLowering : ModelWithOwnerLowering {
return declaration.copy(type = lowerTypeModel(NodeOwner(declaration.type, ownerContext)))
}

override fun lowerPropertyParameterModel(ownerContext: NodeOwner<PropertyParameterModel>): PropertyParameterModel {
val declaration = ownerContext.node
return declaration.copy(type = lowerTypeModel(NodeOwner(declaration.type, ownerContext)))
}

override fun lowerParameterModel(ownerContext: NodeOwner<ParameterModel>): ParameterModel {
val declaration = ownerContext.node
return declaration.copy(type = lowerTypeModel(NodeOwner(declaration.type, ownerContext)))
Expand Down Expand Up @@ -163,7 +170,7 @@ interface ModelWithOwnerTypeLowering : ModelWithOwnerLowering {
fun lowerConstructorModel(ownerContext: NodeOwner<ConstructorModel>): ConstructorModel {
val declaration = ownerContext.node
return declaration.copy(
parameters = declaration.parameters.map { parameter -> lowerParameterModel(NodeOwner(parameter, ownerContext)) }
parameters = declaration.parameters.map { parameter -> lowerCallableParameterModel(NodeOwner(parameter, ownerContext)) }
)
}

Expand All @@ -179,7 +186,7 @@ interface ModelWithOwnerTypeLowering : ModelWithOwnerLowering {
val declaration = ownerContext.node
return declaration.copy(
primaryConstructor = declaration.primaryConstructor?.let { constructorModel ->
constructorModel.copy(parameters = constructorModel.parameters.map { lowerParameterModel(ownerContext.wrap(it)) })
constructorModel.copy(parameters = constructorModel.parameters.map { lowerCallableParameterModel(ownerContext.wrap(it)) })
},
members = declaration.members.mapNotNull { member -> lowerMemberModel(NodeOwner(member, ownerContext), parentModule) },
typeParameters = declaration.typeParameters.map { typeParameterModel -> lowerTypeParameterModel(ownerContext.wrap(typeParameterModel)) },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jetbrains.dukat.model.commonLowerings

import org.jetbrains.dukat.astModel.CallableParameterModel
import org.jetbrains.dukat.astModel.ClassModel
import org.jetbrains.dukat.astModel.EnumModel
import org.jetbrains.dukat.astModel.FunctionModel
Expand All @@ -10,6 +11,7 @@ import org.jetbrains.dukat.astModel.MemberModel
import org.jetbrains.dukat.astModel.ModuleModel
import org.jetbrains.dukat.astModel.ObjectModel
import org.jetbrains.dukat.astModel.ParameterModel
import org.jetbrains.dukat.astModel.PropertyParameterModel
import org.jetbrains.dukat.astModel.SourceSetModel
import org.jetbrains.dukat.astModel.TypeAliasModel
import org.jetbrains.dukat.astModel.VariableModel
Expand Down Expand Up @@ -46,6 +48,10 @@ private class ModifyVisibility(private val visibility: VisibilityModifierModel)
return ownerContext.node.copy(visibilityModifier = visibility)
}

override fun lowerPropertyParameterModel(ownerContext: NodeOwner<PropertyParameterModel>): PropertyParameterModel {
return ownerContext.node.copy(visibilityModifier = visibility)
}

override fun lowerLambdaParameterModel(ownerContext: NodeOwner<LambdaParameterModel>) = ownerContext.node
override fun lowerParameterModel(ownerContext: NodeOwner<ParameterModel>): ParameterModel = ownerContext.node

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.jetbrains.dukat.translatorString

import org.jetbrains.dukat.astModel.PropertyParameterModel
import org.jetbrains.dukat.astCommon.CommentEntity
import org.jetbrains.dukat.astCommon.IdentifierEntity
import org.jetbrains.dukat.astCommon.SimpleCommentEntity
import org.jetbrains.dukat.astModel.AnnotationModel
import org.jetbrains.dukat.astModel.CallableParameterModel
import org.jetbrains.dukat.astModel.ClassLikeReferenceModel
import org.jetbrains.dukat.astModel.ClassModel
import org.jetbrains.dukat.astModel.ConstructorModel
Expand Down Expand Up @@ -75,7 +77,6 @@ import org.jetbrains.dukat.astModel.statements.ThrowStatementModel
import org.jetbrains.dukat.astModel.statements.WhenStatementModel
import org.jetbrains.dukat.astModel.statements.WhileStatementModel
import org.jetbrains.dukat.panic.raiseConcern
import org.jetbrains.dukat.stdlib.TSLIBROOT
import org.jetbrains.dukat.translator.ModelVisitor
import org.jetbrains.dukat.translator.ROOT_PACKAGENAME

Expand Down Expand Up @@ -163,33 +164,52 @@ fun TypeModel.translate(): String {
}
}

private fun ParameterModel.translate(needsMeta: Boolean = true): String {
private fun CallableParameterModel.translate(needsMeta: Boolean = true): String {
var res = name + ": " + type.translate()
if (vararg) {
res = "vararg $res"
}
return when (this) {
is ParameterModel -> {
if (vararg) {
res = "vararg $res"
}

modifier?.let {
val modifierTranslated = when (it) {
ParameterModifierModel.NOINLINE -> "noinline"
ParameterModifierModel.CROSSINLINE -> "crossinline"
}
modifier?.let {
val modifierTranslated = when (it) {
ParameterModifierModel.NOINLINE -> "noinline"
ParameterModifierModel.CROSSINLINE -> "crossinline"
}

res = "$modifierTranslated $res"
}
res = "$modifierTranslated $res"
}

if (needsMeta) {
res += type.translateMeta()
}
if (needsMeta) {
res += type.translateMeta()
}

initializer?.let {
res += " = ${it.translateAsOneLine()}"
if (needsMeta) {
res += it.translateMeta()
}
}

initializer?.let {
res += " = ${it.translateAsOneLine()}"
if (needsMeta) {
res += it.translateMeta()
res
}
}
is PropertyParameterModel -> {
if (needsMeta) {
res += type.translateMeta()
}

return res
initializer?.let {
res += " = ${it.translateAsOneLine()}"
if (needsMeta) {
res += it.translateMeta()
}
}

"${visibilityModifier.asClause()}var $res"
}
else -> res
}
}

private fun translateTypeParameters(typeParameters: List<TypeParameterModel>): String {
Expand Down Expand Up @@ -224,7 +244,7 @@ private fun translateTypeArguments(typeParameters: List<TypeModel>): String {
}


private fun translateParameters(parameters: List<ParameterModel>, needsMeta: Boolean = true): String {
private fun translateParameters(parameters: List<CallableParameterModel>, needsMeta: Boolean = true): String {
return parameters
.map { parameter -> parameter.translate(needsMeta) }
.joinToString(", ")
Expand Down Expand Up @@ -253,7 +273,7 @@ private fun CallExpressionModel.translate(): String {

private fun LiteralExpressionModel.translate(): String {
return when (this) {
is StringLiteralExpressionModel -> "\"$value\""
is StringLiteralExpressionModel -> "\"${value.replace("\"", "\\\"")}\""
is NumericLiteralExpressionModel -> value.toString()
is BooleanLiteralExpressionModel -> value.toString()
is NullLiteralExpressionModel -> "null"
Expand Down
46 changes: 33 additions & 13 deletions typescript/ts-converter/src/AstConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {ExportContext, resolveDeclarations} from "./ExportContext";
import {tsInternals} from "./TsInternals";
import {
CaseDeclarationProto,
ConstructorParameterDeclarationProto,
ModifierDeclarationProto,
ModuleDeclarationProto,
ReferenceClauseDeclarationProto,
Expand Down Expand Up @@ -571,6 +572,25 @@ export class AstConverter {
);
}

convertPropertyParameterDeclaration(param: ts.ParameterDeclaration, index: number): ConstructorParameterDeclarationProto {
let initializer: Expression | null = null;

if (param.initializer != null) {
initializer = this.astExpressionConverter.convertExpression(param.initializer)
}

let paramType = this.convertType(param.type);

let name = ts.isIdentifier(param.name) ? param.name.getText() : `__${index}`;

return this.astFactory.createPropertyParameterDeclaration(
name,
paramType,
initializer,
this.convertModifiers(param.modifiers)
);
}

convertPropertySignature(node: ts.PropertySignature): MemberDeclaration | null {
let name = this.convertName(node.name);

Expand Down Expand Up @@ -689,24 +709,24 @@ export class AstConverter {
}

convertConstructorDeclaration(constructorDeclaration: ts.ConstructorDeclaration): Array<MemberDeclaration> {
let params: Array<ParameterDeclaration> = [];
let params: Array<ConstructorParameterDeclarationProto> = [];

let res: Array<MemberDeclaration> = [];

constructorDeclaration.parameters.forEach((parameter, count) => {
if (parameter.modifiers) {
let isField = parameter.modifiers.some(modifier => modifier.kind == ts.SyntaxKind.PublicKeyword);
if (isField) {
let convertedVariable = this.convertPropertyDeclaration(
parameter as ts.ParameterDeclaration
);
if (convertedVariable != null) {
res.push(convertedVariable)
}
}
if (parameter.modifiers && parameter.modifiers.some(modifier =>
modifier.kind == ts.SyntaxKind.PublicKeyword ||
modifier.kind == ts.SyntaxKind.ProtectedKeyword ||
modifier.kind == ts.SyntaxKind.PrivateKeyword
)) {
params.push(this.convertPropertyParameterDeclaration(
parameter, count
));
} else {
params.push(this.astFactory.createSimpleConstructorParameterDeclaration(
this.convertParameterDeclaration(parameter, count))
);
}

params.push(this.convertParameterDeclaration(parameter, count));
});

res.push(this.astFactory.createConstructorDeclaration(
Expand Down
Loading