From 0aac37bb8c65e8cdb8b949248b1507c91772d8a3 Mon Sep 17 00:00:00 2001 From: Ed Willink Date: Sun, 23 Oct 2016 13:06:11 +0100 Subject: [500962] Introduce distinct Strict/Simple (Incremental) Connections --- .../qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java | 122 ++++------- .../qvtd/compiler/AbstractCompilerChain.java | 4 + .../org/eclipse/qvtd/compiler/CompilerChain.java | 1 + .../internal/qvts2qvti/AbstractRegion2Mapping.java | 13 -- .../qvts2qvti/AbstractScheduledRegion2Mapping.java | 99 ++++----- .../internal/qvts2qvti/BasicRegion2Mapping.java | 30 +-- .../internal/qvts2qvti/QVTs2QVTiVisitor.java | 4 +- .../evaluation/Execution2GraphVisitor.java | 8 +- .../utilities/QVTimperativeHelper.java | 14 +- .../utilities/QVTimperativeToStringVisitor.java | 11 +- .../runtime/evaluation/AbstractConnection.java | 116 +++++++++++ .../runtime/evaluation/AbstractInvocation.java | 4 + .../qvtd/runtime/evaluation/Connection.java | 73 +++---- .../runtime/evaluation/EnforcedConnection.java | 31 --- .../eclipse/qvtd/runtime/evaluation/Interval.java | 2 + .../runtime/evaluation/InvocationConstructor.java | 5 +- .../qvtd/runtime/evaluation/SimpleConnection.java | 31 +++ .../evaluation/SimpleIncrementalConnection.java | 31 +++ .../qvtd/runtime/evaluation/StrictConnection.java | 29 +++ .../evaluation/StrictIncrementalConnection.java | 31 +++ .../runtime/evaluation/UnenforcedConnection.java | 31 --- .../evaluation/AbstractConnectionInternal.java | 227 +++------------------ .../AbstractEnforcedConnectionInternal.java | 134 ------------ .../AbstractIncrementalConnectionInternal.java | 180 ++++++++++++++++ .../evaluation/AbstractIntervalInternal.java | 36 +++- .../evaluation/AbstractInvocationConstructor.java | 26 +-- .../AbstractUnenforcedConnectionInternal.java | 100 --------- .../evaluation/IncrementalConnectionInternal.java | 100 +++++++++ .../evaluation/StrictConnectionInternal.java | 76 +++++++ .../StrictIncrementalConnectionInternal.java | 134 ++++++++++++ .../formatting/QVTimperativeFormatter.java | 7 + .../Tree2TallTree/Tree2TallTreeInstallManual.java | 11 +- 32 files changed, 983 insertions(+), 738 deletions(-) create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/AbstractConnection.java delete mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/EnforcedConnection.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleConnection.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleIncrementalConnection.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictConnection.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictIncrementalConnection.java delete mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/UnenforcedConnection.java delete mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractEnforcedConnectionInternal.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractIncrementalConnectionInternal.java delete mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractUnenforcedConnectionInternal.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/IncrementalConnectionInternal.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictConnectionInternal.java create mode 100644 plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictIncrementalConnectionInternal.java 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 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 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 VALIDATE_KEY = new Key("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 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(); @@ -727,21 +742,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'. */ 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 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 accept(@NonNull ExecutionVisitor 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 typedIterable(Class elementClass); } \ 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/EnforcedConnection.java deleted file mode 100644 index 25c6da625..000000000 --- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/EnforcedConnection.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * 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.AbstractEnforcedConnectionInternal; - -/** - * An EnforcedConnection 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 supported by a revoke() or an append(), or a replace() of an appended value. - * - * Incremental update is supported by a revoke() or an append(), or a replace() of an appended value. - */ -public class EnforcedConnection extends AbstractEnforcedConnectionInternal -{ - public EnforcedConnection(@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/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/SimpleIncrementalConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleIncrementalConnection.java new file mode 100644 index 000000000..aa9196da9 --- /dev/null +++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/SimpleIncrementalConnection.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.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 StrictIncrementalConnection to enforce uniqueness internally. + * + * Incremental update is supported by a revoke() or an append(), or a replace() of an appended value. + */ +public class SimpleIncrementalConnection extends IncrementalConnectionInternal +{ + 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/StrictIncrementalConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictIncrementalConnection.java new file mode 100644 index 000000000..971b1678e --- /dev/null +++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/StrictIncrementalConnection.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.StrictIncrementalConnectionInternal; + +/** + * An EnforcedConnection 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 supported by a revoke() or an append(), or a replace() of an appended value. + * + * Incremental update is supported by a revoke() or an append(), or a replace() of an appended value. + */ +public class StrictIncrementalConnection extends StrictIncrementalConnectionInternal +{ + 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/evaluation/UnenforcedConnection.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/UnenforcedConnection.java deleted file mode 100644 index 1f5d06015..000000000 --- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/UnenforcedConnection.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * 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.AbstractUnenforcedConnectionInternal; - -/** - * 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. - * - * Incremental update is supported by a revoke() or an append(), or a replace() of an appended value. - */ -public class UnenforcedConnection extends AbstractUnenforcedConnectionInternal -{ - public UnenforcedConnection(@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 implements Iterator { - - 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 accept(@NonNull ExecutionVisitor 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 typedIterable(Class elementClass) { - return new Iterable() - { - @Override - public Iterator<@NonNull T> iterator() { - return new ValueIterator(); - } - }; + @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/AbstractEnforcedConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractEnforcedConnectionInternal.java deleted file mode 100644 index 9327e1820..000000000 --- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractEnforcedConnectionInternal.java +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************* - * 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.HashMap; -import java.util.List; -import java.util.Map; - -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.AbstractInvocation; -import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer; -import org.eclipse.qvtd.runtime.evaluation.Interval; -import org.eclipse.qvtd.runtime.evaluation.Invocation; - -/** - * An AbstractEnforcedConnectionInternal 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 supported by a revoke() or an append(), or a replace() of an appended value. - */ -public abstract class AbstractEnforcedConnectionInternal extends AbstractConnectionInternal -{ - /** - * 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) { - 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)); - } - List<@NonNull Object> valueAndConsumingInvocations = uniqueValues2valueAndConsumingInvocations.get(aValue); - if (valueAndConsumingInvocations == null) { - valueAndConsumingInvocations = new ArrayList<>(); - valueAndConsumingInvocations.add(aValue); // VALUE_INDEX - valueAndConsumingInvocations.add(listOfValueAndConsumingInvocations.size()); // INDEX_INDEX - valueAndConsumingInvocations.add(1); // COUNT_INDEX - listOfValueAndConsumingInvocations.add(valueAndConsumingInvocations); - uniqueValues2valueAndConsumingInvocations.put(aValue, valueAndConsumingInvocations); - queue(); - } - else { - Integer count = (Integer) valueAndConsumingInvocations.get(COUNT_INDEX); - valueAndConsumingInvocations.set(COUNT_INDEX, count+1); - } - return valueAndConsumingInvocations; - } - - @Override - public void check() { - for (int i = 0; i < listOfValueAndConsumingInvocations.size(); i++) { - List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(i); - if (valueAndConsumingInvocations != null) { - assert valueAndConsumingInvocations.get(INDEX_INDEX) == Integer.valueOf(i); - assert valueAndConsumingInvocations.contains(valueAndConsumingInvocations.get(VALUE_INDEX)); - } - } - } - - /** - * 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. - */ - @Override - public synchronized @NonNull Object replace(@NonNull Object connectionKey, @NonNull Object newValue) { - @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; - Object oldValue = valueAndConsumingInvocations.get(VALUE_INDEX); - if (newValue != oldValue) { // FIXME ?? equals/oclEquals ?? - Integer count = (Integer) valueAndConsumingInvocations.get(COUNT_INDEX); - if (count > 1) { - valueAndConsumingInvocations.set(COUNT_INDEX, count-1); - return append(newValue); - } - valueAndConsumingInvocations.set(VALUE_INDEX, newValue); - int iMax = valueAndConsumingInvocations.size(); - for (int i = COUNT_INDEX+1; i < iMax; i++) { - Invocation consumer = (Invocation) valueAndConsumingInvocations.get(i); - interval.queue(consumer); - } - } - return connectionKey; - } - - /** - * 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. - */ - @Override - public synchronized void revoke(@NonNull Object connectionKey) { - @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; - int valueIndex = (int) valueAndConsumingInvocations.get(INDEX_INDEX); - Integer count = (Integer) valueAndConsumingInvocations.get(COUNT_INDEX); - if (count > 1) { - valueAndConsumingInvocations.set(COUNT_INDEX, count-1); - return; - } - listOfValueAndConsumingInvocations.set(valueIndex, null); // Do not disrupt index equivalence. - int iMax = valueAndConsumingInvocations.size(); - for (int i = COUNT_INDEX+1; i < iMax; i++) { - AbstractInvocation consumingInvocation = (AbstractInvocation) valueAndConsumingInvocations.get(i); - consumingInvocation.revoke(); - } - } -} \ 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 implements Iterator { + + 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 typedIterable(Class elementClass) { + return new Iterable() + { + @Override + public Iterator<@NonNull T> iterator() { + return new ValueIterator(); + } + }; + } +} \ 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/AbstractUnenforcedConnectionInternal.java deleted file mode 100644 index b1d1011f8..000000000 --- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/AbstractUnenforcedConnectionInternal.java +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* - * 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.List; - -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.AbstractInvocation; -import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer; -import org.eclipse.qvtd.runtime.evaluation.Interval; -import org.eclipse.qvtd.runtime.evaluation.Invocation; - -/** - * 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 AbstractUnenforcedConnectionInternal extends AbstractConnectionInternal -{ - protected AbstractUnenforcedConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) { - super(interval, name, typeId); - } - - /** - * Append aValue to the contents, 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)); - } - List<@NonNull Object> valueAndConsumingInvocations = new ArrayList<>(); - valueAndConsumingInvocations.add(aValue); // VALUE_INDEX - valueAndConsumingInvocations.add(listOfValueAndConsumingInvocations.size()); // INDEX_INDEX - listOfValueAndConsumingInvocations.add(valueAndConsumingInvocations); - queue(); - return valueAndConsumingInvocations; - } - - @Override - public void check() { - for (int i = 0; i < listOfValueAndConsumingInvocations.size(); i++) { - List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(i); - if (valueAndConsumingInvocations != null) { - assert valueAndConsumingInvocations.get(INDEX_INDEX) == Integer.valueOf(i); - } - } - } - - /** - * Replace the old value at connectionKey by newValue.The old value is removed, - * its consumingInvocations are invalidated so that they recompute with the newValue which replaces the old. - */ - @Override - public synchronized @NonNull Object replace(@NonNull Object connectionKey, @NonNull Object newValue) { - @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; - Object oldValue = valueAndConsumingInvocations.get(VALUE_INDEX); - if (newValue != oldValue) { // FIXME ?? equals/oclEquals ?? - valueAndConsumingInvocations.set(VALUE_INDEX, newValue); - int iMax = valueAndConsumingInvocations.size(); - for (int i = INDEX_INDEX+1; i < iMax; i++) { - Invocation consumer = (Invocation) valueAndConsumingInvocations.get(i); - interval.queue(consumer); - } - } - return connectionKey; - } - - /** - * Revoke, inverse append, the old value at connectionKey. The old value is removed, - * its consumingInvocations are revoked so that their appends are also revoked. - */ - @Override - public synchronized void revoke(@NonNull Object connectionKey) { - @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; - int valueIndex = (int) valueAndConsumingInvocations.get(INDEX_INDEX); - listOfValueAndConsumingInvocations.set(valueIndex, null); // Do not disrupt index equivalence. - int iMax = valueAndConsumingInvocations.size(); - for (int i = INDEX_INDEX+1; i < iMax; i++) { - AbstractInvocation consumingInvocation = (AbstractInvocation) valueAndConsumingInvocations.get(i); - consumingInvocation.revoke(); - } - } -} \ No newline at end of file diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/IncrementalConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/IncrementalConnectionInternal.java new file mode 100644 index 000000000..4a0544b1a --- /dev/null +++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/IncrementalConnectionInternal.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * 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.List; + +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.AbstractInvocation; +import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer; +import org.eclipse.qvtd.runtime.evaluation.Interval; +import org.eclipse.qvtd.runtime.evaluation.Invocation; + +/** + * 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 class IncrementalConnectionInternal extends AbstractIncrementalConnectionInternal +{ + protected IncrementalConnectionInternal(@NonNull Interval interval, @NonNull String name, @NonNull CollectionTypeId typeId) { + super(interval, name, typeId); + } + + /** + * Append aValue to the contents, 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)); + } + List<@NonNull Object> valueAndConsumingInvocations = new ArrayList<>(); + valueAndConsumingInvocations.add(aValue); // VALUE_INDEX + valueAndConsumingInvocations.add(listOfValueAndConsumingInvocations.size()); // INDEX_INDEX + listOfValueAndConsumingInvocations.add(valueAndConsumingInvocations); + queue(); + return valueAndConsumingInvocations; + } + + @Override + public void check() { + for (int i = 0; i < listOfValueAndConsumingInvocations.size(); i++) { + List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(i); + if (valueAndConsumingInvocations != null) { + assert valueAndConsumingInvocations.get(INDEX_INDEX) == Integer.valueOf(i); + } + } + } + + /** + * Replace the old value at connectionKey by newValue.The old value is removed, + * its consumingInvocations are invalidated so that they recompute with the newValue which replaces the old. + */ + @Override + public synchronized @NonNull Object replace(@NonNull Object connectionKey, @NonNull Object newValue) { + @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; + Object oldValue = valueAndConsumingInvocations.get(VALUE_INDEX); + if (newValue != oldValue) { // FIXME ?? equals/oclEquals ?? + valueAndConsumingInvocations.set(VALUE_INDEX, newValue); + int iMax = valueAndConsumingInvocations.size(); + for (int i = INDEX_INDEX+1; i < iMax; i++) { + Invocation consumer = (Invocation) valueAndConsumingInvocations.get(i); + interval.queue(consumer); + } + } + return connectionKey; + } + + /** + * Revoke, inverse append, the old value at connectionKey. The old value is removed, + * its consumingInvocations are revoked so that their appends are also revoked. + */ + @Override + public synchronized void revoke(@NonNull Object connectionKey) { + @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; + int valueIndex = (int) valueAndConsumingInvocations.get(INDEX_INDEX); + listOfValueAndConsumingInvocations.set(valueIndex, null); // Do not disrupt index equivalence. + int iMax = valueAndConsumingInvocations.size(); + for (int i = INDEX_INDEX+1; i < iMax; i++) { + AbstractInvocation consumingInvocation = (AbstractInvocation) valueAndConsumingInvocations.get(i); + consumingInvocation.revoke(); + } + } +} \ No newline at end of file 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/StrictIncrementalConnectionInternal.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictIncrementalConnectionInternal.java new file mode 100644 index 000000000..c46d387ea --- /dev/null +++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/internal/evaluation/StrictIncrementalConnectionInternal.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * 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.HashMap; +import java.util.List; +import java.util.Map; + +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.AbstractInvocation; +import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer; +import org.eclipse.qvtd.runtime.evaluation.Interval; +import org.eclipse.qvtd.runtime.evaluation.Invocation; + +/** + * An AbstractEnforcedConnectionInternal 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 supported by a revoke() or an append(), or a replace() of an appended value. + */ +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 StrictIncrementalConnectionInternal(@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)); + } + List<@NonNull Object> valueAndConsumingInvocations = uniqueValues2valueAndConsumingInvocations.get(aValue); + if (valueAndConsumingInvocations == null) { + valueAndConsumingInvocations = new ArrayList<>(); + valueAndConsumingInvocations.add(aValue); // VALUE_INDEX + valueAndConsumingInvocations.add(listOfValueAndConsumingInvocations.size()); // INDEX_INDEX + valueAndConsumingInvocations.add(1); // COUNT_INDEX + listOfValueAndConsumingInvocations.add(valueAndConsumingInvocations); + uniqueValues2valueAndConsumingInvocations.put(aValue, valueAndConsumingInvocations); + queue(); + } + else { + Integer count = (Integer) valueAndConsumingInvocations.get(COUNT_INDEX); + valueAndConsumingInvocations.set(COUNT_INDEX, count+1); + } + return valueAndConsumingInvocations; + } + + @Override + public void check() { + for (int i = 0; i < listOfValueAndConsumingInvocations.size(); i++) { + List<@NonNull Object> valueAndConsumingInvocations = listOfValueAndConsumingInvocations.get(i); + if (valueAndConsumingInvocations != null) { + assert valueAndConsumingInvocations.get(INDEX_INDEX) == Integer.valueOf(i); + assert valueAndConsumingInvocations.contains(valueAndConsumingInvocations.get(VALUE_INDEX)); + } + } + } + + /** + * 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. + */ + @Override + public synchronized @NonNull Object replace(@NonNull Object connectionKey, @NonNull Object newValue) { + @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; + Object oldValue = valueAndConsumingInvocations.get(VALUE_INDEX); + if (newValue != oldValue) { // FIXME ?? equals/oclEquals ?? + Integer count = (Integer) valueAndConsumingInvocations.get(COUNT_INDEX); + if (count > 1) { + valueAndConsumingInvocations.set(COUNT_INDEX, count-1); + return append(newValue); + } + valueAndConsumingInvocations.set(VALUE_INDEX, newValue); + int iMax = valueAndConsumingInvocations.size(); + for (int i = COUNT_INDEX+1; i < iMax; i++) { + Invocation consumer = (Invocation) valueAndConsumingInvocations.get(i); + interval.queue(consumer); + } + } + return connectionKey; + } + + /** + * 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. + */ + @Override + public synchronized void revoke(@NonNull Object connectionKey) { + @SuppressWarnings("unchecked") List<@NonNull Object> valueAndConsumingInvocations = (List<@NonNull Object>) connectionKey; + int valueIndex = (int) valueAndConsumingInvocations.get(INDEX_INDEX); + Integer count = (Integer) valueAndConsumingInvocations.get(COUNT_INDEX); + if (count > 1) { + valueAndConsumingInvocations.set(COUNT_INDEX, count-1); + return; + } + listOfValueAndConsumingInvocations.set(valueIndex, null); // Do not disrupt index equivalence. + int iMax = valueAndConsumingInvocations.size(); + for (int i = COUNT_INDEX+1; i < iMax; i++) { + AbstractInvocation consumingInvocation = (AbstractInvocation) valueAndConsumingInvocations.get(i); + consumingInvocation.revoke(); + } + } +} \ No newline at end of file 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()); } { @@ -131,6 +133,11 @@ public class QVTimperativeFormatter extends AbstractEssentialOCLFormatter ImportCSElements a = f.getImportCSAccess(); 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()); 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]); } } -- cgit v1.2.3