blob: 883c44e4803d707375e4eb28201f668ffd44b5a6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2018 Borland Software Corporation and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Borland Software Corporation - initial API and implementation
* Alex Paperno - bugs 404647
********************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.stdlib;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv;
import org.eclipse.m2m.internal.qvt.oml.evaluator.ModuleInstance;
import org.eclipse.m2m.qvt.oml.util.MutableList;
import org.eclipse.m2m.qvt.oml.util.Utils;
import org.eclipse.ocl.expressions.CollectionKind;
import org.eclipse.ocl.types.OCLStandardLibrary;
import org.eclipse.ocl.util.CollectionUtil;
import org.eclipse.ocl.util.TypeUtil;
import org.eclipse.ocl.utilities.PredefinedType;
public class ListOperations extends AbstractContextualOperations {
static final String ADD_NAME = "add"; //$NON-NLS-1$
static final String REMOVE_NAME = "remove"; //$NON-NLS-1$
static final String REMOVE_ALL_NAME = "removeAll"; //$NON-NLS-1$
static final String REMOVE_AT_NAME = "removeAt"; //$NON-NLS-1$
static final String REMOVE_FIRST_NAME = "removeFirst"; //$NON-NLS-1$
static final String REMOVE_LAST_NAME = "removeLast"; //$NON-NLS-1$
static final String JOINFIELDS_NAME = "joinfields"; //$NON-NLS-1$
static final String SELECT_BY_TYPE_NAME = "selectByType"; //$NON-NLS-1$
static final String SELECT_BY_KIND_NAME = "selectByKind"; //$NON-NLS-1$
public ListOperations(AbstractQVTStdlib library) {
super(library, library.getList());
}
@Override
protected OperationProvider[] getOperations() {
OCLStandardLibrary<EClassifier> oclStdlib = getStdlib().getOCLStdLib();
EClassifier listOfT2 = getStdlib().getEnvironment().getTypeResolver().resolveListType(oclStdlib.getT2());
EClassifier listOfCommonT = getStdlib().getEnvironment().getTypeResolver().resolveListType(getStdlib().getCommonT());
EClassifier collectionOfT2 = TypeUtil.resolveCollectionType(getStdlib().getEnvironment(),
CollectionKind.COLLECTION_LITERAL, oclStdlib.getT2());
return new OperationProvider[] {
new OperationProvider(ADD, ADD_NAME, new String[] { "object"}, oclStdlib.getOclVoid(), oclStdlib.getT()), //$NON-NLS-1$
new OperationProvider(UNSUPPORTED_OPER, ADD_NAME,
new String[] {"obj", "List(T)::add(object:T2) is supported only for case T2_isSubtypeOf_T"}, //$NON-NLS-1$ //$NON-NLS-2$
oclStdlib.getOclVoid(), oclStdlib.getT2()),
new OperationProvider(INSERT_AT_VOID, PredefinedType.INSERT_AT_NAME, new String[] { "object", "index"}, //$NON-NLS-1$ //$NON-NLS-2$
oclStdlib.getOclVoid(), oclStdlib.getT(), oclStdlib.getInteger()),
// new OperationProvider(UNSUPPORTED_OPER, PredefinedType.INSERT_AT_NAME,
// new String[] { "obj", "index", "List(T)::insertAt(object:T2,index:Integer) is supported only for case T2_isSubtypeOf_T" }, //$NON-NLS-1$ //$NON-NLS-2$
// oclStdlib.getOclVoid(), oclStdlib.getT2(), oclStdlib.getInteger()),
new OperationProvider(REMOVE, REMOVE_NAME, new String[] { "element"}, oclStdlib.getOclVoid(), oclStdlib.getT2()), //$NON-NLS-1$
new OperationProvider(REMOVE_ALL, REMOVE_ALL_NAME, new String[] { "elements"}, oclStdlib.getOclVoid(), collectionOfT2), //$NON-NLS-1$
new OperationProvider(REMOVE_AT, REMOVE_AT_NAME, new String[] { "index"}, oclStdlib.getT(), oclStdlib.getInteger()), //$NON-NLS-1$
new OperationProvider(REMOVE_FIRST, REMOVE_FIRST_NAME, oclStdlib.getT()), //$NON-NLS-1$
new OperationProvider(REMOVE_LAST, REMOVE_LAST_NAME, oclStdlib.getT()), //$NON-NLS-1$
new OperationProvider(JOINFIELDS, JOINFIELDS_NAME, new String[] { "sep", "begin", "end" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
oclStdlib.getString(), oclStdlib.getString(), oclStdlib.getString(), oclStdlib.getString()),
new OperationProvider(FIRST, PredefinedType.FIRST_NAME, oclStdlib.getT()),
new OperationProvider(LAST, PredefinedType.LAST_NAME, oclStdlib.getT()),
new OperationProvider(AT, PredefinedType.AT_NAME, new String[] { "i" }, //$NON-NLS-1$
oclStdlib.getT(), oclStdlib.getInteger()),
new OperationProvider(CLONE, ElementOperations.CLONE_NAME, getStdlib().getList()),
new OperationProvider(UNSUPPORTED_OPER, ElementOperations.DEEP_CLONE_NAME,
new String[] { "List(T)::deepclone() is not supported yet" }, //$NON-NLS-1$ //$NON-NLS-2$
getStdlib().getList()),
new OperationProvider(SELECT_BY_TYPE, SELECT_BY_TYPE_NAME, new String[] { "type" }, //$NON-NLS-1$ //$NON-NLS-2$
getStdlib().getList(), oclStdlib.getOclType()),
new OperationProvider(SELECT_BY_KIND, SELECT_BY_KIND_NAME, new String[] { "type" }, //$NON-NLS-1$ //$NON-NLS-2$
getStdlib().getList(), oclStdlib.getOclType()),
new OperationProvider(SUB_SEQUENCE, PredefinedType.SUB_SEQUENCE_NAME, new String[] { "lower", "upper" }, //$NON-NLS-1$ //$NON-NLS-2$
getStdlib().getList(), oclStdlib.getInteger(), oclStdlib.getInteger()),
new OperationProvider(CollectionTypeOperations.FLATTEN, PredefinedType.FLATTEN_NAME, listOfT2),
new OperationProvider(SetTypeOperations.INCLUDING, PredefinedType.INCLUDING_NAME, new String[] {"object"}, //$NON-NLS-1$
listOfCommonT, oclStdlib.getT2()),
new OperationProvider(SetTypeOperations.EXCLUDING, PredefinedType.EXCLUDING_NAME, new String[] {"object"}, //$NON-NLS-1$
getStdlib().getList(), oclStdlib.getT2()),
new OperationProvider(SetTypeOperations.UNION, PredefinedType.UNION_NAME, new String[] {"s"}, //$NON-NLS-1$
listOfCommonT, listOfT2),
new OperationProvider(OrderedSetTypeOperations.REVERSE, OrderedSetTypeOperations.REVERSE_NAME, getStdlib().getList()),
new OperationProvider(OrderedSetTypeOperations.APPEND, PredefinedType.APPEND_NAME, new String[] {"object"}, //$NON-NLS-1$
listOfCommonT, oclStdlib.getT2()),
new OperationProvider(OrderedSetTypeOperations.PREPEND, PredefinedType.PREPEND_NAME, new String[] {"object"}, //$NON-NLS-1$
listOfCommonT, oclStdlib.getT2()),
new OperationProvider(OrderedSetTypeOperations.INSERT_AT, PredefinedType.INSERT_AT_NAME, new String[] {"index", "object"}, //$NON-NLS-1$ //$NON-NLS-2$
listOfCommonT, oclStdlib.getInteger(), oclStdlib.getT2()),
new OperationProvider(OrderedSetTypeOperations.INDEX_OF, PredefinedType.INDEX_OF_NAME, new String[] {"object"}, //$NON-NLS-1$
oclStdlib.getInteger(), oclStdlib.getT2()),
};
}
static CallHandler ADD = new CallHandlerMutator() {
@SuppressWarnings("unchecked")
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList && args.length > 0) {
List<Object> list = (List<Object>) source;
Object element = args[0];
if(element != CallHandlerAdapter.getInvalidResult(evalEnv)) {
list.add(element);
}
return list;
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
static CallHandler INSERT_AT_VOID = new CallHandlerMutator() {
@SuppressWarnings("unchecked")
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList && args.length > 1 && args[1] instanceof Integer) {
MutableList<Object> list = (MutableList<Object>) source;
Object element = args[0];
if(element != CallHandlerAdapter.getInvalidResult(evalEnv)) {
list.insertAt(element, (Integer) args[1]);
}
return list;
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
static CallHandler REMOVE = new CallHandlerMutator() {
@SuppressWarnings("unchecked")
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList && args.length > 0) {
List<Object> list = (List<Object>) source;
Object element = args[0];
if(element != CallHandlerAdapter.getInvalidResult(evalEnv)) {
list.removeAll(Collections.singleton(element));
}
return list;
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
static CallHandler REMOVE_ALL = new CallHandlerMutator() {
@SuppressWarnings("unchecked")
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList && args.length > 0 && args[0] instanceof Collection) {
List<Object> list = (List<Object>) source;
list.removeAll((Collection<?>) args[0]);
return list;
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
static CallHandler REMOVE_AT = new CallHandlerMutator() {
@SuppressWarnings("unchecked")
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList && args.length > 0 && args[0] instanceof Integer) {
List<Object> list = (List<Object>) source;
int index = (Integer) args[0] - 1;
if (index < 0 || index >= list.size()) {
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
return list.remove(index);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
static CallHandler REMOVE_FIRST = new CallHandlerMutator() {
@SuppressWarnings("unchecked")
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList) {
List<Object> list = (List<Object>) source;
if (list.isEmpty()) {
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
return list.remove(0);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
static CallHandler REMOVE_LAST = new CallHandlerMutator() {
@SuppressWarnings("unchecked")
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList) {
List<Object> list = (List<Object>) source;
if (list.isEmpty()) {
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
return list.remove(list.size()-1);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
static CallHandler JOINFIELDS = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof MutableList && args.length > 2 && args[0] instanceof String && args[1] instanceof String && args[2] instanceof String) {
MutableList<?> list = (MutableList<?>) source;
String sep = (String) args[0];
String begin = (String) args[1];
String end = (String) args[2];
return list.joinfields(sep, begin, end);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
private static CallHandler FIRST = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof Collection) {
if (((Collection<?>) source).isEmpty()) {
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
return CollectionUtil.first((Collection<?>) source);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
private static CallHandler LAST = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof Collection) {
if (((Collection<?>) source).isEmpty()) {
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
return CollectionUtil.last((Collection<?>) source);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
private static CallHandler AT = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof Collection && args.length > 0 && args[0] instanceof Integer) {
int index = (Integer) args[0] - 1;
if (index < 0 || index >= ((Collection<?>) source).size()) {
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
return CollectionUtil.at((Collection<?>) source, (Integer) args[0]);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
private static CallHandler CLONE = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof Collection) {
return Utils.createList((Collection<?>) source);
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
private static CallHandler SELECT_BY_TYPE = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof Collection && args.length > 0 && args[0] instanceof EClassifier) {
MutableList<Object> result = Utils.createList();
EClassifier type = (EClassifier) args[0];
for (Iterator<?> it = ((Collection<?>) source).iterator(); it.hasNext();) {
Object object = it.next();
if (evalEnv.isTypeOf(object, type)) {
result.add(object);
}
}
return result;
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
private static CallHandler SELECT_BY_KIND = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof Collection && args.length > 0 && args[0] instanceof EClassifier) {
MutableList<Object> result = Utils.createList();
EClassifier type = (EClassifier) args[0];
for (Iterator<?> it = ((Collection<?>) source).iterator(); it.hasNext();) {
Object object = it.next();
if (evalEnv.isKindOf(object, type)) {
result.add(object);
}
}
return result;
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
private static CallHandler SUB_SEQUENCE = new CallHandler() {
public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) {
if(source instanceof Collection && args.length > 1 && args[0] instanceof Integer && args[1] instanceof Integer) {
Collection<?> result = CollectionUtil.subSequence((Collection<?>) source, (Integer) args[0], (Integer) args[1]);
if (source instanceof MutableList && false == result instanceof MutableList) {
result = Utils.createList(result);
}
return result;
}
return CallHandlerAdapter.getInvalidResult(evalEnv);
}
};
}