| /******************************************************************************* |
| * Copyright (c) 2010, 2018 SAP AG 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: |
| * Axel Uhl - Initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ocl.ecore.parser; |
| |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EEnumLiteral; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EParameter; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.ocl.Environment; |
| import org.eclipse.ocl.LookupException; |
| import org.eclipse.ocl.cst.CSTNode; |
| import org.eclipse.ocl.cst.SimpleNameCS; |
| import org.eclipse.ocl.ecore.CallOperationAction; |
| import org.eclipse.ocl.ecore.Constraint; |
| import org.eclipse.ocl.ecore.EnvironmentWithHiddenOpposites; |
| import org.eclipse.ocl.ecore.OppositePropertyCallExp; |
| import org.eclipse.ocl.ecore.SendSignalAction; |
| import org.eclipse.ocl.ecore.utilities.OCLFactoryWithHiddenOpposite; |
| import org.eclipse.ocl.expressions.NavigationCallExp; |
| import org.eclipse.ocl.expressions.OCLExpression; |
| import org.eclipse.ocl.expressions.PropertyCallExp; |
| import org.eclipse.ocl.expressions.Variable; |
| import org.eclipse.ocl.expressions.VariableExp; |
| import org.eclipse.ocl.parser.AbstractOCLParser; |
| |
| /** |
| * @since 3.1 |
| */ |
| public class OCLAnalyzer |
| extends |
| org.eclipse.ocl.parser.OCLAnalyzer<EPackage, EClassifier, EOperation, EStructuralFeature, |
| EEnumLiteral, EParameter, EObject, |
| CallOperationAction, SendSignalAction, Constraint, |
| EClass, EObject> { |
| |
| public OCLAnalyzer(AbstractOCLParser parser) { |
| super(parser); |
| } |
| |
| public OCLAnalyzer( |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> rootEnvironment, |
| String input) { |
| super(rootEnvironment, input); |
| } |
| |
| /** |
| * Attempts to parse a <tt>simpleNameCS</tt> as a property call expression. |
| * |
| * @param simpleNameCS |
| * the simple name |
| * @param env |
| * the current environment |
| * @param source |
| * the navigation source expression, or <code>null</code> if the |
| * source is implicit |
| * @param owner |
| * the owner of the property to be navigated, or |
| * <code>null</code> if the source is implicit |
| * @param simpleName |
| * the simple name, as a string |
| * @return the parsed property call, or <code>null</code> if the simple name |
| * does not resolve to an available property |
| * |
| * @see #simpleNameCS(SimpleNameCS, Environment, OCLExpression) |
| */ |
| @Override |
| protected NavigationCallExp<EClassifier, EStructuralFeature> simpleNavigationName( |
| SimpleNameCS simpleNameCS, |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, |
| EEnumLiteral, EParameter, EObject, |
| CallOperationAction, SendSignalAction, Constraint, |
| EClass, EObject> env, |
| OCLExpression<EClassifier> source, EClassifier owner, String simpleName) { |
| if (simpleName == null) { |
| return null; |
| } |
| NavigationCallExp<EClassifier, EStructuralFeature> result = null; |
| |
| EStructuralFeature property = lookupProperty(simpleNameCS, env, owner, simpleName); |
| if (property != null) { |
| if ((uml.getOwningClassifier(property) == null) && (property instanceof EReference)) { |
| // marks a temporary property that encodes a "hidden" opposite |
| result = createOppositePropertyCallExp(simpleNameCS, (EnvironmentWithHiddenOpposites)env, |
| source, owner, simpleName, ((EReference) property).getEOpposite()); |
| } else { |
| result = createPropertyCallExp(simpleNameCS, env, source, |
| owner, simpleName, property); |
| } |
| } |
| return result; |
| } |
| |
| private PropertyCallExp<EClassifier, EStructuralFeature> createPropertyCallExp( |
| SimpleNameCS simpleNameCS, |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, |
| EEnumLiteral, EParameter, EObject, |
| CallOperationAction, SendSignalAction, Constraint, |
| EClass, EObject> env, |
| OCLExpression<EClassifier> source, EClassifier owner, String simpleName, EStructuralFeature property) { |
| PropertyCallExp<EClassifier, EStructuralFeature> result; |
| TRACE("variableExpCS", "Property: " + simpleName);//$NON-NLS-2$//$NON-NLS-1$ |
| |
| result = oclFactory.createPropertyCallExp(); |
| initASTMapping(env, result, simpleNameCS, null); |
| result.setReferredProperty(property); |
| result.setType(getPropertyType(simpleNameCS, env, owner, property)); |
| |
| if (source != null) { |
| result.setSource(source); |
| } else { |
| Variable<EClassifier, EParameter> implicitSource = env |
| .lookupImplicitSourceForProperty(simpleName); |
| VariableExp<EClassifier, EParameter> src = createVariableExp(env, simpleNameCS, |
| implicitSource); |
| result.setSource(src); |
| } |
| |
| initPropertyPositions(result, simpleNameCS); |
| return result; |
| } |
| |
| private OppositePropertyCallExp createOppositePropertyCallExp( |
| SimpleNameCS simpleNameCS, EnvironmentWithHiddenOpposites env, |
| OCLExpression<EClassifier> source, EClassifier owner, String simpleName, EReference property) { |
| OppositePropertyCallExp result; |
| TRACE("variableExpCS", "Opposite Property: " + simpleName);//$NON-NLS-2$//$NON-NLS-1$ |
| |
| // The following cast is permissible because opposite property calls can only occur in |
| // environments that have factories implementing OCLFactoryWithHiddenOpposite, e.g., |
| // the OCLFactory implementation for OCLEcore. |
| result = ((OCLFactoryWithHiddenOpposite) oclFactory).createOppositePropertyCallExp(); |
| initASTMapping(env, result, simpleNameCS, null); |
| result.setReferredOppositeProperty(property); |
| EClassifier propertyType = env.getOppositePropertyType(owner, property); |
| initASTMapping(env, propertyType, simpleNameCS, property); |
| result.setType(propertyType); |
| |
| if (source != null) { |
| result.setSource(source); |
| } else { |
| Variable<EClassifier, EParameter> implicitSource = |
| env.lookupImplicitSourceForOppositeProperty(simpleName); |
| VariableExp<EClassifier, EParameter> src = createVariableExp(env, |
| simpleNameCS, implicitSource); |
| result.setSource(src); |
| } |
| |
| initPropertyPositions(result, simpleNameCS); |
| return result; |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| protected EReference lookupOppositeProperty(CSTNode cstNode, |
| EnvironmentWithHiddenOpposites env, EClassifier owner, String name) { |
| try { |
| EReference property = env.lookupOppositeProperty(owner, name); |
| if (cstNode != null) { |
| cstNode.setAst(property); |
| } |
| return property; |
| } catch (LookupException e) { |
| ERROR(cstNode, null, e.getMessage()); |
| return e.getAmbiguousMatches().isEmpty() |
| ? null |
| : (EReference) e.getAmbiguousMatches().get(0); |
| } |
| } |
| |
| } |