/* * Copyright (c) 2003- michael lawley and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation * which accompanies this distribution, and is available by writing to * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contributors: * michael lawley * David Hearnden */ package tefkat.engine; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EFactory; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import tefkat.engine.trace.impl.TracePackageImpl; import tefkat.model.*; import tefkat.model.internal.ModelUtils; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * TargetResolver performs SLDNF resolution on a provided goal, creating an SLDNF resolution tree. * The success nodes of this tree represent different * variable bindings that make the provided goal true. * * Example: * TargetResolver r = new TargetResolver(); * Tree t = r.resolve(goal, binding); * Collection solutions = t.getAnswers(); * * @author David Hearnden, Aug 2003 * @author michael lawley, Aug 2003 -- modified for QVT model */ class TargetResolver extends AbstractResolver { private static final String NOT_BOUND_MESSAGE = " was not bound in source term!"; // private static final String DELAYING_MESSAGE = " was not bound in source term! Attempting to delay and continue."; static { // Ensure EMF runtime knows about the Trace metamodel TracePackageImpl.init(); } /** * Create a new TargetResolver for goal using rules in transformation, and solve. * @param goal The goal to solve. * @param transformation The rule database to use. */ TargetResolver(RuleEvaluator evaluator, ResourceSet tgtModels, List listeners) { super(evaluator); } protected void doResolveNode(final Context context, final Term literal) throws ResolutionException, NotGroundException { if (literal instanceof Injection) { resolveInjection(context, (Injection) literal); } else { super.doResolveNode(context, literal); } } /** * * @param values a List of Lists * @return */ private static List buildCrossProduct(List values) { if (values.size() == 0) { List result = new ArrayList(1); result.add(new ArrayList()); return result; } Collection vals = (Collection) values.remove(0); if (values.size() == 0) { List result = new ArrayList(vals.size()); for (Iterator itr = vals.iterator(); itr.hasNext(); ) { List l = new ArrayList(); l.add(itr.next()); result.add(l); } return result; } List xp = buildCrossProduct(values); List result = new ArrayList(); for (Iterator itr = xp.iterator(); itr.hasNext(); ) { Collection l = (Collection) itr.next(); for (Iterator itr2 = vals.iterator(); itr2.hasNext(); ) { Object o2 = itr2.next(); List l2 = new ArrayList(l); l2.add(0, o2); result.add(l2); } } return result; } protected boolean resolveInjection( final Context context, final Injection literal) throws ResolutionException, NotGroundException { List keySet = new ArrayList(); List sources = literal.getSources(); for (Iterator itr = sources.iterator(); itr.hasNext(); ) { Expression expr = (Expression) itr.next(); // System.out.println("Eval: " + expr); List vals = exprEval.eval(context, expr); if (vals.size() == 1 && vals.get(0) instanceof WrappedVar) { WrappedVar wVar = (WrappedVar) vals.get(0); Collection instances = exprEval.expand(context, wVar); List pairs = new ArrayList(instances.size()); for (Iterator instItr = instances.iterator(); instItr.hasNext(); ) { Object o = instItr.next(); BindingPair bp = new BindingPair(o); bp.add(wVar.getVar(), o); pairs.add(bp); } keySet.add(pairs); // ruleEval.fireInfo(expr + DELAYING_MESSAGE); // context.delay(expr + NOT_BOUND_MESSAGE); } else { keySet.add(vals); } } // do expr eval before we create things in case we need to delay VarUse targetVarUse = literal.getTarget(); Object targetVal = exprEval.eval(context, targetVarUse).get(0); // Can only be one thing keySet = buildCrossProduct(keySet); for (Iterator itr = keySet.iterator(); itr.hasNext(); ) { List keys = (List) itr.next(); keys.add(0, literal.getName()); EObject targetObject = context.lookup(keys, literal.getTRuleTgt()); Binding unifier = new Binding(); for (Iterator keyItr = keys.iterator(); keyItr.hasNext(); ) { Object k = keyItr.next(); if (k instanceof BindingPair) { unifier.composeRight((BindingPair) k); } } if (targetVal instanceof WrappedVar) { unifier.add(((WrappedVar) targetVal).getVar(), targetObject); } else if (!targetVal.equals(targetObject)) { context.error("Incompatible values for variable: " + targetVarUse.getVar()); } context.createBranch(unifier); } return true; } int counter = 0; int[] elapsed = {0, 0, 0, 0}; /** * Looks up a tracking class instance based on the supplied type and feature values, * creating a new instance if nothing suitable is found. * <p> * The basic method is as follows: * <ol> * <li> For each feature of the TrackingUse, evaluate its Expression and store the set of results * <li> Find all instances of the tracking class * <li> For each KeyPart of each Key of each instance: * <ol> * <li> get the value of the keyPart * <li> compare with the values of the TrackingUse * <li> if different, try next Key * </ol> * <li> If all KeyParts match, then instance is a match * </ol> * * @param tree * @param node * @param goal * @param literal */ protected void resolveTrackingUse( final Context context, final TrackingUse literal) throws ResolutionException, NotGroundException { long t1 = System.currentTimeMillis(); // Get the properties of the TrackingUse EClass trackingClass = literal.getTracking(); if (trackingClass.eIsProxy()) { // If it's still a proxy after the getTracking() call, the cross-document reference proxy has // not been resolved, meaning the reference was dodgy, i.e. to a non-existent class or something // context.error("Unable to locate tracking class: " + trackingClass); } Map featureVal = new HashMap(); List featureList = literal.getFeatures(); for (Iterator itr = featureList.iterator(); itr.hasNext(); ) { Map.Entry keyEntry = (Map.Entry) itr.next(); String name = (String) keyEntry.getKey(); Expression expr = (Expression) keyEntry.getValue(); List vals = exprEval.eval(context, expr); if (vals.size() == 1 && vals.get(0) instanceof WrappedVar) { // ruleEval.fireInfo(expr + " delayed in LINKING"); context.delay(expr + NOT_BOUND_MESSAGE); } EStructuralFeature feature = getFeature(context, trackingClass, name); featureVal.put(feature, coerceTypes(vals, feature)); // System.err.println("**** " + keyEntry.getKey() + " = " + vals); } long t2 = System.currentTimeMillis(); Extent trackingExtent = context.tree.getTrackingExtent(); List trackings = trackingExtent.getObjectsByClass(trackingClass, false); ExtentUtil.highlightNodes(trackings, ExtentUtil.CLASS_LOOKUP); long t3 = System.currentTimeMillis(); boolean isMatch = false; for (final Iterator itr = trackings.iterator(); !isMatch && itr.hasNext(); ) { EObject inst = (EObject) itr.next(); isMatch = true; for (final Iterator fvItr = featureVal.entrySet().iterator(); isMatch && fvItr.hasNext(); ) { Map.Entry entry = (Map.Entry) fvItr.next(); EStructuralFeature feature = (EStructuralFeature) entry.getKey(); List featureValues = (List) entry.getValue(); Object value = inst.eGet(feature); if (feature.isMany()) { if (!featureValues.equals(value)) { isMatch = false; } } else { if (featureValues.size() != 1 || !featureValues.get(0).equals(value)) { isMatch = false; } } } } long t4 = System.currentTimeMillis(); if (!isMatch) { createTrackingInstance(context, trackingClass, trackingExtent, featureVal); counter++; } elapsed[0] += t2-t1; elapsed[1] += t3-t2; elapsed[2] += t4-t3; context.createBranch(); } private void createTrackingInstance(Context context, EClass trackingClass, Extent trackingExtent, Map featureVal) throws ResolutionException, NotGroundException { EObject trackingInstance; // instantiate the class using the factory // find the package // System.out.println("==== Creating a tracking: " + trackingClass.getName()); // TODO fixme - should probably use DynamicObjects for tracking instances EPackage trackingPackage = trackingClass.getEPackage(); if (null == trackingPackage) { context.error("Malformed class: " + ModelUtils.getFullyQualifiedName(trackingClass) + " not contained in a package."); } EFactory trackingFactory = trackingPackage.getEFactoryInstance(); trackingInstance = trackingFactory.create(trackingClass); trackingExtent.add(trackingInstance); // fill in the values of the fields for (Iterator featureValIter = featureVal.entrySet().iterator(); featureValIter.hasNext(); ) { Map.Entry entry = (Map.Entry) featureValIter.next(); EStructuralFeature feature = (EStructuralFeature) entry.getKey(); List featureValues = (List) entry.getValue(); if (feature.isMany()) { // System.out.println("==== Adding tracking features: " + featureName + " = " + featureValues); List vals = (List) trackingInstance.eGet(feature); // System.out.println("==== " + vals); vals.addAll(featureValues); // System.out.println("==== " + trackingInstance.eGet(feature)); for (Iterator itr = featureValues.iterator(); itr.hasNext(); ) { Object val = itr.next(); if (val instanceof DynamicObject) { DynamicObject dynVal = (DynamicObject) val; dynVal.addMultiReferenceFrom(trackingInstance, feature); } } } else { // If the feature isn't multi-valued, then there better be only // one possible value for it. if (featureValues.size() > 1) { context.error("Too many values (" + featureValues + ") for feature " + trackingClass + "." + feature.getName()); } Object val = featureValues.get(0); // System.out.println(" Setting tracking feature: " + feature + " = " + val); trackingInstance.eSet(feature, val); if (val instanceof DynamicObject) { DynamicObject dynVal = (DynamicObject) val; dynVal.addReferenceFrom(trackingInstance, feature); } } } long start = System.currentTimeMillis(); // tracking instance created - now tell others about it ruleEval.trackingCreate(trackingClass, trackingInstance); long end = System.currentTimeMillis(); EClass idc = TefkatPackage.eINSTANCE.getTrackingUse(); int total = elapsedTime.get(idc); total -= (end - start); elapsedTime.put(idc, total); } protected boolean resolveMofInstance( final Context context, final MofInstance literal) throws ResolutionException, NotGroundException { Expression instanceExpr = literal.getInstance(); Collection instances = exprEval.eval(context, instanceExpr); // deal with type List results = exprEval.eval(context, literal.getTypeName()); if (results.size() != 1) { context.error("Expected only a single type name, got: " + results); } Object typeObj = results.get(0); Binding unifier = new Binding(); for (Iterator itr = instances.iterator(); itr.hasNext(); ) { Object obj = itr.next(); // System.err.println(obj); // TODO delete if (obj instanceof WrappedVar) { // ruleEval.fireInfo(obj + DELAYING_MESSAGE); context.delay(obj + NOT_BOUND_MESSAGE); } else { EObject eObj = (EObject) obj; boolean makeExact = literal.isExact(); if (typeObj instanceof WrappedVar) { unifier.add(((WrappedVar) typeObj).getVar(), eObj.eClass().getName()); } else if (typeObj instanceof String) { // _ is the universal type -> it always matches if ("_".equals(typeObj)) { // It's not possible to make an instance exactly no type // (although we _might_ consider the possibilty that one // would like the possiblity to freeze the current type) makeExact = false; } else { Map nameMap = getNameMap(); String typeName = (String) typeObj; EClassifier eClassifier = ModelUtils.findClassifierByName(nameMap, typeName); if (null == eClassifier) { // for (final Iterator nItr = nameMap.keySet().iterator(); nItr.hasNext(); ) { // Object entry = nItr.next(); // System.out.println(entry); // } context.error("Expected an EClass called: " + typeName + ", but found nothing"); } else if (!(eClassifier instanceof EClass)) { context.error("Expected an EClass called: " + typeName + ", but found an EDataType or EEnum"); } EClass subCls = (EClass) eClassifier; boolean result = conformToType(eObj, subCls); if (!result) { context.error("Type mismatch, " + typeName + " not compatible with " + eObj.eClass()); } } } else if (typeObj instanceof EClass) { EClass subCls = (EClass) typeObj; boolean result = conformToType(eObj, subCls); if (!result) { context.error("Type mismatch, " + subCls + " not compatible with " + eObj.eClass()); } } else { context.error("Invalid Expression type for MofInstance.typeName: " + typeObj); } if (makeExact && eObj instanceof DynamicObject) { if (eObj.eResource() != null) { eObj.eResource().getContents().remove(eObj); // System.err.println(" ...removed: " + eObj.hashCode()); } eObj = ((DynamicObject) eObj).getStaticInstance(); } // deal with extent Extent extentObj = (Extent) context.lookup(literal.getExtent()); if (null != extentObj) { // Extents are optional, but dangling objects may be created that // should cause errors when the Resource is saved, but only if there // is a reference to the object, but no containment reference. Resource res = eObj.eResource(); if (null == res) { extentObj.add(eObj); } else if (!extentObj.contains(eObj)) { context.error("Object (" + eObj + ") cannot exist in multiple resources, " + res + " and " + extentObj); } } } } context.createBranch(unifier); return true; } /** * @param eObj * @param subCls * @return */ private boolean conformToType(EObject eObj, EClass subCls) { boolean result = true; EClass cls = eObj.eClass(); if (eObj instanceof DynamicObject) { if (cls.equals(EcorePackage.eINSTANCE.getEObject())) { // EObject is a supertype of all types ((DynamicObject) eObj).narrow(subCls); } else if (subCls.isSuperTypeOf(cls)) { // never widen the type of the object (this catches the // equals case also, so must come before next test) } else if (cls.isSuperTypeOf(subCls)) { // narrow the type of the previously created object ((DynamicObject) eObj).narrow(subCls); } else { result = false; } } else { if (subCls.isSuperTypeOf(cls)) { // never widen the type of the object (this catches the // equals case also, so must come before next test) // } else if (cls.isSuperTypeOf(subCls)) { // throw new RuntimeException("Can't narrow the type of a non-dynamic instance"); } else { result = false; } } return result; } protected void resolveCondition(final Context context, final Condition literal) throws ResolutionException, NotGroundException { Condition term = (Condition) literal; String relation = term.getRelation(); if (relation.equals("=")) { handleBindingCondition(context, term); } else if (relation.equals("boolean")) { handleBooleanCondition(context, term); } else { context.error("Target condition containing " + relation + " is Not Yet Implemented"); } } /** * @param context * @param term * @throws ResolutionException * @throws NotGroundException */ private void handleBooleanCondition(final Context context, final Condition term) throws ResolutionException, NotGroundException { List args = term.getArg(); Collection vals = exprEval.eval(context, (Expression) args.get(0)); for (Iterator itr = vals.iterator(); itr.hasNext(); ) { Object val = itr.next(); if (Boolean.TRUE.equals(val)) { // do nothing } else if (Boolean.FALSE.equals(val)) { context.error("Stopping on target-side FALSE."); } else if (val instanceof WrappedVar) { context.delay("Unbound Var, " + val + ", not allowed in Condition."); } else { context.error("Condition did not reference a boolean valued Expression."); } } // This is outside the loop since there's no point in creating // multiple branches for the same (new) goal and empty Binding. context.createBranch(); } /** * @param context * @param term * @throws ResolutionException * @throws NotGroundException */ private void handleBindingCondition(final Context context, final Condition term) throws ResolutionException, NotGroundException { List args = term.getArg(); // The following possibilities exist: // LHS & RHS unbound // LHS unbound & RHS bound // LHS bound & RHS unbound // LHS & RHS bound // For now, implement the following: // <expr>.y = <valExpr>; Expression valExpr = (Expression) args.get(1); List vals = exprEval.eval(context, valExpr); if (args.get(0) instanceof FeatureExpr) { Binding unifier = null; FeatureExpr featExpr = (FeatureExpr) args.get(0); Collection featureNames = exprEval.eval(context, featExpr.getFeature()); Collection objs = exprEval.eval(context, (Expression) featExpr.getArg().get(0)); for (Iterator fItr = featureNames.iterator(); fItr.hasNext(); ) { Object fObj = fItr.next(); EStructuralFeature featureObj = null; String featureName = null; if (fObj instanceof WrappedVar) { Var var = ((WrappedVar) fObj).getVar(); context.delay( "Unsupported mode (unbound '" + var.getName() + "') for FeatureExpr: " + var.getName() + "." + featExpr.getFeature()); } else if (fObj instanceof EStructuralFeature) { featureObj = (EStructuralFeature) fObj; } else if (!(fObj instanceof String)) { context.error("The Feature Expression " + featExpr + " must evaluate to a feature name of type String, not " + fObj.getClass()); } else { featureName = (String) fObj; } for (Iterator itr = objs.iterator(); itr.hasNext(); ) { Object obj = itr.next(); if (obj instanceof WrappedVar) { Var var = ((WrappedVar) obj).getVar(); context.delay( "Unsupported mode (unbound '" + var.getName() + "') for FeatureExpr: " + var.getName() + "." + featureName); } else if (!(obj instanceof EObject)) { context.error("Target object is not an EObject (i.e., not a valid model instance)" + featExpr.getArg().get(0)); } EObject instance = (EObject) obj; EStructuralFeature theFeature; if (null == featureObj) { theFeature = getFeature(context, instance.eClass(), featureName); } else { EClass objClass = instance.eClass(); EClass featureClass = featureObj.getEContainingClass(); if (objClass.equals(featureClass) || objClass.getEAllSuperTypes().contains(featureClass)) { theFeature = featureObj; } else { context.error("The target feature " + featureObj + " does not belong to the object " + instance); theFeature = null; // notreached } } if (theFeature.isMany()) { // Adding multiple feature values: featureName = vals if (vals.size() == 1 && vals.get(0) instanceof WrappedVar) { Object newVal = vals.get(0); // ruleEval.fireInfo(newVal + DELAYING_MESSAGE); context.delay(newVal + NOT_BOUND_MESSAGE); } // values are always added for multi-valued features List featureValues = (List) instance.eGet(theFeature); List newVals = coerceTypes(vals, theFeature); try { // Insert at beginning so that we have a chance of preserving // the order from the source model (the Node-tree traversal // would otherwise naturally invert the order). if (featExpr.isCollect()) { for (final Iterator nvItr = newVals.iterator(); nvItr.hasNext(); ) { final List valList = (List) nvItr.next(); if (theFeature.isUnique()) { // This is normally done by the EMF code, but not in the // case where the theFeature is backed by a FeatureMap. // Hence, we do it ourselves valList.removeAll(featureValues); } featureValues.addAll(0, valList); recordMultiReference(instance, theFeature, valList); } } else { if (theFeature.isUnique()) { // This is normally done by the EMF code, but not in the // case where the theFeature is backed by a FeatureMap. // Hence, we do it ourselves newVals.removeAll(featureValues); } featureValues.addAll(0, newVals); recordMultiReference(instance, theFeature, newVals); } } catch (ArrayStoreException e) { context.error("Couldn't add values to feature (type mismatch?): " + ModelUtils.getFullyQualifiedName(theFeature) + " <- " + newVals, e); } } else if (vals.size() > 1) { context.error("Too many values for, " + ModelUtils.getFullyQualifiedName(theFeature)); } else if (vals.size() == 1) { Object newVal = coerceType(vals.get(0), theFeature); if (instance.eIsSet(theFeature)) { Object curVal = instance.eGet(theFeature); if (newVal instanceof WrappedVar) { ruleEval.fireInfo(newVal + " was not bound in source term! Attempting to bind and continue."); unifier = new Binding(); unifier.add(((WrappedVar) newVal).getVar(), curVal); } else if (!curVal.equals(newVal)) { context.error("Conflicting value: " + newVal + " found for feature, " + ModelUtils.getFullyQualifiedName(theFeature) + ", which is already set to: " + curVal); } } else { // System.err.println("Setting " + theFeature.getName() + " to " + newVal); // System.err.println("O **** " + instance); // System.err.println(instance.eClass()); // System.err.println("F **** " + theFeature); // System.err.println(theFeature.getEType()); // System.err.println("V **** " + newVal); // System.err.println(newVal.getClass()); if (newVal instanceof WrappedVar) { // ruleEval.fireInfo(newVal + DELAYING_MESSAGE); context.delay(newVal + NOT_BOUND_MESSAGE); } instance.eSet(theFeature, newVal); if (newVal instanceof DynamicObject) { ((DynamicObject) newVal).addReferenceFrom(instance, theFeature); } } } else { if (theFeature.getLowerBound() > 0) { context.error("No value for " + ModelUtils.getFullyQualifiedName(theFeature) + " but lower bound is " + theFeature.getLowerBound()); } ruleEval.fireWarning("No value for " + ModelUtils.getFullyQualifiedName(theFeature)); } context.createBranch(unifier); } } } else { context.error("Non FeatureExpr LHS, " + args.get(0) + ", Not Yet Implemented"); } } private void recordMultiReference(EObject instance, EStructuralFeature theFeature, List newVals) { for (Iterator newValsItr = newVals.iterator(); newValsItr.hasNext(); ) { Object newVal = newValsItr.next(); if (newVal instanceof DynamicObject) { ((DynamicObject) newVal).addMultiReferenceFrom(instance, theFeature); } } } /** * Returns an object compatible with the type of eFeature if possible. * * @param object * @param eFeature * @return */ static private Object coerceType(Object object, EStructuralFeature eFeature) { Object result; if ("java.lang.String".equals(eFeature.getEType().getInstanceClassName())) { result = String.valueOf(object); } else if (object instanceof Number) { int typeID = eFeature.getEType().getClassifierID(); if (typeID == EcorePackage.EINTEGER_OBJECT|| typeID == EcorePackage.EINT) { result = new Integer(((Number) object).intValue()); } else if (typeID == EcorePackage.ELONG_OBJECT || typeID == EcorePackage.ELONG) { result = new Long(((Number) object).longValue()); } else if (typeID == EcorePackage.ESHORT_OBJECT || typeID == EcorePackage.ESHORT) { result = new Short(((Number) object).shortValue()); } else if (typeID == EcorePackage.EFLOAT_OBJECT || typeID == EcorePackage.EFLOAT) { result = new Float(((Number) object).floatValue()); } else if (typeID == EcorePackage.EDOUBLE_OBJECT || typeID == EcorePackage.EDOUBLE) { result = new Double(((Number) object).doubleValue()); } else if (typeID == EcorePackage.EBYTE_OBJECT || typeID == EcorePackage.EBYTE) { result = new Byte(((Number) object).byteValue()); } else if (typeID == EcorePackage.EBIG_INTEGER) { result = new BigInteger(String.valueOf(object)); } else if (typeID == EcorePackage.EBIG_DECIMAL) { result = new BigDecimal(String.valueOf(object)); } else { result = object; } } else { result = object; } return result; } static private List coerceTypes(List l, EStructuralFeature eFeature) { List cl = new ArrayList(l.size()); for (int i = 0; i < l.size(); i++) { cl.add(i, coerceType(l.get(i), eFeature)); } return cl; } /** * @throws ResolutionException NotTerms on the target side are not supported */ protected void resolveNotTerm( final Context context, final NotTerm literal) throws ResolutionException { context.error("NotTerm not supported in target term"); } /** * @throws ResolutionException OrTerms on the target side are not supported (since they lead to nondeterminism) */ protected void resolveOrTerm( final Context context, final OrTerm literal) throws ResolutionException { context.error("OrTerm not supported in target term"); } protected void resolveMofOrder(final Context context, final MofOrder term) throws ResolutionException, NotGroundException { List featVals = exprEval.eval(context, term.getFeature()); List instVals = exprEval.eval(context, term.getInstance()); List lesserVals = exprEval.eval(context, term.getLesser()); List greaterVals = exprEval.eval(context, term.getGreater()); for (final Iterator fItr = featVals.iterator(); fItr.hasNext(); ) { Object feat = fItr.next(); Binding fUnifier = null; if (feat instanceof WrappedVar) { Var var = ((WrappedVar) feat).getVar(); context.delay("Unsupported mode (unbound '" + var.getName() + "') for MofOrder: " + term); } else if (feat instanceof BindingPair) { fUnifier = (BindingPair) feat; feat = ((BindingPair) feat).getValue(); } for (final Iterator iItr = instVals.iterator(); iItr.hasNext(); ) { Object inst = iItr.next(); Binding iUnifier = fUnifier; if (inst instanceof WrappedVar) { Var var = ((WrappedVar) inst).getVar(); context.delay("Unsupported mode (unbound '" + var.getName() + "') for MofOrder: " + term); } else if (inst instanceof BindingPair) { if (null == iUnifier) { iUnifier = (BindingPair) inst; } else { iUnifier = new Binding(fUnifier); iUnifier.composeRight((BindingPair) inst); } inst = ((BindingPair) inst).getValue(); } for (final Iterator lItr = lesserVals.iterator(); lItr.hasNext(); ) { Object lesser = lItr.next(); Binding lUnifier = iUnifier; if (lesser instanceof WrappedVar) { Var var = ((WrappedVar) lesser).getVar(); context.delay("Unsupported mode (unbound '" + var.getName() + "') for MofOrder: " + term); } else if (lesser instanceof BindingPair) { if (null == lUnifier) { lUnifier = (BindingPair) lesser; } else { lUnifier = new Binding(iUnifier); lUnifier.composeRight((BindingPair) lesser); } lesser = ((BindingPair) lesser).getValue(); } for (final Iterator gItr = greaterVals.iterator(); gItr.hasNext(); ) { Object greater = gItr.next(); Binding gUnifier = lUnifier; if (greater instanceof WrappedVar) { Var var = ((WrappedVar) greater).getVar(); context.delay("Unsupported mode (unbound '" + var.getName() + "') for MofOrder: " + term); } else if (greater instanceof BindingPair) { if (null == gUnifier) { gUnifier = (BindingPair) greater; } else { gUnifier = new Binding(lUnifier); gUnifier.composeRight((BindingPair) greater); } greater = ((BindingPair) greater).getValue(); } ruleEval.addPartialOrder(inst, feat, lesser, greater); context.createBranch(gUnifier); } } } } } }