Skip to content

Commit

Permalink
Merge pull request #336 from modelix/MODELIX-618
Browse files Browse the repository at this point in the history
MODELIX-618 Notation language in MPS for the new text editor
  • Loading branch information
slisson authored Mar 14, 2024
2 parents 7d86075 + bb517af commit 00dd73c
Show file tree
Hide file tree
Showing 28 changed files with 640 additions and 74 deletions.
1 change: 1 addition & 0 deletions .github/workflows/mps-compatibility.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
- "2021.3.3"
- "2022.2"
- "2022.3"
- "2023.2"

steps:
- uses: actions/checkout@v4
Expand Down
7 changes: 0 additions & 7 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ plugins {
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.gitVersion)
alias(libs.plugins.ktlint) apply false
alias(libs.plugins.spotless) apply false
alias(libs.plugins.tasktree)
alias(libs.plugins.dokka)
Expand Down Expand Up @@ -78,7 +77,6 @@ subprojects {
val subproject = this
apply(plugin = "maven-publish")
apply(plugin = "org.jetbrains.dokka")
apply(plugin = "org.jlleitschuh.gradle.ktlint")
apply(plugin = "io.gitlab.arturbosch.detekt")

version = rootProject.version
Expand All @@ -90,11 +88,6 @@ subprojects {
}
}

configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
// IMPORTANT: keep in sync with the version in .pre-commit-config.yaml
version.set("0.50.0")
}

