/*
* 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.
*/
/*
* SourceIdentifier.java
* Creation date: Feb 10, 2004
* By: Iulian Radu
*/
package org.openquark.cal.compiler;
import java.util.Comparator;
/**
* Tracks the category and position of an identifier and its module name (if any) within a CAL source stream.
*
* @author Iulian Radu
*/
public abstract class SourceIdentifier {
/**
* A qualifiable source identifier is an identifier that may (but does not neccessarily) have a module name associated with it.
* Note that in some cases having an unqualified qualifiable identifier may mean that if you were to add a module name to the
* identifier, the category would be changed. For example, a function definition can not actually be have a module name associated
* with it, but a function reference may, so for simplicity we consider both to be "qualifiable".
* @author Peter Cardwell
*/
static final class Qualifiable extends SourceIdentifier {
/**
* Name of the module the identifier is qualified to.
* <p>
* This field is null for unqualified identifiers.
*/
private final ModuleName moduleName;
/**
* If {@link #moduleName} is resolvable, then this is the fully qualified module name it resolves to.
* Otherwise, this holds the same value as {@link #moduleName}.
* <p>
* This field is null for unqualified identifiers.
*/
private final ModuleName resolvedModuleName;
/**
* If {@link #moduleName} is resolvable, then this is the minimally qualified module name that resolves to the same module.
* Otherwise, this holds the same value as {@link #moduleName}.
* <p>
* This field is null for unqualified identifiers.
*/
private final ModuleName minimallyQualifiedModuleName;
/**
* Source range of the module name. Note that CAL allows for module name and identifier name to be
* separated by whitespace, including newlines, so for convenience we track both positions. Note also that
* a module name itself could have multiple components separated by dots (which can have whitespace around them).
* <p>
* This field is null for unqualified identifiers.
*/
private final SourceRange moduleSourceRange;
/**
* Symbol representing the definition of the current identifier (null if this is not known)
*/
private final SourceIdentifier definitionIdentifier;
/** @return the name of the module containing the identifier (null if none was specified)*/
@Override
public ModuleName getRawModuleName() {
return moduleName;
}
/**
* {@inheritDoc}
*/
@Override
public ModuleName getResolvedModuleName() {
return resolvedModuleName;
}
/**
* {@inheritDoc}
*/
@Override
public ModuleName getMinimallyQualifiedModuleName() {
return minimallyQualifiedModuleName;
}
/** @return the source range of the module name (null if none was specified)*/
@Override
public SourceRange getRawModuleSourceRange() {
return moduleSourceRange;
}
/** @return whether the module name has a source position associated with it */
@Override
public boolean hasRawModuleSourceRange() {
return moduleSourceRange != null;
}
/** @return symbol representing the definition of this identifier */
@Override
public SourceIdentifier getDefinition() {
return definitionIdentifier;
}
public Qualifiable(String identifierName, SourceRange range, Category category, ModuleName rawModuleName, ModuleName resolvedModuleName, ModuleName minimallyQualifiedModuleName, SourceRange moduleRange, SourceIdentifier definitionIdentifier) {
super(identifierName, range, category);
this.moduleName = rawModuleName;
this.resolvedModuleName = resolvedModuleName;
this.minimallyQualifiedModuleName = minimallyQualifiedModuleName;
this.moduleSourceRange = moduleRange;
this.definitionIdentifier = definitionIdentifier;
}
public Qualifiable(String identifierName, SourceRange range, Category category, ModuleName rawModuleName, ModuleName resolvedModuleName, ModuleName minimallyQualifiedModuleName, SourceRange moduleRange) {
this (identifierName, range, category, rawModuleName, resolvedModuleName, minimallyQualifiedModuleName, moduleRange, null);
}
}
/**
* Class enumerating category of a CAL identifier stored in an SourceIdentifier.
* The category can be a top-level function, data constructor, type constructor or type class
*
* @author Iulian Radu
*/
public static final class Category {
private final String enumType;
private Category(String type) {
if (type == null) {
throw new NullPointerException();
}
enumType = type;
}
/** Identifier is a data constructor (eg: True) */
public static final Category
DATA_CONSTRUCTOR = new Category("DATA_CONSTRUCTOR");
/** Identifier is a type constructor (eg: Boolean) */
public static final Category
TYPE_CONSTRUCTOR = new Category("TYPE_CONSTRUCTOR");
/** Identifier is a type class (eg: Ordering) */
public static final Category
TYPE_CLASS = new Category("TYPE_CLASS");
/** Identifier is a top-level function or class method (eg: not) */
public static final Category
TOP_LEVEL_FUNCTION_OR_CLASS_METHOD = new Category("TOP_LEVEL_FUNCTION_OR_CLASS_METHOD");
/** Identifies the definition of a local variable (eg: let myVar = 1.0 in ..) */
public static final Category
LOCAL_VARIABLE_DEFINITION = new Category("LOCAL_DEFINITION");
/** Identifier is a reference to a local variable (eg. second myVar in: let myVar =... in myVar) */
public static final Category
LOCAL_VARIABLE = new Category("LOCAL_VARIABLE");
/** Identifier is a reference to a module */
public static final Category
MODULE_NAME = new Category("MODULE_NAME");
/** the identifier is a field name in a data constructor */
public static final Category
DATA_CONSTRUCTOR_FIELD_NAME = new Category("DATA_CONSTRUCTOR_FIELD_NAME");
/**
* Converts enumeration to string.
*/
@Override
public String toString() {
return enumType;
}
}
/** Name of the identifier we are referring to */
private final String identifierName;
/** Source position of identifier */
private final SourceRange sourceRange;
/** Category of the identifier */
private final Category category;
/**
* Comparator object to order Source Identifier by increasing start source position of
* the identifier unqualified name.
*/
public static final Comparator<SourceIdentifier> compareByStartPosition = new CompareByStartPosition();
private static class CompareByStartPosition implements Comparator<SourceIdentifier> {
public int compare(SourceIdentifier o1, SourceIdentifier o2) {
if ((o1 == null) || (o2 == null)) {
throw new IllegalArgumentException();
}
return SourcePosition.compareByPosition.compare(
o1.getSourceRange().getStartSourcePosition(),
o2.getSourceRange().getStartSourcePosition());
}
}
/**
* Constructor
*
* @param identifierName unqualified name of the identifier
* @param range source range of the identifier
* @param category category of the identifier
*/
private SourceIdentifier(String identifierName, SourceRange range, Category category) {
if ((identifierName == null) || (category == null) || (range == null)) {
throw new IllegalArgumentException();
}
this.category = category;
this.identifierName = identifierName;
this.sourceRange = range;
}
/** @return the name of the module containing the identifier (null if none was specified) */
abstract public ModuleName getRawModuleName();
/**
* @return if the value returned by {@link #getRawModuleName()} is resolvable, then this is the fully qualified module name it
* resolves to. Otherwise, this is the same value as {@link #getRawModuleName()}.
*/
abstract public ModuleName getResolvedModuleName();
/**
* @return if the value returned by {@link #getRawModuleName()} is resolvable, then this is the minimally qualified module name that
* resolves to the same module. Otherwise, this is the same value as {@link #getRawModuleName()}.
*/
abstract public ModuleName getMinimallyQualifiedModuleName();
/** @return the source range of the module name (null if none was specified)*/
abstract public SourceRange getRawModuleSourceRange();
/** @return whether the module name has a source range associated with it */
abstract public boolean hasRawModuleSourceRange();
/** @return symbol representing the definition of this identifier */
abstract public SourceIdentifier getDefinition();
/** @return the unqualified name of identifier */
public String getName() {
return identifierName;
}
/** @return range of identifier */
public SourceRange getSourceRange() {
return sourceRange;
}
/** @return category of identifier */
public Category getCategory() {
return category;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getName() + " (" + category + ") at line: " + getSourceRange().getStartLine() + " col: " + getSourceRange().getStartColumn() + " of source: " + getSourceRange().getSourceName();
}
}