/* * Copyright (c) 2004- 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 * * * */ package tefkat.engine.runtime; import org.eclipse.emf.ecore.EClass; /** * @author lawley * */ public class WrappedVar { final private Var var; private EClass type; private Extent extent; private boolean isExact; public WrappedVar(Var var) { if (null == var) { throw new IllegalArgumentException("Var must not be null"); } this.var = var; } public Var getVar() { return var; } /** * Posiible cases: * oldType == null * * oldType == newType 0 0000 * oldType < newType 1 0001 * oldType > newType 2 0010 * oldType <> newType 3 0011 * * oldExact && newExact 0 0000 * oldExact && !newExact 4 0100 * !oldExact && newExact 8 1000 * !oldExact && !newExact 12 1100 * * So there are 4 * 4 + 1 = 17 possibilities * * @param type * @param isExact * @return */ public boolean setType(EClass type, boolean isExact) { if (null == this.type) { // The most common case this.type = type; this.isExact = isExact; return true; } int cmp; if (this.type.equals(type)) { cmp = 0; } else if (this.type.isSuperTypeOf(type)) { cmp = 1; } else if (type.isSuperTypeOf(this.type)) { cmp = 2; } else { cmp = 3; } if (this.isExact && isExact) { cmp |= 0; } else if (this.isExact && !isExact) { cmp |= 4; } else if (isExact) { cmp |= 8; } else { cmp |= 12; } switch (cmp) { // types are equal - just update exactness case 0: case 4: case 8: case 12: this.isExact |= isExact; return true; // types are not comparable - can never match case 3: case 7: case 11: case 15: return false; // must be exactly two different types - can never match case 1: case 2: return false; // must be exactly a supertype and also a strict subtype - can never match case 5: return false; // must be exactly a subtype case 6: return true; // converse of 6 case 9: this.type = type; this.isExact = isExact; return true; // converse of 5 case 10: return false; // just narrow the type (no exactness) case 13: this.type = type; return true; // widening the type with no exactness is a NO-OP case 14: return true; default: throw new Error("INTERNAL ERROR: Should never reach here!"); } } public EClass getType() { return type; } public void setExtent(Extent extent) { this.extent = extent; } public Extent getExtent() { return extent; } public boolean isExact() { return isExact; } public boolean equals(Object obj) { if (obj instanceof WrappedVar) { return var.equals(((WrappedVar) obj).getVar()); } else { return false; } } public int hashCode() { // Base on var's hashCode to preserve contract that equal // Objects have the same hashCode, // but add one so that this and var hash to different values return var.hashCode() + 1; } public String toString() { return var + (isExact ? "!" : "/") + (null == type ? "_" : type.getName() + (null == extent ? "@_" : ("@" + extent))); } }