tasks.withType<Detekt> {
parallel = true
// For now, we only use the results here as hints
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ kotlin {
sourceSets.named("main") {
kotlin.srcDir(kotlinGenDir)
}
jvmToolchain(11)
}

metamodel {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ class PushTest {
?.getDescendants(false)
?.find { it.getConceptReference() == ConceptReference(_C_UntypedImpl_Graph.getUID()) },
)
assertEquals(solution1Graph, solution2Graph.getReferenceTarget(C_Graph.relatedGraph))
assertEquals(solution1Graph, solution2Graph.getReferenceTarget(C_Graph.relatedGraph.untyped()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,41 @@ abstract class GenerateAntScriptForMpsMetaModelExport @Inject constructor(of: Ob
<arg value="-Didea.system.path=${"$"}{build.mps.system.path}" />
<arg value="-ea" />
<arg value="-Xmx${heapSize.get()}" />
<arg value="--add-opens=java.base/java.io=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.lang=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.lang.reflect=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.net=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.nio=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.nio.charset=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.text=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.time=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.util=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.util.concurrent=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/sun.nio.fs=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/sun.security.ssl=ALL-UNNAMED"/>
<arg value="--add-opens=java.base/sun.security.util=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/java.awt=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/java.awt.dnd.peer=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/java.awt.event=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/java.awt.image=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/java.awt.peer=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/javax.swing=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/javax.swing.text.html=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/sun.awt.datatransfer=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/sun.awt.image=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/sun.awt=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/sun.font=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/sun.java2d=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/sun.swing=ALL-UNNAMED"/>
<arg value="--add-opens=jdk.attach/sun.tools.attach=ALL-UNNAMED"/>
<arg value="--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"/>
<arg value="--add-opens=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED"/>
<arg value="--add-opens=jdk.jdi/com.sun.tools.jdi=ALL-UNNAMED"/>
<arg value="--add-opens=java.desktop/sun.lwawt=ALL-UNNAMED"/>
${
if (exportModulesFilter.isPresent) {
"""<arg value="-Dmodelix.export.includedModules=${exportModulesFilter.get()}" />"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,10 @@ abstract class GeneratedChildLink<ChildNodeT : ITypedNode, ChildConceptT : IConc

override fun getSimpleName(): String = simpleName
}
fun IChildLink.typed() = this as? ITypedChildLink<ITypedNode>
fun IChildLink.typed(): ITypedChildLink<ITypedNode> {
return this as? ITypedChildLink<ITypedNode>
?: if (isMultiple) UnknownTypedChildLinkList(this) else UnknownTypedSingleChildLink(this)
}

open class GeneratedSingleChildLink<ChildNodeT : ITypedNode, ChildConceptT : IConceptOfTypedNode<ChildNodeT>>(
owner: IConcept,
Expand Down Expand Up @@ -281,4 +284,4 @@ class GeneratedReferenceLink<TargetNodeT : ITypedNode, TargetConceptT : IConcept

override fun getSimpleName(): String = simpleName
}
fun IReferenceLink.typed() = this as? ITypedReferenceLink<ITypedNode>
fun IReferenceLink.typed() = this as? ITypedReferenceLink<ITypedNode> ?: UnknownTypedReferenceLink(this)
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.modelix.model.api.IChildLink
import org.modelix.model.api.INode
import org.modelix.model.api.remove

interface ITypedChildLink<ChildT : ITypedNode> : ITypedConceptFeature {
interface ITypedChildLink<out ChildT : ITypedNode> : ITypedConceptFeature {
fun untyped(): IChildLink
fun castChild(childNode: INode): ChildT
fun getTypedChildConcept(): IConceptOfTypedNode<ChildT>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ package org.modelix.metamodel
import org.modelix.model.api.INode
import org.modelix.model.api.IReferenceLink

interface ITypedReferenceLink<TargetT : ITypedNode> : ITypedConceptFeature {
interface ITypedReferenceLink<out TargetT : ITypedNode> : ITypedConceptFeature {
fun untyped(): IReferenceLink
fun castTarget(target: INode): TargetT
fun getTypedTargetConcept(): IConceptOfTypedNode<TargetT>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object TypedLanguagesRegistry : ILanguageRepository {
override fun getPriority(): Int = 2000
}

fun <NodeT : ITypedNode> INode.typed(nodeClass: KClass<NodeT>): NodeT = nodeClass.cast(TypedLanguagesRegistry.wrapNode(this))
fun <NodeT : ITypedNode> INode.typed(nodeClass: KClass<out NodeT>): NodeT = nodeClass.cast(TypedLanguagesRegistry.wrapNode(this))
inline fun <reified NodeT : ITypedNode> INode.typed(): NodeT = TypedLanguagesRegistry.wrapNode(this) as NodeT
fun <NodeT : ITypedNode> INode.typedUnsafe(): NodeT = TypedLanguagesRegistry.wrapNode(this) as NodeT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ package org.modelix.metamodel

import org.modelix.model.api.IConcept
import org.modelix.model.api.INode
import org.modelix.model.api.getConcept

abstract class TypedNodeImpl(val wrappedNode: INode) : ITypedNode {

init {
val expected: IConcept = _concept._concept
val actual: IConcept? = unwrap().getConcept()
val actual: IConcept? = unwrap().concept
require(actual != null && actual.isSubConceptOf(expected)) {
"Concept of node ${unwrap()} expected to be a sub-concept of $expected, but was $actual"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.modelix.model.api.INode
import org.modelix.model.api.IProperty
import org.modelix.model.api.IReferenceLink
import org.modelix.model.area.IArea
import kotlin.reflect.KClass

abstract class EmptyConcept : IConcept {
override fun isAbstract(): Boolean = true
Expand Down Expand Up @@ -77,15 +78,52 @@ data class UnknownConcept(private val ref: IConceptReference) : EmptyConcept() {
override fun getLongName(): String = getShortName()
}

data class UnknownTypedConcept(private val ref: IConceptReference?) : ITypedConcept {
data class UnknownTypedConcept(private val ref: IConcept?) : IConceptOfTypedNode<UnknownConceptInstance> {
override fun untyped(): IConcept {
return ref?.let { UnknownConcept(it) } ?: NullConcept
return ref ?: NullConcept
}

override fun getInstanceInterface(): KClass<out UnknownConceptInstance> {
return UnknownConceptInstance::class
}
}

data class UnknownConceptInstance(val node: INode) : ITypedNode {
override val _concept: ITypedConcept
get() = UnknownTypedConcept(node.getConceptReference())
get() = UnknownTypedConcept(node.concept)

override fun unwrap(): INode = node
}

abstract class UnknownTypedChildLink : ITypedChildLink<ITypedNode> {

override fun castChild(childNode: INode): ITypedNode {
return childNode.typed()
}

override fun getTypedChildConcept(): IConceptOfTypedNode<ITypedNode> {
return untyped().targetConcept.typed() as IConceptOfTypedNode<ITypedNode>
}
}

data class UnknownTypedSingleChildLink(private val link: IChildLink) : UnknownTypedChildLink(), ITypedSingleChildLink<ITypedNode> {
override fun untyped(): IChildLink = link
}

data class UnknownTypedChildLinkList(private val link: IChildLink) : UnknownTypedChildLink(), ITypedChildListLink<ITypedNode> {
override fun untyped(): IChildLink = link
}

data class UnknownTypedReferenceLink(private val link: IReferenceLink) : ITypedReferenceLink<ITypedNode> {
override fun untyped(): IReferenceLink {
return link
}

override fun castTarget(target: INode): ITypedNode {
return target.typed()
}

override fun getTypedTargetConcept(): IConceptOfTypedNode<ITypedNode> {
return untyped().targetConcept.typed() as IConceptOfTypedNode<ITypedNode>
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.TypeVariableName
import com.squareup.kotlinpoet.asClassName
import com.squareup.kotlinpoet.asTypeName
import org.modelix.metamodel.GeneratedProperty
import org.modelix.metamodel.IConceptOfTypedNode
import org.modelix.metamodel.INonAbstractConcept
import org.modelix.metamodel.ITypedConcept
Expand Down Expand Up @@ -91,6 +89,7 @@ internal class ConceptWrapperInterfaceGenerator(
private fun TypeSpec.Builder.addConceptMetaPropertiesIfNecessary() {
if (conceptPropertiesInterfaceName == null) return

// TODO use IConcept.getConceptProperty(name: String)
concept.metaProperties.forEach { (key, value) ->
val propertySpec = PropertySpec.builder(key, String::class.asTypeName()).runBuild {
addModifiers(KModifier.OVERRIDE)
Expand All @@ -102,7 +101,7 @@ internal class ConceptWrapperInterfaceGenerator(
}

private fun TypeSpec.Builder.addConceptWrapperInterfaceReferenceLink(referenceLink: ProcessedReferenceLink) {
val propertySpec = PropertySpec.builder(referenceLink.generatedName, referenceLink.generatedReferenceLinkType()).runBuild {
val propertySpec = PropertySpec.builder(referenceLink.generatedName, referenceLink.typedLinkType()).runBuild {
getter(FunSpec.getterBuilder().addCode(referenceLink.returnKotlinRef()).build())
addDeprecationIfNecessary(referenceLink)
}
Expand All @@ -111,7 +110,7 @@ internal class ConceptWrapperInterfaceGenerator(
}

private fun TypeSpec.Builder.addConceptWrapperInterfaceChildLink(childLink: ProcessedChildLink) {
val propertySpec = PropertySpec.builder(childLink.generatedName, childLink.generatedChildLinkType()).runBuild {
val propertySpec = PropertySpec.builder(childLink.generatedName, childLink.typedLinkType()).runBuild {
getter(FunSpec.getterBuilder().addCode(childLink.returnKotlinRef()).build())
addDeprecationIfNecessary(childLink)
}
Expand All @@ -122,8 +121,7 @@ internal class ConceptWrapperInterfaceGenerator(
private fun TypeSpec.Builder.addConceptWrapperInterfaceProperty(property: ProcessedProperty) {
val propertySpec = PropertySpec.builder(
name = property.generatedName,
type = GeneratedProperty::class.asClassName()
.parameterizedBy(property.asKotlinType(alwaysUseNonNullableProperties)),
type = property.typedPropertyType(alwaysUseNonNullableProperties),
).runBuild {
val getterSpec = FunSpec.getterBuilder().runBuild {
addCode(property.returnKotlinRef())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ import org.modelix.metamodel.GeneratedChildListLink
import org.modelix.metamodel.GeneratedMandatorySingleChildLink
import org.modelix.metamodel.GeneratedReferenceLink
import org.modelix.metamodel.GeneratedSingleChildLink
import org.modelix.metamodel.ITypedChildListLink
import org.modelix.metamodel.ITypedMandatorySingleChildLink
import org.modelix.metamodel.ITypedProperty
import org.modelix.metamodel.ITypedReferenceLink
import org.modelix.metamodel.ITypedSingleChildLink
import org.modelix.metamodel.generator.NameConfig
import org.modelix.metamodel.generator.ProcessedChildLink
import org.modelix.metamodel.generator.ProcessedConcept
Expand Down Expand Up @@ -77,6 +82,18 @@ internal abstract class NameConfigBasedGenerator(open val nameConfig: NameConfig
)
}

protected fun ProcessedChildLink.typedLinkType(): TypeName {
val childConcept = type.resolved
val linkClass = if (multiple) {
ITypedChildListLink::class
} else {
if (optional) ITypedSingleChildLink::class else ITypedMandatorySingleChildLink::class
}
return linkClass.asClassName().parameterizedBy(
childConcept.nodeWrapperInterfaceType(),
)
}

protected fun ProcessedReferenceLink.generatedReferenceLinkType(): TypeName {
val targetConcept = type.resolved
return GeneratedReferenceLink::class.asClassName().parameterizedBy(
Expand All @@ -85,6 +102,19 @@ internal abstract class NameConfigBasedGenerator(open val nameConfig: NameConfig
)
}

protected fun ProcessedReferenceLink.typedLinkType(): TypeName {
val targetConcept = type.resolved
return ITypedReferenceLink::class.asClassName().parameterizedBy(
targetConcept.nodeWrapperInterfaceType(),
)
}

protected fun ProcessedProperty.typedPropertyType(alwaysUseNonNullableProperties: Boolean): TypeName {
return ITypedProperty::class.asClassName().parameterizedBy(
asKotlinType(alwaysUseNonNullableProperties),
)
}

protected fun ProcessedProperty.asKotlinType(alwaysUseNonNullableProperties: Boolean): TypeName {
val nonNullableType = when (type) {
is PrimitivePropertyType -> when ((type as PrimitivePropertyType).primitive) {
Expand Down
11 changes: 0 additions & 11 deletions model-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@ plugins {

description = "API to access models stored in Modelix"

ktlint {
filter {
exclude {
val kotlinGeneratedFromTypeScript =
project(":ts-model-api").layout.buildDirectory.get().asFile.toPath().toAbsolutePath()
it.file.toPath().toAbsolutePath().startsWith(kotlinGeneratedFromTypeScript)
}
}
}

kotlin {
jvm()
js(IR) {
Expand Down Expand Up @@ -70,7 +60,6 @@ kotlin {

listOf(
"sourcesJar",
"runKtlintCheckOverJsMainSourceSet",
"jsSourcesJar",
"jsPackageJson",
"compileKotlinJs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,16 @@ interface IConcept {
* @return reference link
*/
fun getReferenceLink(name: String): IReferenceLink

/**
* The alias of an MPS concept is one example of a concept property.
*/
fun getConceptProperty(name: String): String? = null
}

/**
* @see IConcept.isSubConceptOf
*/
fun IConcept?.isSubConceptOf(superConcept: IConcept?) = this?.isSubConceptOf(superConcept) == true

fun IConcept.conceptAlias() = getConceptProperty("alias")
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ fun INode.setReferenceTarget(link: IReferenceLink, target: INodeReference?): Uni
fun INode.getPropertyValue(property: IProperty): String? = if (this is INodeEx) getPropertyValue(property) else getPropertyValue(property.key(this))
fun INode.setPropertyValue(property: IProperty, value: String?): Unit = if (this is INodeEx) setPropertyValue(property, value) else setPropertyValue(property.key(this), value)

@Deprecated("use INode.concept", ReplaceWith("concept"))
fun INode.getConcept(): IConcept? = getConceptReference()?.resolve()
fun INode.getResolvedReferenceTarget(role: String): INode? = getReferenceTargetRef(role)?.resolveIn(getArea()!!)
fun INode.getResolvedConcept(): IConcept? = getConceptReference()?.resolve()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.api

interface ITransactionManager {
fun <R> executeRead(body: () -> R): R
fun <R> executeWrite(body: () -> R): R
fun canRead(): Boolean
fun canWrite(): Boolean
}
Loading

0 comments on commit 00dd73c

Please sign in to comment.