Skip to content
Snippets Groups Projects
Commit 39f1effb authored by Sebastian Ebert's avatar Sebastian Ebert
Browse files

merged upstream master in fork-master

parents 38c4a6a2 24062cab
No related branches found
No related tags found
1 merge request!11Merge/dev to fork master merge
Showing
with 366 additions and 0 deletions
// --- update receive definitions ---
// Error: there must not be two receive definitions for the same token
receive B.DoubledValue ;
receive B.DoubledValue using IntToInt ;
// NOT HANDLED \\ Error: the token must be resolvable within the parent type
// NOT HANDLED \\ receive B.NonExisting ;
// Error: the Token must not be a TokenNTA (i.e., check for !Token.getNTA())
receive B.ErrorNTA ;
// Error: from-type of first mapping must be byte[] or a supported primitive type
receive B.ErrorTypeOfFirstMapping using ListToList ;
// Error: to-type of last mapping must be type of the Token
receive B.ErrorTypeOfLastMapping using StringToList ;
// Error: types of mappings must match (modulo inheritance)
receive B.ErrorTypeMismatch using StringToList, IntToInt ;
// --- update send definitions ---
// NOT HANDLED \\ Error: the token must be resolvable within the parent type
// NOT HANDLED \\ receive C.NonExisting ;
// Error: Token must be a TokenNTA (i.e., check for Token.getNTA())
send C.ErrorNotNTA ;
// Error: from-type of first mapping must be type of Token
send C.ErrorTypeOfFirstMapping using IntToInt ;
// Error: to-type of last mapping must be byte[] or a supported primitive type
send C.ErrorTypeOfLastMapping1 using StringToList ;
send C.ErrorTypeOfLastMapping2 ;
// Error: types of mappings must match (modulo inheritance)
send C.ErrorTypeMismatch using StringToList, IntToInt ;
// Error: no more than one send mapping for each TokenComponent
send C.DoubledValue ;
send C.DoubledValue using IntToInt ;
// --- dependency definitions ---
// NOT HANDLED \\ Error: Both, source and target must be resolvable within the parent type
// NOT HANDLED \\ D.SourceNonExistingTarget canDependOn D.NonExisting as NonExistingTarget ;
// NOT HANDLED \\ D.NonExisting canDependOn D.TargetNonExistingSource as NonExistingSource ;
// Error: There must be a send update definition for the target token
D.SourceNoWriteDef canDependOn D.TargetNoWriteDef as NoWriteDef ;
// Error: The name of a dependency definition must not be equal to a list-node on the source
D.SourceSameAsListNode canDependOn D.TargetSameAsListNode as MyList ;
send D.TargetSameAsListNode;
// Error: There must not be two dependency definitions with the same name
D.SourceDoubledValue canDependOn D.TargetDoubledValue as DoubledValue ;
D.SourceDoubledValue canDependOn D.TargetDoubledValue as DoubledValue ;
send D.TargetDoubledValue;
// --- mapping definitions ---
ListToList maps java.util.List<String> list to java.util.List<String> {:
return list;
:}
StringToList maps String s to List<String> {:
java.util.List<String> result = new java.util.ArrayList<>();
result.add(s);
return result;
:}
IntToInt maps int number to int {:
return number + 1;
:}
A ::= B C D ;
// read definitions
B ::= /<ErrorNTA:String>/ <ErrorTypeOfFirstMapping:String> <ErrorTypeOfLastMapping:String> <DoubledValue:int> <ErrorTypeMismatch:String> ;
// write definitions
C ::= <ErrorNotNTA:String> /<ErrorTypeOfFirstMapping:String>/ /<ErrorTypeOfLastMapping1:String>/ /<ErrorTypeOfLastMapping2:List<String>>/ /<ErrorTypeMismatch:String>/ /<DoubledValue:int>/ ;
// dependency definitions
D ::= <SourceNonExistingTarget>
/<TargetNonExistingSource>/
<SourceNoWriteDef> /<TargetNoWriteDef>/
<SourceSameAsListNode> /<TargetSameAsListNode>/
<SourceDoubledValue> /<TargetDoubledValue>/
MyList:D* ;
Ideas for errors:
- Read-Update
- the token must be resolvable within the parent type
- the Token must not be a TokenNTA (i.e., check for `!Token.getNTA()`)
- type of first mapping must be `byte[]`
- type of last mapping must be type of the Token
- types of mappings must match (modulo inheritance)
- Write-Update
- the token must be resolvable within the parent type
- Token must be a TokenNTA (i.e., check for `Token.getNTA()`)
- type of first mapping must be type of Token
- type of last mapping must be `byte[]`
- types of mappings must match (modulo inheritance)
- no more than one write mapping for each TokenComponent
- for all type checks, there are three cases regarding the two types to check against:
1) both are nonterminal types, check with grammar
2) both are known classes, check with `Class.forName()` and subclass-checking-methods
3) otherwise issue warning, that types could not be matched
- dependency-definition
- There **must be** a write update definition for the target token
- Otherwise there are missing update and write methods used in the virtual setter
- Both, source and target must be resolvable within the parent type
- The name of a dependency definition must not be equal to a list-node on the source
- There must not be two dependency definitions with the same name
# Example
Idea: Use the motivating example from our paper as a test case, including one read, one write update definition
/* Version 2020-07-15 */
// --- update definitions ---
receive Link.CurrentPosition using ParseRobotState, RobotStateToIntPosition ;
send RobotArm.AppropriateSpeed using CreateSpeedMessage, SerializeRobotConfig ;
// --- dependency definitions ---
RobotArm.AppropriateSpeed canDependOn Link.CurrentPosition as dependency1 ;
// --- mapping definitions ---
ParseRobotState maps byte[] bytes to robot.RobotStateOuterClass.RobotState {:
TestCounter.INSTANCE.numberParseLinkState += 1;
return robot.RobotStateOuterClass.RobotState.parseFrom(bytes);
:}
SerializeRobotConfig maps config.Config.RobotConfig rc to byte[] {:
TestCounter.INSTANCE.numberSerializeRobotConfig += 1;
return rc.toByteArray();
:}
RobotStateToIntPosition maps robot.RobotStateOuterClass.RobotState rs to IntPosition {:
TestCounter.INSTANCE.numberLinkStateToIntPosition += 1;
robot.RobotStateOuterClass.RobotState.Position p = rs.getPosition();
return IntPosition.of((int) (Math.round(p.getX() * 10)), (int) (Math.round(p.getY() * 10)), (int) (Math.round(p.getZ() * 10)));
:}
CreateSpeedMessage maps double speed to config.Config.RobotConfig {:
TestCounter.INSTANCE.numberCreateSpeedMessage += 1;
return config.Config.RobotConfig.newBuilder()
.setSpeed(speed)
.build();
:}
aspect GrammarTypes {
public class TestCounter {
public static TestCounter INSTANCE = new TestCounter();
public int numberParseLinkState = 0;
public int numberSerializeRobotConfig = 0;
public int numberLinkStateToIntPosition = 0;
public int numberCreateSpeedMessage = 0;
public int numberInSafetyZone = 0;
public static void reset() {
TestCounter.INSTANCE = new TestCounter();
}
}
public class IntPosition {
private final int x, y, z;
private IntPosition(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public static IntPosition of(int x, int y, int z) {
return new IntPosition(x, y, z);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IntPosition that = (IntPosition) o;
return x == that.x &&
y == that.y &&
z == that.z;
}
@Override
public int hashCode() {
return java.util.Objects.hash(x, y, z);
}
@Override
public String toString() {
return "(" + x + ", " + y + ", " + z + ")";
}
}
inh Model RobotArm.model();
eq Model.getRobotArm().model() = this;
inh RobotArm Link.containingRobotArm();
eq RobotArm.getLink().containingRobotArm() = this;
eq RobotArm.getEndEffector().containingRobotArm() = this;
syn boolean RobotArm.isInSafetyZone() {
TestCounter.INSTANCE.numberInSafetyZone += 1;
for (Link link : getLinkList()) {
if (model().getZoneModel().isInSafetyZone(link.getCurrentPosition())) {
return true;
}
}
return model().getZoneModel().isInSafetyZone(getEndEffector().getCurrentPosition());
}
cache ZoneModel.isInSafetyZone(IntPosition pos);
syn boolean ZoneModel.isInSafetyZone(IntPosition pos) {
for (Zone sz : getSafetyZoneList()) {
for (Coordinate coordinate : sz.getCoordinateList()) {
if (coordinate.getPosition().equals(pos)) {
return true;
}
}
}
return false;
}
syn double RobotArm.speedLow() = 0.4d;
syn double RobotArm.speedHigh() = 1.0d;
syn double RobotArm.getAppropriateSpeed() {
return isInSafetyZone() ? speedLow() : speedHigh();
}
}
Model ::= RobotArm ZoneModel ;
ZoneModel ::= SafetyZone:Zone* ;
Zone ::= Coordinate* ;
RobotArm ::= Link* EndEffector /<AppropriateSpeed:double>/ ;
Link ::= <Name:String> <CurrentPosition:IntPosition> ;
EndEffector : Link;
Coordinate ::= <Position:IntPosition> ;
{
"joints": [
{"name": "Joint1", "topic": "robot/arm/joint1"},
{"name": "Joint2", "topic": "robot/arm/joint2"},
{"name": "EndEffector", "topic": "-", "isEndEffector": true}
],
"robotConfigTopic": "robot/config",
"dataConfigTopic": "-"
}
# Read one - Write two
Idea: Define Read-Update for one terminal, add dependencies to two other terminals, which each have Write-Update defined. Test, whether code gets generated correctly and that write is trigger for each of the two terminals upon read.
// --- update definitions ---
// OnSameNonterminal
receive OnSameNonterminal.Input;
send OnSameNonterminal.OutInteger;
send OnSameNonterminal.OutString;
// OnDifferentNonterminal
receive OnDifferentNonterminal.Input;
send TheOther.OutInteger;
send TheOther.OutString;
// --- dependency definitions ---
// OnSameNonterminal
OnSameNonterminal.OutInteger canDependOn OnSameNonterminal.Input as IntDependency;
OnSameNonterminal.OutString canDependOn OnSameNonterminal.Input as StringDependency;
// OnDifferentNonterminal
TheOther.OutInteger canDependOn OnDifferentNonterminal.Input as IntDependency;
TheOther.OutString canDependOn OnDifferentNonterminal.Input as StringDependency;
aspect Computation{
// OnSameNonterminal
syn int OnSameNonterminal.getOutInteger() = Integer.parseInt(getInput());
syn String OnSameNonterminal.getOutString() = "prefix" + getInput();
// OnDifferentNonterminal
syn int TheOther.getOutInteger() = Integer.parseInt(input());
syn String TheOther.getOutString() = "prefix" + input();
inh String TheOther.input();
eq OnDifferentNonterminal.getTheOther().input() = getInput();
}
A ::= OnSameNonterminal OnDifferentNonterminal ;
OnSameNonterminal ::= <Input:String> /<OutInteger:int>/ /<OutString:String>/ ;
OnDifferentNonterminal ::= <Input:String> TheOther* ;
TheOther ::= /<OutInteger:int>/ /<OutString:String>/ ;
// --- update definitions ---
// OnSameNonterminal
receive OnSameNonterminal.Input1;
receive OnSameNonterminal.Input2;
send OnSameNonterminal.OutInteger;
// OnDifferentNonterminal
receive OnDifferentNonterminal.Input1;
receive OnDifferentNonterminal.Input2;
send TheOther.OutInteger;
// --- dependency definitions ---
// OnSameNonterminal
OnSameNonterminal.OutInteger canDependOn OnSameNonterminal.Input1 as Int1Dependency;
OnSameNonterminal.OutInteger canDependOn OnSameNonterminal.Input2 as Int2Dependency;
// OnDifferentNonterminal
TheOther.OutInteger canDependOn OnDifferentNonterminal.Input1 as Int1Dependency;
TheOther.OutInteger canDependOn OnDifferentNonterminal.Input2 as Int2Dependency;
aspect Computation{
// OnSameNonterminal
syn int OnSameNonterminal.getOutInteger() = Integer.parseInt(getInput1() + getInput2());
// OnDifferentNonterminal
syn int TheOther.getOutInteger() = Integer.parseInt(input1() + input2());
inh String TheOther.input1();
eq OnDifferentNonterminal.getTheOther().input1() = getInput1();
inh String TheOther.input2();
eq OnDifferentNonterminal.getTheOther().input2() = getInput2();
}
A ::= OnSameNonterminal OnDifferentNonterminal ;
OnSameNonterminal ::= <Input1:String> <Input2:String> /<OutInteger:int>/ ;
OnDifferentNonterminal ::= <Input1:String> <Input2:String> TheOther* ;
TheOther ::= /<OutInteger:int>/ ;
# Token Value Send
Idea: 1) Test normal token send, 2) Test combined receive and send on same token, 3) Test combined receive, send and a dependency
// OnlySend
send OnlySend.Value using AddPostfix ;
// ReceiveAndSend
receive ReceiveAndSend.Value using AddPrefix ;
send ReceiveAndSend.Value using AddPostfix ;
// ReceiveSendAndDepend
receive ReceiveSendAndDepend.Value using AddPrefix ;
send ReceiveSendAndDepend.Value using AddPostfix ;
send ReceiveSendAndDepend.OtherOutput using AddPostfix ;
ReceiveSendAndDepend.OtherOutput canDependOn ReceiveSendAndDepend.Value as dependency1 ;
AddPrefix maps String s to String {:
System.out.println("receive " + s);
return "Pre-" + s;
:}
AddPostfix maps String s to String {:
System.out.println("send " + s);
return s + "-Post";
:}
aspect Computation{
// ReceiveSendAndDepend
syn String ReceiveSendAndDepend.getOtherOutput() = getValue() + "-T";
}
A ::= OnlySend ReceiveAndSend ReceiveSendAndDepend ;
OnlySend ::= <Value:String> ;
ReceiveAndSend ::= <Value:String> ;
ReceiveSendAndDepend ::= <Value:String> /<OtherOutput:String>/ ;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment