Skip to content

Commit 60517cd

Browse files
committed
feat(mps-model-adapters): re-implementation of the model-api adapters for MPS
There is an implementation of the model-api in MPS-extensions written inside an MPS solution in baseLanguage. Having this functionality as a separate library inside this repository makes it much easier to maintain, update and reuse. It also solves version conflicts, because an MPS module can have its own version of the library loaded by its own classloader.
1 parent 4c4bd1d commit 60517cd

14 files changed

+934
-0
lines changed

commitlint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module.exports = {
1515
"model-client",
1616
"model-server",
1717
"model-sync-lib",
18+
"mps-model-adapters",
1819
"ts-model-api",
1920
],
2021
],
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
plugins {
2+
kotlin("jvm")
3+
`maven-publish`
4+
alias(libs.plugins.ktlint)
5+
}
6+
7+
dependencies {
8+
api(project(":model-api"))
9+
10+
compileOnly("com.jetbrains:mps-openapi:2021.1.4")
11+
compileOnly("com.jetbrains:mps-core:2021.1.4")
12+
compileOnly("com.jetbrains:mps-environment:2021.1.4")
13+
14+
implementation(kotlin("stdlib"))
15+
implementation(libs.kotlin.logging)
16+
}
17+
18+
group = "org.modelix.mps"
19+
20+
publishing {
21+
publications {
22+
create<MavenPublication>("maven") {
23+
artifactId = "model-adapters"
24+
from(components["kotlin"])
25+
}
26+
}
27+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package org.modelix.model.mpsadapters
15+
16+
import org.jetbrains.mps.openapi.module.SRepository
17+
import org.modelix.model.api.IBranch
18+
import org.modelix.model.api.IConcept
19+
import org.modelix.model.api.IConceptReference
20+
import org.modelix.model.api.INode
21+
import org.modelix.model.api.INodeReference
22+
import org.modelix.model.area.IArea
23+
import org.modelix.model.area.IAreaListener
24+
import org.modelix.model.area.IAreaReference
25+
26+
data class MPSArea(val repository: SRepository) : IArea {
27+
override fun getRoot(): INode {
28+
return MPSRepositoryAsNode(repository)
29+
}
30+
31+
override fun resolveConcept(ref: IConceptReference): IConcept? {
32+
TODO("Not yet implemented")
33+
}
34+
35+
override fun resolveNode(ref: INodeReference): INode? {
36+
return MPSNodeReference.tryConvert(ref)?.ref?.resolve(repository)?.let { MPSNode(it) }
37+
}
38+
39+
override fun resolveOriginalNode(ref: INodeReference): INode? {
40+
return resolveNode(ref)
41+
}
42+
43+
override fun resolveBranch(id: String): IBranch? {
44+
return null
45+
}
46+
47+
override fun collectAreas(): List<IArea> {
48+
return listOf(this)
49+
}
50+
51+
override fun getReference(): IAreaReference {
52+
TODO("Not yet implemented")
53+
}
54+
55+
override fun resolveArea(ref: IAreaReference): IArea? {
56+
TODO("Not yet implemented")
57+
}
58+
59+
override fun <T> executeRead(f: () -> T): T {
60+
var result: T? = null
61+
repository.modelAccess.runReadAction {
62+
result = f()
63+
}
64+
return result as T
65+
}
66+
67+
override fun <T> executeWrite(f: () -> T): T {
68+
TODO("Not yet implemented")
69+
}
70+
71+
override fun canRead(): Boolean {
72+
return repository.modelAccess.canRead()
73+
}
74+
75+
override fun canWrite(): Boolean {
76+
return repository.modelAccess.canWrite()
77+
}
78+
79+
override fun addListener(l: IAreaListener) {
80+
TODO("Not yet implemented")
81+
}
82+
83+
override fun removeListener(l: IAreaListener) {
84+
TODO("Not yet implemented")
85+
}
86+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package org.modelix.model.mpsadapters
15+
16+
import jetbrains.mps.smodel.adapter.structure.link.SContainmentLinkAdapter
17+
import org.jetbrains.mps.openapi.language.SContainmentLink
18+
import org.modelix.model.api.IChildLink
19+
import org.modelix.model.api.IConcept
20+
21+
data class MPSChildLink(val link: SContainmentLinkAdapter) : IChildLink {
22+
constructor(link: SContainmentLink) : this(link as SContainmentLinkAdapter)
23+
override val isMultiple: Boolean
24+
get() = link.isMultiple
25+
override val childConcept: IConcept
26+
get() = targetConcept
27+
override val targetConcept: IConcept
28+
get() = MPSConcept(link.targetConcept)
29+
30+
override fun getConcept(): IConcept {
31+
return MPSConcept(link.owner)
32+
}
33+
34+
override fun getUID(): String {
35+
return link.id.serialize()
36+
}
37+
38+
override fun getSimpleName(): String {
39+
return link.name
40+
}
41+
42+
override val isOptional: Boolean
43+
get() = link.isOptional
44+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package org.modelix.model.mpsadapters
15+
16+
import jetbrains.mps.smodel.adapter.ids.SConceptId
17+
import jetbrains.mps.smodel.adapter.structure.concept.SAbstractConceptAdapter
18+
import jetbrains.mps.smodel.adapter.structure.concept.SConceptAdapterById
19+
import jetbrains.mps.smodel.adapter.structure.concept.SInterfaceConceptAdapterById
20+
import org.jetbrains.mps.openapi.language.SAbstractConcept
21+
import org.jetbrains.mps.openapi.language.SConcept
22+
import org.jetbrains.mps.openapi.language.SInterfaceConcept
23+
import org.modelix.model.api.ConceptReference
24+
import org.modelix.model.api.IChildLink
25+
import org.modelix.model.api.IConcept
26+
import org.modelix.model.api.IConceptReference
27+
import org.modelix.model.api.ILanguage
28+
import org.modelix.model.api.IProperty
29+
import org.modelix.model.api.IReferenceLink
30+
31+
data class MPSConcept(val concept: SAbstractConceptAdapter) : IConcept {
32+
constructor(concept: SAbstractConcept) : this(concept as SAbstractConceptAdapter)
33+
override fun getReference(): IConceptReference {
34+
return ConceptReference(getUID())
35+
}
36+
37+
override val language: ILanguage?
38+
get() = TODO("Not yet implemented")
39+
40+
override fun getUID(): String {
41+
val id: SConceptId = when (concept) {
42+
is SConceptAdapterById -> concept.id
43+
is SInterfaceConceptAdapterById -> concept.id
44+
else -> throw RuntimeException("Unknown concept type: $concept")
45+
}
46+
return "mps:" + id.serialize()
47+
}
48+
49+
override fun getShortName(): String {
50+
return concept.name
51+
}
52+
53+
override fun getLongName(): String {
54+
return concept.language.qualifiedName + "." + concept.name
55+
}
56+
57+
override fun isAbstract(): Boolean {
58+
return concept.isAbstract
59+
}
60+
61+
override fun isSubConceptOf(superConcept: IConcept?): Boolean {
62+
val mpsSuperConcept = superConcept as? MPSConcept ?: return false
63+
return concept.isSubConceptOf(mpsSuperConcept.concept)
64+
}
65+
66+
override fun getDirectSuperConcepts(): List<IConcept> {
67+
return when (concept) {
68+
is SConcept -> listOfNotNull<SAbstractConcept>(concept.superConcept) + concept.superInterfaces
69+
is SInterfaceConcept -> concept.superInterfaces
70+
else -> emptyList()
71+
}.map { MPSConcept(it) }
72+
}
73+
74+
override fun isExactly(other: IConcept?): Boolean {
75+
val otherMpsConcept = other as? MPSConcept ?: return false
76+
return this.concept == otherMpsConcept.concept
77+
}
78+
79+
override fun getOwnProperties(): List<IProperty> {
80+
return concept.properties.filter { it.owner == concept }.map { MPSProperty(it) }
81+
}
82+
83+
override fun getOwnChildLinks(): List<IChildLink> {
84+
return concept.containmentLinks.filter { it.owner == concept }.map { MPSChildLink(it) }
85+
}
86+
87+
override fun getOwnReferenceLinks(): List<IReferenceLink> {
88+
return concept.referenceLinks.filter { it.owner == concept }.map { MPSReferenceLink(it) }
89+
}
90+
91+
override fun getAllProperties(): List<IProperty> {
92+
return concept.properties.map { MPSProperty(it) }
93+
}
94+
95+
override fun getAllChildLinks(): List<IChildLink> {
96+
return concept.containmentLinks.map { MPSChildLink(it) }
97+
}
98+
99+
override fun getAllReferenceLinks(): List<IReferenceLink> {
100+
return concept.referenceLinks.map { MPSReferenceLink(it) }
101+
}
102+
103+
override fun getProperty(name: String): IProperty {
104+
return MPSProperty(concept.properties.first { it.name == name })
105+
}
106+
107+
override fun getChildLink(name: String): IChildLink {
108+
return MPSChildLink(concept.containmentLinks.first { it.name == name })
109+
}
110+
111+
override fun getReferenceLink(name: String): IReferenceLink {
112+
return MPSReferenceLink(concept.referenceLinks.first { it.name == name })
113+
}
114+
}

0 commit comments

Comments
 (0)