blob: f41bc03d601b19bf16735629293f641ad3cbb110 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2011 E.D.Willink and others.
* 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:
* E.D.Willink - initial API and implementation
*
* </copyright>
*
* $Id$
*/
package org.eclipse.ocl.examples.pivot.manager;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.ocl.examples.pivot.Operation;
import org.eclipse.ocl.examples.pivot.Parameter;
import org.eclipse.ocl.examples.pivot.Precedence;
import org.eclipse.ocl.examples.pivot.Type;
import org.eclipse.ocl.examples.pivot.utilities.PivotUtil;
/**
* PrecedenceManager encapsulates the knowledge about known precedences.
*/
public class PrecedenceManager
{
/**
* Map of precedence name to precedence objects. Multiple precedence objects
* may be associated with a single name since alternate contributions
* provide independent lists that must be successfully interleaved so that
* all same-named precedence objects get the same compiled ordering.
* <p>
* e.g. <tt> precedence A B D</tt> and <tt>precedence B C D</tt> merge to
* <tt>A B C D</tt> with duplicate precedence objects for B and D.
*/
private Map<String, List<Precedence>> nameToPrecedencesMap = null;
private Map<String, String> infixToPrecedenceNameMap = null;
private Map<String, String> prefixToPrecedenceNameMap = null;
/**
* Interleave the ownedPrecedences of the rootPackages to establish a merged
* ordering and assign the index in that ordering to each
* rootPackages.ownedPrecedences. Any inconsistent ordering and
* associativity is diagnosed.
*/
public List<String> compilePrecedences(Iterable<? extends org.eclipse.ocl.examples.pivot.Package> rootPackages) {
List<String> errors = new ArrayList<String>();
List<String> orderedPrecedences = new ArrayList<String>();
nameToPrecedencesMap = new HashMap<String, List<Precedence>>();
infixToPrecedenceNameMap = new HashMap<String, String>();
prefixToPrecedenceNameMap = new HashMap<String, String>();
for (org.eclipse.ocl.examples.pivot.Package rootPackage : rootPackages) {
List<Precedence> precedences = rootPackage.getOwnedPrecedence();
if (precedences.size() > 0) {
compilePrecedencePackage(errors, rootPackage);
int prevIndex = -1;
List<Precedence> list = null;
String name = null;
for (Precedence precedence : precedences) {
name = precedence.getName();
int index = orderedPrecedences.indexOf(name);
if (index < 0) {
index = prevIndex < 0
? orderedPrecedences.size()
: prevIndex + 1;
orderedPrecedences.add(index, name);
list = new ArrayList<Precedence>();
nameToPrecedencesMap.put(name, list);
} else {
list = nameToPrecedencesMap.get(name);
if (index <= prevIndex) {
errors.add("Inconsistent precedence ordering for '"
+ name + "'");
} else if ((prevIndex >= 0) && (index != prevIndex + 1)) {
errors.add("Ambiguous precedence ordering for '"
+ name + "'");
}
if (precedence.getAssociativity() != list.get(0)
.getAssociativity()) {
errors
.add("Inconsistent precedence associativity for '"
+ name + "'");
}
}
prevIndex = index;
list.add(precedence);
}
if ((list != null) && (list.size() == 1)
&& (prevIndex != orderedPrecedences.size() - 1)) {
errors.add("Ambiguous precedence ordering for '" + name
+ "' at tail");
}
}
}
for (int i = 0; i < orderedPrecedences.size(); i++) {
String name = orderedPrecedences.get(i);
BigInteger order = BigInteger.valueOf(i);
for (Precedence precedence : nameToPrecedencesMap.get(name)) {
precedence.setOrder(order);
}
}
return errors;
}
protected void compilePrecedenceOperation(List<String> errors, Operation operation) {
Precedence precedence = operation.getPrecedence();
if (precedence != null) {
List<Parameter> parameters = operation.getOwnedParameter();
if (parameters.size() == 0) {
String newName = precedence.getName();
String operatorName = operation.getName();
String oldName = prefixToPrecedenceNameMap.put(operatorName,
newName);
if ((oldName != null) && !oldName.equals(newName)) {
errors.add("Conflicting precedences for prefix operation '" + operatorName + "'");
}
} else if (parameters.size() == 1) {
String newName = precedence.getName();
String operatorName = operation.getName();
String oldName = infixToPrecedenceNameMap.put(operatorName,
newName);
if ((oldName != null) && !oldName.equals(newName)) {
errors.add("Conflicting precedences for infix operation '" + operatorName + "'");
}
}
}
}
protected void compilePrecedencePackage(List<String> errors, org.eclipse.ocl.examples.pivot.Package pivotPackage) {
for (org.eclipse.ocl.examples.pivot.Package nestedPackage : pivotPackage.getNestedPackage()) {
compilePrecedencePackage(errors, nestedPackage);
}
for (Type type : pivotPackage.getOwnedType()) {
if (PivotUtil.isLibraryType(type)) {
compilePrecedenceType(errors, type);
}
}
}
protected void compilePrecedenceType(List<String> errors, Type pivotType) {
for (Operation operation : pivotType.getOwnedOperation()) {
compilePrecedenceOperation(errors, operation);
}
}
public void dispose() {
nameToPrecedencesMap = null;
infixToPrecedenceNameMap = null;
prefixToPrecedenceNameMap = null;
}
public Precedence getInfixPrecedence(String operatorName) {
String precedenceName = infixToPrecedenceNameMap.get(operatorName);
if (precedenceName == null) {
return null;
}
List<Precedence> precedences = nameToPrecedencesMap.get(precedenceName);
if (precedences == null) {
return null;
}
return precedences.get(0);
}
public Precedence getPrefixPrecedence(String operatorName) {
String precedenceName = prefixToPrecedenceNameMap.get(operatorName);
if (precedenceName == null) {
return null;
}
List<Precedence> precedences = nameToPrecedencesMap.get(precedenceName);
if (precedences == null) {
return null;
}
return precedences.get(0);
}
}