Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Willink2016-10-23 12:06:11 +0000
committerEd Willink2016-10-30 11:38:47 +0000
commit0aac37bb8c65e8cdb8b949248b1507c91772d8a3 (patch)
tree450708cf528fab6cadbbb592872959c1de1f17f5
parent3cc5dc7ff76317ff8c5cdae607930b9df68cd7d9 (diff)
downloadorg.eclipse.qvtd-0aac37bb8c65e8cdb8b949248b1507c91772d8a3.tar.gz
org.eclipse.qvtd-0aac37bb8c65e8cdb8b949248b1507c91772d8a3.tar.xz
org.eclipse.qvtd-0aac37bb8c65e8cdb8b949248b1507c91772d8a3.zip
[500962] Introduce distinct Strict/Simple (Incremental) Connections
-rw-r--r--plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java122
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/AbstractCompilerChain.java4
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/CompilerChain.java1
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractRegion2Mapping.java13
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractScheduledRegion2Mapping.java99
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/BasicRegion2Mapping.java30
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/QVTs2QVTiVisitor.java4
-rw-r--r--plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/evaluation/Execution2GraphVisitor.java8
-rw-r--r--plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeHelper.java14
-rw-r--r--plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeToStringVisitor.java11
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractConnection.java116
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractInvocation.java4
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Connection.java73
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Interval.java2
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/InvocationConstructor.java5
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleConnection.java31
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleIncrementalConnection.java (renamed from plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/UnenforcedConnection.java)8
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictConnection.java29
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictIncrementalConnection.java (renamed from plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/EnforcedConnection.java)6
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractConnectionInternal.java227
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIncrementalConnectionInternal.java180
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIntervalInternal.java36
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractInvocationConstructor.java26
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/IncrementalConnectionInternal.java (renamed from plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractUnenforcedConnectionInternal.java)4
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictConnectionInternal.java76
-rw-r--r--plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictIncrementalConnectionInternal.java (renamed from plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractEnforcedConnectionInternal.java)4
-rw-r--r--plugins/org.eclipse.qvtd.xtext.qvtimperative/src/org/eclipse/qvtd/xtext/qvtimperative/formatting/QVTimperativeFormatter.java7
-rw-r--r--tests/org.eclipse.qvtd.xtext.qvtimperative.tests/src/org/eclipse/qvtd/xtext/qvtimperative/tests/Tree2TallTree/Tree2TallTreeInstallManual.java11
28 files changed, 698 insertions, 453 deletions
diff --git a/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java b/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java
index c6fa21dd9..63b6641b1 100644
--- a/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java
+++ b/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java
@@ -98,14 +98,17 @@ import org.eclipse.qvtd.codegen.qvticgmodel.CGTransformation;
import org.eclipse.qvtd.codegen.qvticgmodel.CGTypedModel;
import org.eclipse.qvtd.codegen.qvticgmodel.util.QVTiCGModelVisitor;
import org.eclipse.qvtd.codegen.utilities.QVTiCGUtil;
+import org.eclipse.qvtd.pivot.qvtimperative.AppendParameter;
import org.eclipse.qvtd.pivot.qvtimperative.AppendParameterBinding;
import org.eclipse.qvtd.pivot.qvtimperative.BufferStatement;
import org.eclipse.qvtd.pivot.qvtimperative.ConnectionVariable;
+import org.eclipse.qvtd.pivot.qvtimperative.GuardParameter;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeTransformation;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeTypedModel;
import org.eclipse.qvtd.pivot.qvtimperative.LoopParameterBinding;
import org.eclipse.qvtd.pivot.qvtimperative.Mapping;
import org.eclipse.qvtd.pivot.qvtimperative.MappingCall;
+import org.eclipse.qvtd.pivot.qvtimperative.MappingParameter;
import org.eclipse.qvtd.pivot.qvtimperative.MappingParameterBinding;
import org.eclipse.qvtd.pivot.qvtimperative.ObservableStatement;
import org.eclipse.qvtd.pivot.qvtimperative.SetStatement;
@@ -158,6 +161,16 @@ public class QVTiCG2JavaVisitor extends CG2JavaVisitor<@NonNull QVTiCodeGenerato
this.useGot = isIncremental;
}
+ protected void appendConnectionBinding(@NonNull CGMappingCallBinding cgMappingCallBinding) {
+ TypeDescriptor checkedType = needsTypeCheck(cgMappingCallBinding);
+ if (checkedType != null) {
+ js.append("(");
+ js.appendClassReference(checkedType);
+ js.append(")");
+ }
+ js.appendValueName(cgMappingCallBinding.getValue());
+ }
+
protected void appendEcoreSet(@NonNull CGValuedElement cgSlot, @NonNull EStructuralFeature eStructuralFeature, @NonNull CGValuedElement cgInit) {
if (eStructuralFeature.isMany()) {
String getAccessor = genModelHelper.getGetAccessor(eStructuralFeature);
@@ -1203,20 +1216,6 @@ public class QVTiCG2JavaVisitor extends CG2JavaVisitor<@NonNull QVTiCodeGenerato
return allImports;
}
- private @Nullable Iterable<@NonNull CGMappingCallBinding> getAppendBindings(@NonNull List<CGMappingCallBinding> cgMappingCallBindings) {
- List<@NonNull CGMappingCallBinding> bindings = null;
- for (CGMappingCallBinding cgMappingCallBinding : cgMappingCallBindings) {
- Element ast = cgMappingCallBinding.getAst();
- if (ast instanceof AppendParameterBinding) {
- if (bindings == null) {
- bindings = new ArrayList<>();
- }
- bindings.add(cgMappingCallBinding);
- }
- }
- return bindings;
- }
-
private EObject getContainer(EObject eObject) {
EObject eContainer = eObject.eContainer();
if (eContainer != null) {
@@ -1230,20 +1229,6 @@ public class QVTiCG2JavaVisitor extends CG2JavaVisitor<@NonNull QVTiCodeGenerato
return null;
}
- private @Nullable Iterable<@NonNull CGMappingCallBinding> getConsumeBindings(@NonNull List<CGMappingCallBinding> cgMappingCallBindings) {
- List<@NonNull CGMappingCallBinding> bindings = null;
- for (CGMappingCallBinding cgMappingCallBinding : cgMappingCallBindings) {
- Element ast = cgMappingCallBinding.getAst();
- if (!(ast instanceof AppendParameterBinding)) {
- if (bindings == null) {
- bindings = new ArrayList<>();
- }
- bindings.add(cgMappingCallBinding);
- }
- }
- return bindings;
- }
-
@Override
protected @Nullable EStructuralFeature getESObject(@NonNull Property asProperty) {
EObject esObject = asProperty.getESObject();
@@ -1373,7 +1358,18 @@ public class QVTiCG2JavaVisitor extends CG2JavaVisitor<@NonNull QVTiCodeGenerato
return true;
}
Mapping asMapping = ClassUtil.nonNullState((Mapping) cgMapping.getAst());
- return QVTimperativeUtil.isObserver(asMapping);
+ if (QVTimperativeUtil.isObserver(asMapping)) {
+ return true;
+ }
+ for (MappingParameter asParameter : asMapping.getOwnedParameters()) {
+ if (asParameter instanceof AppendParameter) {
+ return true;
+ }
+ if (asParameter instanceof GuardParameter) { // FIXME only if 'consumes'
+ return true;
+ }
+ }
+ return false;
}
@Override
@@ -1828,63 +1824,21 @@ public class QVTiCG2JavaVisitor extends CG2JavaVisitor<@NonNull QVTiCodeGenerato
// Emit the mapping call.
//
Iterable<@NonNull CGMappingCallBinding> iterateBindings = getIterateBindings(cgMappingCallBindings);
- if (isIncremental && (iterateBindings == null)) {
- js.append(getMappingCtorName(cgReferredMapping));
- js.append(".connect(");
- Iterable<@NonNull CGMappingCallBinding> consumeBindings = getConsumeBindings(cgMappingCallBindings);
- Iterable<@NonNull CGMappingCallBinding> appendBindings = getAppendBindings(cgMappingCallBindings);
- if (consumeBindings == null) {
- js.append("null");
- }
- else {
- js.append("new ");
- js.appendClassReference(true, Connection.class);
- js.append("[]{");
- boolean isFirst = true;
- for (@NonNull CGMappingCallBinding cgMappingCallBinding : consumeBindings) {
- if (!isFirst) {
- js.append(", ");
- }
- TypeDescriptor checkedType = needsTypeCheck(cgMappingCallBinding);
- if (checkedType != null) {
- js.append("(");
- js.appendClassReference(checkedType);
- js.append(")");
- }
- js.appendValueName(cgMappingCallBinding.getValue());
- isFirst = false;
- }
- js.append("}");
- }
- js.append(", ");
- if (appendBindings == null) {
- js.append("null");
- }
- else {
- js.append("new ");
- js.appendClassReference(true, Connection.class);
- js.append("[]{");
- boolean isFirst = true;
- for (@NonNull CGMappingCallBinding cgMappingCallBinding : appendBindings) {
- if (!isFirst) {
- js.append(", ");
- }
- TypeDescriptor checkedType = needsTypeCheck(cgMappingCallBinding);
- if (checkedType != null) {
- js.append("(");
- js.appendClassReference(checkedType);
- js.append(")");
- }
- js.appendValueName(cgMappingCallBinding.getValue());
- isFirst = false;
- }
- js.append("}");
+ String mappingCtorName = getMappingCtorName(cgReferredMapping);
+ if (useClass(cgReferredMapping) && (iterateBindings == null)) {
+ for (CGMappingCallBinding cgMappingCallBinding : cgMappingCallBindings) {
+ Element ast = cgMappingCallBinding.getAst();
+ js.append(mappingCtorName);
+ js.append(".");
+ js.append(ast instanceof AppendParameterBinding ? "addAppendedConnection" : "addConsumedConnection");
+ js.append("(");
+ appendConnectionBinding(cgMappingCallBinding);
+ js.append(");\n");
}
- js.append(");\n");
}
else {
if (useClass(cgReferredMapping)) {
- js.append(getMappingCtorName(cgReferredMapping));
+ js.append(mappingCtorName);
js.append(".invoke(");
}
else {
@@ -1937,10 +1891,10 @@ public class QVTiCG2JavaVisitor extends CG2JavaVisitor<@NonNull QVTiCodeGenerato
for (@NonNull CGAccumulator cgAccumulator : cgAccumulators) {
Element ast = cgAccumulator.getAst();
js.append("final ");
- js.appendClassReference(true, Connection.class);
+ js.appendClassReference(true, isIncremental ? Connection.Incremental.class : Connection.class);
js.append(" ");
js.appendValueName(cgAccumulator);
- js.append(" = createConnection(");
+ js.append(isIncremental ? " = createIncrementalConnection(" : " = createConnection(");
js.appendString(QVTiCGUtil.getName(cgAccumulator));
js.append(", ");
js.appendValueName(cgAccumulator.getTypeId());
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/AbstractCompilerChain.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/AbstractCompilerChain.java
index c65f7434d..df5428f32 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/AbstractCompilerChain.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/AbstractCompilerChain.java
@@ -161,6 +161,10 @@ public abstract class AbstractCompilerChain extends CompilerUtil implements Comp
if (javaExtraPrefix != null) {
options.setPackagePrefix(javaExtraPrefix);
}
+ Boolean javaIsIncremental = compilerChain.getOption(JAVA_STEP, JAVA_INCREMENTAL_KEY);
+ if (javaIsIncremental != null) {
+ options.setIsIncremental(true);
+ }
String javaCodeSource;
try {
javaCodeSource = cg.generateClassFile();
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/CompilerChain.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/CompilerChain.java
index 150d42d77..d2563f7a1 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/CompilerChain.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/CompilerChain.java
@@ -74,6 +74,7 @@ public interface CompilerChain
public static final @NonNull Key<Boolean> VALIDATE_KEY = new Key<Boolean>("validate");
public static final @NonNull Key<@Nullable String> JAVA_EXTRA_PREFIX_KEY = new Key<@Nullable String>("javaExtraPrefix");
+ public static final @NonNull Key<@Nullable Boolean> JAVA_INCREMENTAL_KEY = new Key<@Nullable Boolean>("javaIncremental");
public static final @NonNull String GENMODEL_BASE_PREFIX = "genModelBasePrefix";
public static final @NonNull String GENMODEL_COPYRIGHT_TEXT = "genModelCopyrightText";
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractRegion2Mapping.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractRegion2Mapping.java
index 983797dc9..9249977cc 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractRegion2Mapping.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractRegion2Mapping.java
@@ -371,19 +371,6 @@ public abstract class AbstractRegion2Mapping
return false;
}
- // FIXME temporary backward compatibility
- protected void setLegacyIsPolled(@NonNull Mapping calledMapping, @NonNull MappingParameterBinding mappingParameterBinding) {
- /* for (Domain domain : calledMapping.getDomain()) {
- if (domain instanceof ImperativeDomain) {
- ImperativeDomain imperativeDomain = (ImperativeDomain)domain;
- if (imperativeDomain.getCheckedProperties().size() > 0) {
- mappingParameterBinding.setIsPolled(true);
- return;
- }
- }
- } */
- }
-
@Override
public String toString() {
return mapping.toString();
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractScheduledRegion2Mapping.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractScheduledRegion2Mapping.java
index 24eef481e..1f1bfdae9 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractScheduledRegion2Mapping.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/AbstractScheduledRegion2Mapping.java
@@ -31,6 +31,7 @@ import org.eclipse.qvtd.pivot.qvtimperative.ConnectionVariable;
import org.eclipse.qvtd.pivot.qvtimperative.GuardParameter;
import org.eclipse.qvtd.pivot.qvtimperative.LoopVariable;
import org.eclipse.qvtd.pivot.qvtimperative.Mapping;
+import org.eclipse.qvtd.pivot.qvtimperative.MappingCall;
import org.eclipse.qvtd.pivot.qvtimperative.MappingParameterBinding;
import org.eclipse.qvtd.pivot.qvtimperative.MappingStatement;
import org.eclipse.qvtd.pivot.qvtimperative.SimpleParameter;
@@ -69,13 +70,11 @@ public abstract class AbstractScheduledRegion2Mapping extends AbstractRegion2Map
}
}
MappingParameterBinding mappingParameterBinding = createMappingParameterBinding(connectionExpression, calledGuardNode, loopVariables);
- setLegacyIsPolled(calledMapping, mappingParameterBinding);
mappingParameterBindings.add(mappingParameterBinding);
}
for (@NonNull Node callingNode : calledGuardNode.getUsedBindingSources()) {
if (callingNode.getRegion() == region) {
MappingParameterBinding mappingParameterBinding = createMappingParameterBinding(createSelectByKind(callingNode), calledGuardNode, loopVariables);
- setLegacyIsPolled(calledMapping, mappingParameterBinding);
mappingParameterBindings.add(mappingParameterBinding);
}
}
@@ -120,65 +119,71 @@ public abstract class AbstractScheduledRegion2Mapping extends AbstractRegion2Map
return mappingCallStatement;
}
- /* protected @NonNull MappingStatement createCalls(@Nullable MappingStatement mappingStatement, @NonNull Region calledRegion) {
+ protected @NonNull MappingStatement createInstall(@NonNull Region calledRegion) {
+ // Iterable<Connection> connectionRegions = getConnectionRegions(calledRegion);
+ // assert !calledRegion.isConnectionRegion();
AbstractRegion2Mapping calledRegion2Mapping = visitor.getRegion2Mapping(calledRegion);
- Mapping calledMapping = calledRegion2Mapping.getMapping();
- Map<@NonNull Variable, @NonNull OCLExpression> loopVariables = new HashMap<@NonNull Variable, @NonNull OCLExpression>();
- List<@NonNull MappingParameterBinding> mappingParameterBindings = new ArrayList<@NonNull MappingParameterBinding>();
+ // Mapping calledMapping = calledRegion2Mapping.getMapping();
+ List<@NonNull MappingParameterBinding> mappingParameterBindings = new ArrayList<>();
for (@NonNull Node calledGuardNode : calledRegion2Mapping.getGuardNodes()) {
+ VariableDeclaration guardVariable = calledRegion2Mapping.getGuardVariable(calledGuardNode);
NodeConnection callingConnection = calledGuardNode.getIncomingPassedConnection();
- if (callingConnection != null) {
- Variable connectionVariable = connection2variable.get(callingConnection);
- MappingParameterBinding mappingParameterBinding;
- if (connectionVariable != null) {
- mappingParameterBinding = createMappingParameterBinding(PivotUtil.createVariableExp(connectionVariable), calledGuardNode, loopVariables);
- }
- else {
- Node callingNode = callingConnection.getSource(region);
- mappingParameterBinding = createMappingParameterBinding(createSelectByKind(callingNode), calledGuardNode, loopVariables);
- }
- setLegacyIsPolled(calledMapping, mappingParameterBinding);
- mappingParameterBindings.add(mappingParameterBinding);
+ assert callingConnection != null;
+ ConnectionVariable connectionVariable = connection2variable.get(callingConnection);
+ assert connectionVariable != null;
+ if (guardVariable instanceof GuardParameter) {
+ mappingParameterBindings.add(helper.createGuardParameterBinding((GuardParameter) guardVariable, connectionVariable));
+ }
+ else {
+ mappingParameterBindings.add(helper.createAppendParameterBinding((AppendParameter) guardVariable, connectionVariable));
}
for (@NonNull Node callingNode : calledGuardNode.getUsedBindingSources()) {
if (callingNode.getRegion() == region) {
- MappingParameterBinding mappingParameterBinding = createMappingParameterBinding(createSelectByKind(callingNode), calledGuardNode, loopVariables);
- setLegacyIsPolled(calledMapping, mappingParameterBinding);
- mappingParameterBindings.add(mappingParameterBinding);
+ OCLExpression sourceExpression = createSelectByKind(callingNode);
+ mappingParameterBindings.add(helper.createSimpleParameterBinding((SimpleParameter) guardVariable, sourceExpression));
}
}
}
- for (@NonNull Node node : calledRegion.getPredicatedNodes()) {
- NodeConnection connection = node.getIncomingUsedConnection();
- if (connection != null) {
- Node sourceNode = connection.basicGetSource(region);
- if (sourceNode != null) {
- OCLExpression sourceExpression = createVariableExp(sourceNode);
- Variable guardVariable = calledRegion2Mapping.getGuardVariable(connection.getTarget(region));
- mappingParameterBindings.add(QVTimperativeUtil.createMappingParameterBinding(guardVariable, sourceExpression));
- }
- }
- }
- for (@NonNull NodeConnection intermediateConnection : calledRegion.getIntermediateConnections()) {
- Variable calledConnectionVariable = calledRegion2Mapping.getConnectionVariable(intermediateConnection);
- Variable callingConnectionVariable = outgoing2variable.get(intermediateConnection);
- if (callingConnectionVariable == null) {
- callingConnectionVariable = connection2variable.get(intermediateConnection);
- }
+ /* for (@NonNull NodeConnection headConnection : calledRegion.getHeadConnections()) { // FIXME unify headConnections/headNodes
+ Variable calledConnectionVariable = calledRegion2Mapping.getConnectionVariable(headConnection);
+ Variable callingConnectionVariable = connection2variable.get(headConnection);
assert callingConnectionVariable != null;
OCLExpression sourceExpression = PivotUtil.createVariableExp(callingConnectionVariable);
mappingParameterBindings.add(QVTimperativeUtil.createMappingParameterBinding(calledConnectionVariable, sourceExpression));
+ } */
+ for (@NonNull NodeConnection intermediateConnection : calledRegion.getIntermediateConnections()) {
+ ConnectionVariable calledConnectionVariable = calledRegion2Mapping.getConnectionVariable(intermediateConnection);
+ /* OCLExpression connectionExpression = null;
+ if (guardVariable2expression != null) {
+ connectionExpression = guardVariable2expression.get(calledConnectionVariable);
+ }
+ if (connectionExpression == null) { */
+ ConnectionVariable callingConnectionVariable = connection2variable.get(intermediateConnection);
+ assert callingConnectionVariable != null;
+ /* OCLExpression sourceExpression = PivotUtil.createVariableExp(callingConnectionVariable);
+ Type calledType = calledConnectionVariable.getType();
+ Type callingType = callingConnectionVariable.getType();
+ assert calledType != null;
+ assert callingType != null;
+ if (getCollectionDepth(calledType) < getCollectionDepth(callingType)) {
+ LoopVariable loopVariable = helper.createLoopVariable("loop" + loopVariables.size(), calledType);//, true, sourceExpression);
+ loopVariables.put(loopVariable, sourceExpression);
+ sourceExpression = PivotUtil.createVariableExp(loopVariable);
+ }
+ connectionExpression = sourceExpression;
+ } */
+ mappingParameterBindings.add(QVTimperativeUtil.createAppendParameterBinding((AppendParameter)calledConnectionVariable, callingConnectionVariable));
}
Collections.sort(mappingParameterBindings, QVTimperativeUtil.MappingParameterBindingComparator.INSTANCE);
- MappingStatement mappingCallStatement = calledRegion2Mapping.createMappingCall(mappingParameterBindings);
- for (Map.Entry<@NonNull Variable, @NonNull OCLExpression> loopEntry : loopVariables.entrySet()) {
- @NonNull Variable loopVariable = loopEntry.getKey();
- @NonNull OCLExpression loopSource = loopEntry.getValue();
- mappingCallStatement = QVTimperativeUtil.createMappingLoop(loopSource, loopVariable, mappingCallStatement);
- }
- mappingStatement = QVTimperativeUtil.addMappingStatement(mappingStatement, mappingCallStatement);
- return mappingStatement;
- } */
+ MappingCall mappingCallStatement = calledRegion2Mapping.createMappingCall(mappingParameterBindings);
+ mappingCallStatement.setIsInstall(true);
+ // for (Map./*@NonNull*/Entry<@NonNull LoopVariable, @NonNull OCLExpression> loopEntry : loopVariables.entrySet()) {
+ // @NonNull LoopVariable loopVariable = loopEntry.getKey();
+ // @NonNull OCLExpression loopSource = loopEntry.getValue();
+ // mappingCallStatement = QVTimperativeUtil.createMappingLoop(loopSource, loopVariable, mappingCallStatement);
+ // }
+ return mappingCallStatement;
+ }
private @NonNull MappingParameterBinding createMappingParameterBinding(@NonNull OCLExpression sourceExpression, @NonNull Node targetNode,
@NonNull Map<@NonNull LoopVariable, @NonNull OCLExpression> loopVariables) {
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/BasicRegion2Mapping.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/BasicRegion2Mapping.java
index 3711678d1..ef91efcc4 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/BasicRegion2Mapping.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/BasicRegion2Mapping.java
@@ -691,6 +691,21 @@ public class BasicRegion2Mapping extends AbstractRegion2Mapping
return node2variable.get(node);
}
+ /**
+ * Create accumulation assignments for connections.
+ */
+ private void createAddStatements() {
+ if (connection2variable != null) {
+ for (@NonNull NodeConnection connection : connection2variable.keySet()) {
+ Node sourceNode = connection.getSource(region);
+ OCLExpression variableExpression = createVariableExp(sourceNode);
+ ConnectionVariable connectionVariable = connection2variable.get(connection);
+ assert connectionVariable != null;
+ createAddStatement(connectionVariable, variableExpression);
+ }
+ }
+ }
+
private @NonNull DeclareStatement createBottomVariable(@NonNull Node node, @NonNull OCLExpression initExpression) {
// String string = initExpression.toString();
Type variableType = node.getCompleteClass().getPrimaryClass();
@@ -728,21 +743,6 @@ public class BasicRegion2Mapping extends AbstractRegion2Mapping
}
/**
- * Create accumulation assignments for connections.
- */
- private void createAddStatements() {
- if (connection2variable != null) {
- for (@NonNull NodeConnection connection : connection2variable.keySet()) {
- Node sourceNode = connection.getSource(region);
- OCLExpression variableExpression = createVariableExp(sourceNode);
- ConnectionVariable connectionVariable = connection2variable.get(connection);
- assert connectionVariable != null;
- createAddStatement(connectionVariable, variableExpression);
- }
- }
- }
-
- /**
* Create a predicate expression for each TRUE 'head'.
*/
private void createExternalPredicates() {
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/QVTs2QVTiVisitor.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/QVTs2QVTiVisitor.java
index a06791894..4fca645f5 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/QVTs2QVTiVisitor.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvti/QVTs2QVTiVisitor.java
@@ -18,7 +18,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
@@ -492,7 +491,8 @@ public class QVTs2QVTiVisitor extends QVTimperativeHelper implements Visitor<Ele
region2Mapping.createStatements();
// }
}
- ECollections.sort(qvtiTransformation.getRule(), NameUtil.NameableComparator.INSTANCE);
+ // Mappings are in schedule index order.
+ // ECollections.sort(qvtiTransformation.getRule(), NameUtil.NameableComparator.INSTANCE);
/* org.eclipse.ocl.pivot.Package rootPackage = PivotUtil.createPackage("", "yy", "zz", null);
rootPackage.getOwnedClasses().add(qvtiTransformation);
Model model = PivotUtil.createModel(ImperativeModel.class, QVTimperativePackage.Literals.IMPERATIVE_MODEL, null);
diff --git a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/evaluation/Execution2GraphVisitor.java b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/evaluation/Execution2GraphVisitor.java
index 19fd86596..e7e54ca36 100644
--- a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/evaluation/Execution2GraphVisitor.java
+++ b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/evaluation/Execution2GraphVisitor.java
@@ -352,9 +352,11 @@ public class Execution2GraphVisitor extends AbstractExecutionVisitor<@Nullable O
@Override
public @Nullable Object visitConnection(@NonNull Connection object) {
GraphNode connectionNode = getConnectionNode(object);
- for (@NonNull InvocationConstructor producer : object.getAppenders()) {
- GraphNode producerNode = getInvocationConstructorNode(producer);
- appendEdge(producerNode, connectionNode, "brown", null);
+ if (object instanceof Connection.Incremental) {
+ for (@NonNull InvocationConstructor producer : ((Connection.Incremental)object).getAppenders()) {
+ GraphNode producerNode = getInvocationConstructorNode(producer);
+ appendEdge(producerNode, connectionNode, "brown", null);
+ }
}
for (@NonNull InvocationConstructor consumer : object.getConsumers()) {
GraphNode consumerNode = getInvocationConstructorNode(consumer);
diff --git a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeHelper.java b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeHelper.java
index 227c9746d..9bc3175e3 100644
--- a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeHelper.java
+++ b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeHelper.java
@@ -12,6 +12,7 @@ package org.eclipse.qvtd.pivot.qvtimperative.utilities;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
@@ -19,6 +20,7 @@ import org.eclipse.ocl.pivot.utilities.EnvironmentFactory;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseHelper;
import org.eclipse.qvtd.pivot.qvtimperative.AddStatement;
import org.eclipse.qvtd.pivot.qvtimperative.AppendParameter;
+import org.eclipse.qvtd.pivot.qvtimperative.AppendParameterBinding;
import org.eclipse.qvtd.pivot.qvtimperative.BufferStatement;
import org.eclipse.qvtd.pivot.qvtimperative.CheckStatement;
import org.eclipse.qvtd.pivot.qvtimperative.ConnectionVariable;
@@ -56,6 +58,13 @@ public class QVTimperativeHelper extends QVTbaseHelper
return asVariable;
}
+ public @NonNull AppendParameterBinding createAppendParameterBinding(@NonNull AppendParameter variable, @NonNull ConnectionVariable value) {
+ AppendParameterBinding mappingParameterBinding = QVTimperativeFactory.eINSTANCE.createAppendParameterBinding();
+ mappingParameterBinding.setBoundVariable(variable);
+ mappingParameterBinding.setValue(value);
+ return mappingParameterBinding;
+ }
+
public @NonNull BufferStatement createBufferStatement(@NonNull String name, @NonNull Type asType, boolean isRequired, @Nullable OCLExpression initExpression) {
BufferStatement asVariable = QVTimperativeFactory.eINSTANCE.createBufferStatement();
asVariable.setName(name);
@@ -94,7 +103,10 @@ public class QVTimperativeHelper extends QVTbaseHelper
GuardParameterBinding mappingParameterBinding = QVTimperativeFactory.eINSTANCE.createGuardParameterBinding();
mappingParameterBinding.setBoundVariable(variable);
mappingParameterBinding.setValue(value);
- mappingParameterBinding.setIsCheck(!value.getType().conformsTo(standardLibrary, ClassUtil.nonNullState(variable.getType())));
+ CollectionType collectionType = (CollectionType) value.getType();
+ Type elementType = collectionType.getElementType();
+ Type guardType = ClassUtil.nonNullState(variable.getType());
+ mappingParameterBinding.setIsCheck(!elementType.conformsTo(standardLibrary, guardType));
return mappingParameterBinding;
}
diff --git a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeToStringVisitor.java b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeToStringVisitor.java
index f353ae814..cc84e29c0 100644
--- a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeToStringVisitor.java
+++ b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/QVTimperativeToStringVisitor.java
@@ -111,7 +111,7 @@ public class QVTimperativeToStringVisitor extends QVTbaseToStringVisitor impleme
@Override
public @Nullable String visitBufferStatement(@NonNull BufferStatement asVariable) {
if (asVariable.isIsStrict()) {
- context.append("strict ");
+ context.append("«strict»");
}
append("buffer ");
appendName(asVariable);
@@ -230,15 +230,18 @@ public class QVTimperativeToStringVisitor extends QVTbaseToStringVisitor impleme
@Override
public @Nullable String visitMapping(@NonNull Mapping asMapping) {
- // if (asMapping.isIsStrict()) {
- // context.append("strict ");
- // }
+ if (asMapping.isIsStrict()) {
+ context.append("«strict»");
+ }
appendQualifiedName(asMapping);
return null;
}
@Override
public @Nullable String visitMappingCall(@NonNull MappingCall object) {
+ if (object.isIsInstall()) {
+ append("«install»");
+ }
appendQualifiedName(object.getReferredMapping());
append(" {");
boolean isFirst = true;
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractConnection.java
new file mode 100644
index 000000000..0a7fce165
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractConnection.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Willink Transformations and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.qvtd.runtime.evaluation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.ocl.pivot.ids.CollectionTypeId;
+
+public abstract class AbstractConnection implements Connection
+{
+ protected final boolean debugAppends = AbstractTransformer.APPENDS.isActive();
+ protected final @NonNull Interval interval;
+ protected final @NonNull String name;
+ protected final @NonNull CollectionTypeId typeId;
+
+ /**
+ * The consumers of each appended value.
+ */
+ protected final @NonNull List<@NonNull InvocationConstructor> consumers = new ArrayList<>();
+
+ /**
+ * Singly linked list element of connections awaiting propagation from their interval, null when last/unlinked.
+ */
+ private @Nullable AbstractConnection nextConnection = null;
+
+ /**
+ * True when this connection is part of the interval's list of connections awaiting propagation.
+ */
+ private boolean isQueued = false;
+
+ protected AbstractConnection(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ this.interval = interval;
+ this.name = name;
+ this.typeId = typeId;
+ }
+
+ @Override
+ public <R> R accept(@NonNull ExecutionVisitor<R> visitor) {
+ return visitor.visitConnection(this);
+ }
+
+ @Override
+ public boolean addConsumer(@NonNull InvocationConstructor consumer) {
+ // assert listOfValueAndConsumingInvocations.isEmpty() || listOfValueAndConsumingInvocations.get(0).;
+ if (!consumers.contains(consumer)) {
+ consumers.add(consumer);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public @NonNull Iterable<@NonNull InvocationConstructor> getConsumers() {
+ return consumers;
+ }
+
+ @Override
+ public @NonNull String getName() {
+ return name;
+ }
+
+ public final @Nullable AbstractConnection getNextConnection() {
+ return nextConnection;
+ }
+
+ @Override
+ public void propagate() {
+ for (@NonNull InvocationConstructor consumer : consumers) {
+ consumer.propagate();
+ }
+ }
+
+ protected final void queue() {
+ if (!isQueued) {
+ isQueued = true;
+ interval.queue(this);
+ }
+ }
+
+ public void resetQueued() {
+ isQueued = false;
+ this.nextConnection = null;
+ }
+
+ public void setNextConnection(@NonNull AbstractConnection nextConnection) {
+ assert nextConnection != this;
+ assert isQueued;
+ this.nextConnection = nextConnection;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append("<");
+ s.append(interval.getIndex());
+ s.append(">");
+ s.append(name);
+ // s.append(" : ");
+ // s.append(typeId);
+ s.append("[");
+ s.append(getCapacity());
+ s.append("]");
+ return s.toString();
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractInvocation.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractInvocation.java
index 4b3dd1e4d..2cc6fadc0 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractInvocation.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractInvocation.java
@@ -72,6 +72,10 @@ public abstract class AbstractInvocation extends AbstractInvocationInternal
return constructor.getInterval().createConnection(name, typeId, isStrict);
}
+ protected Connection.@NonNull Incremental createIncrementalConnection(@NonNull String name, @NonNull CollectionTypeId typeId, boolean isStrict) {
+ return constructor.getInterval().createIncrementalConnection(name, typeId, isStrict);
+ }
+
@Override
public @NonNull Iterable<@NonNull Object> getCreatedObjects() {
return createdObjects != null ? createdObjects : EMPTY_OBJECT_LIST;
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Connection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Connection.java
index 34b0193a1..0d99d4b53 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Connection.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Connection.java
@@ -27,59 +27,62 @@ import org.eclipse.ocl.pivot.utilities.Nameable;
*/
public interface Connection extends ExecutionVisitable, Nameable
{
+ public interface Incremental extends Connection
+ {
+ void check();
+
+ /**
+ * Remove the revoked entries and update the internal indexes accordingly.
+ */
+ void cleanup();
+
+ void consume(int elementIndex, @NonNull Invocation mapping);
+
+ @NonNull Iterable<@NonNull InvocationConstructor> getAppenders();
+
+ /**
+ * Replace the old value at connectionKey by newValue.
+ *
+ * If the old value is a multiple value in a unique value connection, the multi-value count is decremented
+ * and a new entry created for the newValue by delegating to append to enforce uniqueness of the newValue.
+ *
+ * Otherwise the old value is removed, its consumingInvocations are invalidated
+ * so that they recompute with the newValue which replaces the old.
+ */
+ @NonNull Object replace(@NonNull Object connectionKey, @NonNull Object newValue);
+
+ /**
+ * Revoke, inverse append, the old value at connectionKey.
+ *
+ * If the old value is a multiple value in a unique value connection, the multi-value count is decremented.
+ *
+ * Otherwise the old value is removed, its consumingInvocations are revoked
+ * so that their appends are also revoked.
+ */
+ void revoke(@NonNull Object connectionKey);
+ }
+
void addAppender(@NonNull InvocationConstructor appendingInvoker);
- void addConsumer(@NonNull InvocationConstructor consumingInvoker);
+ boolean addConsumer(@NonNull InvocationConstructor consumingInvoker);
/**
* Append aValue to the contents, enforcing uniqueness if necessary, and waking up the overall
* connection manager to schedule a propagate() to consumers when convenient.
+ *
+ * Return the new entry.
*/
@NonNull Object append(@NonNull Object aValue);
- void check();
-
- /**
- * Remove the revoked entries and update the internal indexes accordingly.
- */
- void cleanup();
-
- void consume(int elementIndex, @NonNull Invocation mapping);
-
- @NonNull Iterable<@NonNull InvocationConstructor> getAppenders();
-
int getCapacity();
@NonNull Iterable<@NonNull InvocationConstructor> getConsumers();
- // @NonNull Iterable<@NonNull Invocation> getConsumers(int i);
-
@Nullable Object getValue(int i);
int getValues();
void propagate();
- /**
- * Replace the old value at connectionKey by newValue.
- *
- * If the old value is a multiple value in a unique value connection, the multi-value count is decremented
- * and a new entry created for the newValue by delegating to append to enforce uniqueness of the newValue.
- *
- * Otherwise the old value is removed, its consumingInvocations are invalidated
- * so that they recompute with the newValue which replaces the old.
- */
- @NonNull Object replace(@NonNull Object connectionKey, @NonNull Object newValue);
-
- /**
- * Revoke, inverse append, the old value at connectionKey.
- *
- * If the old value is a multiple value in a unique value connection, the multi-value count is decremented.
- *
- * Otherwise the old value is removed, its consumingInvocations are revoked
- * so that their appends are also revoked.
- */
- void revoke(@NonNull Object connectionKey);
-
<@NonNull T> @NonNull Iterable<T> typedIterable(Class<T> elementClass);
} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Interval.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Interval.java
index ce1ffb415..7792f5407 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Interval.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Interval.java
@@ -24,6 +24,8 @@ public interface Interval extends ExecutionVisitable, Nameable
{
@NonNull Connection createConnection(@NonNull String name, @NonNull CollectionTypeId typeId, boolean isStrict);
+ Connection.@NonNull Incremental createIncrementalConnection(@NonNull String name, @NonNull CollectionTypeId typeId, boolean isStrict);
+
boolean flush();
@NonNull Iterable<@NonNull Connection> getConnections();
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/InvocationConstructor.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/InvocationConstructor.java
index 03d9334b4..55a96ecd7 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/InvocationConstructor.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/InvocationConstructor.java
@@ -22,10 +22,13 @@ public interface InvocationConstructor extends ExecutionVisitable, Nameable
{
public interface Incremental extends InvocationConstructor
{
+
int nextSequence();
}
- void addConsumedConection(@NonNull Connection connection);
+ void addAppendedConnection(@NonNull Connection connection);
+
+ void addConsumedConnection(@NonNull Connection connection);
@NonNull Interval getInterval();
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleConnection.java
new file mode 100644
index 000000000..962e54793
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleConnection.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Willink Transformations and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.qvtd.runtime.evaluation;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.ocl.pivot.ids.CollectionTypeId;
+import org.eclipse.qvtd.runtime.internal.evaluation.AbstractConnectionInternal;
+
+/**
+ * A SimpleConnection maintains the unique values between one or more sources,
+ * typically Mappings, that invoke append() and one or more consumers that consume each value.
+ *
+ * It is assumed that the overall application enforces unqiueness externally if uniqueness of values is required.
+ * Use StrictConnection to enforce uniqueness internally.
+ *
+ * Incremental update is not supported.
+ */
+public class SimpleConnection extends AbstractConnectionInternal
+{
+ public SimpleConnection(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ super(interval, name, typeId);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/UnenforcedConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleIncrementalConnection.java
index 1f5d06015..aa9196da9 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/UnenforcedConnection.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleIncrementalConnection.java
@@ -12,20 +12,20 @@ package org.eclipse.qvtd.runtime.evaluation;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
-import org.eclipse.qvtd.runtime.internal.evaluation.AbstractUnenforcedConnectionInternal;
+import org.eclipse.qvtd.runtime.internal.evaluation.IncrementalConnectionInternal;
/**
* An UnenforcedConnection maintains the values between one or more sources, typically Mappings, that
* invoke append() and one or more consumers that consume each value.
*
* It is assumed that the overall application enforces unqiueness externally if uniqueness of values is required.
- * Use EnforcedConnection to enforce uniqueness internally.
+ * Use StrictIncrementalConnection to enforce uniqueness internally.
*
* Incremental update is supported by a revoke() or an append(), or a replace() of an appended value.
*/
-public class UnenforcedConnection extends AbstractUnenforcedConnectionInternal
+public class SimpleIncrementalConnection extends IncrementalConnectionInternal
{
- public UnenforcedConnection(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ public SimpleIncrementalConnection(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
super(interval, name, typeId);
}
} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictConnection.java
new file mode 100644
index 000000000..0b1de4cc4
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictConnection.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Willink Transformations and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.qvtd.runtime.evaluation;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.ocl.pivot.ids.CollectionTypeId;
+import org.eclipse.qvtd.runtime.internal.evaluation.StrictConnectionInternal;
+
+/**
+ * A StrictConnection maintains the unique values between one or more sources,
+ * typically Mappings, that invoke append() and one or more consumers that consume each value.
+ * Uniqueness on the internal values on behalf of an overall application that is unable to do so automatically.
+ *
+ * Incremental update is not supported.
+ */
+public class StrictConnection extends StrictConnectionInternal
+{
+ public StrictConnection(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ super(interval, name, typeId);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/EnforcedConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictIncrementalConnection.java
index 25c6da625..971b1678e 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/EnforcedConnection.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictIncrementalConnection.java
@@ -12,7 +12,7 @@ package org.eclipse.qvtd.runtime.evaluation;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
-import org.eclipse.qvtd.runtime.internal.evaluation.AbstractEnforcedConnectionInternal;
+import org.eclipse.qvtd.runtime.internal.evaluation.StrictIncrementalConnectionInternal;
/**
* An EnforcedConnection maintains the unqiue values between one or more sources,
@@ -23,9 +23,9 @@ import org.eclipse.qvtd.runtime.internal.evaluation.AbstractEnforcedConnectionIn
*
* Incremental update is supported by a revoke() or an append(), or a replace() of an appended value.
*/
-public class EnforcedConnection extends AbstractEnforcedConnectionInternal
+public class StrictIncrementalConnection extends StrictIncrementalConnectionInternal
{
- public EnforcedConnection(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ public StrictIncrementalConnection(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
super(interval, name, typeId);
}
} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractConnectionInternal.java
index 763115fcc..407e14342 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractConnectionInternal.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractConnectionInternal.java
@@ -11,19 +11,14 @@
package org.eclipse.qvtd.runtime.internal.evaluation;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-import java.util.NoSuchElementException;
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
import org.eclipse.ocl.pivot.utilities.LabelUtil;
+import org.eclipse.qvtd.runtime.evaluation.AbstractConnection;
import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer;
-import org.eclipse.qvtd.runtime.evaluation.Connection;
-import org.eclipse.qvtd.runtime.evaluation.ExecutionVisitor;
import org.eclipse.qvtd.runtime.evaluation.Interval;
-import org.eclipse.qvtd.runtime.evaluation.Invocation;
import org.eclipse.qvtd.runtime.evaluation.InvocationConstructor;
/**
@@ -33,231 +28,55 @@ import org.eclipse.qvtd.runtime.evaluation.InvocationConstructor;
* The AbstractConnection may optionally enforce uniqueness on the internal values where the overall
* application is unable to do so automatically.
*
- * Incremental update is supported by a revoke() or an append(), or a replace() of an appended value.
+ * Incremental update is not supported.
*/
-public abstract class AbstractConnectionInternal implements Connection
+public abstract class AbstractConnectionInternal extends AbstractConnection
{
- protected final class ValueIterator<T> implements Iterator<T> {
-
- private final int size = listOfValueAndConsumingInvocations.size();
-
- private int cursor = next(0);
-
- @Override
- public boolean hasNext() {
- return cursor < size;
- }
-
- @Override
- public @NonNull T next() {
- List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(cursor);
- if (valueAndConsumingInvocations == null) {
- throw new NoSuchElementException();
- }
- cursor = next(cursor+1);
- return (T) valueAndConsumingInvocations.get(VALUE_INDEX);
- }
-
- private int next(int i) {
- while (i < size) {
- if (listOfValueAndConsumingInvocations.get(i) != null) {
- return i;
- }
- i++;
- }
- return size;
- }
- }
-
- protected static final int VALUE_INDEX = 0;
- protected static final int INDEX_INDEX = 1;
- protected static final int COUNT_INDEX = 2;
-
- protected final boolean debugAppends = AbstractTransformer.APPENDS.isActive();
- protected final boolean debugConsumes = AbstractTransformer.CONSUMES.isActive();
- protected final @NonNull Interval interval;
- protected final @NonNull String name;
- protected final @NonNull CollectionTypeId typeId;
-
- /**
- * Singly linked list element of connections awaiting propagation from their interval, null when last/unlinked.
- */
- private @Nullable AbstractConnectionInternal nextConnection = null;
-
/**
- * True when this connection is part of the interval's list of connections awaiting propagation.
+ * THe values passed by the coonnection..
*/
- private boolean isQueued = false;
-
- /**
- * The consumers of each appended value.
- */
- protected final @NonNull List<@NonNull InvocationConstructor> consumers = new ArrayList<>();
-
- /**
- * The appenders of values.
- */
- protected final @NonNull List<@NonNull InvocationConstructor> appenders = new ArrayList<>();
-
- /**
- * The earlist interval at which a consumer can execute.
- */
- // private /*@LazyNonNull*/ Interval earliestInterval = null;
-
- /**
- * First VALUE_INDEX entry of each list is the @NonNull Object element value.
- * Second INDEX_INDEX entry of each list is the @NonNull Integer index within the outer list.
- * If unique values are maintained the third COUNT_INDEX entry of each list is the number of copies of this value.
- * Subsequent entries are @NonNull AbstractMapping consumers of the value.
- * The entry is returned opaquely as a connectionKey to enable append() to return a
- * key that may subsequently be used by remove() or replace().
- * Revoked entries are set to null in order to preserve index validity until a cleanup.
- */
- protected final @NonNull List<@Nullable List<@NonNull Object>> listOfValueAndConsumingInvocations = new ArrayList<>();
+ protected final @NonNull List<@NonNull Object> values = new ArrayList<>();
protected AbstractConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
- this.interval = interval;
- this.name = name;
- this.typeId = typeId;
- }
-
- @Override
- public <R> R accept(@NonNull ExecutionVisitor<R> visitor) {
- return visitor.visitConnection(this);
+ super(interval, name, typeId);
}
@Override
- public void addAppender(@NonNull InvocationConstructor appender) {
- if (!appenders.contains(appender)) {
- appenders.add(appender);
- }
- }
-
- @Override
- public void addConsumer(@NonNull InvocationConstructor consumer) {
- // assert listOfValueAndConsumingInvocations.isEmpty() || listOfValueAndConsumingInvocations.get(0).;
- if (!consumers.contains(consumer)) {
- consumers.add(consumer);
- if (!listOfValueAndConsumingInvocations.isEmpty()) {
- queue();
- }
- }
- }
+ public void addAppender(@NonNull InvocationConstructor appendingInvoker) {}
/**
- * Remove the revoked entries and update the internal indexes accordingly.
+ * Append aValue to the contents, and waking up the overall
+ * connection manager to schedule a propagate() to consumers when convenient.
*/
@Override
- public synchronized void cleanup() {
- int iWrite = 0;
- for (int iRead = 0; iRead < listOfValueAndConsumingInvocations.size(); iRead++) {
- List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(iRead);
- if (valueAndConsumingInvocations != null) {
- if (iWrite != iRead) {
- listOfValueAndConsumingInvocations.set(iWrite, valueAndConsumingInvocations);
- }
- valueAndConsumingInvocations.set(INDEX_INDEX, iWrite);
- iWrite++;
- }
- }
- }
-
- @Override
- public void consume(int elementIndex, @NonNull Invocation invocation) {
- List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(elementIndex);
- assert valueAndConsumingInvocations != null;
- assert !valueAndConsumingInvocations.contains(invocation); // Earlier indexes cannot be the invocation, so no need for a sub-list
- valueAndConsumingInvocations.add(invocation);
- // FIXME empty status if all consumers at final index
- // invocationManager.dequeue(this);
- if (debugConsumes) {
- AbstractTransformer.CONSUMES.println(this + " => " + LabelUtil.getLabel(valueAndConsumingInvocations.get(VALUE_INDEX)));
+ public synchronized @NonNull Object append(@NonNull Object aValue) {
+ if (debugAppends) {
+ AbstractTransformer.APPENDS.println(this + " <= " + LabelUtil.getLabel(aValue));
}
+ values.add(aValue);
+ queue();
+ return aValue;
}
@Override
- public @NonNull Iterable<@NonNull InvocationConstructor> getAppenders() {
- return appenders;
- }
-
- @Override
- public int getCapacity() { // not getSize() since some entries may be null.
- return listOfValueAndConsumingInvocations.size();
- }
-
- @Override
- public @NonNull Iterable<@NonNull InvocationConstructor> getConsumers() {
- return consumers;
- }
-
- @Override
- public @NonNull String getName() {
- return name;
- }
-
- final @Nullable AbstractConnectionInternal getNextConnection() {
- return nextConnection;
+ public int getCapacity() {
+ return values.size();
}
@Override
- public @Nullable Object getValue(int i) {
- List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(i);
- return valueAndConsumingInvocations != null ? valueAndConsumingInvocations.get(VALUE_INDEX) : null;
+ public @NonNull Object getValue(int i) {
+ return values.get(i);
}
@Override
public int getValues() {
- return listOfValueAndConsumingInvocations.size();
- }
-
- @Override
- public void propagate() {
- for (@NonNull InvocationConstructor consumer : consumers) {
- consumer.propagate();
- }
- }
-
- protected final void queue() {
- if (!isQueued) {
- isQueued = true;
- interval.queue(this);
- }
- }
-
- void resetQueued() {
- isQueued = false;
- this.nextConnection = null;
- }
-
- void setNextConnection(@NonNull AbstractConnectionInternal nextConnection) {
- assert nextConnection != this;
- assert isQueued;
- this.nextConnection = nextConnection;
- }
-
- @Override
- public String toString() {
- StringBuilder s = new StringBuilder();
- s.append("<");
- s.append(interval.getIndex());
- s.append(">");
- s.append(name);
- // s.append(" : ");
- // s.append(typeId);
- s.append("[");
- s.append(listOfValueAndConsumingInvocations.size());
- s.append("]");
- return s.toString();
+ return values.size();
}
@Override
public <@NonNull T> @NonNull Iterable<T> typedIterable(Class<T> elementClass) {
- return new Iterable<T>()
- {
- @Override
- public Iterator<@NonNull T> iterator() {
- return new ValueIterator<T>();
- }
- };
+ @SuppressWarnings("unchecked")
+ @NonNull Iterable<@NonNull T> castValues = (Iterable<@NonNull T>) values;
+ return castValues;
}
} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIncrementalConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIncrementalConnectionInternal.java
new file mode 100644
index 000000000..0afe7171b
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIncrementalConnectionInternal.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Willink Transformations and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.qvtd.runtime.internal.evaluation;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.ocl.pivot.ids.CollectionTypeId;
+import org.eclipse.ocl.pivot.utilities.LabelUtil;
+import org.eclipse.qvtd.runtime.evaluation.AbstractConnection;
+import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer;
+import org.eclipse.qvtd.runtime.evaluation.Connection;
+import org.eclipse.qvtd.runtime.evaluation.Interval;
+import org.eclipse.qvtd.runtime.evaluation.Invocation;
+import org.eclipse.qvtd.runtime.evaluation.InvocationConstructor;
+
+/**
+ * An AbstractConnection maintains the values between one or more sources, typically Mappings, that
+ * invoke append() and one or more consumers that consume each value.
+ *
+ * The AbstractConnection may optionally enforce uniqueness on the internal values where the overall
+ * application is unable to do so automatically.
+ *
+ * Incremental update is supported by a revoke() or an append(), or a replace() of an appended value.
+ */
+public abstract class AbstractIncrementalConnectionInternal extends AbstractConnection implements Connection.Incremental
+{
+ protected final class ValueIterator<T> implements Iterator<T> {
+
+ private final int size = listOfValueAndConsumingInvocations.size();
+
+ private int cursor = next(0);
+
+ @Override
+ public boolean hasNext() {
+ return cursor < size;
+ }
+
+ @Override
+ public @NonNull T next() {
+ List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(cursor);
+ if (valueAndConsumingInvocations == null) {
+ throw new NoSuchElementException();
+ }
+ cursor = next(cursor+1);
+ return (T) valueAndConsumingInvocations.get(VALUE_INDEX);
+ }
+
+ private int next(int i) {
+ while (i < size) {
+ if (listOfValueAndConsumingInvocations.get(i) != null) {
+ return i;
+ }
+ i++;
+ }
+ return size;
+ }
+ }
+
+ protected static final int VALUE_INDEX = 0;
+ protected static final int INDEX_INDEX = 1;
+ protected static final int COUNT_INDEX = 2;
+
+ protected final boolean debugConsumes = AbstractTransformer.CONSUMES.isActive();
+
+ /**
+ * The appenders of values.
+ */
+ protected final @NonNull List<@NonNull InvocationConstructor> appenders = new ArrayList<>();
+
+ /**
+ * First VALUE_INDEX entry of each list is the @NonNull Object element value.
+ * Second INDEX_INDEX entry of each list is the @NonNull Integer index within the outer list.
+ * If unique values are maintained the third COUNT_INDEX entry of each list is the number of copies of this value.
+ * Subsequent entries are @NonNull AbstractMapping consumers of the value.
+ * The entry is returned opaquely as a connectionKey to enable append() to return a
+ * key that may subsequently be used by remove() or replace().
+ * Revoked entries are set to null in order to preserve index validity until a cleanup.
+ */
+ protected final @NonNull List<@Nullable List<@NonNull Object>> listOfValueAndConsumingInvocations = new ArrayList<>();
+
+ protected AbstractIncrementalConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ super(interval, name, typeId);
+ }
+
+ @Override
+ public void addAppender(@NonNull InvocationConstructor appender) {
+ if (!appenders.contains(appender)) {
+ appenders.add(appender);
+ }
+ }
+
+ @Override
+ public boolean addConsumer(@NonNull InvocationConstructor consumer) {
+ // assert listOfValueAndConsumingInvocations.isEmpty() || listOfValueAndConsumingInvocations.get(0).;
+ if (!super.addConsumer(consumer)) {
+ return false;
+ }
+ if (!listOfValueAndConsumingInvocations.isEmpty()) {
+ queue();
+ }
+ return true;
+ }
+
+ /**
+ * Remove the revoked entries and update the internal indexes accordingly.
+ */
+ @Override
+ public synchronized void cleanup() {
+ int iWrite = 0;
+ for (int iRead = 0; iRead < listOfValueAndConsumingInvocations.size(); iRead++) {
+ List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(iRead);
+ if (valueAndConsumingInvocations != null) {
+ if (iWrite != iRead) {
+ listOfValueAndConsumingInvocations.set(iWrite, valueAndConsumingInvocations);
+ }
+ valueAndConsumingInvocations.set(INDEX_INDEX, iWrite);
+ iWrite++;
+ }
+ }
+ }
+
+ @Override
+ public void consume(int elementIndex, @NonNull Invocation invocation) {
+ List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(elementIndex);
+ assert valueAndConsumingInvocations != null;
+ assert !valueAndConsumingInvocations.contains(invocation); // Earlier indexes cannot be the invocation, so no need for a sub-list
+ valueAndConsumingInvocations.add(invocation);
+ // FIXME empty status if all consumers at final index
+ // invocationManager.dequeue(this);
+ if (debugConsumes) {
+ AbstractTransformer.CONSUMES.println(this + " => " + LabelUtil.getLabel(valueAndConsumingInvocations.get(VALUE_INDEX)));
+ }
+ }
+
+ @Override
+ public @NonNull Iterable<@NonNull InvocationConstructor> getAppenders() {
+ return appenders;
+ }
+
+ @Override
+ public int getCapacity() { // not getSize() since some entries may be null.
+ return listOfValueAndConsumingInvocations.size();
+ }
+
+ @Override
+ public @Nullable Object getValue(int i) {
+ List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(i);
+ return valueAndConsumingInvocations != null ? valueAndConsumingInvocations.get(VALUE_INDEX) : null;
+ }
+
+ @Override
+ public int getValues() {
+ return listOfValueAndConsumingInvocations.size();
+ }
+
+
+ @Override
+ public <@NonNull T> @NonNull Iterable<T> typedIterable(Class<T> elementClass) {
+ return new Iterable<T>()
+ {
+ @Override
+ public Iterator<@NonNull T> iterator() {
+ return new ValueIterator<T>();
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIntervalInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIntervalInternal.java
index 2df355dbf..34f3e18ec 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIntervalInternal.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIntervalInternal.java
@@ -16,16 +16,19 @@ import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
+import org.eclipse.qvtd.runtime.evaluation.AbstractConnection;
import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer;
import org.eclipse.qvtd.runtime.evaluation.Connection;
-import org.eclipse.qvtd.runtime.evaluation.EnforcedConnection;
+import org.eclipse.qvtd.runtime.evaluation.StrictIncrementalConnection;
import org.eclipse.qvtd.runtime.evaluation.ExecutionVisitor;
import org.eclipse.qvtd.runtime.evaluation.Interval;
import org.eclipse.qvtd.runtime.evaluation.Invocation;
import org.eclipse.qvtd.runtime.evaluation.InvocationFailedException;
import org.eclipse.qvtd.runtime.evaluation.InvocationManager;
+import org.eclipse.qvtd.runtime.evaluation.SimpleConnection;
import org.eclipse.qvtd.runtime.evaluation.SlotState;
-import org.eclipse.qvtd.runtime.evaluation.UnenforcedConnection;
+import org.eclipse.qvtd.runtime.evaluation.StrictConnection;
+import org.eclipse.qvtd.runtime.evaluation.SimpleIncrementalConnection;
/**
* AbstractIntervalInternal provides the shared implementation of the intrusive blocked/waiting linked list functionality.
@@ -42,12 +45,12 @@ public abstract class AbstractIntervalInternal implements Interval
/**
* Head of a singly linked list element of connections awaiting propagation, null when empty.
*/
- private @Nullable AbstractConnectionInternal headConnection = null;
+ private @Nullable AbstractConnection headConnection = null;
/**
* Tail of a singly linked list element of connections awaiting propagation, null when empty.
*/
- private @Nullable AbstractConnectionInternal tailConnection = null;
+ private @Nullable AbstractConnection tailConnection = null;
/**
* Head of doubly linked list of blocked invocations.
@@ -100,10 +103,23 @@ public abstract class AbstractIntervalInternal implements Interval
public @NonNull Connection createConnection(@NonNull String name, @NonNull CollectionTypeId typeId, boolean isStrict) {
Connection connection;
if (isStrict) {
- connection = new EnforcedConnection(this, name, typeId);
+ connection = new StrictConnection(this, name, typeId);
}
else {
- connection = new UnenforcedConnection(this, name, typeId);
+ connection = new SimpleConnection(this, name, typeId);
+ }
+ connections.add(connection);
+ return connection;
+ }
+
+ @Override
+ public Connection.@NonNull Incremental createIncrementalConnection(@NonNull String name, @NonNull CollectionTypeId typeId, boolean isStrict) {
+ Connection.Incremental connection;
+ if (isStrict) {
+ connection = new StrictIncrementalConnection(this, name, typeId);
+ }
+ else {
+ connection = new SimpleIncrementalConnection(this, name, typeId);
}
connections.add(connection);
return connection;
@@ -112,7 +128,7 @@ public abstract class AbstractIntervalInternal implements Interval
@Override
public boolean flush() {
while (headConnection != null) {
- AbstractConnectionInternal nextConnection2;
+ AbstractConnection nextConnection2;
synchronized(this) {
nextConnection2 = headConnection;
if (nextConnection2 != null) {
@@ -210,8 +226,8 @@ public abstract class AbstractIntervalInternal implements Interval
@Override
public synchronized void queue(@NonNull Connection connection) {
- AbstractConnectionInternal connection2 = (AbstractConnectionInternal)connection;
- AbstractConnectionInternal tailConnection2 = tailConnection;
+ AbstractConnection connection2 = (AbstractConnection)connection;
+ AbstractConnection tailConnection2 = tailConnection;
if (tailConnection2 == null) { // Empty list
assert headConnection == null;
assert connection2.getNextConnection() == null;
@@ -251,7 +267,7 @@ public abstract class AbstractIntervalInternal implements Interval
s.append(intervalIndex);
s.append("> ");
int i = 0;
- for (AbstractConnectionInternal aConnection = headConnection; aConnection != null; aConnection = aConnection.getNextConnection()) {
+ for (AbstractConnection aConnection = headConnection; aConnection != null; aConnection = aConnection.getNextConnection()) {
i++;
if (i > 100) {
i = 999999;
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractInvocationConstructor.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractInvocationConstructor.java
index 232763e02..9db92d72b 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractInvocationConstructor.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractInvocationConstructor.java
@@ -36,21 +36,6 @@ public abstract class AbstractInvocationConstructor implements InvocationConstru
super(invocationManager, name, isStrict);
}
- public void connect(@NonNull Connection @Nullable [] consumedConnections, @NonNull Connection @Nullable [] appendedConnections) {
- if (consumedConnections != null) {
- for (@NonNull Connection consumedConnection : consumedConnections) {
- consumedConnection.addConsumer(this);
- addConsumedConection(consumedConnection);
- }
- }
- if (appendedConnections != null) {
- for (@NonNull Connection appendedConnection : appendedConnections) {
- appendedConnection.addAppender(this);
- addAppendedConnection(appendedConnection);
- }
- }
- }
-
@Override
public int nextSequence() {
return sequence++;
@@ -93,16 +78,19 @@ public abstract class AbstractInvocationConstructor implements InvocationConstru
return visitor.visitInvocationConstructor(this);
}
- protected void addAppendedConnection(@NonNull Connection connection) {
+ @Override
+ public void addAppendedConnection(@NonNull Connection connection) {
assert oldConsumedIndexes == null;
assert !appendedConnections.contains(connection);
appendedConnections.add(connection);
+ connection.addAppender(this);
}
@Override
- public void addConsumedConection(@NonNull Connection connection) {
+ public void addConsumedConnection(@NonNull Connection connection) {
assert !consumedConnections.contains(connection);
consumedConnections.add(connection);
+ connection.addConsumer(this);
}
@Override
@@ -248,7 +236,9 @@ public abstract class AbstractInvocationConstructor implements InvocationConstru
Invocation mappingInstance = invoke(boundValues);
for (int i = 0; i < consumedConnectionsSize; i++) {
Connection consumedConnection = consumedConnections.get(i);
- consumedConnection.consume(consumeIndexes[i], mappingInstance);
+ if (consumedConnection instanceof Connection.Incremental) {
+ ((Connection.Incremental)consumedConnection).consume(consumeIndexes[i], mappingInstance);
+ }
}
}
}
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractUnenforcedConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/IncrementalConnectionInternal.java
index b1d1011f8..4a0544b1a 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractUnenforcedConnectionInternal.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/IncrementalConnectionInternal.java
@@ -30,9 +30,9 @@ import org.eclipse.qvtd.runtime.evaluation.Invocation;
*
* Incremental update is supported by a revoke() or an append(), or a replace() of an appended value.
*/
-public abstract class AbstractUnenforcedConnectionInternal extends AbstractConnectionInternal
+public class IncrementalConnectionInternal extends AbstractIncrementalConnectionInternal
{
- protected AbstractUnenforcedConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ protected IncrementalConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
super(interval, name, typeId);
}
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictConnectionInternal.java
new file mode 100644
index 000000000..31e9fca17
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictConnectionInternal.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Willink Transformations and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.qvtd.runtime.internal.evaluation;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.ocl.pivot.ids.CollectionTypeId;
+import org.eclipse.ocl.pivot.utilities.LabelUtil;
+import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer;
+import org.eclipse.qvtd.runtime.evaluation.Interval;
+
+/**
+ * A StrictConnectionInternal maintains the unqiue values between one or more sources,
+ * typically Mappings, that invoke append() and one or more consumers that consume each value.
+ * Uniqueness on the internal values on behalf of an overall application that is unable to do so automatically.
+ *
+ * Incremental update is not supported.
+ */
+public abstract class StrictConnectionInternal extends AbstractConnectionInternal
+{
+ /**
+ * Distinct connection values, if there are more than 10 values.
+ */
+ private /*@LazyNonNull*/ Set<@NonNull Object> uniqueValues = null;
+
+ protected StrictConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ super(interval, name, typeId);
+ }
+
+ /**
+ * Append aValue to the contents, enforcing uniqueness if necessary, and waking up the overall
+ * connection manager to schedule a propagate() to consumers when convenient.
+ */
+ @Override
+ public synchronized @NonNull Object append(@NonNull Object aValue) {
+ if (debugAppends) {
+ AbstractTransformer.APPENDS.println(this + " <= " + LabelUtil.getLabel(aValue));
+ }
+ if (uniqueValues != null) {
+ if (!uniqueValues.add(aValue)) {
+ return aValue;
+ }
+ }
+ else if (values.size() < 10) {
+ for (@NonNull Object value : values) {
+ if (value.equals(aValue)) { // FIXME ==/oclEquals
+ return aValue;
+ }
+ }
+ }
+ else if (!createUniqueValues().add(aValue)) {
+ return aValue;
+ }
+ values.add(aValue);
+ queue();
+ return aValue;
+ }
+
+ private @NonNull Set<@NonNull Object> createUniqueValues() {
+ Set<@NonNull Object> uniqueValues2 = uniqueValues = new HashSet<>();
+ for (@NonNull Object value : values) {
+ uniqueValues2.add(value);
+ }
+ return uniqueValues2;
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractEnforcedConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictIncrementalConnectionInternal.java
index 9327e1820..c46d387ea 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractEnforcedConnectionInternal.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictIncrementalConnectionInternal.java
@@ -30,14 +30,14 @@ import org.eclipse.qvtd.runtime.evaluation.Invocation;
*
* Incremental update is supported by a revoke() or an append(), or a replace() of an appended value.
*/
-public abstract class AbstractEnforcedConnectionInternal extends AbstractConnectionInternal
+public abstract class StrictIncrementalConnectionInternal extends AbstractIncrementalConnectionInternal
{
/**
* Map from each unique value to the entry for that value.
*/
private final @NonNull Map<@NonNull Object, @NonNull List<@NonNull Object>> uniqueValues2valueAndConsumingInvocations = new HashMap<>();
- protected AbstractEnforcedConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
+ protected StrictIncrementalConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) {
super(interval, name, typeId);
}
diff --git a/plugins/org.eclipse.qvtd.xtext.qvtimperative/src/org/eclipse/qvtd/xtext/qvtimperative/formatting/QVTimperativeFormatter.java b/plugins/org.eclipse.qvtd.xtext.qvtimperative/src/org/eclipse/qvtd/xtext/qvtimperative/formatting/QVTimperativeFormatter.java
index f673a4426..08a97fcae 100644
--- a/plugins/org.eclipse.qvtd.xtext.qvtimperative/src/org/eclipse/qvtd/xtext/qvtimperative/formatting/QVTimperativeFormatter.java
+++ b/plugins/org.eclipse.qvtd.xtext.qvtimperative/src/org/eclipse/qvtd/xtext/qvtimperative/formatting/QVTimperativeFormatter.java
@@ -22,6 +22,7 @@ import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.
import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.GuardParameterBindingCSElements;
import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.GuardParameterCSElements;
import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.ImportCSElements;
+import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.LoopParameterBindingCSElements;
import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.MappingCSElements;
import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.MappingCallCSElements;
import org.eclipse.qvtd.xtext.qvtimperative.services.QVTimperativeGrammarAccess.MappingLoopCSElements;
@@ -87,6 +88,7 @@ public class QVTimperativeFormatter extends AbstractEssentialOCLFormatter
}
{
AppendParameterBindingCSElements a = f.getAppendParameterBindingCSAccess();
+ c.setLinewrap(1).before(a.getGroup());
setNoSpaceLineWrap(c, a.getSemicolonKeyword_3());
}
{
@@ -132,6 +134,11 @@ public class QVTimperativeFormatter extends AbstractEssentialOCLFormatter
setNoSpaceLineWrap(c, a.getSemicolonKeyword_4());
}
{
+ LoopParameterBindingCSElements a = f.getLoopParameterBindingCSAccess();
+ c.setLinewrap(1).before(a.getGroup());
+ c.setNoSpace().before(a.getSemicolonKeyword_4());
+ }
+ {
MappingCSElements a = f.getMappingCSAccess();
c.setLinewrap(2).before(a.getGroup());
c.setNoSpace().between(a.getLeftCurlyBracketKeyword_5(), a.getRightCurlyBracketKeyword_10());
diff --git a/tests/org.eclipse.qvtd.xtext.qvtimperative.tests/src/org/eclipse/qvtd/xtext/qvtimperative/tests/Tree2TallTree/Tree2TallTreeInstallManual.java b/tests/org.eclipse.qvtd.xtext.qvtimperative.tests/src/org/eclipse/qvtd/xtext/qvtimperative/tests/Tree2TallTree/Tree2TallTreeInstallManual.java
index 84aef5879..576b59e54 100644
--- a/tests/org.eclipse.qvtd.xtext.qvtimperative.tests/src/org/eclipse/qvtd/xtext/qvtimperative/tests/Tree2TallTree/Tree2TallTreeInstallManual.java
+++ b/tests/org.eclipse.qvtd.xtext.qvtimperative.tests/src/org/eclipse/qvtd/xtext/qvtimperative/tests/Tree2TallTree/Tree2TallTreeInstallManual.java
@@ -234,11 +234,12 @@ public class Tree2TallTreeInstallManual extends AbstractTransformer
for (@NonNull Node iterator : ValueUtil.typedIterable(Node.class, sortedBy)) {
nodes.append(iterator);
}
- final @NonNull Connection node2tallNodes_1 = createConnection("node2tallNodes_1", SEQ_CLSSid_Node2TallNode, false);
+ final Connection.@NonNull Incremental node2tallNodes_1 = createIncrementalConnection("node2tallNodes_1", SEQ_CLSSid_Node2TallNode, false);
// mapping statements
- CTOR_Node2MiddleNode.connect(new @NonNull Connection[]{nodes}, new @NonNull Connection[]{node2tallNodes_1});
- CTOR_Edge2MiddleEdge.connect(new @NonNull Connection[]{nodes}, null);
- CTOR_MiddleNode2TallNode.connect(new @NonNull Connection[]{node2tallNodes_1}, null);
+ CTOR_Node2MiddleNode.addConsumedConnection(nodes);
+ CTOR_Node2MiddleNode.addAppendedConnection(node2tallNodes_1);
+ CTOR_Edge2MiddleEdge.addConsumedConnection(nodes);
+ CTOR_MiddleNode2TallNode.addConsumedConnection(node2tallNodes_1);
final /*@Thrown*/ @Nullable Boolean __root__ = ValueUtil.TRUE_VALUE;
return __root__;
} catch (Throwable e) {
@@ -302,7 +303,7 @@ public class Tree2TallTreeInstallManual extends AbstractTransformer
@Override
public boolean isEqual(@NonNull IdResolver idResolver, @NonNull Object @NonNull [] thoseValues) {
return idResolver.oclEquals(node, thoseValues[0])
- && idResolver.oclEquals(node2tallNodes, thoseValues[1]);
+ && idResolver.oclEquals(node2tallNodes, thoseValues[1]);
}
}

Back to the top