/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * QualifiedName.java * Created: July 16, 2001 * By: Bo Ilic */ package org.openquark.cal.compiler; /** * A simple wrapper class for holding onto names qualified by their module source. * There are also a variety of static constants representing the names of well known * Prelude type constructors, data constructors and functions. * * This class must remain immutable. * * @author Bo Ilic */ public final class QualifiedName implements Name, Comparable<QualifiedName> { /** the name of the module. Must not be null. */ private final ModuleName moduleName; /** the name of the entity, without its module part. Must not be null. */ private final String unqualifiedName; /** * Constructs a QualifiedName from a module name and an unqualified name. * @param moduleName the module name. * @param unqualifiedName the unqualified name. */ private QualifiedName(ModuleName moduleName, String unqualifiedName) { if (moduleName == null) { throw new NullPointerException ("QualifiedName constructor: moduleName can't be null."); } if (unqualifiedName == null) { throw new NullPointerException ("QualifiedName constructor: unqualifiedName can't be null."); } this.moduleName = moduleName; this.unqualifiedName = unqualifiedName; } /** * Factory method for constructing a QualifiedName from a module name and an unqualified name. * @param moduleName the module name. * @param unqualifiedName the unqualified name. * @return an instance of QualifiedName. */ public static QualifiedName make(ModuleName moduleName, String unqualifiedName) { return new QualifiedName(moduleName, unqualifiedName); } /** * Factory method for constructing a QualifiedName from a module name and an unqualified name. * @param moduleName the module name. * @param unqualifiedName the unqualified name. * @return an instance of QualifiedName. */ public static QualifiedName make(String moduleName, String unqualifiedName) { return make(ModuleName.make(moduleName), unqualifiedName); } /** * Provides an ordering on QualifiedNames where the module part is compared first, as String values, followed by * the unqualified part. * @param otherName * @return int */ public int compareTo(QualifiedName otherName) { int cmp = moduleName.compareTo(otherName.moduleName); if (cmp != 0) { return cmp; } return unqualifiedName.compareTo(otherName.unqualifiedName); } /** * @param other * @return boolean true if other is an instance of QualifiedName and both the module and unqualified parts are the same * as that of this QualifiedName. */ @Override public boolean equals(Object other) { if (other instanceof QualifiedName) { return equals((QualifiedName) other); } return false; } /** * @param otherName * @return true if both the module name and unqualified parts for otherName are that same as that of this QualifiedName. */ public boolean equals(QualifiedName otherName) { if (otherName == null) { return false; } if (this == otherName) { return true; } return unqualifiedName.equals(otherName.unqualifiedName) && moduleName.equals(otherName.moduleName); } /** * {@inheritDoc} * @return the module part of the qualified name e.g. for "List.filter" this would be "List". */ public ModuleName getModuleName() { return moduleName; } /** * @return the full name, represented as a string e.g. "List.filter". */ public String getQualifiedName() { return moduleName.toSourceText() + '.' + unqualifiedName; } /** * {@inheritDoc} * @return the full name, represented as a string e.g. "List.filter". */ public String toSourceText() { return getQualifiedName(); } /** * @return the name, without its module part e.g. "filter". */ public String getUnqualifiedName() { return unqualifiedName; } /** * @return int */ @Override public int hashCode() { //Joshua Bloch in Effective Java has a tip on computing hash codes for compound objects. //In this case, it reduces to: //int result = 17; //result = 37*result + unqualifiedName.hashCode(); //result = 37*result + moduleName.hashCode(); //return result; // //this simplifies to: //37*(37 * 17 + unqualifiedName.hashCode()) + moduleName.hasCode(); return 37 * (37 * 17 + unqualifiedName.hashCode()) + moduleName.hashCode(); } /** * A helper function that makes a QualifiedName from a compound name String. * <p> * Creation date: (7/16/01 2:34:12 PM) * * @param compoundName a name of the form <em>moduleName.unqualifiedName</em>, * where <em>moduleName</em> can be a hierarchical module name containing * one or more components separated by '.'. * @return a new QualifiedName */ static public QualifiedName makeFromCompoundName(String compoundName) { // look for the last dot because the other dots are part of the hierarchical module name int periodPos = compoundName.lastIndexOf('.'); if (periodPos == -1) { throw new IllegalArgumentException("QualifiedName.makeFromCompoundName: " + compoundName + " is not a compound name."); } ModuleName moduleName = ModuleName.make(compoundName.substring(0, periodPos)); String unqualifiedName = compoundName.substring(periodPos + 1); return make(moduleName, unqualifiedName); } /** * Return whether a string is a valid qualified name. * * @param compoundName a name of the form <em>moduleName.unqualifiedName</em>, * where <em>moduleName</em> can be a hierarchical module name containing * one or more components separated by '.'. * @return boolean whether the name is a valid compound name. */ static public boolean isValidCompoundName(String compoundName) { try { makeFromCompoundName(compoundName); } catch (IllegalArgumentException iae) { return false; } catch (NullPointerException npe) { return false; } return true; } /** * {@inheritDoc} */ @Override public String toString() { return getQualifiedName(); } /** * Return a clone of this object. * @return a clone of this QualifiedName * @throws CloneNotSupportedException */ @Override public Object clone() throws CloneNotSupportedException { return make(moduleName, unqualifiedName); } /** * Can be used to quickly triage whether a qualified name is in the lowercase namespace * (functions, class methods) or the uppercase namespace (type classes, type constructors, data constructors). * * @return true if the unqualified name has a lowercase ascii letter as its first letter. False otherwise. */ public boolean lowercaseFirstChar() { return unqualifiedName.length() > 0 && LanguageInfo.isCALVarStart(unqualifiedName.charAt(0)); } }