Skip to content
Snippets Groups Projects
Commit c1cecf6a authored by René Schöne's avatar René Schöne
Browse files

Merge branch '40-make-grammar-s-more-concise' into 'dev'

Resolve "Make grammar(s) more concise"

Closes #40

See merge request !21
parents 48684df4 4811d22d
Branches
No related tags found
3 merge requests!39Version 1.1.0,!35Version 1.0.0,!21Resolve "Make grammar(s) more concise"
Pipeline #12141 passed
Pipeline: RagConnect Dev Pages

#12143

    Showing
    with 1067 additions and 1107 deletions
    ...@@ -38,6 +38,7 @@ test: ...@@ -38,6 +38,7 @@ test:
    needs: needs:
    - build - build
    script: script:
    - ./gradlew --console=plain --no-daemon test
    - ./gradlew --console=plain --no-daemon allTests - ./gradlew --console=plain --no-daemon allTests
    artifacts: artifacts:
    when: always when: always
    ......
    # Extending `RagConnect` # Extending `RagConnect`
    To add a new communication protocol, the following locations have to be changed (replace `ABC` and `abc` with the name of the protocol): To add a new communication protocol, the following locations have to be changed (replace `ABC` and `abc` with the name of the protocol).
    Within `ragconnect.base/src/main/resources`: ### Within `ragconnect.base/src/main/resources`
    {% raw %} {% raw %}
    - Add a new handler `ABCHandler`, if appropriate, similar to the existing handlers - Add a new handler `ABCHandler.jadd`, similar to the existing handlers.
    - If further methods are needed for handler initialization, add a new template `abc.mustache` containing those procedures. Add `{{#usesABC}}{{> abc}}{{/usesABC}}` at the top of `ragconnect.mustache` to use this template - In `handler.mustache`, add further methods if needed for handler usage in the application code (similar to `{{rootNodeName}}.{{SetupWaitUntilReadyMethodName}}` for `mqtt`)
    - In `receiveDefinition.mustache` and `sendDefinition.mustache`: add a new case in the switch statement defining the logic to happen for both definitions. If the new protocol is close to a PUSH semantic, follow `mqtt`. If it is closer to PULL semantic, follow `rest`. - In `receiveDefinition.mustache` and `sendDefinition.mustache`: add a new case in the switch statements defining the logic to happen upon connect and disconnect for both definitions. If the new protocol is close to a PUSH semantic, follow `mqtt`. If it is closer to PULL semantic, follow `rest`.
    {% endraw %} {% endraw %}
    Within `ragconnect.base/src/main/jastadd`: ### Within `ragconnect.base/src/main/jastadd`
    - In `backend/Configuration`: In `Handlers.jrag`: Add a new attribute `RagConnect.abcHandler()` returning the resolved handler
    - Add a new static boolean flag `usesABC` to indicate whether the protocol is used
    - In `backend/Generation`:
    - Add new attributes for type `MRagConnect` for handler attribute and handler field, if needed
    - Add attributes for newly introduced references in changed mustache templates, if any
    - Add a newly constructed handler within the definition of `RagConnect.toMustache` with the needed fields (class name, construction snippet, handler attribute, handler field, the boolean flag you just added to Configuration)
    - In `backend/MustacheNodesToYAML`:
    - Add key-value-pair for `usesABC` (and handler, if any)
    - Add key-value-pairs for newly introduced referemces in changed mustache templates, if any
    In `ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java`: ### Within `ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler`
    In `Compiler.java`:
    - Add a new choice for `--protocols` similar to the existing ones - Add a new choice for `--protocols` similar to the existing ones
    - Set the flag `usesABC` if the choice is given. - Add a newly constructed handler in `setConfiguration` with the needed fields (definition file name within `resources` directory, commonly `ABCHandler.jadd`; class name of the handler; unique name for the protocol; whether the handler is used, i.e., if it was given in `--protocols`)
    - Add code to add the handler to the list `handlers` if the choice is given, i.e., if `ASTNode.usesABC`
    Furthermore, new test cases are appreciated, see [below](#writing-tests). Furthermore, new test cases are appreciated, see [below](#writing-tests).
    ...@@ -58,7 +50,7 @@ All tests are required to run both locally, and within the CI. ...@@ -58,7 +50,7 @@ All tests are required to run both locally, and within the CI.
    ### build.gradle ### build.gradle
    Use the [PreprocessorPlugin][preprocessor-plugin], the build process can be written concisely in three parts per task: Using the [PreprocessorPlugin][preprocessor-plugin], the build process can be written concisely in three parts per task:
    ```groovy ```groovy
    task compileTreeAllowedTokens(type: RagConnectTest) { task compileTreeAllowedTokens(type: RagConnectTest) {
    ......
    ...@@ -4,12 +4,18 @@ Please see [API documentation](ragdoc/index.html) for more details. ...@@ -4,12 +4,18 @@ Please see [API documentation](ragdoc/index.html) for more details.
    ![ros2rag-process](img/ros2rag-process.png) ![ros2rag-process](img/ros2rag-process.png)
    `RagConnect` uses the [relast-preprocessor](https://git-st.inf.tu-dresden.de/jastadd/relast-preprocessor) to parse `.relast` grammar files. This results in an ASTNode of type `Program`. `RagConnect` uses the [relast-preprocessor](https://git-st.inf.tu-dresden.de/jastadd/relast-preprocessor) to parse `.relast` grammar files.
    It further uses a dedicated parser for `.connect` files containing endpoint-, mapping-, and dependency-definitions. This results in an ASTNode of type `RagConnect`. This results in an ASTNode of type `Program`.
    It further uses a dedicated parser for `.connect` files containing endpoint-, mapping-, and dependency-definitions.
    This results in an ASTNode of type `RagConnect`.
    The goal is to generate an aspect file containing setters and getters of tokens referred to by endpoint-definitions The goal is to generate an aspect file containing setters and getters of tokens referred to by endpoint-definitions
    We use [mustache](https://mustache.github.io/) (currently its [Java version](https://github.com/spullara/mustache.java)) making use of partials resulting in a set of `.mustache` files located in `ragconnect.base/src/main/resources`. We use [mustache](https://mustache.github.io/) (currently its [Java version](https://github.com/spullara/mustache.java)) making use of partials to separate concerns.
    The generation process uses an intermediate NTA of type `MRagConnect` defined in `MustacheNodes.relast` to separate this generation concern from the content of the DSL The `.mustache` files are located in `ragconnect.base/src/main/resources`.
    The generation process uses intermediates NTAs (whose types are defined in `Intermediate.relast`) to ease the definition of two main generation "problems".
    Those problems are differentiation on both kinds of an endpoint (send/receive and type/token/list), and attributes depending on position in n-ary relations.
    There are aspect files for `Navigation` (mainly isX/asX attributes), `Analysis` (lookup attributes), `Printing`, `backend/Mappings` (default mappings) There are aspect files for `Navigation` (mainly isX/asX attributes), `Analysis` (static analysis attributes), `Printing`, `Mappings` (default mappings).
    One of the main aspects is `backend/Generation` containing attributes to construct the `MRagConnect` NTA and all necessary attributes used within the mustache templates One of the main aspects is `Intermediate` containing all attributes consumed by `mustache` and other attributes the former depend on.
    The other main aspect (which is currently not really used) is `backend/MustacheNodesToYAML.jrag` containing the transformation from a `MRagConnect` subtree to a `Document` subtree defined by `YAML.relast`. This is used to generate a YAML file containing the data used by mustache. It can be used by the default mustache implementation together with the templates. The other main aspect (which is currently not really used) is `IntermediateToYAML` containing the transformation from a `RagConnect` subtree to a `Document` subtree defined by `Mustache.relast` (located in `relast-preprocessor` submodule).
    This is used to generate a YAML file containing the data used by mustache.
    It can be used by the default mustache implementation together with the templates.
    ...@@ -24,6 +24,9 @@ repositories { ...@@ -24,6 +24,9 @@ repositories {
    mavenCentral() mavenCentral()
    jcenter() jcenter()
    } }
    tasks.compileJava {
    options.release.set(11)
    }
    dependencies { dependencies {
    implementation project(':relast-preprocessor') implementation project(':relast-preprocessor')
    ...@@ -33,6 +36,12 @@ dependencies { ...@@ -33,6 +36,12 @@ dependencies {
    api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
    } }
    java {
    toolchain {
    languageVersion.set(JavaLanguageVersion.of(11))
    }
    }
    def versionFile = 'src/main/resources/ragConnectVersion.properties' def versionFile = 'src/main/resources/ragConnectVersion.properties'
    def props = new Properties() def props = new Properties()
    ...@@ -77,7 +86,7 @@ jar { ...@@ -77,7 +86,7 @@ jar {
    File preprocessorGrammar = file('../relast-preprocessor/src/main/jastadd/RelAst.relast') File preprocessorGrammar = file('../relast-preprocessor/src/main/jastadd/RelAst.relast')
    File ragConnectGrammar = file('./src/main/jastadd/RagConnect.relast') File ragConnectGrammar = file('./src/main/jastadd/RagConnect.relast')
    File intermediateGrammar = file('./src/main/jastadd/intermediate/MustacheNodes.relast') File intermediateGrammar = file('./src/main/jastadd/Intermediate.relast')
    File mustacheGrammar = file('../relast-preprocessor/src/main/jastadd/mustache/Mustache.relast') File mustacheGrammar = file('../relast-preprocessor/src/main/jastadd/mustache/Mustache.relast')
    task relast(type: JavaExec) { task relast(type: JavaExec) {
    group = 'Build' group = 'Build'
    ......
    aspect Analysis { aspect Analysis {
    // --- lookupTokenEndpointDefinition ---
    inh java.util.List<TokenEndpointDefinition> TokenEndpointDefinition.lookupTokenEndpointDefinitions(TokenComponent token);
    eq RagConnect.getConnectSpecificationFile().lookupTokenEndpointDefinitions(TokenComponent token) = lookupTokenEndpointDefinitions(token);
    syn java.util.List<TokenEndpointDefinition> RagConnect.lookupTokenEndpointDefinitions(TokenComponent token) {
    java.util.List<TokenEndpointDefinition> result = new java.util.ArrayList<>();
    for (EndpointDefinition def : allEndpointDefinitionList()) {
    if (def.isTokenEndpointDefinition() && def.asTokenEndpointDefinition().getToken().equals(token)) {
    result.add(def.asTokenEndpointDefinition());
    }
    }
    return result;
    }
    // --- lookupTypeEndpointDefinition ---
    inh java.util.List<TypeEndpointDefinition> TypeEndpointDefinition.lookupTypeEndpointDefinitions(TypeComponent type);
    eq RagConnect.getConnectSpecificationFile().lookupTypeEndpointDefinitions(TypeComponent type) = lookupTypeEndpointDefinitions(type);
    syn java.util.List<TypeEndpointDefinition> RagConnect.lookupTypeEndpointDefinitions(TypeComponent type) {
    java.util.List<TypeEndpointDefinition> result = new java.util.ArrayList<>();
    for (EndpointDefinition def : allEndpointDefinitionList()) {
    if (def.isTypeEndpointDefinition() && def.asTypeEndpointDefinition().getType().equals(type)) {
    result.add(def.asTypeEndpointDefinition());
    }
    }
    return result;
    }
    // --- lookupDependencyDefinition ---
    inh DependencyDefinition DependencyDefinition.lookupDependencyDefinition(TypeDecl source, String id);
    eq RagConnect.getConnectSpecificationFile().lookupDependencyDefinition(TypeDecl source, String id) {
    for (DependencyDefinition def : allDependencyDefinitionList()) {
    if (def.getID().equals(id) && def.getSource().containingTypeDecl().equals(source)) {
    return def;
    }
    }
    return null;
    }
    // --- isAlreadyDefined --- // --- isAlreadyDefined ---
    syn boolean TokenEndpointDefinition.isAlreadyDefined() { syn boolean EndpointDefinition.isAlreadyDefined() = getEndpointTarget().isAlreadyDefined();
    syn boolean EndpointTarget.isAlreadyDefined();
    eq TokenEndpointTarget.isAlreadyDefined() {
    return lookupTokenEndpointDefinitions(getToken()).stream() return lookupTokenEndpointDefinitions(getToken()).stream()
    .filter(this::matchesType) .filter(containingEndpointDefinition()::matchesType)
    .count() > 1;
    }
    eq TypeEndpointTarget.isAlreadyDefined() {
    return lookupTypeEndpointDefinitions(getType()).stream()
    .filter(containingEndpointDefinition()::matchesType)
    .count() > 1; .count() > 1;
    } }
    syn boolean DependencyDefinition.isAlreadyDefined() = lookupDependencyDefinition(getSource().containingTypeDecl(), getID()) != this; syn boolean DependencyDefinition.isAlreadyDefined() = lookupDependencyDefinition(getSource().containingTypeDecl(), getID()) != this;
    // --- matchesType --- // --- matchesType ---
    syn boolean TokenEndpointDefinition.matchesType(TokenEndpointDefinition other); syn boolean EndpointDefinition.matchesType(EndpointDefinition other) = this.getSend() == other.getSend();
    eq ReceiveTokenEndpointDefinition.matchesType(TokenEndpointDefinition other) = other.isReceiveTokenEndpointDefinition();
    eq SendTokenEndpointDefinition.matchesType(TokenEndpointDefinition other) = other.isSendTokenEndpointDefinition();
    // --- assignableTo --- // --- assignableTo ---
    syn boolean MappingDefinitionType.assignableTo(JavaTypeUse target); syn boolean MappingDefinitionType.assignableTo(JavaTypeUse target);
    eq JavaMappingDefinitionType.assignableTo(JavaTypeUse target) = getType().assignableTo(target); eq JavaMappingDefinitionType.assignableTo(JavaTypeUse target) = getType().assignableTo(target);
    eq JavaArrayMappingDefinitionType.assignableTo(JavaTypeUse target) { eq JavaArrayMappingDefinitionType.assignableTo(JavaTypeUse target) {
    if (!target.getName().endsWith("[]")) { return false; } if (!target.getName().endsWith("[]")) {
    return false;
    }
    return getType().assignableTo(new SimpleJavaTypeUse(target.getName().replace("[]", ""))); return getType().assignableTo(new SimpleJavaTypeUse(target.getName().replace("[]", "")));
    } }
    syn boolean JavaTypeUse.assignableTo(JavaTypeUse target) { syn boolean JavaTypeUse.assignableTo(JavaTypeUse target) {
    ...@@ -63,29 +33,37 @@ aspect Analysis { ...@@ -63,29 +33,37 @@ aspect Analysis {
    syn String JavaTypeUse.primitivePrettyPrint() { syn String JavaTypeUse.primitivePrettyPrint() {
    switch (getName()) { switch (getName()) {
    case "boolean": case "boolean":
    case "Boolean": return "boolean"; case "Boolean":
    return "boolean";
    case "int": case "int":
    case "Integer": return "int"; case "Integer":
    return "int";
    case "short": case "short":
    case "Short": return "short"; case "Short":
    return "short";
    case "long": case "long":
    case "Long": return "long"; case "Long":
    return "long";
    case "float": case "float":
    case "Float": return "float"; case "Float":
    return "float";
    case "double": case "double":
    case "Double": return "double"; case "Double":
    return "double";
    case "char": case "char":
    case "Character": return "char"; case "Character":
    default: return getName(); return "char";
    default:
    return getName();
    } }
    } }
    // --- shouldSendValue --- syn boolean EndpointTarget.entityIsNormalAttribute();
    syn boolean TokenEndpointDefinition.shouldSendValue() = isSendTokenEndpointDefinition() && !getToken().getNTA(); eq TokenEndpointTarget.entityIsNormalAttribute() = !getToken().getNTA();
    syn boolean TypeEndpointDefinition.shouldSendValue() = isSendTypeEndpointDefinition() && !getType().getNTA(); eq TypeEndpointTarget.entityIsNormalAttribute() = !getType().getNTA();
    // --- needProxyToken --- // --- needProxyToken ---
    syn boolean TokenComponent.needProxyToken() = !getDependencySourceDefinitionList().isEmpty() || getTokenEndpointDefinitionList().stream().anyMatch(TokenEndpointDefinition::shouldSendValue); syn boolean TokenComponent.needProxyToken() = !getDependencySourceDefinitionList().isEmpty() || getTokenEndpointTargetList().stream().map(EndpointTarget::containingEndpointDefinition).anyMatch(EndpointDefinition::shouldSendValue);
    // --- effectiveUsedAt --- // --- effectiveUsedAt ---
    coll Set<EndpointDefinition> MappingDefinition.effectiveUsedAt() coll Set<EndpointDefinition> MappingDefinition.effectiveUsedAt()
    ...@@ -95,10 +73,4 @@ aspect Analysis { ...@@ -95,10 +73,4 @@ aspect Analysis {
    to MappingDefinition.effectiveUsedAt() to MappingDefinition.effectiveUsedAt()
    for each effectiveMappings(); for each effectiveMappings();
    // --- typeIsList ---
    syn boolean EndpointDefinition.typeIsList() = false;
    eq TypeEndpointDefinition.typeIsList() {
    return getType().isListComponent();
    }
    } }
    aspect Configuration { aspect ConfigurationShortcuts {
    public static boolean ASTNode.loggingEnabledForReads = false; syn TypeDecl RagConnect.rootNode() = getConfiguration().getRootNode();
    public static boolean ASTNode.loggingEnabledForWrites = false;
    public static boolean ASTNode.loggingEnabledForIncremental = false;
    public static TypeDecl ASTNode.rootNode;
    public static String ASTNode.JastAddList = "List";
    public static boolean ASTNode.usesMqtt;
    public static boolean ASTNode.usesRest;
    public static boolean ASTNode.incrementalOptionActive;
    public static boolean ASTNode.experimentalJastAdd329;
    } }
    ...@@ -3,29 +3,28 @@ aspect Errors { ...@@ -3,29 +3,28 @@ aspect Errors {
    [new TreeSet<ErrorMessage>()] [new TreeSet<ErrorMessage>()]
    root RagConnect; root RagConnect;
    ReceiveTokenEndpointDefinition contributes error("Receive definition already defined for " + getToken().getName()) EndpointDefinition contributes error("Endpoint definition already defined for " + parentTypeName() + "." + entityName())
    when isAlreadyDefined() when isAlreadyDefined()
    to RagConnect.errors(); to RagConnect.errors();
    ReceiveTokenEndpointDefinition contributes error("Receiving target token must not be an NTA token!") EndpointDefinition contributes error("Receiving target token must not be an NTA token!")
    when getToken().getNTA() when !getSend() && getEndpointTarget().isTokenEndpointTarget() && token().getNTA()
    to RagConnect.errors(); to RagConnect.errors();
    // if first mapping is null, then suitableDefaultMapping() == null // if first mapping is null, then suitableDefaultMapping() == null
    ReceiveTokenEndpointDefinition contributes error("No suitable default mapping found for type " + EndpointDefinition contributes error("No suitable default mapping found for type " +
    ((getMappingList().isEmpty()) ((getMappingList().isEmpty())
    ? getToken().effectiveJavaTypeUse().prettyPrint() ? token().effectiveJavaTypeUse().prettyPrint()
    : getMappingList().get(0).getFromType().prettyPrint())) : getMappingList().get(0).getFromType().prettyPrint()))
    when effectiveMappings().get(0) == null when !getSend() && getEndpointTarget().isTokenEndpointTarget() && effectiveMappings().get(0) == null
    to RagConnect.errors(); to RagConnect.errors();
    ReceiveTokenEndpointDefinition contributes error("to-type of last mapping (" + effectiveMappings().get(effectiveMappings().size() - 1).getToType().prettyPrint() + ") not assignable to type of the Token (" + getToken().effectiveJavaTypeUse().prettyPrint() + ")!") EndpointDefinition contributes error("to-type of last mapping (" +
    when !effectiveMappings().get(effectiveMappings().size() - 1).getToType().assignableTo( effectiveMappings().get(effectiveMappings().size() - 1).getToType().prettyPrint() +
    getToken().effectiveJavaTypeUse()) ") not assignable to type of the token (" + token().effectiveJavaTypeUse().prettyPrint() + ")!")
    to RagConnect.errors(); when !getSend() && getEndpointTarget().isTokenEndpointTarget() &&
    !effectiveMappings().get(effectiveMappings().size() - 1).getToType().assignableTo(
    SendTokenEndpointDefinition contributes error("Send definition already defined for " + getToken().getName()) token().effectiveJavaTypeUse())
    when isAlreadyDefined()
    to RagConnect.errors(); to RagConnect.errors();
    DependencyDefinition contributes error("Dependency definition already defined for " + getSource().containingTypeDecl().getName() + " with name " + getID()) DependencyDefinition contributes error("Dependency definition already defined for " + getSource().containingTypeDecl().getName() + " with name " + getID())
    ...@@ -46,7 +45,6 @@ aspect ErrorHelpers { ...@@ -46,7 +45,6 @@ aspect ErrorHelpers {
    } }
    return false; return false;
    } }
    syn String TokenComponent.parentTypeDeclAndName() = containingTypeDecl().getName() + "." + getName();
    } }
    aspect ErrorMessage { aspect ErrorMessage {
    ...@@ -68,12 +66,15 @@ aspect ErrorMessage { ...@@ -68,12 +66,15 @@ aspect ErrorMessage {
    public ASTNode getNode() { public ASTNode getNode() {
    return node; return node;
    } }
    public int getLine() { public int getLine() {
    return line; return line;
    } }
    public int getCol() { public int getCol() {
    return col; return col;
    } }
    public String getMessage() { public String getMessage() {
    return message; return message;
    } }
    ......
    aspect RagConnectHandlers {
    syn Handler RagConnect.mqttHandler() = resolveHandlerByName("mqtt");
    syn Handler RagConnect.restHandler() = resolveHandlerByName("rest");
    private Handler RagConnect.resolveHandlerByName(String uniqueName) {
    for (Handler handler : getHandlerList()) {
    if (uniqueName.equals(handler.getUniqueName())) {
    return handler;
    }
    }
    System.err.println("Could not find handler with name '" + uniqueName + "'");
    return null;
    }
    }
    /*
    Design considerations
    - InnerMappingDefinition needed for iteration attribute (first, last) - not possible with list-relation
    - no complete intermediate structure, but instead single nodes where applicable/needed
    */
    aspect SharedMustache {
    // === RagConnect ===
    syn boolean RagConnect.configIncrementalOptionActive() = getConfiguration().getIncrementalOptionActive();
    syn boolean RagConnect.configLoggingEnabledForIncremental() = getConfiguration().getLoggingEnabledForIncremental();
    syn boolean RagConnect.configExperimentalJastAdd329() = getConfiguration().getExperimentalJastAdd329();
    syn String RagConnect.rootNodeName() = getConfiguration().getRootNode().getName();
    // === EndpointDefinition ===
    syn String EndpointDefinition.lastResult() = lastDefinition().outputVarName();
    }
    aspect MustacheDependencyDefinition {
    // === DependencyDefinition ===
    syn String DependencyDefinition.dependencyMethodName() = "add" + capitalize(getID());
    syn String DependencyDefinition.internalRelationPrefix() = "_internal_" + getID();
    syn String DependencyDefinition.sourceParentTypeName() = getSource().containingTypeDecl().getName();
    syn String DependencyDefinition.targetParentTypeName() = getTarget().containingTypeDecl().getName();
    }
    aspect MustacheHandler {
    // === RagConnect ===
    syn String RagConnect.closeMethodName() = "ragconnectCloseConnections";
    syn boolean RagConnect.hasRootTypeComponents() = !rootTypeComponents().isEmpty();
    syn List<TypeComponent> RagConnect.rootTypeComponents() {
    List<TypeComponent> result = new ArrayList<>();
    for (Component child : rootNode().getComponentList()) {
    if (child.isTypeComponent()) {
    result.add(child.asTypeComponent());
    }
    }
    return result;
    }
    // === Handler ===
    syn String Handler.attributeName() = "_" + getUniqueName() + "Handler";
    syn String Handler.constructionSnippet() = "new " + getClassName() + "(\"Handler for " + ragconnect().rootNodeName() + ".\" + this.hashCode())";
    syn String Handler.fieldName() = "_" + getUniqueName() + "Handler";
    syn String Handler.setupWaitUntilReadyMethodName() = "ragconnectSetup" + capitalize(getUniqueName()) + "WaitUntilReady";
    }
    aspect MustacheHandleUri { /* empty */ }
    aspect MustacheListAspect {
    // === RagConnect ===
    syn String RagConnect.configJastAddList() = getConfiguration().getJastAddList();
    syn boolean RagConnect.hasTreeListEndpoints() {
    for (EndpointDefinition endpointDef : allEndpointDefinitionList()) {
    if (endpointDef.typeIsList()) {
    return true;
    }
    }
    return false;
    }
    syn Set<TypeDecl> RagConnect.typesForReceivingListEndpoints() {
    Set<TypeDecl> result = new HashSet<>();
    for (EndpointDefinition endpointDef : allEndpointDefinitionList()) {
    if (endpointDef.typeIsList() && !endpointDef.getSend()) {
    result.add(endpointDef.type().getTypeDecl());
    }
    }
    return result;
    }
    }
    aspect MustacheMappingApplicationAndDefinition {
    // === EndpointDefinition ===
    syn String EndpointDefinition.condition() {
    // TODO [OLD] probably, this has to be structured in a better way
    if (lastDefinition().getMappingDefinition().getToType().isArray()) {
    return "java.util.Arrays.equals(" + preemptiveExpectedValue() + ", " + lastResult() + ")";
    }
    if (getEndpointTarget().isTokenEndpointTarget() && token().isPrimitiveType() && lastDefinition().getMappingDefinition().getToType().isPrimitiveType()) {
    return preemptiveExpectedValue() + " == " + lastResult();
    }
    if (!getSend() && getEndpointTarget().isTypeEndpointTarget() && getWithAdd()) {
    // only check if received list is not null
    return lastResult() + " == null";
    }
    if (getEndpointTarget().isTypeEndpointTarget() && type().isOptComponent()) {
    // use "hasX()" instead of "getX() != null" for optionals
    return "has" + typeName() + "()" + " && " + preemptiveExpectedValue() + ".equals(" + lastResult() + ")";
    }
    if (lastDefinition().getMappingDefinition().getToType().isPrimitiveType() || lastDefinition().getMappingDefinition().isDefaultMappingDefinition()) {
    return preemptiveExpectedValue() + " != null && " + preemptiveExpectedValue() + ".equals(" + lastResult() + ")";
    }
    return preemptiveExpectedValue() + " != null ? " + preemptiveExpectedValue() + ".equals(" + lastResult() + ") : " + lastResult() + " == null";
    }
    syn JastAddList<MInnerMappingDefinition> EndpointDefinition.innerMappingDefinitions() = toMustache().getInnerMappingDefinitionList();
    syn String EndpointDefinition.lastDefinitionToType() = lastDefinition().toType();
    syn String EndpointDefinition.preemptiveReturn() = toMustache().preemptiveReturn();
    // === (MInner)MappingDefinition ===
    syn String MappingDefinition.fromType() = getFromType().prettyPrint();
    inh boolean MInnerMappingDefinition.isLast();
    eq MEndpointDefinition.getInnerMappingDefinition(int i).isLast() {
    return i == getNumInnerMappingDefinition() - 1;
    }
    inh String MInnerMappingDefinition.inputVarName();
    eq MEndpointDefinition.getInnerMappingDefinition(int i).inputVarName() {
    return i == 0
    ? firstInputVarName()
    : getInnerMappingDefinition(i - 1).outputVarName();
    }
    syn String MInnerMappingDefinition.methodName() = getMappingDefinition().methodName();
    syn String MappingDefinition.methodName() = "_apply_" + getID();
    syn String MInnerMappingDefinition.outputVarName() = "result" + methodName(); // we do not need "_" in between here, because methodName begins with one
    syn String MInnerMappingDefinition.toType() = getMappingDefinition().toType();
    syn String MappingDefinition.toType() = getToType().prettyPrint();
    // === attributes needed for computing above ones ===
    syn String EndpointDefinition.preemptiveExpectedValue() = toMustache().preemptiveExpectedValue();
    syn String EndpointDefinition.firstInputVarName() = toMustache().firstInputVarName();
    syn String MEndpointDefinition.preemptiveExpectedValue();
    syn String MEndpointDefinition.preemptiveReturn();
    syn String MEndpointDefinition.firstInputVarName();
    eq MTokenReceiveDefinition.firstInputVarName() = "message";
    eq MTokenReceiveDefinition.preemptiveExpectedValue() = getterMethodName() + "()";
    eq MTokenReceiveDefinition.preemptiveReturn() = "return;";
    eq MTokenSendDefinition.firstInputVarName() = getterMethodName() + "()";
    eq MTokenSendDefinition.preemptiveExpectedValue() = lastValue();
    eq MTokenSendDefinition.preemptiveReturn() = "return false;";
    eq MTypeReceiveDefinition.firstInputVarName() = "message";
    eq MTypeReceiveDefinition.preemptiveExpectedValue() = getterMethodName() + "()";
    eq MTypeReceiveDefinition.preemptiveReturn() = "return;";
    eq MTypeSendDefinition.firstInputVarName() = getterMethodName() + "()";
    eq MTypeSendDefinition.preemptiveExpectedValue() = lastValue();
    eq MTypeSendDefinition.preemptiveReturn() = "return false;";
    syn String MEndpointDefinition.parentTypeName() = getEndpointDefinition().parentTypeName();
    syn String MEndpointDefinition.getterMethodName() = getEndpointDefinition().getterMethodName();
    }
    aspect MustacheRagConnect {
    // === RagConnect ===
    syn List<DependencyDefinition> RagConnect.allDependencyDefinitionList() {
    List<DependencyDefinition> result = new ArrayList<>();
    for (ConnectSpecification spec : getConnectSpecificationFileList()) {
    spec.getDependencyDefinitionList().forEach(result::add);
    }
    return result;
    }
    syn List<EndpointDefinition> RagConnect.allEndpointDefinitionList() {
    List<EndpointDefinition> result = new ArrayList<>();
    for (ConnectSpecification spec : getConnectSpecificationFileList()) {
    spec.getEndpointDefinitionList().forEach(result::add);
    }
    return result;
    }
    // > allMappingDefinitions in Mappings.jrag
    syn List<TokenComponent> RagConnect.tokenComponentsThatNeedProxy() {
    List<TokenComponent> result = new ArrayList<>();
    for (TokenComponent token : getProgram().allTokenComponents()) {
    if (token.needProxyToken()) {
    result.add(token);
    }
    }
    return result;
    }
    // === MappingDefinition ===
    syn boolean MappingDefinition.isUsed() = !effectiveUsedAt().isEmpty();
    }
    aspect MustacheReceiveAndSendAndHandleUri {
    // === EndpointDefinition ===
    syn String EndpointDefinition.connectMethodName() = "connect" + entityName();
    syn String EndpointDefinition.connectParameterName() = "uriString";
    syn String EndpointDefinition.disconnectMethodName() {
    // if both (send and receive) are defined for an endpoint, ensure methods with different names
    String extra;
    if (getEndpointTarget().isTokenEndpointTarget()) {
    extra = lookupTokenEndpointDefinitions(token()).size() > 1 ? uniqueSuffix() : "";
    } else if (getEndpointTarget().isTypeEndpointTarget()) {
    extra = lookupTypeEndpointDefinitions(type()).size() > 1 ? uniqueSuffix() : "";
    } else {
    extra = "";
    }
    return "disconnect" + extra + entityName();
    }
    syn String EndpointDefinition.entityName() = getEndpointTarget().entityName();
    syn String EndpointDefinition.getterMethodName() = getEndpointTarget().getterMethodName();
    syn String EndpointDefinition.parentTypeName() = getEndpointTarget().parentTypeName();
    // === attributes needed for computing above ones ===
    syn String EndpointTarget.getterMethodName();
    syn String EndpointTarget.parentTypeName();
    syn String EndpointTarget.entityName();
    eq TokenEndpointTarget.getterMethodName() = "get" + getToken().getName();
    eq TokenEndpointTarget.parentTypeName() = getToken().containingTypeDecl().getName();
    eq TokenEndpointTarget.entityName() = getToken().getName();
    eq TypeEndpointTarget.getterMethodName() = "get" + getType().getName() + (typeIsList() ? "List" : "");
    eq TypeEndpointTarget.parentTypeName() = getType().containingTypeDecl().getName();
    eq TypeEndpointTarget.entityName() = getType().getName() + (typeIsList() && !containingEndpointDefinition().getIndexBasedListAccess() ? "List" : "");
    }
    aspect MustacheReceiveDefinition {
    // === RagConnect ===
    syn boolean RagConnect.configLoggingEnabledForReads() = getConfiguration().getLoggingEnabledForReads();
    // === EndpointDefinition ===
    syn boolean EndpointDefinition.hasTypeEndpointTarget() = getEndpointTarget().isTypeEndpointTarget();
    syn String EndpointDefinition.idTokenName() = "InternalRagconnectTopicInList";
    syn String EndpointDefinition.internalConnectMethodName() = "_internal_" + connectMethodName();
    syn String EndpointDefinition.resolveInListMethodName() = "_ragconnect_resolve" + entityName() + "InList";
    syn boolean EndpointDefinition.typeIsList() = getEndpointTarget().typeIsList();
    // === attributes needed for computing above ones ===
    syn boolean EndpointTarget.typeIsList() = false;
    eq TypeEndpointTarget.typeIsList() {
    return getType().isListComponent();
    }
    syn String EndpointDefinition.uniqueSuffix() = getSend() ? "Send" : "Receive";
    }
    aspect MustacheSendDefinition {
    // === RagConnect ===
    syn boolean RagConnect.configLoggingEnabledForWrites() = getConfiguration().getLoggingEnabledForWrites();
    // === EndpointDefinition ===
    syn String EndpointDefinition.lastValue() = senderName() + ".lastValue";
    syn String EndpointDefinition.senderName() = getEndpointTarget().senderName();
    syn boolean EndpointDefinition.shouldSendValue() = getSend() && getEndpointTarget().entityIsNormalAttribute();
    syn String EndpointDefinition.tokenResetMethodName() = getterMethodName() + "_reset";
    syn String EndpointDefinition.updateMethodName() = toMustache().updateMethodName();
    syn String EndpointDefinition.writeMethodName() = toMustache().writeMethodName();
    // === attributes needed for computing above ones ===
    syn String EndpointTarget.senderName();
    eq TokenEndpointTarget.senderName() = "_sender_" + getToken().getName();
    eq TypeEndpointTarget.senderName() = "_sender_" + getType().getName();
    syn String MEndpointDefinition.updateMethodName();
    syn String MEndpointDefinition.writeMethodName();
    // MTokenReceiveDefinition
    eq MTokenReceiveDefinition.updateMethodName() = null;
    eq MTokenReceiveDefinition.writeMethodName() = null;
    // MTokenSendDefinition
    eq MTokenSendDefinition.updateMethodName() = "_update_" + tokenName();
    eq MTokenSendDefinition.writeMethodName() = "_writeLastValue_" + tokenName();
    // MTypeReceiveDefinition
    eq MTypeReceiveDefinition.updateMethodName() = null;
    eq MTypeReceiveDefinition.writeMethodName() = null;
    // MTypeSendDefinition
    eq MTypeSendDefinition.updateMethodName() = "_update_" + typeName();
    eq MTypeSendDefinition.writeMethodName() = "_writeLastValue_" + typeName();
    syn String EndpointDefinition.tokenName() = token().getName();
    syn String MEndpointDefinition.tokenName() = getEndpointDefinition().tokenName();
    syn String EndpointDefinition.typeName() = type().getName();
    syn String MEndpointDefinition.typeName() = getEndpointDefinition().typeName();
    }
    aspect MustacheTokenComponent {
    // === TokenComponent ===
    syn String TokenComponent.internalName() = needProxyToken() ? "_internal_" + getName() : getName();
    syn String TokenComponent.javaType() = effectiveJavaTypeUse().prettyPrint();
    syn EndpointDefinition TokenComponent.normalTokenSendDef() {
    for (EndpointTarget target : getTokenEndpointTargetList()) {
    if (target.isTokenEndpointTarget() && target.containingEndpointDefinition().shouldSendValue()) {
    return target.containingEndpointDefinition();
    }
    }
    return null;
    }
    syn String TokenComponent.parentTypeName() = containingTypeDecl().getName();
    // > see MustacheDependencyDefinition for internalRelationPrefix, targetParentTypeName
    // === DependencyDefinition ===
    syn EndpointDefinition DependencyDefinition.targetEndpointDefinition() {
    // resolve definition in here, as we do not need resolveMethod in any other place (yet)
    for (EndpointDefinition endpointDefinition : ragconnect().allEndpointDefinitionList()) {
    if (!endpointDefinition.getSend()) {
    continue;
    }
    EndpointTarget endpointTarget = endpointDefinition.getEndpointTarget();
    if (endpointTarget.isTokenEndpointTarget() &&
    endpointTarget.asTokenEndpointTarget().getToken().equals(this.getTarget())) {
    return endpointDefinition;
    }
    if (endpointTarget.isTypeEndpointTarget() &&
    endpointTarget.asTypeEndpointTarget().getType().equals(this.getTarget())) {
    return endpointDefinition;
    }
    }
    return null;
    }
    // > see MustacheSend for updateMethodName, writeMethodName
    }
    aspect AttributesForMustache {
    syn String MEndpointDefinition.lastValue() = getEndpointDefinition().lastValue();
    // token and type are potentially dangerous because asXEndpointTarget can return null
    syn TokenComponent EndpointDefinition.token() = getEndpointTarget().asTokenEndpointTarget().getToken();
    syn TypeComponent EndpointDefinition.type() = getEndpointTarget().asTypeEndpointTarget().getType();
    syn MInnerMappingDefinition EndpointDefinition.lastDefinition() = toMustache().lastDefinition();
    syn MInnerMappingDefinition MEndpointDefinition.lastDefinition() = getInnerMappingDefinition(getNumInnerMappingDefinition() - 1);
    syn nta MEndpointDefinition EndpointDefinition.toMustache() {
    final MEndpointDefinition result;
    if (getEndpointTarget().isTokenEndpointTarget()) {
    if (getSend()) {
    result = new MTokenSendDefinition();
    } else {
    result = new MTokenReceiveDefinition();
    }
    } else if (getEndpointTarget().isTypeEndpointTarget()) {
    if (getSend()) {
    result = new MTypeSendDefinition();
    } else {
    result = new MTypeReceiveDefinition();
    }
    } else {
    throw new RuntimeException("Unknown endpoint target type: " + getEndpointTarget());
    }
    result.setEndpointDefinition(this);
    for (MappingDefinition def : effectiveMappings()) {
    MInnerMappingDefinition inner = new MInnerMappingDefinition();
    inner.setMappingDefinition(def);
    result.addInnerMappingDefinition(inner);
    }
    return result;
    }
    }
    aspect GrammarGeneration {
    syn java.util.List<Relation> RagConnect.additionalRelations() {
    java.util.List<Relation> result = new java.util.ArrayList<>();
    for (DependencyDefinition dd : allDependencyDefinitionList()) {
    result.add(dd.getRelationToCreate());
    }
    return result;
    }
    syn nta Relation DependencyDefinition.getRelationToCreate() {
    BidirectionalRelation result = new BidirectionalRelation();
    NavigableRole left = new ListRole(internalRelationPrefix() + "Source");
    left.setType(getTarget().containingTypeDecl());
    NavigableRole right = new ListRole(internalRelationPrefix() + "Target");
    right.setType(getSource().containingTypeDecl());
    result.setLeft(left);
    result.setRight(right);
    result.addComment(new WhitespaceComment("\n"));
    return result;
    }
    syn java.util.Map<TypeDecl, TokenComponent> RagConnect.additionalTokens() {
    java.util.Map<TypeDecl, TokenComponent> result = new java.util.HashMap<>();
    for (EndpointDefinition def : allEndpointDefinitionList()) {
    if (def.getTokenToCreate() != null) {
    result.put(def.type().getTypeDecl(), def.getTokenToCreate());
    }
    }
    return result;
    }
    syn TokenComponent EndpointDefinition.getTokenToCreate() {
    if (typeIsList() && getIndexBasedListAccess()) {
    TokenComponent result = new TokenComponent();
    result.setName(idTokenName());
    result.setNTA(false);
    result.setJavaTypeUse(new SimpleJavaTypeUse("String"));
    return result;
    } else {
    return null;
    }
    }
    }
    aspect GrammarExtension {
    refine BackendAbstractGrammar public void TokenComponent.generateAbstractGrammar(StringBuilder b) {
    if (getNTA()) {
    b.append("/");
    }
    b.append("<");
    if (!getName().equals("")) {
    b.append(internalName()).append(":");
    }
    effectiveJavaTypeUse().generateAbstractGrammar(b);
    b.append(">");
    if (getNTA()) {
    b.append("/");
    }
    }
    }
    abstract MEndpointDefinition ::= InnerMappingDefinition:MInnerMappingDefinition*;
    rel MEndpointDefinition.EndpointDefinition -> EndpointDefinition;
    abstract MTokenEndpointDefinition : MEndpointDefinition;
    MTokenReceiveDefinition : MTokenEndpointDefinition;
    MTokenSendDefinition : MTokenEndpointDefinition;
    abstract MTypeEndpointDefinition : MEndpointDefinition;
    MTypeReceiveDefinition : MTypeEndpointDefinition;
    MTypeSendDefinition : MTypeEndpointDefinition;
    MInnerMappingDefinition;
    rel MInnerMappingDefinition.MappingDefinition -> MappingDefinition;
    aspect IntermediateToYAML {
    syn Document RagConnect.toYAML() {
    Document doc = new Document();
    MappingElement root = new MappingElement();
    // grammar children
    ListElement handlersElement = new ListElement();
    for (Handler handler : getHandlerList()) {
    handlersElement.add(handler.toYAML());
    }
    root.put("Handlers" , handlersElement);
    // shared
    root.put("configIncrementalOptionActive" , configIncrementalOptionActive());
    root.put("configLoggingEnabledForIncremental" , configLoggingEnabledForIncremental());
    root.put("configExperimentalJastAdd329" , configExperimentalJastAdd329());
    root.put("rootNodeName" , rootNodeName());
    // handler
    root.put("closeMethodName" , closeMethodName());
    root.put("hasRootTypeComponents" , hasRootTypeComponents());
    ListElement rootTypeComponentsElement = new ListElement();
    for (TypeComponent comp : rootTypeComponents()) {
    rootTypeComponentsElement.addElement(comp.toYAML());
    }
    root.put("rootTypeComponents" , rootTypeComponentsElement);
    // listAspect
    root.put("configJastAddList" , configJastAddList());
    root.put("hasTreeListEndpoints" , hasTreeListEndpoints());
    ListElement typesForReceivingListEndpointsElement = new ListElement();
    for (TypeDecl typeDecl : typesForReceivingListEndpoints()) {
    typesForReceivingListEndpointsElement.addElement(typeDecl.toYAML());
    }
    root.put("typesForReceivingListEndpoints" , typesForReceivingListEndpointsElement);
    // ragconnect
    ListElement dependencyDefinitionsElement = new ListElement();
    for (DependencyDefinition def : allDependencyDefinitionList()) {
    dependencyDefinitionsElement.addElement(def.toYAML());
    }
    root.put("allDependencyDefinitionList" , dependencyDefinitionsElement);
    ListElement endpointDefinitionsElement = new ListElement();
    for (EndpointDefinition def : allEndpointDefinitionList()) {
    endpointDefinitionsElement.addElement(def.toYAML());
    }
    root.put("allEndpointDefinitionList" , endpointDefinitionsElement);
    ListElement mappingDefinitionsElement = new ListElement();
    for (MappingDefinition def : allMappingDefinitions()) {
    mappingDefinitionsElement.addElement(def.toYAML());
    }
    root.put("allMappingDefinitions" , mappingDefinitionsElement);
    ListElement tokenComponentsElement = new ListElement();
    for (TokenComponent comp : tokenComponentsThatNeedProxy()) {
    tokenComponentsElement.addElement(comp.toYAML());
    }
    root.put("tokenComponentsThatNeedProxy" , tokenComponentsElement);
    // receive
    root.put("configLoggingEnabledForReads" , configLoggingEnabledForReads());
    // send
    root.put("configLoggingEnabledForWrites" , configLoggingEnabledForWrites());
    // from Handlers.jrag
    root.put("mqttHandler" , mqttHandler().toYAML());
    root.put("restHandler" , restHandler().toYAML());
    doc.setRootElement(root);
    return doc;
    }
    syn MappingElement EndpointDefinition.toYAML() {
    MappingElement result = new MappingElement();
    // grammar children
    result.put("AlwaysApply" , getAlwaysApply());
    result.put("IndexBasedListAccess" , getIndexBasedListAccess());
    result.put("WithAdd" , getWithAdd());
    result.put("Send" , getSend());
    // shared
    result.put("lastResult" , lastResult());
    // mapping
    result.put("condition" , sanitizeValueForYAML(condition()));
    ListElement innerMappingDefinitions = new ListElement();
    for (MInnerMappingDefinition def : innerMappingDefinitions()) {
    innerMappingDefinitions.addElement(def.toYAML());
    }
    result.put("innerMappingDefinitions" , innerMappingDefinitions);
    result.put("lastDefinitionToType" , lastDefinitionToType());
    result.put("preemptiveReturn" , preemptiveReturn());
    // receive + send
    result.put("connectMethodName" , connectMethodName());
    result.put("connectParameterName" , connectParameterName());
    result.put("disconnectMethodName" , disconnectMethodName());
    result.put("entityName" , entityName());
    result.put("getterMethodName" , getterMethodName());
    result.put("parentTypeName" , parentTypeName());
    if (getSend()) {
    result.put("lastValue" , lastValue());
    result.put("senderName" , senderName());
    result.put("shouldSendValue" , shouldSendValue());
    result.put("tokenResetMethodName" , tokenResetMethodName());
    result.put("updateMethodName" , updateMethodName());
    result.put("writeMethodName" , writeMethodName());
    } else {
    result.put("hasTypeEndpointTarget" , hasTypeEndpointTarget());
    result.put("idTokenName" , idTokenName());
    result.put("internalConnectMethodName" , internalConnectMethodName());
    result.put("resolveInListMethodName" , resolveInListMethodName());
    result.put("typeIsList" , getEndpointTarget().typeIsList());
    }
    return result;
    }
    void UntypedEndpointTarget.addToYAML(MappingElement result) {
    // empty
    }
    syn Element MInnerMappingDefinition.toYAML() {
    MappingElement result = new MappingElement();
    result.put("last" , isLast());
    result.put("inputVarName" , inputVarName());
    result.put("methodName" , methodName());
    result.put("outputVarName" , outputVarName());
    result.put("toType" , toType());
    return result;
    }
    syn Element MappingDefinition.toYAML() {
    MappingElement result = new MappingElement();
    // grammar children
    result.put("FromVariableName" , getFromVariableName());
    result.put("Content" , sanitizeValueForYAML(getContent()));
    // mapping
    result.put("fromType" , fromType());
    result.put("methodName" , methodName());
    result.put("toType" , toType());
    // ragconnect
    result.put("isUsed" , isUsed());
    return result;
    }
    syn Element DependencyDefinition.toYAML() {
    MappingElement result = new MappingElement();
    // dependencyDefinition
    result.put("dependencyMethodName" , dependencyMethodName());
    result.put("internalRelationPrefix" , internalRelationPrefix());
    result.put("sourceParentTypeName" , sourceParentTypeName());
    result.put("targetParentTypeName" , targetParentTypeName());
    // tokenComponent
    result.put("targetEndpointDefinition" , targetEndpointDefinition().toYAML());
    return result;
    }
    syn Element TokenComponent.toYAML() {
    MappingElement result = new MappingElement();
    result.put("Name" , getName());
    ListElement dependencySourceDefinitions = new ListElement();
    for (DependencyDefinition def : getDependencySourceDefinitionList()) {
    dependencySourceDefinitions.add(def.toYAML());
    }
    result.put("DependencySourceDefinitions" , dependencySourceDefinitions);
    result.put("javaType" , javaType());
    result.put("normalTokenSendDef" , normalTokenSendDef().toYAML());
    result.put("parentTypeName" , parentTypeName());
    return result;
    }
    syn MappingElement Handler.toYAML() {
    MappingElement result = new MappingElement();
    result.put("ClassName" , getClassName());
    result.put("InUse" , getInUse());
    result.put("attributeName" , attributeName());
    result.put("constructionSnippet" , constructionSnippet());
    result.put("fieldName" , fieldName());
    result.put("setupWaitUntilReadyMethodName" , setupWaitUntilReadyMethodName());
    return result;
    }
    syn MappingElement TypeComponent.toYAML() {
    return new MappingElement().put("Name", getName());
    }
    syn MappingElement TypeDecl.toYAML() {
    return new MappingElement().put("Name", getName());
    }
    protected StringElement ASTNode.sanitizeValueForYAML(String value) {
    return StringElement.of(value.replace("\"" , "\\\"").replace("\n" , "\\n"));
    }
    }
    aspect Navigation {
    eq Document.getChild().program() = null;
    eq Document.getChild().ragconnect() = null;
    eq Document.getChild().containedFile() = null;
    eq Document.containedFileName() = getFileName();
    }
    ...@@ -68,18 +68,18 @@ aspect DefaultMappings { ...@@ -68,18 +68,18 @@ aspect DefaultMappings {
    } }
    syn nta DefaultMappingDefinition RagConnect.defaultBytesToListTreeMapping(String typeName) { syn nta DefaultMappingDefinition RagConnect.defaultBytesToListTreeMapping(String typeName) {
    return treeDefaultMappingDefinition("byte[]", JastAddList + "<" + typeName + ">", return treeDefaultMappingDefinition("byte[]", configJastAddList() + "<" + typeName + ">",
    "String content = new String(input);\n" + "String content = new String(input);\n" +
    "com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();\n" + "com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();\n" +
    "com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();\n" + "com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();\n" +
    "com.fasterxml.jackson.core.JsonParser parser = factory.createParser(content);\n" + "com.fasterxml.jackson.core.JsonParser parser = factory.createParser(content);\n" +
    JastAddList + "<" + typeName + ">" + " result = " + typeName + ".deserializeList((com.fasterxml.jackson.databind.node.ArrayNode)mapper.readTree(parser));\n" + configJastAddList() + "<" + typeName + ">" + " result = " + typeName + ".deserializeList((com.fasterxml.jackson.databind.node.ArrayNode)mapper.readTree(parser));\n" +
    "parser.close();\n" + "parser.close();\n" +
    "return result;" "return result;"
    ); );
    } }
    syn nta DefaultMappingDefinition RagConnect.defaultListTreeToBytesMapping() { syn nta DefaultMappingDefinition RagConnect.defaultListTreeToBytesMapping() {
    return treeDefaultMappingDefinition(JastAddList, "byte[]", return treeDefaultMappingDefinition(configJastAddList(), "byte[]",
    "java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();\n" + "java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();\n" +
    "com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();\n" + "com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();\n" +
    "com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(outputStream, com.fasterxml.jackson.core.JsonEncoding.UTF8);\n" + "com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(outputStream, com.fasterxml.jackson.core.JsonEncoding.UTF8);\n" +
    ...@@ -141,7 +141,7 @@ aspect Mappings { ...@@ -141,7 +141,7 @@ aspect Mappings {
    // --- effectiveMappings --- // --- effectiveMappings ---
    syn java.util.List<MappingDefinition> EndpointDefinition.effectiveMappings() { syn java.util.List<MappingDefinition> EndpointDefinition.effectiveMappings() {
    java.util.List<MappingDefinition> result; java.util.List<MappingDefinition> result;
    if (isReceiveTokenEndpointDefinition() || isReceiveTypeEndpointDefinition()) { if (!getSend()) {
    // if no mappings are specified, or if first mapping is not suitable. // if no mappings are specified, or if first mapping is not suitable.
    // then prepend the suitable default mapping // then prepend the suitable default mapping
    if (getMappingList().isEmpty() || !getMappingList().get(0).getFromType().isByteArray()) { if (getMappingList().isEmpty() || !getMappingList().get(0).getFromType().isByteArray()) {
    ...@@ -151,7 +151,7 @@ aspect Mappings { ...@@ -151,7 +151,7 @@ aspect Mappings {
    } else { } else {
    result = getMappingList(); result = getMappingList();
    } }
    } else if (isSendTokenEndpointDefinition() || isSendTypeEndpointDefinition()) { } else {
    // if no mappings are specified, or if last mapping is not suitable // if no mappings are specified, or if last mapping is not suitable
    // then append the suitable default mapping // then append the suitable default mapping
    if (getMappingList().isEmpty() || !getMappingList().get(getMappingList().size() - 1).getToType().isByteArray()) { if (getMappingList().isEmpty() || !getMappingList().get(getMappingList().size() - 1).getToType().isByteArray()) {
    ...@@ -160,8 +160,6 @@ aspect Mappings { ...@@ -160,8 +160,6 @@ aspect Mappings {
    } else { } else {
    result = getMappingList(); result = getMappingList();
    } }
    } else {
    throw new RuntimeException("Unknown endpoint definition: " + this);
    } }
    return result; return result;
    } }
    ...@@ -178,8 +176,10 @@ aspect Mappings { ...@@ -178,8 +176,10 @@ aspect Mappings {
    case "float": case "float":
    case "double": case "double":
    case "char": case "char":
    case "byte": return true; case "byte":
    default: return false; return true;
    default:
    return false;
    } }
    } }
    syn boolean MappingDefinitionType.isPrimitiveType() = false; syn boolean MappingDefinitionType.isPrimitiveType() = false;
    ...@@ -191,98 +191,109 @@ aspect Mappings { ...@@ -191,98 +191,109 @@ aspect Mappings {
    // --- suitableReceiveDefaultMapping --- // --- suitableReceiveDefaultMapping ---
    syn DefaultMappingDefinition EndpointDefinition.suitableReceiveDefaultMapping() { syn DefaultMappingDefinition EndpointDefinition.suitableReceiveDefaultMapping() {
    if (getEndpointTarget().isTypeEndpointTarget()) {
    try {
    TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName());
    return typeIsList() && !getIndexBasedListAccess() ? ragconnect().defaultBytesToListTreeMapping(typeDecl.getName()) : ragconnect().defaultBytesToTreeMapping(typeDecl.getName());
    } catch (Exception ignore) {
    }
    }
    switch (targetTypeName()) { switch (targetTypeName()) {
    case "boolean": case "boolean":
    case "Boolean": return ragconnect().defaultBytesToBooleanMapping(); case "Boolean":
    return ragconnect().defaultBytesToBooleanMapping();
    case "int": case "int":
    case "Integer": return ragconnect().defaultBytesToIntMapping(); case "Integer":
    return ragconnect().defaultBytesToIntMapping();
    case "short": case "short":
    case "Short": return ragconnect().defaultBytesToShortMapping(); case "Short":
    return ragconnect().defaultBytesToShortMapping();
    case "long": case "long":
    case "Long": return ragconnect().defaultBytesToLongMapping(); case "Long":
    return ragconnect().defaultBytesToLongMapping();
    case "float": case "float":
    case "Float": return ragconnect().defaultBytesToFloatMapping(); case "Float":
    return ragconnect().defaultBytesToFloatMapping();
    case "double": case "double":
    case "Double": return ragconnect().defaultBytesToDoubleMapping(); case "Double":
    return ragconnect().defaultBytesToDoubleMapping();
    case "char": case "char":
    case "Character": return ragconnect().defaultBytesToCharMapping(); case "Character":
    case "String": return ragconnect().defaultBytesToStringMapping(); return ragconnect().defaultBytesToCharMapping();
    case "String":
    return ragconnect().defaultBytesToStringMapping();
    default: default:
    try { try {
    TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName()); TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName());
    // TODO: also support list-types, if list is first type // TODO: also support list-types, if list is first type
    return ragconnect().defaultBytesToTreeMapping(typeDecl.getName()); return ragconnect().defaultBytesToTreeMapping(typeDecl.getName());
    } catch (Exception ignore) {} } catch (Exception ignore) {
    }
    System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this); System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this);
    return null; return null;
    } }
    } }
    eq TypeEndpointDefinition.suitableReceiveDefaultMapping() {
    try {
    TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName());
    return typeIsList() && !getIndexBasedListAccess() ? ragconnect().defaultBytesToListTreeMapping(typeDecl.getName()) : ragconnect().defaultBytesToTreeMapping(typeDecl.getName());
    } catch (Exception ignore) {}
    return super.suitableReceiveDefaultMapping();
    }
    // --- suitableSendDefaultMapping --- // --- suitableSendDefaultMapping ---
    syn DefaultMappingDefinition EndpointDefinition.suitableSendDefaultMapping() { syn DefaultMappingDefinition EndpointDefinition.suitableSendDefaultMapping() {
    if (getEndpointTarget().isTypeEndpointTarget()) {
    try {
    TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName());
    return typeIsList() && !getIndexBasedListAccess() ? ragconnect().defaultListTreeToBytesMapping() : ragconnect().defaultTreeToBytesMapping(typeDecl.getName());
    } catch (Exception ignore) {
    }
    }
    switch (targetTypeName()) { switch (targetTypeName()) {
    case "boolean": case "boolean":
    case "Boolean": return ragconnect().defaultBooleanToBytesMapping(); case "Boolean":
    return ragconnect().defaultBooleanToBytesMapping();
    case "int": case "int":
    case "Integer": return ragconnect().defaultIntToBytesMapping(); case "Integer":
    return ragconnect().defaultIntToBytesMapping();
    case "short": case "short":
    case "Short": return ragconnect().defaultShortToBytesMapping(); case "Short":
    return ragconnect().defaultShortToBytesMapping();
    case "long": case "long":
    case "Long": return ragconnect().defaultLongToBytesMapping(); case "Long":
    return ragconnect().defaultLongToBytesMapping();
    case "float": case "float":
    case "Float": return ragconnect().defaultFloatToBytesMapping(); case "Float":
    return ragconnect().defaultFloatToBytesMapping();
    case "double": case "double":
    case "Double": return ragconnect().defaultDoubleToBytesMapping(); case "Double":
    return ragconnect().defaultDoubleToBytesMapping();
    case "char": case "char":
    case "Character": return ragconnect().defaultCharToBytesMapping(); case "Character":
    case "String": return ragconnect().defaultStringToBytesMapping(); return ragconnect().defaultCharToBytesMapping();
    case "String":
    return ragconnect().defaultStringToBytesMapping();
    default: default:
    try { try {
    TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName()); TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName());
    // TODO: also support list-types, if list is last type // TODO: also support list-types, if list is last type
    return ragconnect().defaultTreeToBytesMapping(typeDecl.getName()); return ragconnect().defaultTreeToBytesMapping(typeDecl.getName());
    } catch (Exception ignore) {} } catch (Exception ignore) {
    }
    System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this); System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this);
    return null; return null;
    } }
    } }
    eq TypeEndpointDefinition.suitableSendDefaultMapping() {
    try {
    TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName());
    return typeIsList() && !getIndexBasedListAccess() ? ragconnect().defaultListTreeToBytesMapping() : ragconnect().defaultTreeToBytesMapping(typeDecl.getName());
    } catch (Exception ignore) {}
    return super.suitableSendDefaultMapping();
    }
    // --- targetTypeName --- // --- targetTypeName ---
    syn String EndpointDefinition.targetTypeName(); syn String EndpointDefinition.targetTypeName() {
    eq ReceiveTokenEndpointDefinition.targetTypeName() { if (getMappingList().isEmpty()) {
    return getMappingList().isEmpty() ? return getEndpointTarget().targetTypeName();
    getToken().effectiveJavaTypeUse().getName() : } else {
    getMappingList().get(0).getFromType().prettyPrint(); if (getSend()) {
    } return getMappingList().get(getMappingList().size() - 1).getToType().prettyPrint();
    eq ReceiveTypeEndpointDefinition.targetTypeName() { } else {
    return getMappingList().isEmpty() ? return getMappingList().get(0).getFromType().prettyPrint();
    getType().getTypeDecl().getName() : }
    getMappingList().get(0).getFromType().prettyPrint(); }
    }
    eq SendTokenEndpointDefinition.targetTypeName() {
    return getMappingList().isEmpty() ?
    getToken().effectiveJavaTypeUse().getName() :
    getMappingList().get(getMappingList().size() - 1).getToType().prettyPrint();
    }
    eq SendTypeEndpointDefinition.targetTypeName() {
    return getMappingList().isEmpty() ?
    getType().getTypeDecl().getName() :
    getMappingList().get(getMappingList().size() - 1).getToType().prettyPrint();
    } }
    syn String EndpointTarget.targetTypeName();
    eq TokenEndpointTarget.targetTypeName() = getToken().effectiveJavaTypeUse().getName();
    eq TypeEndpointTarget.targetTypeName() = getType().getTypeDecl().getName();
    // eq ReceiveFromRestDefinition.suitableDefaultMapping() { // eq ReceiveFromRestDefinition.suitableDefaultMapping() {
    // String typeName = getMappingList().isEmpty() ? // String typeName = getMappingList().isEmpty() ?
    ...@@ -337,7 +348,7 @@ aspect Mappings { ...@@ -337,7 +348,7 @@ aspect Mappings {
    syn java.util.List<MappingDefinition> RagConnect.allMappingDefinitions() { syn java.util.List<MappingDefinition> RagConnect.allMappingDefinitions() {
    java.util.List<MappingDefinition> result = new java.util.ArrayList<>(); java.util.List<MappingDefinition> result = new java.util.ArrayList<>();
    // user-defined mappings // user-defined mappings
    allMappingDefinitionList().iterator().forEachRemaining(result::add); givenMappingDefinitionList().iterator().forEachRemaining(result::add);
    // byte[] <-> primitive conversion // byte[] <-> primitive conversion
    result.add(defaultBytesToBooleanMapping()); result.add(defaultBytesToBooleanMapping());
    result.add(defaultBytesToIntMapping()); result.add(defaultBytesToIntMapping());
    ......
    aspect RagConnectNameResolution { aspect RagConnectNameResolution {
    // --- lookupTokenEndpointDefinition ---
    inh java.util.List<EndpointDefinition> EndpointDefinition.lookupTokenEndpointDefinitions(TokenComponent token);
    inh java.util.List<EndpointDefinition> EndpointTarget.lookupTokenEndpointDefinitions(TokenComponent token);
    eq RagConnect.getConnectSpecificationFile().lookupTokenEndpointDefinitions(TokenComponent token) = lookupTokenEndpointDefinitions(token);
    syn java.util.List<EndpointDefinition> RagConnect.lookupTokenEndpointDefinitions(TokenComponent token) {
    java.util.List<EndpointDefinition> result = new java.util.ArrayList<>();
    for (EndpointTarget target : allEndpointTargetList()) {
    if (target.isTokenEndpointTarget() && target.asTokenEndpointTarget().getToken().equals(token)) {
    result.add(target.containingEndpointDefinition());
    }
    }
    return result;
    }
    // --- lookupTypeEndpointDefinition ---
    inh java.util.List<EndpointDefinition> EndpointDefinition.lookupTypeEndpointDefinitions(TypeComponent type);
    inh java.util.List<EndpointDefinition> EndpointTarget.lookupTypeEndpointDefinitions(TypeComponent type);
    eq RagConnect.getConnectSpecificationFile().lookupTypeEndpointDefinitions(TypeComponent type) = lookupTypeEndpointDefinitions(type);
    syn java.util.List<EndpointDefinition> RagConnect.lookupTypeEndpointDefinitions(TypeComponent type) {
    java.util.List<EndpointDefinition> result = new java.util.ArrayList<>();
    for (EndpointTarget target : allEndpointTargetList()) {
    if (target.isTypeEndpointTarget() && target.asTypeEndpointTarget().getType().equals(type)) {
    result.add(target.containingEndpointDefinition());
    }
    }
    return result;
    }
    // --- lookupDependencyDefinition ---
    inh DependencyDefinition DependencyDefinition.lookupDependencyDefinition(TypeDecl source, String id);
    eq RagConnect.getConnectSpecificationFile().lookupDependencyDefinition(TypeDecl source, String id) {
    for (DependencyDefinition def : allDependencyDefinitionList()) {
    if (def.getID().equals(id) && def.getSource().containingTypeDecl().equals(source)) {
    return def;
    }
    }
    return null;
    }
    // rel EndpointDefinition.Mapping* -> MappingDefinition // rel EndpointDefinition.Mapping* -> MappingDefinition
    refine RefResolverStubs eq EndpointDefinition.resolveMappingByToken(String id, int position) { refine RefResolverStubs eq EndpointDefinition.resolveMappingByToken(String id, int position) {
    ...@@ -9,7 +47,7 @@ aspect RagConnectNameResolution { ...@@ -9,7 +47,7 @@ aspect RagConnectNameResolution {
    return result; return result;
    } }
    syn MappingDefinition EndpointDefinition.tryResolveMappingByToken(String id) { syn MappingDefinition EndpointDefinition.tryResolveMappingByToken(String id) {
    for (MappingDefinition mappingDefinition : ragconnect().allMappingDefinitionList()) { for (MappingDefinition mappingDefinition : ragconnect().givenMappingDefinitionList()) {
    if (mappingDefinition.getID().equals(id)) { if (mappingDefinition.getID().equals(id)) {
    return mappingDefinition; return mappingDefinition;
    } }
    ...@@ -64,7 +102,7 @@ aspect RagConnectNameResolution { ...@@ -64,7 +102,7 @@ aspect RagConnectNameResolution {
    } }
    // rel ___ -> TokenComponent (from relast-preprocessor) // rel ___ -> TokenComponent (from relast-preprocessor)
    // refine here to have an attribute without writing on stderr if not found // refine from relast PP here to have an attribute that does not write on stderr if no TokenComponent was found
    refine NameResolution eq ASTNode.globallyResolveTokenComponentByToken(String id) { refine NameResolution eq ASTNode.globallyResolveTokenComponentByToken(String id) {
    TokenComponent result = tryGloballyResolveTokenComponentByToken(id); TokenComponent result = tryGloballyResolveTokenComponentByToken(id);
    if (result == null) { if (result == null) {
    ......
    aspect NewStuff {
    /** Tests if EndpointTarget is a TokenEndpointTarget.
    * @return 'true' if this is a TokenEndpointTarget, otherwise 'false'
    */
    syn boolean EndpointTarget.isTokenEndpointTarget() = false;
    eq TokenEndpointTarget.isTokenEndpointTarget() = true;
    /** Tests if EndpointTarget is a TypeEndpointTarget.
    * @return 'true' if this is a TypeEndpointTarget, otherwise 'false'
    */
    syn boolean EndpointTarget.isTypeEndpointTarget() = false;
    eq TypeEndpointTarget.isTypeEndpointTarget() = true;
    /** Tests if EndpointTarget is a UntypedEndpointTarget.
    * @return 'true' if this is a UntypedEndpointTarget, otherwise 'false'
    */
    syn boolean EndpointTarget.isUntypedEndpointTarget() = false;
    eq UntypedEndpointTarget.isUntypedEndpointTarget() = true;
    /** casts a EndpointTarget into a TokenEndpointTarget if possible.
    * @return 'this' cast to a TokenEndpointTarget or 'null'
    */
    syn TokenEndpointTarget EndpointTarget.asTokenEndpointTarget();
    eq EndpointTarget.asTokenEndpointTarget() = null;
    eq TokenEndpointTarget.asTokenEndpointTarget() = this;
    /** casts a EndpointTarget into a TypeEndpointTarget if possible.
    * @return 'this' cast to a TypeEndpointTarget or 'null'
    */
    syn TypeEndpointTarget EndpointTarget.asTypeEndpointTarget();
    eq EndpointTarget.asTypeEndpointTarget() = null;
    eq TypeEndpointTarget.asTypeEndpointTarget() = this;
    /** casts a EndpointTarget into a UntypedEndpointTarget if possible.
    * @return 'this' cast to a UntypedEndpointTarget or 'null'
    */
    syn UntypedEndpointTarget EndpointTarget.asUntypedEndpointTarget();
    eq EndpointTarget.asUntypedEndpointTarget() = null;
    eq UntypedEndpointTarget.asUntypedEndpointTarget() = this;
    }
    aspect RagConnectNavigation { aspect RagConnectNavigation {
    // --- program --- // --- program ---
    eq RagConnect.getChild().program() = getProgram(); eq RagConnect.getChild().program() = getProgram();
    eq MRagConnect.getChild().program() = getRagConnect().program();
    // --- ragconnect --- // --- ragconnect ---
    inh RagConnect ASTNode.ragconnect(); inh RagConnect ASTNode.ragconnect();
    eq RagConnect.getChild().ragconnect() = this; eq RagConnect.getChild().ragconnect() = this;
    eq MRagConnect.getChild().ragconnect() = getRagConnect();
    // --- containedConnectSpecification --- // --- containedConnectSpecification ---
    inh ConnectSpecification ASTNode.containedConnectSpecification(); inh ConnectSpecification ASTNode.containedConnectSpecification();
    eq RagConnect.getChild().containedConnectSpecification() = null; eq RagConnect.getChild().containedConnectSpecification() = null;
    eq MRagConnect.getChild().containedConnectSpecification() = null;
    eq Document.getChild().containedConnectSpecification() = null; eq Document.getChild().containedConnectSpecification() = null;
    eq Program.getChild().containedConnectSpecification() = null; eq Program.getChild().containedConnectSpecification() = null;
    eq ConnectSpecification.getChild().containedConnectSpecification() = this; eq ConnectSpecification.getChild().containedConnectSpecification() = this;
    // --- containingEndpointDefinition ---
    inh EndpointDefinition EndpointTarget.containingEndpointDefinition();
    eq EndpointDefinition.getEndpointTarget().containingEndpointDefinition() = this;
    // --- containedFile // --- containedFile
    eq RagConnect.getChild().containedFile() = null; eq RagConnect.getChild().containedFile() = null;
    eq MRagConnect.getChild().containedFile() = null;
    // --- containedFileName --- // --- containedFileName ---
    eq ConnectSpecificationFile.containedFileName() = getFileName(); eq ConnectSpecificationFile.containedFileName() = getFileName();
    ...@@ -31,97 +72,26 @@ aspect RagConnectNavigation { ...@@ -31,97 +72,26 @@ aspect RagConnectNavigation {
    // return containedFile().getFileName(); // return containedFile().getFileName();
    } }
    //--- allEndpointDefinitionList ---
    syn List<EndpointDefinition> RagConnect.allEndpointDefinitionList() {
    List<EndpointDefinition> result = new ArrayList<>();
    for (var spec : getConnectSpecificationFileList()) {
    spec.getEndpointDefinitionList().forEach(result::add);
    }
    return result;
    }
    //--- allDependencyDefinitionList --- //--- allEndpointTargetList ---
    syn List<DependencyDefinition> RagConnect.allDependencyDefinitionList() { syn List<EndpointTarget> RagConnect.allEndpointTargetList() {
    List<DependencyDefinition> result = new ArrayList<>(); List<EndpointTarget> result = new ArrayList<>();
    for (var spec : getConnectSpecificationFileList()) { for (ConnectSpecification spec : getConnectSpecificationFileList()) {
    spec.getDependencyDefinitionList().forEach(result::add); spec.getEndpointDefinitionList().forEach(endpointDef -> result.add(endpointDef.getEndpointTarget()));
    } }
    return result; return result;
    } }
    //--- allMappingDefinitionList ---
    syn List<MappingDefinition> RagConnect.allMappingDefinitionList() { //--- givenMappingDefinitionList ---
    syn List<MappingDefinition> RagConnect.givenMappingDefinitionList() {
    List<MappingDefinition> result = new ArrayList<>(); List<MappingDefinition> result = new ArrayList<>();
    for (var spec : getConnectSpecificationFileList()) { for (ConnectSpecification spec : getConnectSpecificationFileList()) {
    spec.getMappingDefinitionList().forEach(result::add); spec.getMappingDefinitionList().forEach(result::add);
    } }
    return result; return result;
    } }
    // --- isTokenEndpointDefinition ---
    syn boolean EndpointDefinition.isTokenEndpointDefinition() = false;
    eq TokenEndpointDefinition.isTokenEndpointDefinition() = true;
    // --- asTokenEndpointDefinition ---
    syn TokenEndpointDefinition EndpointDefinition.asTokenEndpointDefinition() = null;
    eq TokenEndpointDefinition.asTokenEndpointDefinition() = this;
    // --- isTypeEndpointDefinition ---
    syn boolean EndpointDefinition.isTypeEndpointDefinition() = false;
    eq TypeEndpointDefinition.isTypeEndpointDefinition() = true;
    // --- asTypeEndpointDefinition ---
    syn TypeEndpointDefinition EndpointDefinition.asTypeEndpointDefinition() = null;
    eq TypeEndpointDefinition.asTypeEndpointDefinition() = this;
    // --- isReceiveTokenEndpointDefinition ---
    syn boolean EndpointDefinition.isReceiveTokenEndpointDefinition() = false;
    eq ReceiveTokenEndpointDefinition.isReceiveTokenEndpointDefinition() = true;
    // --- asReceiveTokenEndpointDefinition ---
    syn ReceiveTokenEndpointDefinition EndpointDefinition.asReceiveTokenEndpointDefinition() = null;
    eq ReceiveTokenEndpointDefinition.asReceiveTokenEndpointDefinition() = this;
    // --- isSendTokenEndpointDefinition ---
    syn boolean EndpointDefinition.isSendTokenEndpointDefinition() = false;
    eq SendTokenEndpointDefinition.isSendTokenEndpointDefinition() = true;
    // --- asSendTokenEndpointDefinition ---
    syn SendTokenEndpointDefinition EndpointDefinition.asSendTokenEndpointDefinition() = null;
    eq SendTokenEndpointDefinition.asSendTokenEndpointDefinition() = this;
    // --- isReceiveTypeEndpointDefinition ---
    syn boolean EndpointDefinition.isReceiveTypeEndpointDefinition() = false;
    eq ReceiveTypeEndpointDefinition.isReceiveTypeEndpointDefinition() = true;
    // --- asReceiveTypeEndpointDefinition ---
    syn ReceiveTypeEndpointDefinition EndpointDefinition.asReceiveTypeEndpointDefinition() = null;
    eq ReceiveTypeEndpointDefinition.asReceiveTypeEndpointDefinition() = this;
    // --- isSendTypeEndpointDefinition ---
    syn boolean EndpointDefinition.isSendTypeEndpointDefinition() = false;
    eq SendTypeEndpointDefinition.isSendTypeEndpointDefinition() = true;
    // --- asSendTypeEndpointDefinition ---
    syn SendTypeEndpointDefinition EndpointDefinition.asSendTypeEndpointDefinition() = null;
    eq SendTypeEndpointDefinition.asSendTypeEndpointDefinition() = this;
    // --- targetEndpointDefinition ---
    syn EndpointDefinition DependencyDefinition.targetEndpointDefinition() {
    // resolve definition in here, as we do not need resolveMethod in any other place (yet)
    for (EndpointDefinition endpointDefinition : ragconnect().allEndpointDefinitionList()) {
    if (endpointDefinition.isSendTokenEndpointDefinition() &&
    endpointDefinition.asSendTokenEndpointDefinition().getToken().equals(this.getTarget())) {
    return endpointDefinition;
    }
    if (endpointDefinition.isSendTypeEndpointDefinition() &&
    endpointDefinition.asSendTypeEndpointDefinition().getType().equals(this.getTarget())) {
    return endpointDefinition;
    }
    }
    return null;
    }
    // --- effectiveJavaTypeUse (should be in preprocessor) --- // --- effectiveJavaTypeUse (should be in preprocessor) ---
    syn lazy JavaTypeUse TokenComponent.effectiveJavaTypeUse() = hasJavaTypeUse() ? getJavaTypeUse() : new SimpleJavaTypeUse("String"); syn lazy JavaTypeUse TokenComponent.effectiveJavaTypeUse() = hasJavaTypeUse() ? getJavaTypeUse() : new SimpleJavaTypeUse("String");
    ...@@ -129,13 +99,6 @@ aspect RagConnectNavigation { ...@@ -129,13 +99,6 @@ aspect RagConnectNavigation {
    syn boolean MappingDefinition.isDefaultMappingDefinition() = false; syn boolean MappingDefinition.isDefaultMappingDefinition() = false;
    eq DefaultMappingDefinition.isDefaultMappingDefinition() = true; eq DefaultMappingDefinition.isDefaultMappingDefinition() = true;
    // --- mragconnect ---
    inh MRagConnect MHandler.mragconnect();
    eq MRagConnect.getHandler().mragconnect() = this;
    // --- rootTypeComponents ---
    syn JastAddList<MTypeComponent> MHandler.rootTypeComponents() = mragconnect().getRootTypeComponents();
    // --- isListComponent --- (defined in PP, but only on TypeComponent) // --- isListComponent --- (defined in PP, but only on TypeComponent)
    syn boolean Component.isListComponent() = false; syn boolean Component.isListComponent() = false;
    } }
    RagConnect ::= ConnectSpecificationFile* Program ; RagConnect ::= ConnectSpecificationFile* Program Handler* Configuration;
    abstract ConnectSpecification ::= EndpointDefinition* DependencyDefinition* MappingDefinition*; abstract ConnectSpecification ::= EndpointDefinition* DependencyDefinition* MappingDefinition*;
    ConnectSpecificationFile : ConnectSpecification ::= <FileName>; ConnectSpecificationFile : ConnectSpecification ::= <FileName>;
    abstract EndpointDefinition ::= <AlwaysApply:boolean> ; EndpointDefinition ::= <AlwaysApply:boolean> <IndexBasedListAccess:boolean> <WithAdd:boolean> <Send:boolean> EndpointTarget;
    rel EndpointDefinition.Mapping* <-> MappingDefinition.UsedAt*; rel EndpointDefinition.Mapping* <-> MappingDefinition.UsedAt*;
    abstract TokenEndpointDefinition : EndpointDefinition; abstract EndpointTarget;
    rel TokenEndpointDefinition.Token <-> TokenComponent.TokenEndpointDefinition*; TokenEndpointTarget : EndpointTarget;
    rel TokenEndpointTarget.Token <-> TokenComponent.TokenEndpointTarget*;
    ReceiveTokenEndpointDefinition : TokenEndpointDefinition; TypeEndpointTarget : EndpointTarget;
    SendTokenEndpointDefinition : TokenEndpointDefinition; rel TypeEndpointTarget.Type <-> TypeComponent.TypeEndpointTarget*;
    UntypedEndpointTarget : EndpointTarget ::= <TokenOrType>; // only used by parser
    abstract TypeEndpointDefinition : EndpointDefinition ::= <IndexBasedListAccess:boolean> ; // to be integrated:
    rel TypeEndpointDefinition.Type <-> TypeComponent.TypeEndpointDefinition*; //AttributeEndpointTarget : EndpointTarget ::= <Name> ;
    //RelationEndpointTarget : EndpointTarget ;
    ReceiveTypeEndpointDefinition : TypeEndpointDefinition ::= <WithAdd:boolean>; //rel RelationEndpointTarget.Role <-> Role.RelationEndpointTarget* ;
    SendTypeEndpointDefinition : TypeEndpointDefinition;
    DependencyDefinition ::= <ID>; DependencyDefinition ::= <ID>;
    rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*; rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*;
    ...@@ -29,7 +27,13 @@ JavaMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse ; ...@@ -29,7 +27,13 @@ JavaMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse ;
    JavaArrayMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse; JavaArrayMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse;
    DefaultMappingDefinition : MappingDefinition; DefaultMappingDefinition : MappingDefinition;
    // only used by parser Handler ::= <DefinitionFileName> <ClassName> <UniqueName> <InUse:boolean>;
    abstract UntypedEndpointDefinition : EndpointDefinition ::= <TokenOrType> <Indexed:boolean> <WithAdd:boolean> ;
    ReceiveUntypedEndpointDefinition : UntypedEndpointDefinition; Configuration ::=
    SendUntypedEndpointDefinition : UntypedEndpointDefinition; <LoggingEnabledForReads:boolean>
    <LoggingEnabledForWrites:boolean>
    <LoggingEnabledForIncremental:boolean>
    <JastAddList:String>
    <IncrementalOptionActive:boolean>
    <ExperimentalJastAdd329:boolean>;
    rel Configuration.RootNode -> TypeDecl ;
    ...@@ -2,4 +2,6 @@ aspect Util { ...@@ -2,4 +2,6 @@ aspect Util {
    static String ASTNode.capitalize(String s) { static String ASTNode.capitalize(String s) {
    return Character.toUpperCase(s.charAt(0)) + s.substring(1); return Character.toUpperCase(s.charAt(0)) + s.substring(1);
    } }
    protected T JastAddList.firstChild() { return getChild(0); }
    protected T JastAddList.lastChild() { return getChild(getNumChild() - 1); }
    } }
    This diff is collapsed.
    MRagConnect ::= TokenReceiveDefinition:MTokenReceiveDefinition* TokenSendDefinition:MTokenSendDefinition* TypeReceiveDefinition:MTypeReceiveDefinition* TypeSendDefinition:MTypeSendDefinition* MappingDefinition:MMappingDefinition* DependencyDefinition:MDependencyDefinition* RootTypeComponent:MTypeComponent* TokenComponent:MTokenComponent* Handler:MHandler*;
    abstract MEndpointDefinition ::= InnerMappingDefinition:MInnerMappingDefinition*;
    abstract MTokenEndpointDefinition : MEndpointDefinition;
    MTokenReceiveDefinition : MTokenEndpointDefinition;
    MTokenSendDefinition : MTokenEndpointDefinition;
    abstract MTypeEndpointDefinition : MEndpointDefinition;
    MTypeReceiveDefinition : MTypeEndpointDefinition;
    MTypeSendDefinition : MTypeEndpointDefinition;
    MMappingDefinition;
    MInnerMappingDefinition;
    MDependencyDefinition;
    MTypeComponent;
    MTokenComponent;
    MHandler ::= <ClassName> <Construction> <AttributeName> <FieldName> <InUse:boolean>;
    rel MRagConnect.RagConnect -> RagConnect;
    rel MInnerMappingDefinition.MMappingDefinition -> MMappingDefinition;
    rel MTokenReceiveDefinition.ReceiveTokenEndpointDefinition -> ReceiveTokenEndpointDefinition;
    rel MTokenSendDefinition.SendTokenEndpointDefinition -> SendTokenEndpointDefinition;
    rel MTypeReceiveDefinition.ReceiveTypeEndpointDefinition -> ReceiveTypeEndpointDefinition;
    rel MTypeSendDefinition.SendTypeEndpointDefinition -> SendTypeEndpointDefinition;
    rel MMappingDefinition.MappingDefinition -> MappingDefinition;
    rel MDependencyDefinition.DependencyDefinition -> DependencyDefinition;
    rel MTypeComponent.TypeComponent -> TypeComponent;
    rel MTokenComponent.TokenComponent -> TokenComponent;
    rel MTokenComponent.DependencyDefinition* -> MDependencyDefinition;
    aspect MustacheNodesToYAML {
    syn Document MRagConnect.toYAML() {
    Document doc = new Document();
    MappingElement root = new MappingElement();
    root.put("rootNodeName", rootNodeName());
    root.put("closeMethod", closeMethod());
    root.put("usesMqtt", usesMqtt);
    root.put("usesRest", usesRest);
    // mqtt
    root.put("mqttHandlerField", mqttHandlerField());
    root.put("mqttHandlerAttribute", mqttHandlerAttribute());
    root.put("mqttSetupWaitUntilReadyMethod", mqttSetupWaitUntilReadyMethod());
    // rootTypeComponents
    ListElement rootTypeComponents = new ListElement();
    for (MTypeComponent comp : getRootTypeComponentList()) {
    MappingElement inner = new MappingElement();
    inner.put("first", comp.isFirst());
    inner.put("name", comp.name());
    rootTypeComponents.addElement(inner);
    }
    root.put("RootTypeComponents", rootTypeComponents);
    // rest
    root.put("restHandlerField", restHandlerField());
    root.put("restHandlerAttribute", restHandlerAttribute());
    // TokenReceiveDefinitions
    ListElement receiveDefinitions = new ListElement();
    for (MTokenReceiveDefinition def : getTokenReceiveDefinitionList()) {
    receiveDefinitions.addElement(def.toYAML());
    }
    root.put("TokenReceiveDefinitions", receiveDefinitions);
    // TokenSendDefinitions
    ListElement sendDefinitions = new ListElement();
    for (MTokenSendDefinition def : getTokenSendDefinitionList()) {
    sendDefinitions.addElement(def.toYAML());
    }
    root.put("TokenSendDefinitions", sendDefinitions);
    // TypeReceiveDefinitions
    ListElement typeReceiveDefinitions = new ListElement();
    for (MTypeReceiveDefinition def : getTypeReceiveDefinitionList()) {
    typeReceiveDefinitions.addElement(def.toYAML());
    }
    root.put("TypeReceiveDefinitions", typeReceiveDefinitions);
    // TypeSendDefinitions
    ListElement typeSendDefinitions = new ListElement();
    for (MTypeSendDefinition def : getTypeSendDefinitionList()) {
    typeSendDefinitions.addElement(def.toYAML());
    }
    root.put("TypeSendDefinitions", typeSendDefinitions);
    // MappingDefinitions
    ListElement mappingDefinitions = new ListElement();
    for (MMappingDefinition def : getMappingDefinitionList()) {
    mappingDefinitions.addElement(def.toYAML());
    }
    root.put("MappingDefinitions", mappingDefinitions);
    // DependencyDefinitions
    ListElement dependencyDefinitions = new ListElement();
    for (MDependencyDefinition def : getDependencyDefinitionList()) {
    dependencyDefinitions.addElement(def.toYAML());
    }
    root.put("DependencyDefinitions", dependencyDefinitions);
    // TokenComponents
    ListElement tokenComponents = new ListElement();
    for (MTokenComponent comp : getTokenComponentList()) {
    tokenComponents.addElement(comp.toYAML());
    }
    root.put("TokenComponents", tokenComponents);
    // Handlers
    ListElement handlers = new ListElement();
    for (MHandler handler : getHandlerList()) {
    handlers.add(handler.toYAML()
    .put("rootTokenComponents", rootTypeComponents.treeCopy()) );
    }
    root.put("Handlers", handlers);
    doc.setRootElement(root);
    return doc;
    }
    syn MappingElement MEndpointDefinition.toYAML() {
    MappingElement result = new MappingElement();
    result.put("parentTypeName", parentTypeName());
    result.put("connectMethod", connectMethod());
    result.put("connectParameterName", connectParameterName());
    result.put("lastDefinitionToType", lastDefinitionToType());
    result.put("preemptiveReturn", preemptiveReturn());
    result.put("alwaysApply", alwaysApply());
    result.put("condition",
    condition().replace("\"", "\\\"").replace("\n", "\\n"));
    result.put("lastResult", lastResult());
    result.put("tokenName", tokenName());
    result.put("InnerMappingDefinitions", innerMappingDefinitionsAsListElement());
    return result;
    }
    syn MappingElement MTokenReceiveDefinition.toYAML() {
    MappingElement result = super.toYAML();
    result.put("loggingEnabledForReads", loggingEnabledForReads);
    return result;
    }
    syn MappingElement MTokenSendDefinition.toYAML() {
    MappingElement result = super.toYAML();
    result.put("sender", sender());
    result.put("lastValue", lastValue());
    result.put("loggingEnabledForWrites", loggingEnabledForWrites);
    result.put("updateMethod", updateMethod());
    result.put("writeMethod", writeMethod());
    result.put("tokenResetMethod", tokenResetMethod());
    return result;
    }
    syn MappingElement MTypeReceiveDefinition.toYAML() {
    MappingElement result = super.toYAML();
    result.put("typeIsList", typeIsList());
    result.put("loggingEnabledForReads", loggingEnabledForReads);
    return result;
    }
    syn MappingElement MTypeSendDefinition.toYAML() {
    MappingElement result = super.toYAML();
    result.put("typeIsList", typeIsList());
    result.put("sender", sender());
    result.put("lastValue", lastValue());
    result.put("loggingEnabledForWrites", loggingEnabledForWrites);
    result.put("updateMethod", updateMethod());
    result.put("writeMethod", writeMethod());
    result.put("tokenResetMethod", tokenResetMethod());
    return result;
    }
    syn Element MMappingDefinition.toYAML() {
    MappingElement result = new MappingElement();
    result.put("toType", toType());
    result.put("methodName", methodName());
    result.put("fromType", fromType());
    result.put("fromVariableName", fromVariableName());
    result.put("content",
    content().replace("\"", "\\\"").replace("\n", "\\n"));
    return result;
    }
    syn Element MDependencyDefinition.toYAML() {
    MappingElement result = new MappingElement();
    result.put("targetParentTypeName", targetParentTypeName());
    result.put("dependencyMethod", dependencyMethod());
    result.put("sourceParentTypeName", sourceParentTypeName());
    result.put("internalRelationPrefix", internalRelationPrefix());
    return result;
    }
    syn Element MTokenComponent.toYAML() {
    MappingElement result = new MappingElement();
    result.put("parentTypeName", parentTypeName());
    result.put("name", name());
    result.put("javaType", javaType());
    result.put("internalName", internalName());
    ListElement dependencyDefinitions = new ListElement();
    for (MDependencyDefinition def : getDependencyDefinitionList()) {
    MappingElement inner = new MappingElement();
    inner.put("targetParentTypeName", def.targetParentTypeName());
    inner.put("internalRelationPrefix", def.internalRelationPrefix());
    MappingElement targetEndpointDefinition = new MappingElement();
    targetEndpointDefinition.put("updateMethod", def.targetEndpointDefinition().updateMethod());
    targetEndpointDefinition.put("writeMethod", def.targetEndpointDefinition().writeMethod());
    inner.put("targetEndpointDefinition", targetEndpointDefinition);
    dependencyDefinitions.addElement(inner);
    }
    result.put("DependencyDefinitions", dependencyDefinitions);
    return result;
    }
    ListElement MEndpointDefinition.innerMappingDefinitionsAsListElement() {
    ListElement innerMappingDefinitions = new ListElement();
    for (MInnerMappingDefinition def : getInnerMappingDefinitionList()) {
    MappingElement inner = new MappingElement();
    inner.put("toType", def.toType());
    inner.put("methodName", def.methodName());
    inner.put("inputVarName", def.inputVarName());
    inner.put("outputVarName", def.outputVarName());
    inner.put("last", def.isLast());
    innerMappingDefinitions.addElement(inner);
    }
    return innerMappingDefinitions;
    }
    syn MappingElement MHandler.toYAML() {
    MappingElement result = new MappingElement();
    result.put("ClassName", getClassName());
    result.put("Construction", getConstruction());
    result.put("AttributeName", getAttributeName());
    result.put("FieldName", getFieldName());
    result.put("InUse", getInUse());
    return result;
    }
    }
    aspect Navigation {
    eq Document.getChild().program() = null;
    eq Document.getChild().ragconnect() = null;
    eq Document.getChild().containedFile() = null;
    eq Document.containedFileName() = getFileName();
    }
    aspect ParserRewrites { aspect ParserRewrites {
    rewrite SendUntypedEndpointDefinition { rewrite UntypedEndpointTarget {
    when (tryGloballyResolveTypeComponentByToken(getTokenOrType()) != null) when (tryGloballyResolveTypeComponentByToken(getTokenOrType()) != null)
    to SendTypeEndpointDefinition { to TypeEndpointTarget {
    SendTypeEndpointDefinition result = new SendTypeEndpointDefinition(); TypeEndpointTarget result = new TypeEndpointTarget();
    result.applyFrom(this); result.setType(TypeComponent.createRef(this.getTokenOrType()));
    result.setIndexBasedListAccess(this.getIndexed());
    return result; return result;
    } }
    }
    rewrite ReceiveUntypedEndpointDefinition {
    when (tryGloballyResolveTypeComponentByToken(getTokenOrType()) != null)
    to ReceiveTypeEndpointDefinition {
    ReceiveTypeEndpointDefinition result = new ReceiveTypeEndpointDefinition();
    result.applyFrom(this);
    result.setWithAdd(this.getWithAdd());
    result.setIndexBasedListAccess(this.getIndexed());
    return result;
    }
    }
    rewrite SendUntypedEndpointDefinition {
    when (tryGloballyResolveTokenComponentByToken(getTokenOrType()) != null)
    to SendTokenEndpointDefinition {
    SendTokenEndpointDefinition result = new SendTokenEndpointDefinition();
    result.applyFrom(this);
    return result;
    }
    }
    rewrite ReceiveUntypedEndpointDefinition {
    when (tryGloballyResolveTokenComponentByToken(getTokenOrType()) != null) when (tryGloballyResolveTokenComponentByToken(getTokenOrType()) != null)
    to ReceiveTokenEndpointDefinition { to TokenEndpointTarget {
    ReceiveTokenEndpointDefinition result = new ReceiveTokenEndpointDefinition(); TokenEndpointTarget result = new TokenEndpointTarget();
    result.applyFrom(this); result.setToken(TokenComponent.createRef(this.getTokenOrType()));
    return result; return result;
    } }
    } }
    protected void TypeEndpointDefinition.applyFrom(UntypedEndpointDefinition def) { eq UntypedEndpointTarget.senderName() = "<untyped.senderName>";
    this.setAlwaysApply(def.getAlwaysApply()); eq UntypedEndpointTarget.getterMethodName() = "<untyped.getterMethodName>";
    this.setType(TypeComponent.createRef(def.getTokenOrType())); eq UntypedEndpointTarget.parentTypeName() = "<untyped.parentTypeName>";
    this.moveMappingsFrom(def); eq UntypedEndpointTarget.entityName() = "<untyped.entityName>";
    } eq UntypedEndpointTarget.isAlreadyDefined() = false;
    eq UntypedEndpointTarget.entityIsNormalAttribute() = false;
    protected void TokenEndpointDefinition.applyFrom(UntypedEndpointDefinition def) { eq UntypedEndpointTarget.targetTypeName() = "<untyped.targetTypeName>";
    this.setAlwaysApply(def.getAlwaysApply());
    this.setToken(TokenComponent.createRef(def.getTokenOrType()));
    this.moveMappingsFrom(def);
    }
    protected void EndpointDefinition.moveMappingsFrom(UntypedEndpointDefinition def) {
    // can safely iterate over list as we get an unmodifyable list
    for (MappingDefinition mapping : def.getMappingList().toArray(new MappingDefinition[0])) {
    def.removeMapping(mapping);
    this.addMapping(mapping);
    }
    }
    private void UntypedEndpointDefinition.clearMappings() {
    }
    eq UntypedEndpointDefinition.targetTypeName() = "<unknown>";
    syn MEndpointDefinition UntypedEndpointDefinition.toMustache() {
    throw new RuntimeException("UntypedEndpoint can not be transformed using toMustache!");
    }
    } }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Please register or to comment