diff --git a/ragconnect.base/src/main/jastadd/Analysis.jrag b/ragconnect.base/src/main/jastadd/Analysis.jrag index 85ff38d40d88ddbc415d3bd3ea39867c00d1e2fd..b48146f5a0a08d5a26b9c0d425e0b079287c5198 100644 --- a/ragconnect.base/src/main/jastadd/Analysis.jrag +++ b/ragconnect.base/src/main/jastadd/Analysis.jrag @@ -64,6 +64,7 @@ aspect Analysis { } syn boolean EndpointTarget.entityIsNormalAttribute(); + // TODO AttributeEndpointTarget.entityIsNormalAttribute eq TokenEndpointTarget.entityIsNormalAttribute() = !getToken().getNTA(); eq TypeEndpointTarget.entityIsNormalAttribute() = !getType().getNTA(); eq ContextFreeTypeEndpointTarget.entityIsNormalAttribute() = false; diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd index bcd4cc4da4242ccd317f3d23bb66bb70a62f3599..b215f18142b88eb5280633fbc1e77edb628cd934 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.jadd +++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd @@ -371,6 +371,10 @@ aspect MustacheReceiveAndSendAndHandleUri { syn String EndpointTarget.parentTypeName(); syn String EndpointTarget.entityName(); + // TODO AttributeEndpointTarget.getterName + eq AttributeEndpointTarget.parentTypeName() = getParentTypeDecl().getName(); + eq AttributeEndpointTarget.entityName() = getName(); + eq TokenEndpointTarget.getterMethodName() = "get" + getToken().getName(); eq TokenEndpointTarget.parentTypeName() = getToken().containingTypeDecl().getName(); eq TokenEndpointTarget.entityName() = getToken().getName(); @@ -456,9 +460,7 @@ aspect MustacheSendDefinition { getTypeDecl().getName() : ragconnect().configJastAddList() + "<" + getTypeDecl().getName() + ">"; - syn String EndpointTarget.senderName(); - eq TokenEndpointTarget.senderName() = ragconnect().internalRagConnectPrefix() + "_sender_" + getToken().getName(); - eq TypeEndpointTarget.senderName() = ragconnect().internalRagConnectPrefix() + "_sender_" + getType().getName(); + syn String EndpointTarget.senderName() = ragconnect().internalRagConnectPrefix() + "_sender_" + entityName(); eq ContextFreeTypeEndpointTarget.senderName() = null; syn String MEndpointDefinition.updateMethodName(); diff --git a/ragconnect.base/src/main/jastadd/Mappings.jrag b/ragconnect.base/src/main/jastadd/Mappings.jrag index 738028b3a264a0c7dcf976618aa0b63f35be62c5..fb7c296cdd1c888488bda1a3ce3cb6399044de2e 100644 --- a/ragconnect.base/src/main/jastadd/Mappings.jrag +++ b/ragconnect.base/src/main/jastadd/Mappings.jrag @@ -191,6 +191,7 @@ aspect Mappings { // --- suitableReceiveDefaultMapping --- syn DefaultMappingDefinition EndpointDefinition.suitableReceiveDefaultMapping() { + // TODO might be expanded to AttributeEndpointTarget if (getEndpointTarget().isTypeEndpointTarget()) { try { TypeDecl typeDecl = program().resolveTypeDecl(targetTypeName()); @@ -236,6 +237,7 @@ aspect Mappings { // --- suitableSendDefaultMapping --- syn DefaultMappingDefinition EndpointDefinition.suitableSendDefaultMapping() { + // TODO might be expanded to AttributeEndpointTarget if (getEndpointTarget().isTypeEndpointTarget() && typeIsList() && !getIndexBasedListAccess()) { return ragconnect().defaultListTreeToBytesMapping(); } @@ -288,6 +290,7 @@ aspect Mappings { } } syn String EndpointTarget.targetTypeName(); + eq AttributeEndpointTarget.targetTypeName() = getTypeName(); eq TokenEndpointTarget.targetTypeName() = getToken().effectiveJavaTypeUse().getName(); eq TypeEndpointTarget.targetTypeName() = getType().getTypeDecl().getName(); eq ContextFreeTypeEndpointTarget.targetTypeName() = getTypeDecl().getName(); diff --git a/ragconnect.base/src/main/jastadd/Navigation.jrag b/ragconnect.base/src/main/jastadd/Navigation.jrag index a65ab72fa946bcec3351bb496f6632c012bac678..260ed5513f71ef4b8d2eade39cee9bc658886991 100644 --- a/ragconnect.base/src/main/jastadd/Navigation.jrag +++ b/ragconnect.base/src/main/jastadd/Navigation.jrag @@ -1,5 +1,6 @@ aspect NewStuff { + // TODO regenerate for AttributeEndpointTarget /** Tests if EndpointTarget is a TokenEndpointTarget. * @return 'true' if this is a TokenEndpointTarget, otherwise 'false' */ diff --git a/ragconnect.base/src/main/jastadd/RagConnect.relast b/ragconnect.base/src/main/jastadd/RagConnect.relast index 01a0f2f884a2f0824bf2787eaf42d7d2d5797c41..f6cf0dd68708157aa291b6b0b50077b2fe72034c 100644 --- a/ragconnect.base/src/main/jastadd/RagConnect.relast +++ b/ragconnect.base/src/main/jastadd/RagConnect.relast @@ -13,9 +13,10 @@ TypeEndpointTarget : EndpointTarget; rel TypeEndpointTarget.Type <-> TypeComponent.TypeEndpointTarget*; ContextFreeTypeEndpointTarget : EndpointTarget; rel ContextFreeTypeEndpointTarget.TypeDecl <-> TypeDecl.ContextFreeTypeEndpointTarget*; -UntypedEndpointTarget : EndpointTarget ::= <TypeName> <ChildName>; // only used by parser +UntypedEndpointTarget : EndpointTarget ::= <TypeName> <ChildName> <IsAttribute:boolean>; // only used by parser // to be integrated: -//AttributeEndpointTarget : EndpointTarget ::= <Name> ; +AttributeEndpointTarget : EndpointTarget ::= <Name> <TypeName> ; +rel AttributeEndpointTarget.ParentTypeDecl <-> TypeDecl.AttributeEndpointTarget*; //RelationEndpointTarget : EndpointTarget ; //rel RelationEndpointTarget.Role <-> Role.RelationEndpointTarget* ; diff --git a/ragconnect.base/src/main/jastadd/parser/ParserRewrites.jrag b/ragconnect.base/src/main/jastadd/parser/ParserRewrites.jrag index f4a8912fe7c2affa7034d3eb8651f9d210bbba54..3de934126aa88278d14488ee61638841170c1f16 100644 --- a/ragconnect.base/src/main/jastadd/parser/ParserRewrites.jrag +++ b/ragconnect.base/src/main/jastadd/parser/ParserRewrites.jrag @@ -23,6 +23,19 @@ aspect ParserRewrites { result.setTypeDecl(TypeDecl.createRef(getTypeName())); return result; } + + when (getIsAttribute()) + to AttributeEndpointTarget { + AttributeEndpointTarget result = new AttributeEndpointTarget(); + String[] tokens = this.getChildName().split(":"); + String attributeName = tokens[0]; + String attributeTypeName = tokens[1]; + result.copyOtherValuesFrom(this); + result.setName(attributeName); + result.setTypeName(attributeTypeName); + result.setParentTypeDecl(TypeDecl.createRef(getTypeName())); + return result; + } } syn String UntypedEndpointTarget.combinedName() = getTypeName() + "." + getChildName(); diff --git a/ragconnect.base/src/main/jastadd/parser/RagConnect.parser b/ragconnect.base/src/main/jastadd/parser/RagConnect.parser index 54a388e51d35bc52296fd4f60e220d325be00674..dcd55d27ecaea7365205835d9eec1efcf6f59870 100644 --- a/ragconnect.base/src/main/jastadd/parser/RagConnect.parser +++ b/ragconnect.base/src/main/jastadd/parser/RagConnect.parser @@ -62,8 +62,10 @@ EndpointDefinition endpoint_definition_type ; EndpointTarget endpoint_target - = ID.type_name DOT ID.child_name {: return new UntypedEndpointTarget(type_name, child_name); :} - | ID.type_name {: return new UntypedEndpointTarget(type_name, ""); :} + = ID.type_name DOT ID.child_name {: return new UntypedEndpointTarget(type_name, child_name, false); :} + | ID.type_name DOT ID.child_name BRACKETS COLON ID.attribute_type_name + {: return new UntypedEndpointTarget(type_name, child_name + ":" + attribute_type_name, true); :} + | ID.type_name {: return new UntypedEndpointTarget(type_name, "", false); :} ; ArrayList string_list diff --git a/ragconnect.base/src/main/jastadd/scanner/Keywords.flex b/ragconnect.base/src/main/jastadd/scanner/Keywords.flex index 8a1eaec1e8d95c0d8786f9f44168d1f060b27cfa..ffa057bc6df906f0a0226ba98bf01a7a6fbdbbf2 100644 --- a/ragconnect.base/src/main/jastadd/scanner/Keywords.flex +++ b/ragconnect.base/src/main/jastadd/scanner/Keywords.flex @@ -8,3 +8,5 @@ "with" { return sym(Terminals.WITH); } "indexed" { return sym(Terminals.INDEXED); } "add" { return sym(Terminals.ADD); } +"()" { return sym(Terminals.BRACKETS); } +":" { return sym(Terminals.COLON); } diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 8d073b55ac6b14ebdf6b295bd993dda64dbbd701..b545b19b84d42435217f239c5ae5dd6d34604e48 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -621,3 +621,29 @@ task compileIndexedSendIncremental(type: RagConnectTest, dependsOn: ':ragconnect extraOptions = JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL } } + +// --- Test: attribute-incremental --- +task compileAttributeIncremental(type: RagConnectTest, dependsOn: ':ragconnect.base:jar') { + ragconnect { + outputDir = file('src/test/02-after-ragconnect/attributeInc') + inputFiles = [file('src/test/01-input/attribute/Test.relast'), + file('src/test/01-input/attribute/Test.connect')] + rootNode = 'Root' + logWrites = true + logReads = true + logIncremental = true + extraOptions = ['--experimental-jastadd-329'] + } + relast { + useJastAddNames = true + grammarName = 'src/test/03-after-relast/attributeInc/attributeInc' + serializer = 'jackson' + } + jastadd { + jastAddList = 'JastAddList' + packageName = 'attributeInc.ast' + inputFiles = [file('src/test/01-input/attribute/Test.jadd')] + extraOptions = JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL + } +} +compileAttributeIncremental.outputs.upToDateWhen { false } diff --git a/ragconnect.tests/src/test/01-input/attribute/README.md b/ragconnect.tests/src/test/01-input/attribute/README.md new file mode 100644 index 0000000000000000000000000000000000000000..08481b7a25582721dfa8435ac199b94acb205de6 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/attribute/README.md @@ -0,0 +1,3 @@ +# Attribute + +Idea: Use send definitions for attributes. diff --git a/ragconnect.tests/src/test/01-input/attribute/Test.connect b/ragconnect.tests/src/test/01-input/attribute/Test.connect new file mode 100644 index 0000000000000000000000000000000000000000..3e6a66ebabdac4e4a7072395519b7d9fd4ab48e8 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/attribute/Test.connect @@ -0,0 +1,31 @@ +send SenderRoot.basic():String ; +send SenderRoot.simple():String ; +send SenderRoot.transformed():int ; +send SenderRoot.toReferenceType():A ; +send SenderRoot.toNTA():A ; + +AddSuffix maps A a to A {: + A result = new A(); + String changedValue = a.getValue() + "post"; + result.setValue(changedValue); + result.setInner(new Inner("inner" + changedValue)); + return result; +:} + +AddStringSuffix maps String s to String {: + return s + "post"; +:} + +AddPlusOne maps int i to int {: + return i + 1; +:} + +receive ReceiverRoot.FromBasic; +receive ReceiverRoot.FromSimpleNoMapping; +receive ReceiverRoot.FromSimpleWithMapping using AddStringSuffix; +receive ReceiverRoot.FromTransformedNoMapping; +receive ReceiverRoot.FromTransformedWithMapping using AddPlusOne; +receive ReceiverRoot.FromReferenceTypeNoMapping; +receive ReceiverRoot.FromReferenceTypeWithMapping using AddSuffix; +receive ReceiverRoot.FromNTANoMapping; +receive ReceiverRoot.FromNTAWithMapping using AddSuffix; diff --git a/ragconnect.tests/src/test/01-input/attribute/Test.jadd b/ragconnect.tests/src/test/01-input/attribute/Test.jadd new file mode 100644 index 0000000000000000000000000000000000000000..c5274c6f73b0a49d77443522d9596cd8e8b5f858 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/attribute/Test.jadd @@ -0,0 +1,39 @@ +aspect Computation { + syn String SenderRoot.basic() = getInput(); + syn String SenderRoot.simple() = getInput() + "Post"; + syn int SenderRoot.transformed() = getInput().length(); + syn A SenderRoot.toReferenceType() { + A result = new A(); + result.setValue(getInput()); + Inner inner = new Inner(); + inner.setInnerValue("1"); + result.setInner(inner); + return result; + } + syn nta A SenderRoot.toNTA() { + A result = new A(); + result.setValue(getInput()); + Inner inner = new Inner(); + inner.setInnerValue("2"); + result.setInner(inner); + return result; + } +} +aspect MakeCodeCompile { + +} +aspect MakeCodeWork { + +} +aspect NameResolution { + // overriding customID guarantees to produce the same JSON representation for equal lists + // otherwise, the value for id is different each time + @Override + protected String A.customID() { + return getClass().getSimpleName() + getValue(); + } + @Override + protected String Inner.customID() { + return getClass().getSimpleName() + getInnerValue(); + } +} diff --git a/ragconnect.tests/src/test/01-input/attribute/Test.relast b/ragconnect.tests/src/test/01-input/attribute/Test.relast new file mode 100644 index 0000000000000000000000000000000000000000..d7edb5c53ae2b4e3380b73e0800395ae26eaae41 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/attribute/Test.relast @@ -0,0 +1,14 @@ +Root ::= SenderRoot ReceiverRoot; +SenderRoot ::= <Input> ; +ReceiverRoot ::= + <FromBasic> + <FromSimpleNoMapping> + <FromSimpleWithMapping> + <FromTransformedNoMapping:int> + <FromTransformedWithMapping:int> + FromReferenceTypeNoMapping:A + FromReferenceTypeWithMapping:A + FromNTANoMapping:A + FromNTAWithMapping:A ; +A ::= <Value> Inner ; +Inner ::= <InnerValue> ; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6b877447b20b78b9e6413afde73abb8670a4473c --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java @@ -0,0 +1,48 @@ +package org.jastadd.ragconnect.tests; + +import attribute.ast.*; +import org.junit.jupiter.api.Tag; + +import java.io.IOException; + +/** + * Test case "attribute". + * + * @author rschoene - Initial contribution + */ +@Tag("Incremental") +@Tag("New") +public class AttributeTest extends AbstractMqttTest { + Root model; + MqttHandler handler; + + @Override + protected void createModel() { + + } + + @Override + protected void setupReceiverAndConnect() throws IOException, InterruptedException { + + } + + @Override + protected void communicateSendInitialValue() throws IOException, InterruptedException { + + } + + @Override + protected void communicateOnlyUpdatedValue() throws IOException, InterruptedException { + + } + + @Override + protected void closeConnections() { + if (handler != null) { + handler.close(); + } + if (model != null) { + model.ragconnectCloseConnections(); + } + } +}