blob: 7c580c7851ee377eaa99d1a07d1084c90e1ae4cd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency
* 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:
* Mathieu Larose (Savoir-faire Linux) - Initial API and implementation
*
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.core.programs.javascript;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.apogy.common.emf.AbstractFeatureListNode;
import org.eclipse.apogy.common.emf.ApogyCommonEMFFactory;
import org.eclipse.apogy.common.emf.ListFeatureNode;
import org.eclipse.apogy.common.emf.ListRootNode;
import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorFactory;
import org.eclipse.apogy.core.invocator.OperationCall;
import org.eclipse.apogy.core.invocator.TypeMember;
import org.eclipse.apogy.core.invocator.TypeMemberReferenceListElement;
import org.eclipse.apogy.core.invocator.Variable;
import org.eclipse.apogy.core.invocator.VariableFeatureReference;
public class VariableFeatureReferenceUtil {
/**
* Clones a VariableFeatureReference
*
* @param source source VariableFeatureReference
* @return a new VariableFeatureReference based on the source
*/
public static VariableFeatureReference clone(VariableFeatureReference source) {
VariableFeatureReference destination = ApogyCoreInvocatorFactory.eINSTANCE.createVariableFeatureReference();
destination.setVariable(source.getVariable());
ListRootNode srcFeatureRoot = source.getFeatureRoot();
if (srcFeatureRoot != null) {
ListRootNode dstFeatureRoot = ApogyCommonEMFFactory.eINSTANCE.createListRootNode();
dstFeatureRoot.setSourceClass(srcFeatureRoot.getSourceClass());
AbstractFeatureListNode srcCurrent = srcFeatureRoot;
AbstractFeatureListNode dstCurrent = dstFeatureRoot;
while (srcCurrent.getChild() != null) {
ListFeatureNode srcChild = (ListFeatureNode) srcCurrent.getChild();
ListFeatureNode dstChild = ApogyCommonEMFFactory.eINSTANCE.createListFeatureNode();
dstChild.setStructuralFeature(srcChild.getStructuralFeature());
dstCurrent.setChild(dstChild);
srcCurrent = srcChild;
dstCurrent = dstChild;
}
destination.setFeatureRoot(dstFeatureRoot);
}
if (source.getTypeMemberReferenceListElement() != null) {
TypeMemberReferenceListElement dstTypeMemberReferenceListElement = ApogyCoreInvocatorFactory.eINSTANCE
.createTypeMemberReferenceListElement();
TypeMemberReferenceListElement srcCurrent = source.getTypeMemberReferenceListElement();
TypeMemberReferenceListElement dstCurrent = dstTypeMemberReferenceListElement;
dstCurrent.setTypeMember(srcCurrent.getTypeMember());
while (srcCurrent.getChild() != null) {
TypeMemberReferenceListElement srcChild = srcCurrent.getChild();
TypeMemberReferenceListElement dstChild = ApogyCoreInvocatorFactory.eINSTANCE
.createTypeMemberReferenceListElement();
dstChild.setTypeMember(srcChild.getTypeMember());
dstCurrent.setChild(dstChild);
srcCurrent = srcChild;
dstCurrent = dstChild;
}
destination.setTypeMemberReferenceListElement(dstTypeMemberReferenceListElement);
}
return destination;
}
/**
* Creates an {@OperationCall} from a {@VariableFeatureReference}
*
* @param source source VariableFeatureReference
* @return an {@OperationCall} from the source VariableFeatureReference
*/
public static OperationCall toOperationCall(VariableFeatureReference source) {
source = clone(source);
OperationCall operationCall = ApogyCoreInvocatorFactory.eINSTANCE.createOperationCall();
operationCall.setVariable(source.getVariable());
operationCall.setTypeMemberReferenceListElement(source.getTypeMemberReferenceListElement());
operationCall.setFeatureRoot(source.getFeatureRoot());
return operationCall;
}
/**
* Given a variable and a TypeMember that is in the type member hierarchy under
* the variable, creates an VariableFeatureReference referring the specified
* TypeMember.
*
* @param variable The variable.
* @param typeMember A TypeMember that is in the type member hierarchy under the
* specified variable.
* @return The VariableFeatureReference referring the specified TypeMember, null
* if none was found.
*/
public VariableFeatureReference createTypeMemberHierarchy(VariableFeatureReference variableFeatureReference,
TypeMember typeMember) {
Variable variable = variableFeatureReference.getVariable();
List<TypeMember> hierarchy = new ArrayList<TypeMember>();
boolean found = false;
Iterator<TypeMember> it = variable.getVariableType().getMembers().iterator();
while (it.hasNext() && !found) {
TypeMember tm = it.next();
found = exploreTypeMember(tm, typeMember, hierarchy);
}
if (found && !hierarchy.isEmpty()) {
Iterator<TypeMember> hierarchyIt = hierarchy.iterator();
TypeMemberReferenceListElement previous = ApogyCoreInvocatorFactory.eINSTANCE
.createTypeMemberReferenceListElement();
previous.setTypeMember(hierarchyIt.next());
variableFeatureReference.setTypeMemberReferenceListElement(previous);
while (hierarchyIt.hasNext()) {
TypeMember tm = hierarchyIt.next();
TypeMemberReferenceListElement current = ApogyCoreInvocatorFactory.eINSTANCE
.createTypeMemberReferenceListElement();
current.setTypeMember(tm);
current.setParent(previous);
previous.setChild(current);
previous = current;
}
}
return variableFeatureReference;
}
/**
* Recursive exploration of a TypeMember to find a specified TypeMember.
*
* @param rootTypeMember The TypeMember to explore from.
* @param targetTypeMember The TypeMember we are looking for.
* @param exploredHierarchy A list were to store the hierarchy leading to the
* TypeMember we are looking for.
* @return
*/
public boolean exploreTypeMember(TypeMember rootTypeMember, TypeMember targetTypeMember,
List<TypeMember> exploredHierarchy) {
boolean found = false;
if (rootTypeMember == targetTypeMember) {
exploredHierarchy.add(rootTypeMember);
found = true;
} else {
exploredHierarchy.add(rootTypeMember);
Iterator<TypeMember> it = rootTypeMember.getMemberType().getMembers().iterator();
while (it.hasNext() && !found) {
TypeMember tm = it.next();
found = exploreTypeMember(tm, targetTypeMember, exploredHierarchy);
}
if (!found) {
int index = exploredHierarchy.indexOf(rootTypeMember);
List<TypeMember> toRemove = new ArrayList<TypeMember>();
for (int i = index; i < exploredHierarchy.size(); i++) {
toRemove.add(exploredHierarchy.get(i));
}
exploredHierarchy.removeAll(toRemove);
}
}
return found;
}
}