From 497a0ad982cb1edb4df92f8cd4525bc5683474fd Mon Sep 17 00:00:00 2001 From: Michael Huster Date: Fri, 10 Nov 2023 12:03:21 +0100 Subject: [PATCH 1/4] feat(mps-model-adapters): implement stubs in NodeAsMPSModel --- .../model/mpsadapters/mps/NodeAsMPSModel.kt | 68 +++++++++++++++---- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt index 7c06d8c3ff..7ce662d058 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt @@ -16,18 +16,28 @@ package org.modelix.model.mpsadapters.mps +import jetbrains.mps.lang.smodel.generator.smodelAdapter.SConceptOperations import jetbrains.mps.smodel.MPSModuleRepository import org.jetbrains.mps.openapi.language.SConcept import org.jetbrains.mps.openapi.model.SModel +import org.jetbrains.mps.openapi.model.SModel.Problem +import org.jetbrains.mps.openapi.model.SModelId import org.jetbrains.mps.openapi.model.SModelListener import org.jetbrains.mps.openapi.model.SModelName +import org.jetbrains.mps.openapi.model.SModelReference import org.jetbrains.mps.openapi.model.SNode import org.jetbrains.mps.openapi.model.SNodeAccessListener import org.jetbrains.mps.openapi.model.SNodeChangeListener import org.jetbrains.mps.openapi.model.SNodeId import org.jetbrains.mps.openapi.module.SRepository +import org.jetbrains.mps.openapi.persistence.DataSource +import org.jetbrains.mps.openapi.persistence.PersistenceFacade import org.modelix.model.api.BuiltinLanguages import org.modelix.model.api.INode +import org.modelix.model.api.getDescendants +import org.modelix.model.api.remove +import org.modelix.model.mpsadapters.MPSConcept +import org.modelix.model.mpsadapters.MPSModelReference import org.modelix.model.mpsadapters.Model class NodeAsMPSModel private constructor(private val node: INode, private val sRepository: SRepository?) : SModel { @@ -45,16 +55,29 @@ class NodeAsMPSModel private constructor(private val node: INode, private val sR override fun addModelListener(l: SModelListener?) = throw UnsupportedOperationException("Not implemented") - override fun addRootNode(node: SNode?) = throw UnsupportedOperationException("Not implemented") + override fun addRootNode(node: SNode?) { + if (node != null) { + this.node.addNewChild(BuiltinLanguages.MPSRepositoryConcepts.Model.rootNodes, -1, MPSConcept(node.concept)) + } + } - override fun createNode(concept: SConcept) = throw UnsupportedOperationException("Not implemented") + override fun createNode(concept: SConcept): SNode? { + return SConceptOperations.createNewNode(concept) + } - override fun createNode(concept: SConcept, nodeId: SNodeId?) = - throw UnsupportedOperationException("Not implemented") + override fun createNode(concept: SConcept, nodeId: SNodeId?): SNode? { + // TODO can we set the id somehow? + return SConceptOperations.createNewNode(concept) + } - override fun getModelId() = throw UnsupportedOperationException("Not implemented") + override fun getModelId(): SModelId { + val serialized = checkNotNull(node.getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Model.id)) { + "No model id found" + } + return PersistenceFacade.getInstance().createModelId(serialized) + } - @Deprecated("Deprecated in Java") + @Deprecated("Deprecated in Java", ReplaceWith("getName()")) override fun getModelName() = name.value override fun getModelRoot() = throw UnsupportedOperationException("Not implemented") @@ -72,13 +95,17 @@ class NodeAsMPSModel private constructor(private val node: INode, private val sR adapter } - override fun getSource() = throw UnsupportedOperationException("Not implemented") + override fun getSource() = object : DataSource { + override fun getLocation() = "modelix" + override fun getTimestamp() = 0L + override fun isReadOnly() = true + } override fun isLoaded() = true override fun isReadOnly() = true - override fun load() = throw UnsupportedOperationException("Not implemented") + override fun load() { /* no-op */ } override fun removeAccessListener(l: SNodeAccessListener?) = throw UnsupportedOperationException("Not implemented") @@ -86,15 +113,30 @@ class NodeAsMPSModel private constructor(private val node: INode, private val sR override fun removeModelListener(l: SModelListener?) = throw UnsupportedOperationException("Not implemented") - override fun removeRootNode(node: SNode?) = throw UnsupportedOperationException("Not implemented") + override fun removeRootNode(node: SNode?) { + if (node == null) return + + val rootNodes = this.node.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Model.rootNodes) + val toDelete = rootNodes.find { it.reference.serialize().endsWith(node.reference.toString()) } + toDelete?.remove() + } + + override fun unload() { /* no-op */ } - override fun unload() = throw UnsupportedOperationException("Not implemented") + override fun getReference(): SModelReference { + val serialized = node.reference.serialize().substringAfter(MPSModelReference.PREFIX) + return PersistenceFacade.getInstance().createModelReference(serialized) + } - override fun getReference() = throw UnsupportedOperationException("Not implemented") + override fun getNode(id: SNodeId?): SNode? { + if (id == null) return null - override fun getNode(id: SNodeId?) = throw UnsupportedOperationException("Not implemented") + val nodeId = PersistenceFacade.getInstance().asString(id) + val node = node.getDescendants(true).firstOrNull { it.reference.serialize().endsWith(nodeId) } + return node?.let { NodeAsMPSNode(it, repository) } + } - override fun getProblems() = throw UnsupportedOperationException("Not implemented") + override fun getProblems() = emptyList() override fun equals(other: Any?) = if (this === other) { From 7681e937ac6f766da52454c4d086c2e1481b764d Mon Sep 17 00:00:00 2001 From: Michael Huster Date: Fri, 10 Nov 2023 12:07:03 +0100 Subject: [PATCH 2/4] feat(mps-model-adapters): implement stubs in NodeAsMPSModule --- .../mpsadapters/mps/NodeAsMPSDependency.kt | 54 +++++++++++++++++++ .../model/mpsadapters/mps/NodeAsMPSModel.kt | 13 +---- .../model/mpsadapters/mps/NodeAsMPSModule.kt | 42 ++++++++++++--- 3 files changed, 91 insertions(+), 18 deletions(-) create mode 100644 mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt new file mode 100644 index 0000000000..3ea166d99e --- /dev/null +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023. + * + * 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.modelix.model.mpsadapters.mps + +import org.jetbrains.mps.openapi.module.SDependency +import org.jetbrains.mps.openapi.module.SDependencyScope +import org.jetbrains.mps.openapi.module.SModule +import org.jetbrains.mps.openapi.module.SModuleReference +import org.jetbrains.mps.openapi.module.SRepository +import org.modelix.model.api.INode +import org.modelix.model.mpsadapters.MPSModuleDependencyAsNode +import org.modelix.model.mpsadapters.MPSModuleReference + +data class NodeAsMPSDependency(val node: INode, val sRepository: SRepository?) : SDependency { + override fun getScope(): SDependencyScope { + return when (node) { + is MPSModuleDependencyAsNode -> node.dependencyScope + else -> null + } ?: error("Node is not a valid dependency") + } + + override fun isReexport(): Boolean { + return when (node) { + is MPSModuleDependencyAsNode -> node.reexport + else -> error("Node is not a valid dependency") + } + } + + override fun getTargetModule(): SModuleReference { + return when (node) { + is MPSModuleDependencyAsNode -> node.moduleReference + else -> null + } ?: error("Node is not a valid dependency") + } + + override fun getTarget(): SModule? { + val ref = MPSModuleReference(targetModule) + return node.getArea().resolveNode(ref)?.let { NodeAsMPSModule(it, sRepository) } + } +} diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt index 7ce662d058..c3456153da 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModel.kt @@ -40,7 +40,7 @@ import org.modelix.model.mpsadapters.MPSConcept import org.modelix.model.mpsadapters.MPSModelReference import org.modelix.model.mpsadapters.Model -class NodeAsMPSModel private constructor(private val node: INode, private val sRepository: SRepository?) : SModel { +data class NodeAsMPSModel(val node: INode, val sRepository: SRepository?) : SModel { companion object { fun wrap(modelNode: INode, repository: SRepository?): SModel = NodeAsMPSModel(modelNode, repository) } @@ -137,15 +137,4 @@ class NodeAsMPSModel private constructor(private val node: INode, private val sR } override fun getProblems() = emptyList() - - override fun equals(other: Any?) = - if (this === other) { - true - } else if (other == null || other !is NodeAsMPSModel) { - false - } else { - node != other.node - } - - override fun hashCode() = 31 + node.hashCode() } diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt index e0722eb99f..0d3039e7ad 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt @@ -18,15 +18,24 @@ package org.modelix.model.mpsadapters.mps import jetbrains.mps.smodel.MPSModuleRepository import org.jetbrains.mps.openapi.language.SLanguage +import org.jetbrains.mps.openapi.model.SModel import org.jetbrains.mps.openapi.model.SModelId +import org.jetbrains.mps.openapi.module.SDependency import org.jetbrains.mps.openapi.module.SModule +import org.jetbrains.mps.openapi.module.SModuleFacet +import org.jetbrains.mps.openapi.module.SModuleId import org.jetbrains.mps.openapi.module.SModuleListener +import org.jetbrains.mps.openapi.module.SModuleReference import org.jetbrains.mps.openapi.module.SRepository +import org.jetbrains.mps.openapi.persistence.PersistenceFacade import org.modelix.model.api.BuiltinLanguages import org.modelix.model.api.INode +import org.modelix.model.api.getDescendants +import org.modelix.model.mpsadapters.MPSJavaModuleFacetAsNode +import org.modelix.model.mpsadapters.MPSModuleReference import org.modelix.model.mpsadapters.Module -class NodeAsMPSModule private constructor(val node: INode, val sRepository: SRepository?) : SModule { +data class NodeAsMPSModule(val node: INode, val sRepository: SRepository?) : SModule { companion object { fun wrap(modelNode: INode, repository: SRepository?): SModule = NodeAsMPSModule(modelNode, repository) @@ -38,21 +47,42 @@ class NodeAsMPSModule private constructor(val node: INode, val sRepository: SRep override fun addModuleListener(listener: SModuleListener?) = throw UnsupportedOperationException("Not implemented") - override fun getDeclaredDependencies() = throw UnsupportedOperationException("Not implemented") + override fun getDeclaredDependencies(): MutableIterable { + val dependencies = node.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Module.dependencies) + return dependencies.map { NodeAsMPSDependency(node, sRepository) }.toMutableList() + } - override fun getFacets() = throw UnsupportedOperationException("Not implemented") + override fun getFacets(): MutableIterable { + val facets = node.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Module.facets) + return facets.mapNotNull { (it as? MPSJavaModuleFacetAsNode)?.facet }.toMutableList() + } - override fun getModel(id: SModelId?) = throw UnsupportedOperationException("Not implemented") + override fun getModel(id: SModelId?): SModel? { + if (id == null) return null + val modelId = PersistenceFacade.getInstance().asString(id) + val model = node.getDescendants(false).firstOrNull { + it.reference.serialize().endsWith(modelId) + } + return model?.let { NodeAsMPSModel(it, repository) } + } override fun getModelRoots() = throw UnsupportedOperationException("Not implemented") override fun getModels() = node.getChildren(Module.models).map { NodeAsMPSModel.wrap(it, sRepository) } - override fun getModuleId() = throw UnsupportedOperationException("Not implemented") + override fun getModuleId(): SModuleId { + val serialized = checkNotNull(node.getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Module.id)) { + "Module id was null for $node" + } + return PersistenceFacade.getInstance().createModuleId(serialized) + } override fun getModuleName() = node.getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name) - override fun getModuleReference() = throw UnsupportedOperationException("Not implemented") + override fun getModuleReference(): SModuleReference { + val serialized = node.reference.serialize().substringAfter(MPSModuleReference.PREFIX) + return PersistenceFacade.getInstance().createModuleReference(serialized) + } override fun getRepository(): SRepository = sRepository ?: MPSModuleRepository.getInstance() From 02e4f5dcbbcb60d4b6fb3ada98e9a52ce6574295 Mon Sep 17 00:00:00 2001 From: Michael Huster Date: Fri, 10 Nov 2023 15:20:52 +0100 Subject: [PATCH 3/4] fix(mps-model-adapters): fix declared dependencies and simplify NodeAsMPSDependency --- .../mpsadapters/mps/NodeAsMPSDependency.kt | 28 ++++--------------- .../model/mpsadapters/mps/NodeAsMPSModule.kt | 5 +++- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt index 3ea166d99e..e5b04a8753 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt @@ -19,36 +19,18 @@ package org.modelix.model.mpsadapters.mps import org.jetbrains.mps.openapi.module.SDependency import org.jetbrains.mps.openapi.module.SDependencyScope import org.jetbrains.mps.openapi.module.SModule -import org.jetbrains.mps.openapi.module.SModuleReference import org.jetbrains.mps.openapi.module.SRepository -import org.modelix.model.api.INode import org.modelix.model.mpsadapters.MPSModuleDependencyAsNode import org.modelix.model.mpsadapters.MPSModuleReference -data class NodeAsMPSDependency(val node: INode, val sRepository: SRepository?) : SDependency { - override fun getScope(): SDependencyScope { - return when (node) { - is MPSModuleDependencyAsNode -> node.dependencyScope - else -> null - } ?: error("Node is not a valid dependency") - } - - override fun isReexport(): Boolean { - return when (node) { - is MPSModuleDependencyAsNode -> node.reexport - else -> error("Node is not a valid dependency") - } - } +data class NodeAsMPSDependency(val node: MPSModuleDependencyAsNode, val sRepository: SRepository?) : SDependency { - override fun getTargetModule(): SModuleReference { - return when (node) { - is MPSModuleDependencyAsNode -> node.moduleReference - else -> null - } ?: error("Node is not a valid dependency") - } + override fun getScope(): SDependencyScope = checkNotNull(node.dependencyScope) { "Invalid dependency scope for dependency $node" } + override fun isReexport() = node.reexport + override fun getTargetModule() = node.moduleReference override fun getTarget(): SModule? { - val ref = MPSModuleReference(targetModule) + val ref = MPSModuleReference(node.moduleReference) return node.getArea().resolveNode(ref)?.let { NodeAsMPSModule(it, sRepository) } } } diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt index 0d3039e7ad..88f7b8cfad 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt @@ -32,6 +32,7 @@ import org.modelix.model.api.BuiltinLanguages import org.modelix.model.api.INode import org.modelix.model.api.getDescendants import org.modelix.model.mpsadapters.MPSJavaModuleFacetAsNode +import org.modelix.model.mpsadapters.MPSModuleDependencyAsNode import org.modelix.model.mpsadapters.MPSModuleReference import org.modelix.model.mpsadapters.Module @@ -49,7 +50,9 @@ data class NodeAsMPSModule(val node: INode, val sRepository: SRepository?) : SMo override fun getDeclaredDependencies(): MutableIterable { val dependencies = node.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Module.dependencies) - return dependencies.map { NodeAsMPSDependency(node, sRepository) }.toMutableList() + return dependencies.mapNotNull { depNode -> + (depNode as? MPSModuleDependencyAsNode)?.let { NodeAsMPSDependency(it, sRepository) } + }.toMutableList() } override fun getFacets(): MutableIterable { From bdefd584ec88f92f26a939effb6859a3805696b7 Mon Sep 17 00:00:00 2001 From: Michael Huster Date: Fri, 10 Nov 2023 15:21:43 +0100 Subject: [PATCH 4/4] refactor(mps-model-adapters): rename NodeAsMPSDependency to NodeAsMPSModuleDependency --- .../kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt | 2 +- .../{NodeAsMPSDependency.kt => NodeAsMPSModuleDependency.kt} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/{NodeAsMPSDependency.kt => NodeAsMPSModuleDependency.kt} (92%) diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt index 88f7b8cfad..2cefd0d8cc 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModule.kt @@ -51,7 +51,7 @@ data class NodeAsMPSModule(val node: INode, val sRepository: SRepository?) : SMo override fun getDeclaredDependencies(): MutableIterable { val dependencies = node.getChildren(BuiltinLanguages.MPSRepositoryConcepts.Module.dependencies) return dependencies.mapNotNull { depNode -> - (depNode as? MPSModuleDependencyAsNode)?.let { NodeAsMPSDependency(it, sRepository) } + (depNode as? MPSModuleDependencyAsNode)?.let { NodeAsMPSModuleDependency(it, sRepository) } }.toMutableList() } diff --git a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModuleDependency.kt similarity index 92% rename from mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt rename to mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModuleDependency.kt index e5b04a8753..b9d56404f5 100644 --- a/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSDependency.kt +++ b/mps-model-adapters/src/main/kotlin/org/modelix/model/mpsadapters/mps/NodeAsMPSModuleDependency.kt @@ -23,7 +23,7 @@ import org.jetbrains.mps.openapi.module.SRepository import org.modelix.model.mpsadapters.MPSModuleDependencyAsNode import org.modelix.model.mpsadapters.MPSModuleReference -data class NodeAsMPSDependency(val node: MPSModuleDependencyAsNode, val sRepository: SRepository?) : SDependency { +data class NodeAsMPSModuleDependency(val node: MPSModuleDependencyAsNode, val sRepository: SRepository?) : SDependency { override fun getScope(): SDependencyScope = checkNotNull(node.dependencyScope) { "Invalid dependency scope for dependency $node" } override fun isReexport() = node.reexport