package com.sap.runlet.interpreter.expressions; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Iterator; import java.util.List; import behavioral.actions.Statement; import com.sap.runlet.abstractinterpreter.Interpreter; import com.sap.runlet.abstractinterpreter.objects.MultiValuedObject; import com.sap.runlet.abstractinterpreter.objects.RunletObject; import com.sap.runlet.interpreter.RunletInterpreter; import com.sap.runlet.interpreter.RunletStackFrame; import data.classes.Association; import data.classes.AssociationEnd; import data.classes.ClassTypeDefinition; import data.classes.NativeImpl; import data.classes.SapClass; import data.classes.SignatureImplementation; import data.classes.TypeDefinition; import dataaccess.expressions.Expression; import dataaccess.expressions.collectionexpressions.Excluding; import dataaccess.expressions.collectionexpressions.ExcludingAt; /** * Interprets the {@link Excluding} expression which creates a new multi-object * from an existing one by copying all contained objects except for those specified * for exclusion.<p> * * TODO currently the semantics implemented are somewhat odd: the exclude sequence * will be removed starting at the "at" position up to the point where the exclude * sequence no longer matches the source sequence. For example, * [1, 2, 3]->excluding[2]([2, 2]) will remove only the 2, resulting in [1, 3] because * the second occurrence of 2 in the exclude sequence is not matched. It may be more * straightforward to try to remove the exclude sequence atomically (all or nothing). * * @author Axel Uhl (D043530) */ public class ExcludingAtInterpreter implements Interpreter<ExcludingAt, SapClass, TypeDefinition, ClassTypeDefinition, Association, AssociationEnd, Statement, Expression, SignatureImplementation, RunletStackFrame, NativeImpl, RunletInterpreter> { private ExcludingAt excluding; public ExcludingAtInterpreter(ExcludingAt excluding) { this.excluding = excluding; } @Override public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> evaluate(RunletInterpreter interpreter) throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { Collection<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> resultCollection = RunletObject.createCollection( /* ordered */ true, excluding.getType().isUnique()); List<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> resultList = (List<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>) resultCollection; RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> arg = interpreter.evaluate(excluding.getArgument()); RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> source = interpreter.evaluate(excluding.getSource()); boolean sequenceMatching = true; int i=0; Iterator<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> argIterator = arg.iterator(); for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> sourceObject:source) { if (sequenceMatching && i>=excluding.getAt()) { if (argIterator.hasNext()) { sequenceMatching = sourceObject.equals(argIterator.next()); } else { sequenceMatching = false; // arg sequence end reached; no further checking required } if (!sequenceMatching) { // mismatch with exclude sequence or exclude sequence ended resultList.add(sourceObject); } } else { // arg sequence ended or hasn't started yet or mismatch found resultList.add(sourceObject); } i++; } MultiValuedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> result = new MultiValuedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>( excluding.getType(), resultList, excluding.getType().isOrdered(), excluding.getType().isUnique()); return result; } }