Skip to content

Commit 080b015

Browse files
committed
typed concept members
1 parent 99045ff commit 080b015

File tree

16 files changed

+426
-65
lines changed

16 files changed

+426
-65
lines changed

editor-runtime/src/commonMain/kotlin/org/modelix/editor/ConceptEditor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class ConceptEditor<NodeT : ITypedNode, ConceptT : ITypedConcept>(
1919
}
2020

2121
fun apply(context: CellCreationContext, node: NodeT): CellData {
22-
return apply(node._concept._concept as GeneratedConcept<NodeT, ConceptT>).apply(context, node)
22+
return apply(node._concept.untyped() as GeneratedConcept<NodeT, ConceptT>).apply(context, node)
2323
}
2424
}
2525

editor-runtime/src/commonMain/kotlin/org/modelix/editor/EditorEngine.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class EditorEngine(incrementalEngine: IncrementalEngine? = null) {
9292

9393
private fun <NodeT : ITypedNode> doCreateCellData(editorState: EditorState, node: NodeT): CellData {
9494
try {
95-
val editor = resolveConceptEditor(node._concept._concept) as ConceptEditor<NodeT, *>
95+
val editor = resolveConceptEditor(node._concept.untyped()) as ConceptEditor<NodeT, *>
9696
val data = editor.apply(CellCreationContext(this, editorState), node)
9797
data.properties[CellActionProperties.substitute] = ReplaceNodeActionProvider(ExistingNode(node.unwrap()))
9898
data.cellReferences += NodeCellReference(node.untypedReference())

metamodel-generator/src/main/kotlin/org/modelix/metamodel/generator/MetaModelGenerator.kt

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.modelix.metamodel.generator
22

33
import com.squareup.kotlinpoet.*
4+
import com.squareup.kotlinpoet.MemberName.Companion.member
45
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
56
import org.modelix.metamodel.*
67
import org.modelix.model.api.*
@@ -18,9 +19,14 @@ private val reservedPropertyNames: Set<String> = setOf(
1819
) + IConcept::class.members.map { it.name }
1920

2021
class MetaModelGenerator(val outputDir: Path) {
22+
var alwaysUseNonNullableProperties: Boolean = true
2123

2224
private val headerComment = "\ngenerated by modelix metamodel generator\n"
2325

26+
private fun PropertyData.asKotlinType(): TypeName {
27+
return if (!optional || alwaysUseNonNullableProperties) type.asKotlinType() else type.asKotlinType().copy(nullable = true)
28+
}
29+
2430
private fun FileSpec.write() {
2531
writeTo(outputDir)
2632
}
@@ -97,7 +103,7 @@ class MetaModelGenerator(val outputDir: Path) {
97103
val receiverType = Iterable::class.asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType())
98104
when (val data = feature.data) {
99105
is PropertyData -> {
100-
addProperty(PropertySpec.builder(feature.validName, List::class.asTypeName().parameterizedBy(data.type.asKotlinType()))
106+
addProperty(PropertySpec.builder(feature.validName, List::class.asTypeName().parameterizedBy(data.asKotlinType()))
101107
.receiver(receiverType)
102108
.getter(FunSpec.getterBuilder().addStatement("return map { it.%N }", feature.validName).build())
103109
.build())
@@ -176,19 +182,40 @@ class MetaModelGenerator(val outputDir: Path) {
176182
for (feature in concept.directFeatures()) {
177183
when (val data = feature.data) {
178184
is PropertyData -> {
179-
addProperty(PropertySpec.builder(feature.validName, IProperty::class)
180-
.initializer("""${GeneratedConcept<*, *>::newProperty.name}("${feature.originalName}", ${data.optional})""")
185+
val serializer = (if (!data.optional || alwaysUseNonNullableProperties) {
186+
when (data.type) {
187+
PropertyType.STRING -> MandatoryStringPropertySerializer::class
188+
PropertyType.BOOLEAN -> MandatoryBooleanPropertySerializer::class
189+
PropertyType.INT -> MandatoryIntPropertySerializer::class
190+
}
191+
} else {
192+
when (data.type) {
193+
PropertyType.STRING -> OptionalStringPropertySerializer::class
194+
PropertyType.BOOLEAN -> OptionalBooleanPropertySerializer::class
195+
PropertyType.INT -> OptionalIntPropertySerializer::class
196+
}
197+
}).asTypeName()
198+
addProperty(PropertySpec.builder(feature.validName, GeneratedProperty::class.asClassName().parameterizedBy(data.asKotlinType()))
199+
.initializer("""newProperty("${feature.originalName}", %T, ${data.optional})""", serializer)
181200
.build())
182201
}
183202
is ChildLinkData -> {
184203
val methodName = if (data.multiple) "newChildListLink" else "newSingleChildLink"
185204
addProperty(PropertySpec.builder(feature.validName, feature.generatedChildLinkType())
186-
.initializer("""$methodName("${feature.originalName}", ${data.optional}, ${data.type.conceptObjectName()})""")
205+
.initializer(
206+
"""$methodName("${feature.originalName}", ${data.optional}, %T, %T::class)""",
207+
data.type.conceptObjectName().parseClassName(),
208+
data.type.nodeWrapperInterfaceName().parseClassName()
209+
)
187210
.build())
188211
}
189212
is ReferenceLinkData -> {
190213
addProperty(PropertySpec.builder(feature.validName, feature.generatedReferenceLinkType())
191-
.initializer("""newReferenceLink("${feature.originalName}", ${data.optional}, ${data.type.conceptObjectName()})""")
214+
.initializer(
215+
"""newReferenceLink("${feature.originalName}", ${data.optional}, %T, %T::class)""",
216+
data.type.conceptObjectName().parseClassName(),
217+
data.type.nodeWrapperInterfaceName().parseClassName()
218+
)
192219
.build())
193220
}
194221
}
@@ -204,22 +231,21 @@ class MetaModelGenerator(val outputDir: Path) {
204231
}
205232
for (feature in concept.directFeatures()) {
206233
when (val data = feature.data) {
207-
is PropertyData -> addProperty(PropertySpec.builder(feature.validName, IProperty::class).build())
234+
is PropertyData -> addProperty(PropertySpec.builder(feature.validName, GeneratedProperty::class.asClassName().parameterizedBy(data.asKotlinType())).build())
208235
is ChildLinkData -> addProperty(PropertySpec.builder(feature.validName, feature.generatedChildLinkType()).build())
209236
is ReferenceLinkData -> addProperty(PropertySpec.builder(feature.validName, feature.generatedReferenceLinkType()).build())
210237
}
211238
}
212239

213240
addType(TypeSpec.companionObjectBuilder().apply {
214241
superclass(concept.conceptWrapperImplType())
215-
if (!concept.concept.abstract) {
216-
addSuperinterface(INonAbstractConcept::class.asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType()))
217-
addFunction(FunSpec.builder(INonAbstractConcept<*>::getInstanceClass.name)
218-
.addModifiers(KModifier.OVERRIDE)
219-
.returns(KClass::class.asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType()))
220-
.addStatement("return ${concept.nodeWrapperInterfaceType().simpleName}::class")
221-
.build())
222-
}
242+
val t = if (concept.concept.abstract) IConceptOfTypedNode::class else INonAbstractConcept::class
243+
addSuperinterface(t.asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType()))
244+
addFunction(FunSpec.builder(IConceptOfTypedNode<*>::getInstanceInterface.name)
245+
.addModifiers(KModifier.OVERRIDE)
246+
.returns(KClass::class.asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType()))
247+
.addStatement("return ${concept.nodeWrapperInterfaceType().simpleName}::class")
248+
.build())
223249
}.build())
224250
}.build()
225251
}
@@ -238,15 +264,16 @@ class MetaModelGenerator(val outputDir: Path) {
238264

239265
primaryConstructor(FunSpec.constructorBuilder().addModifiers(KModifier.PROTECTED).build())
240266

241-
addProperty(PropertySpec.builder(ITypedConcept::_concept.name, IConcept::class)
267+
addFunction(FunSpec.builder(ITypedConcept::untyped.name)
268+
.returns(IConcept::class)
242269
.addModifiers(KModifier.OVERRIDE)
243-
.initializer(concept.conceptObjectName())
270+
.addStatement("return %T", concept.conceptObjectType())
244271
.build())
245272

246273
for (feature in concept.directFeaturesAndConflicts()) {
247274
when (val data = feature.data) {
248275
is PropertyData -> {
249-
addProperty(PropertySpec.builder(feature.validName, IProperty::class)
276+
addProperty(PropertySpec.builder(feature.validName, GeneratedProperty::class.asClassName().parameterizedBy(data.asKotlinType()))
250277
.addModifiers(KModifier.OVERRIDE)
251278
.initializer(feature.kotlinRef())
252279
.build())
@@ -298,20 +325,25 @@ class MetaModelGenerator(val outputDir: Path) {
298325
for (feature in concept.directFeaturesAndConflicts()) {
299326
when (val data = feature.data) {
300327
is PropertyData -> {
301-
val accessorClass = when (data.type) {
302-
PropertyType.STRING -> StringPropertyAccessor::class
303-
PropertyType.BOOLEAN -> BooleanPropertyAccessor::class
304-
PropertyType.INT -> IntPropertyAccessor::class
305-
}
306-
addProperty(PropertySpec.builder(feature.validName, data.type.asKotlinType())
328+
addProperty(PropertySpec.builder(feature.validName, data.asKotlinType())
307329
.addModifiers(KModifier.OVERRIDE)
308330
.mutable(true)
309-
.delegate("""${accessorClass.qualifiedName}(unwrap(), "${feature.originalName}")""")
331+
.delegate(
332+
"""%T(unwrap(), %T.%N)""",
333+
TypedPropertyAccessor::class.asTypeName(),
334+
feature.concept.conceptObjectType(),
335+
feature.validName,
336+
)
310337
.build())
311338
addProperty(PropertySpec.builder("raw_" + feature.validName, String::class.asTypeName().copy(nullable = true))
312339
.addModifiers(KModifier.OVERRIDE)
313340
.mutable(true)
314-
.delegate("""${RawPropertyAccessor::class.qualifiedName}(unwrap(), "${feature.originalName}")""")
341+
.delegate(
342+
"""%T(unwrap(), %T.%N.untyped())""",
343+
RawPropertyAccessor::class.asTypeName(),
344+
feature.concept.conceptObjectType(),
345+
feature.validName,
346+
)
315347
.build())
316348
}
317349
is ChildLinkData -> {
@@ -323,20 +355,32 @@ class MetaModelGenerator(val outputDir: Path) {
323355
val accessorName = accessorSubclass.qualifiedName
324356
addProperty(PropertySpec.builder(feature.validName, type)
325357
.addModifiers(KModifier.OVERRIDE)
326-
.initializer("""$accessorName(${ITypedNode::unwrap.name}(), "${feature.originalName}", ${data.type.conceptObjectName()}, ${data.type.nodeWrapperInterfaceName()}::class)""")
358+
.initializer(
359+
"""$accessorName(${ITypedNode::unwrap.name}(), %T.%N, ${data.type.conceptObjectName()}, ${data.type.nodeWrapperInterfaceName()}::class)""",
360+
feature.concept.conceptObjectType(),
361+
feature.validName,
362+
)
327363
.build())
328364
}
329365
is ReferenceLinkData -> {
330366
val accessorClass = if (data.optional) OptionalReferenceAccessor::class else MandatoryReferenceAccessor::class
331367
addProperty(PropertySpec.builder(feature.validName, data.type.parseConceptRef(concept.language).nodeWrapperInterfaceType().copy(nullable = data.optional))
332368
.addModifiers(KModifier.OVERRIDE)
333369
.mutable(true)
334-
.delegate("""${accessorClass.qualifiedName}(${ITypedNode::unwrap.name}(), "${feature.originalName}", ${data.type.nodeWrapperInterfaceName()}::class)""")
370+
.delegate(
371+
"""${accessorClass.qualifiedName}(${ITypedNode::unwrap.name}(), %T.%N, ${data.type.nodeWrapperInterfaceName()}::class)""",
372+
feature.concept.conceptObjectType(),
373+
feature.validName,
374+
)
335375
.build())
336376
addProperty(PropertySpec.builder("raw_" + feature.validName, INode::class.asTypeName().copy(nullable = true))
337377
.addModifiers(KModifier.OVERRIDE)
338378
.mutable(true)
339-
.delegate("""${RawReferenceAccessor::class.qualifiedName}(${ITypedNode::unwrap.name}(), "${feature.originalName}")""")
379+
.delegate(
380+
"""${RawReferenceAccessor::class.qualifiedName}(${ITypedNode::unwrap.name}(), %T.%N)""",
381+
feature.concept.conceptObjectType(),
382+
feature.validName,
383+
)
340384
.build())
341385
}
342386
}
@@ -353,7 +397,7 @@ class MetaModelGenerator(val outputDir: Path) {
353397
for (feature in concept.directFeatures()) {
354398
when (val data = feature.data) {
355399
is PropertyData -> {
356-
addProperty(PropertySpec.builder(feature.validName, data.type.asKotlinType())
400+
addProperty(PropertySpec.builder(feature.validName, data.asKotlinType())
357401
.mutable(true)
358402
.build())
359403
addProperty(PropertySpec.builder("raw_" + feature.validName, String::class.asTypeName().copy(nullable = true))
@@ -390,6 +434,7 @@ fun PropertyType.asKotlinType(): TypeName {
390434
PropertyType.INT -> Int::class.asTypeName()
391435
}
392436
}
437+
fun String.parseClassName() = ClassName(substringBeforeLast("."), substringAfterLast("."))
393438
fun ConceptRef.conceptWrapperImplType() = ClassName(languageName, conceptName.conceptWrapperImplName())
394439
fun ConceptRef.conceptWrapperInterfaceType() = ClassName(languageName, conceptName.conceptWrapperInterfaceName())
395440
fun ConceptRef.nodeWrapperImplType() = ClassName(languageName, conceptName.nodeWrapperImplName())
@@ -425,7 +470,7 @@ fun LanguageSet.ConceptInLanguage.nodeWrapperInterfaceType() = ClassName(languag
425470
fun LanguageSet.ConceptInLanguage.conceptWrapperImplType() = ClassName(language.name, concept.conceptWrapperImplName())
426471
fun LanguageSet.ConceptInLanguage.conceptWrapperInterfaceType() = ClassName(language.name, concept.conceptWrapperInterfaceName())
427472

428-
fun FeatureInConcept.kotlinRef() = concept.conceptObjectType().canonicalName + "." + CodeBlock.of("%N", validName)
473+
fun FeatureInConcept.kotlinRef() = CodeBlock.of("%T.%N", concept.conceptObjectType(), validName)
429474
fun FeatureInConcept.generatedChildLinkType(): TypeName {
430475
val childConcept = (data as ChildLinkData).type.parseConceptRef(concept.language)
431476
val linkClass = if (data.multiple) GeneratedChildListLink::class else GeneratedSingleChildLink::class

metamodel-runtime/src/commonMain/kotlin/org/modelix/metamodel/ChildAccessor.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package org.modelix.metamodel
22

3+
import org.modelix.model.api.IChildLink
34
import org.modelix.model.api.IConcept
45
import org.modelix.model.api.INode
6+
import org.modelix.model.api.addNewChild
7+
import org.modelix.model.api.getChildren
58
import kotlin.reflect.KClass
69

710
abstract class ChildAccessor<ChildT : ITypedNode>(
811
protected val parent: INode,
9-
protected val role: String,
12+
protected val role: IChildLink,
1013
protected val childConcept: IConcept,
1114
protected val childType: KClass<ChildT>,
1215
): Iterable<ChildT> {

metamodel-runtime/src/commonMain/kotlin/org/modelix/metamodel/ChildListAccessor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package org.modelix.metamodel
22

3+
import org.modelix.model.api.IChildLink
34
import org.modelix.model.api.IConcept
45
import org.modelix.model.api.INode
56
import kotlin.reflect.KClass
67

78
class ChildListAccessor<ChildT : ITypedNode>(
89
parent: INode,
9-
role: String,
10+
role: IChildLink,
1011
childConcept: IConcept,
1112
childType: KClass<ChildT>,
1213
) : ChildAccessor<ChildT>(parent, role, childConcept, childType) {

0 commit comments

Comments
 (0)