| /******************************************************************************* |
| * 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; |
| } |
| } |