/*
* 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.
*/
/*
* SourceModel.java
* Created: Nov 18, 2004
* By: Bo Ilic
*/
package org.openquark.cal.compiler;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import org.openquark.cal.compiler.SourceModel.CALDoc.TextSegment.TopLevel;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
/**
* Models syntactically valid CAL entities, in particular, a syntactically valid CAL module.
* What this means (by definition) is that the source model's CAL text representation
* is guaranteed to be parseable by CAL. And conversely, anything that can be parsed by CAL
* can be represented as a SourceModel.
* <p>
*
* SourceModel can be used to create a CAL module that does not need to be parsed, and can go directly
* to later stages of compilation such as static analysis, type-checking, and code generation. This is
* an efficiency benefit.
* <p>
*
* All parts of the source model are immutable.
* The reason for this is that we want to preserve the invariant that the models constructed produce
* CAL source that is parseable.
* <p>
*
* As a general rule, all the methods below follow the following guidelines, except where explicitly commented:
* <ul>
* <li> Arguments are explictly checked for non-nullness and array element arguments are checked for non-nullness.
* <li> Various names, such as for functions, data constructors etc. are checked for lexical validity e.g. start with
* the appropriate case, not a CAL keyword etc. See the LanguageInfo class for how to ensure your names are OK.
* <li> Array arguments passed in during construction of some of the SourceModel objects are not copied, so the
* constructor of these arrays should not reset elements in them.
* </ul>
* <p>
*
* The source model is useful for programmatically creating CAL modules or parts of modules.
*
* @author Bo Ilic
*/
public abstract class SourceModel {
/**
* Base class for all pieces in the source model of CAL.
* @author Bo Ilic
*/
public static abstract class SourceElement {
/** A SourceRange that specifies the range occupied by this source element in the
* original source text. This field may be null.
*/
private final SourceRange sourceRange;
/**
* SourceElement classes should all be defined within the SourceModel since we need to
* guarantee that the resulting code fragments are parseable when toSourceText is called.
*/
private SourceElement() {
sourceRange = null;
}
/**
* SourceElement classes should all be defined within the SourceModel since we need to
* guarantee that the resulting code fragments are parseable when toSourceText is called.
* @param sourceRange The position that this SourceElement begins at in the source text
* for this module.
*/
private SourceElement(SourceRange sourceRange) {
this.sourceRange = sourceRange;
}
@Override
public final String toString() {
return toSourceText();
}
/**
* Build a string representation of this source element
* This is equivalent to toString.
* @return the formatted source element
*/
public final String toSourceText() {
return SourceModelCodeFormatter.formatCode(this, SourceModelCodeFormatter.DEFAULT_OPTIONS, Collections.<SourceEmbellishment>emptyList());
}
/**
* Build a string representation of this source element and append it
* to the supplied string builder.
* @param stringBuilder StringBuilder accumulate the source text in this StringBuilder.
*/
public final void toSourceText(StringBuilder stringBuilder) {
SourceModelCodeFormatter.formatCode(this, stringBuilder, SourceModelCodeFormatter.DEFAULT_OPTIONS, Collections.<SourceEmbellishment>emptyList());
}
/**
* Converts a SourceModel representation to the internal ParseTreeNode representation.
* SourceModelBuilder does the inverse operation.
* The ParseTreeNode format is an internal format and this method must remain package scope.
* The ParseTreeNode produces by this method (for example for the ModuleDefn) is guaranteed to
* satisfy the tree grammar of CAL as specified in antlr grammar/CALTreeParser.g.
* The main purpose of this method is to allow for the generation of programmatically
* generated modules that bypass the parser for efficiency reasons.
*
* @return A ParseTreeNode generated from this source element.
*/
abstract ParseTreeNode toParseTreeNode();
/**
* Accepts the visitation of a visitor, which implements the
* SourceModelVisitor interface. This abstract method is to be overridden
* by each concrete subclass so that the correct visit method on the
* visitor may be called based upon the type of the element being
* visited. Each concrete subclass of SourceElement should correspond
* one-to-one with a visit method declaration in the SourceModelVisitor
* interface.
* <p>
*
* As the SourceModelVisitor follows a more general visitor pattern
* where arguments can be passed into the visit methods and return
* values obtained from them, this method passes through the argument
* into the visit method, and returns as its return value the return
* value of the visit method.
* <p>
*
* Nonetheless, for a significant portion of the common cases, the state of the
* visitation can simply be kept as member variables within the visitor itself,
* thereby eliminating the need to use the argument and return value of the
* visit methods. In these scenarios, the recommended approach is to use
* {@link Void} as the type argument for both <code>T</code> and <code>R</code>, and
* pass in null as the argument, and return null as the return value.
* <p>
*
* @see SourceModelVisitor
*
* @param <T> the argument type. If the visitation argument is not used, specify {@link Void}.
* @param <R> the return type. If the return value is not used, specify {@link Void}.
*
* @param visitor
* the visitor
* @param arg
* the argument to be passed to the visitor's visitXXX method
* @return the return value of the visitor's visitXXX method
*/
public abstract <T, R> R accept(SourceModelVisitor<T, R> visitor, T arg);
/**
* @return An optional SourcePosition specifying the start of this SourceElement in the
* corresponding source text. This method may return null.
*/
final SourcePosition getSourcePosition() {
if(sourceRange != null) {
return sourceRange.getStartSourcePosition();
} else {
return null;
}
}
/**
* @return An optional SourceRange specifying the range occupied by this source
* element in the original source text. May return null.
*/
// todo-jowong make this final again, when all the offending non-entire-range source ranges in subclasses are refactored
SourceRange getSourceRange() {
return sourceRange;
}
/**
* Most of the source model elements return this as the getSourceRange but a few do not.
* Since we are close to shipping I do not want to change the definition of getSourceRange
* for these function due to possible unforeseen consequences. So I made a new function
* that specifies the source range scope more explicitly.
*
* @return the source range of the entire statement excluding the CAL doc
*/
// todo-jowong this should refactored, so that getSourceRange is *always* the source range of the definition
SourceRange getSourceRangeOfDefn(){
return getSourceRange();
}
}
/**
* Base class for all source elements that can appear anywhere in the top level of a module.
* This includes type constructor definitions, type class definitions, instance definitions,
* function definitions and function type declarations. It does NOT include import declarations,
* since these are a special type of declaration in that they must be at the top of the module and
* describe an attribute of the module rather than forming part of the module definition.
* @author Peter Cardwell
*/
public static abstract class TopLevelSourceElement extends SourceElement {
private TopLevelSourceElement() {}
/**
* A version of the constructor that passes along a sourceRange to the SourceElement constructor.
* @param sourceRange
*/
private TopLevelSourceElement(SourceRange sourceRange) {
super(sourceRange);
}
}
/**
* Models a CAL module, with its various constituents:
*
* module imports
*
* type constructor definitions:
* data type definitions (i.e. "data declarations")
* foreign data type definitions (i.e. "foreign data declarations")
*
* type class definitions
*
* (class) instance definitions
*
* function definitions
* algebraic function definition
* foreign function definitions
* primitive function definitions
*
* function type declarations
*
* @author Bo Ilic
*/
public static final class ModuleDefn extends SourceElement {
/** The CALDoc comment associated with this module definition, or null if there is none. */
private final CALDoc.Comment.Module caldocComment;
/** The name of the module. */
private final Name.Module moduleName;
/** External modules imported by this module */
private final Import[] importedModules;
public static final Import[] NO_IMPORTED_MODULES = new Import[0];
/** Friend modules to this module */
private final Friend[] friendModules;
public static final Friend[] NO_FRIEND_MODULES = new Friend[0];
/** Top-level definitions in the module (not including imports) */
private final TopLevelSourceElement[] topLevelDefns;
public static final TopLevelSourceElement[] NO_TOP_LEVEL_DEFNS = new TopLevelSourceElement[0];
private ModuleDefn(CALDoc.Comment.Module caldocComment, Name.Module moduleName, Import[] importedModules, Friend[] friendModules, TopLevelSourceElement[] topLevelDefns, SourceRange sourceRange) {
super(sourceRange);
this.caldocComment = caldocComment;
verifyArg(moduleName, "moduleName");
this.moduleName = moduleName;
if (importedModules == null || importedModules.length == 0) {
this.importedModules = NO_IMPORTED_MODULES;
} else {
this.importedModules = importedModules.clone();
verifyArrayArg(this.importedModules, "importedModules");
}
if (friendModules == null || friendModules.length == 0) {
this.friendModules = NO_FRIEND_MODULES;
} else {
this.friendModules = friendModules.clone();
verifyArrayArg(this.friendModules, "friendModules");
}
if (topLevelDefns == null || topLevelDefns.length == 0) {
this.topLevelDefns = NO_TOP_LEVEL_DEFNS;
} else {
this.topLevelDefns = topLevelDefns.clone();
verifyArrayArg(this.topLevelDefns, "topLevelDefns");
}
}
/**
* Create an instance of ModuleDefn without an associated CALDoc comment.
* @param moduleName the name of the module.
* @param importedModules external modules imported by this module.
* @param topLevelDefns top-level definitions in the module.
* @return an instance of ModuleDefn without an associated CALDoc comment.
*/
public static ModuleDefn make(Name.Module moduleName, Import[] importedModules, TopLevelSourceElement[] topLevelDefns) {
return new ModuleDefn(null, moduleName, importedModules, null, topLevelDefns, null);
}
/**
* Create an instance of ModuleDefn without an associated CALDoc comment.
* @param moduleName the name of the module.
* @param importedModules external modules imported by this module.
* @param topLevelDefns top-level definitions in the module.
* @return an instance of ModuleDefn without an associated CALDoc comment.
*/
public static ModuleDefn make(ModuleName moduleName, Import[] importedModules, TopLevelSourceElement[] topLevelDefns) {
return new ModuleDefn(null, Name.Module.make(moduleName), importedModules, null, topLevelDefns, null);
}
/**
* Create an instance of ModuleDefn with an associated CALDoc comment.
* @param caldocComment the associated CALDoc comment. May be null if there is no CALDoc comment.
* @param moduleName the name of the module.
* @param importedModules external modules imported by this module.
* @param topLevelDefns top-level definitions in the module.
* @return an instance of ModuleDefn with an associated CALDoc comment.
*/
public static ModuleDefn make(CALDoc.Comment.Module caldocComment, Name.Module moduleName, Import[] importedModules, TopLevelSourceElement[] topLevelDefns) {
return new ModuleDefn(caldocComment, moduleName, importedModules, null, topLevelDefns, null);
}
/**
* Create an instance of ModuleDefn with an associated CALDoc comment.
* @param caldocComment the associated CALDoc comment. May be null if there is no CALDoc comment.
* @param moduleName the name of the module.
* @param importedModules external modules imported by this module.
* @param topLevelDefns top-level definitions in the module.
* @return an instance of ModuleDefn with an associated CALDoc comment.
*/
public static ModuleDefn make(CALDoc.Comment.Module caldocComment, ModuleName moduleName, Import[] importedModules, TopLevelSourceElement[] topLevelDefns) {
return new ModuleDefn(caldocComment, Name.Module.make(moduleName), importedModules, null, topLevelDefns, null);
}
/**
* Create an instance of ModuleDefn with an associated CALDoc comment.
* @param caldocComment the associated CALDoc comment. May be null if there is no CALDoc comment.
* @param moduleName the name of the module.
* @param importedModules external modules imported by this module.
* @param friendModules friend modules of this module.
* @param topLevelDefns top-level definitions in the module.
* @return an instance of ModuleDefn with an associated CALDoc comment.
*/
public static ModuleDefn make(CALDoc.Comment.Module caldocComment, Name.Module moduleName, Import[] importedModules, Friend[] friendModules, TopLevelSourceElement[] topLevelDefns) {
return new ModuleDefn(caldocComment, moduleName, importedModules, friendModules, topLevelDefns, null);
}
/**
* Create an instance of ModuleDefn with an associated CALDoc comment.
* @param caldocComment the associated CALDoc comment. May be null if there is no CALDoc comment.
* @param moduleName the name of the module.
* @param importedModules external modules imported by this module.
* @param friendModules friend modules of this module.
* @param topLevelDefns top-level definitions in the module.
* @return an instance of ModuleDefn with an associated CALDoc comment.
*/
public static ModuleDefn make(CALDoc.Comment.Module caldocComment, ModuleName moduleName, Import[] importedModules, Friend[] friendModules, TopLevelSourceElement[] topLevelDefns) {
return new ModuleDefn(caldocComment, Name.Module.make(moduleName), importedModules, friendModules, topLevelDefns, null);
}
static ModuleDefn makeAnnotated(CALDoc.Comment.Module caldocComment, Name.Module moduleName, Import[] importedModules, Friend[] friendModules, TopLevelSourceElement[] topLevelDefns, SourceRange sourceRange) {
return new ModuleDefn(caldocComment, moduleName, importedModules, friendModules, topLevelDefns, sourceRange);
}
/**
* @return the CALDoc comment associated with this module definition, or null if there is none.
*/
public CALDoc.Comment.Module getCALDocComment() {
return caldocComment;
}
/**
* @return the name of the module.
*/
public Name.Module getModuleName() {
return moduleName;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfModuleName();
}
SourceRange getSourceRangeOfModuleName() {
return super.getSourceRange();
}
/** {@inheritDoc} */
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode moduleDefnNode = new ParseTreeNode (CALTreeParserTokenTypes.MODULE_DEFN, "MODULE_DEFN");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(caldocComment);
ParseTreeNode moduleNameNode = moduleName.toParseTreeNode();
ParseTreeNode importDeclarationListNode = new ParseTreeNode(CALTreeParserTokenTypes.IMPORT_DECLARATION_LIST, "IMPORT_DECLARATION_LIST");
ParseTreeNode friendDeclarationListNode = new ParseTreeNode(CALTreeParserTokenTypes.FRIEND_DECLARATION_LIST, "FRIEND_DECLARATION_LIST");
ParseTreeNode outerDefnListNode = new ParseTreeNode(CALTreeParserTokenTypes.OUTER_DEFN_LIST, "OUTER_DEFN_LIST");
ParseTreeNode[] importedModuleNodes = new ParseTreeNode[importedModules.length];
for (int i = 0; i < importedModules.length; i++) {
importedModuleNodes[i] = importedModules[i].toParseTreeNode();
}
importDeclarationListNode.addChildren(importedModuleNodes);
ParseTreeNode[] friendModuleNodes = new ParseTreeNode[friendModules.length];
for (int i = 0; i < friendModules.length; ++i) {
friendModuleNodes[i] = friendModules[i].toParseTreeNode();
}
friendDeclarationListNode.addChildren(friendModuleNodes);
ParseTreeNode[] outerDefnNodes = new ParseTreeNode[topLevelDefns.length];
for (int i = 0; i < topLevelDefns.length; i++) {
outerDefnNodes[i] = topLevelDefns[i].toParseTreeNode();
}
outerDefnListNode.addChildren(outerDefnNodes);
moduleDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(moduleNameNode);
moduleNameNode.setNextSibling(importDeclarationListNode);
importDeclarationListNode.setNextSibling(friendDeclarationListNode);
friendDeclarationListNode.setNextSibling(outerDefnListNode);
return moduleDefnNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_ModuleDefn(this, arg);
}
/**
* @return the imported modules
*/
public Import[] getImportedModules() {
if (importedModules.length == 0) {
return NO_IMPORTED_MODULES;
}
return importedModules.clone();
}
/**
* Get the number of imported modules.
* @return the number of imported modules.
*/
public int getNImportedModules() {
return importedModules.length;
}
/**
* Get the nth imported module.
* @param n the index of the imported module to return.
* @return the nth imported module.
*/
public Import getNthImportedModule(int n) {
return importedModules[n];
}
/**
* @return the friend modules
*/
public Friend[] getFriendModules() {
if (friendModules.length == 0) {
return NO_FRIEND_MODULES;
}
return friendModules.clone();
}
/**
* Get the number of friend modules.
* @return the number of friend modules.
*/
public int getNFriendModules() {
return friendModules.length;
}
/**
* Get the nth friend module.
* @param n the index of the friend module to return.
* @return the nth friend module.
*/
public Friend getNthFriendModule(int n) {
return friendModules[n];
}
/**
* @return the top level definitions
*/
public TopLevelSourceElement[] getTopLevelDefns() {
if (topLevelDefns.length == 0) {
return NO_TOP_LEVEL_DEFNS;
}
return topLevelDefns.clone();
}
/**
* Get the number of top level definitions.
* @return the number of top level definitions.
*/
public int getNTopLevelDefns() {
return topLevelDefns.length;
}
/**
* Get the nth top level definition.
* @param n the index of the top level definition to return.
* @return the nth top level definition.
*/
public TopLevelSourceElement getNthTopLevelDefn(int n) {
return topLevelDefns[n];
}
}
/**
* Models a "friend" declaration in a CAL module.
* At present these take a very simple form e.g. "friend List;"
* @author Bo Ilic
*/
public static final class Friend extends SourceElement {
/** The name of the friend module. */
private final Name.Module friendModuleName;
private Friend(Name.Module friendModuleName, SourceRange range) {
super(range);
verifyArg(friendModuleName, "friendModuleName");
this.friendModuleName = friendModuleName;
}
public static Friend make(Name.Module friendModuleName) {
return new Friend(friendModuleName, null);
}
static Friend makeAnnotated(Name.Module friendModuleName, SourceRange range) {
return new Friend(friendModuleName, range);
}
public static Friend make(ModuleName friendModuleName) {
return new Friend(Name.Module.make(friendModuleName), null);
}
/**
* @return the name of the friend module.
*/
public Name.Module getFriendModuleName() {
return friendModuleName;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode friendNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_friend, "friend");
ParseTreeNode moduleNameNode = friendModuleName.toParseTreeNode();
friendNode.setFirstChild(moduleNameNode);
return friendNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Friend(this, arg);
}
}
/**
* Models an "import" statement in a CAL module, either with or without a "using" clause.
* @author Bo Ilic
*/
public static final class Import extends SourceElement {
public static final UsingItem[] NO_USING_ITEMS = new UsingItem[0];
/** The name of the imported module. */
private final Name.Module importedModuleName;
/** Using items in this import statement's using clause, if any */
private final UsingItem[] usingItems;
/**
* Models an item in an import statement's using clause. Eg, the following statement
*
* import Prelude using
* typeClass = Eq, Ord;
* typeConstructor = List;
* dataConstructor = Nil, Cons;
* function = abs, negate;
* function = concat, append;
* ;
*
* contains 5 UsingItems.
*
* @author James Wright
*/
public abstract static class UsingItem extends SourceElement {
public static final SourceRange[] NO_SOURCE_RANGES = new SourceRange[0];
/** The names that this using item imports */
private final String[] usingNames;
/** SourceRanges of the names in the using item */
private final SourceRange[] usingNameSourceRanges;
/**
* Models a using item that contains function names. Eg, the following statement
*
* import Prelude using
* typeClass = Eq, Ord;
* typeConstructor = List;
* dataConstructor = Nil, Cons;
* function = abs, negate, signum;
* function = concat, append, empty, isEmpty;
* ;
*
* contains 2 UsingItem.Functions.
*
* @author James Wright
*/
public static final class Function extends UsingItem {
static final String CATEGORY_NAME = "function";
static final int CATEGORY_TOKEN_TYPE = CALTreeParserTokenTypes.LITERAL_function;
private Function(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
super(usingNames, sourceRange, usingNameSourceRanges);
}
public static Function make(String[] usingNames) {
return new Function(usingNames, null, null);
}
static Function makeAnnotated(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
return new Function(usingNames, sourceRange, usingNameSourceRanges);
}
/** {@inheritDoc} */
@Override
boolean isValidUsingName(String usingName) {
return LanguageInfo.isValidFunctionName(usingName);
}
/** {@inheritDoc} */
@Override
String getUsingItemCategoryName() {
return CATEGORY_NAME;
}
/** {@inheritDoc} */
@Override
int getUsingItemCategoryTokenType() {
return CATEGORY_TOKEN_TYPE;
}
/** {@inheritDoc} */
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Import_UsingItem_Function(this, arg);
}
}
/**
* Models a using item that contains data constructor names. Eg, the following statement
*
* import Prelude using
* typeClass = Eq, Ord;
* typeConstructor = List;
* dataConstructor = Nil, Cons;
* function = abs, negate, signum;
* function = concat, append, empty, isEmpty;
* ;
*
* contains 1 UsingItem.DataConstructor.
*
* @author James Wright
*/
public static final class DataConstructor extends UsingItem {
static final String CATEGORY_NAME = "dataConstructor";
static final int CATEGORY_TOKEN_TYPE = CALTreeParserTokenTypes.LITERAL_dataConstructor;
private DataConstructor(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
super(usingNames, sourceRange, usingNameSourceRanges);
}
public static DataConstructor make(String[] usingNames) {
return new DataConstructor(usingNames, null, null);
}
static DataConstructor makeAnnotated(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
return new DataConstructor(usingNames, sourceRange, usingNameSourceRanges);
}
/** {@inheritDoc} */
@Override
boolean isValidUsingName(String usingName) {
return LanguageInfo.isValidDataConstructorName(usingName);
}
/** {@inheritDoc} */
@Override
String getUsingItemCategoryName() {
return CATEGORY_NAME;
}
/** {@inheritDoc} */
@Override
int getUsingItemCategoryTokenType() {
return CATEGORY_TOKEN_TYPE;
}
/** {@inheritDoc} */
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Import_UsingItem_DataConstructor(this, arg);
}
}
/**
* Models a using item that contains type constructor names. Eg, the following statement
*
* import Prelude using
* typeClass = Eq, Ord;
* typeConstructor = List;
* dataConstructor = Nil, Cons;
* function = abs, negate, signum;
* function = concat, append, empty, isEmpty;
* ;
*
* contains 1 UsingItem.TypeConstructor.
*
* @author James Wright
*/
public static final class TypeConstructor extends UsingItem {
static final String CATEGORY_NAME = "typeConstructor";
static final int CATEGORY_TOKEN_TYPE = CALTreeParserTokenTypes.LITERAL_typeConstructor;
private TypeConstructor(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
super(usingNames, sourceRange, usingNameSourceRanges);
}
public static TypeConstructor make(String[] usingNames) {
return new TypeConstructor(usingNames, null, null);
}
static TypeConstructor makeAnnotated(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
return new TypeConstructor(usingNames, sourceRange, usingNameSourceRanges);
}
/** {@inheritDoc} */
@Override
boolean isValidUsingName(String usingName) {
return LanguageInfo.isValidTypeConstructorName(usingName);
}
/** {@inheritDoc} */
@Override
String getUsingItemCategoryName() {
return CATEGORY_NAME;
}
/** {@inheritDoc} */
@Override
int getUsingItemCategoryTokenType() {
return CATEGORY_TOKEN_TYPE;
}
/** {@inheritDoc} */
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Import_UsingItem_TypeConstructor(this, arg);
}
}
/**
* Models a using item that contains type class names. Eg, the following statement
*
* import Prelude using
* typeClass = Eq, Ord;
* typeConstructor = List;
* dataConstructor = Nil, Cons;
* function = abs, negate, signum;
* function = concat, append, empty, isEmpty;
* ;
*
* contains 1 UsingItem.TypeClass.
*
* @author James Wright
*/
public static final class TypeClass extends UsingItem {
static final String CATEGORY_NAME = "typeClass";
static final int CATEGORY_TOKEN_TYPE = CALTreeParserTokenTypes.LITERAL_typeClass;
private TypeClass(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
super(usingNames, sourceRange, usingNameSourceRanges);
}
public static TypeClass make(String[] usingNames) {
return new TypeClass(usingNames, null, null);
}
static TypeClass makeAnnotated(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
return new TypeClass(usingNames, sourceRange, usingNameSourceRanges);
}
/** {@inheritDoc} */
@Override
boolean isValidUsingName(String usingName) {
return LanguageInfo.isValidTypeClassName(usingName);
}
/** {@inheritDoc} */
@Override
String getUsingItemCategoryName() {
return CATEGORY_NAME;
}
/** {@inheritDoc} */
@Override
int getUsingItemCategoryTokenType() {
return CATEGORY_TOKEN_TYPE;
}
/** {@inheritDoc} */
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Import_UsingItem_TypeClass(this, arg);
}
}
private UsingItem(String[] usingNames, SourceRange sourceRange, SourceRange[] usingNameSourceRanges) {
super(sourceRange);
if(usingNames == null) {
throw new NullPointerException();
}
if(usingNames.length == 0) {
throw new IllegalArgumentException("a using clause must contain at least one name");
}
for(int i = 0, nNames = usingNames.length; i < nNames; i++) {
if(!isValidUsingName(usingNames[i])) {
throw new IllegalArgumentException(usingNames[i] + " is not a valid name for this using item");
}
}
this.usingNames = usingNames.clone();
if(usingNameSourceRanges == null || usingNameSourceRanges.length == 0) {
this.usingNameSourceRanges = NO_SOURCE_RANGES;
} else {
this.usingNameSourceRanges = usingNameSourceRanges.clone();
}
}
/**
* Helper function for verifying the names passed into the constructor
* @param usingName String representing a name that should be valid for usingCategory
* @return true if usingName is a valid name for this kind of UsingItem, or false otherwise
*/
abstract boolean isValidUsingName(String usingName);
/**
* @return representing the category of the names in this UsingItem.
* It will be one of ["function", "dataConstructor", "typeConstructor", "typeClass"].
*/
abstract String getUsingItemCategoryName();
/**
* @return Token type for the category node of this UsingItem
*/
abstract int getUsingItemCategoryTokenType();
/** {@inheritDoc} */
@Override
ParseTreeNode toParseTreeNode() {
final int tokenType = getUsingItemCategoryTokenType();
ParseTreeNode usingItemNode = new ParseTreeNode(tokenType, getUsingItemCategoryName());
ParseTreeNode[] nameNodes = new ParseTreeNode[usingNames.length];
if(tokenType == CALTreeParserTokenTypes.LITERAL_function) {
for(int i = 0, nNames = usingNames.length; i < nNames; i++) {
nameNodes[i] = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, usingNames[i]);
}
} else {
for(int i = 0, nNames = usingNames.length; i < nNames; i++) {
nameNodes[i] = new ParseTreeNode(CALTreeParserTokenTypes.CONS_ID, usingNames[i]);
}
}
usingItemNode.addChildren(nameNodes);
return usingItemNode;
}
public String[] getUsingNames() {
return usingNames.clone();
}
// todo-jowong each using item may want to be encapsulated in its own source element
SourceRange[] getUsingNameSourceRanges() {
if(usingNameSourceRanges == null || usingNameSourceRanges.length == 0) {
return NO_SOURCE_RANGES;
} else {
return usingNameSourceRanges.clone();
}
}
}
private Import(Name.Module importedModuleName, UsingItem[] usingClauses, SourceRange sourceRange) {
super(sourceRange);
verifyArg(importedModuleName, "importedModuleName");
this.importedModuleName = importedModuleName;
if(usingClauses == null || usingClauses.length == 0) {
this.usingItems = NO_USING_ITEMS;
} else {
this.usingItems = usingClauses;
}
}
public static Import make(Name.Module importedModuleName, UsingItem[] usingClauses) {
return new Import(importedModuleName, usingClauses, null);
}
public static Import make(ModuleName importedModuleName, UsingItem[] usingClauses) {
return new Import(Name.Module.make(importedModuleName), usingClauses, null);
}
public static Import make(Name.Module importedModuleName,
String[] usingFunctionsOrClassMethods,
String[] usingDataConstructors,
String[] usingTypeConstructors,
String[] usingTypeClasses) {
List<UsingItem> usingItems = new ArrayList<UsingItem>();
if(usingFunctionsOrClassMethods != null && usingFunctionsOrClassMethods.length != 0) {
usingItems.add(UsingItem.Function.make(usingFunctionsOrClassMethods));
}
if(usingDataConstructors != null && usingDataConstructors.length != 0) {
usingItems.add(UsingItem.DataConstructor.make(usingDataConstructors));
}
if(usingTypeConstructors != null && usingTypeConstructors.length != 0) {
usingItems.add(UsingItem.TypeConstructor.make(usingTypeConstructors));
}
if(usingTypeClasses != null && usingTypeClasses.length != 0) {
usingItems.add(UsingItem.TypeClass.make(usingTypeClasses));
}
if(usingItems.size() == 0) {
return new Import(importedModuleName, NO_USING_ITEMS, null);
}
return new Import(importedModuleName, usingItems.toArray(NO_USING_ITEMS), null);
}
public static Import make(ModuleName importedModuleName,
String[] usingFunctionsOrClassMethods,
String[] usingDataConstructors,
String[] usingTypeConstructors,
String[] usingTypeClasses) {
return make(Name.Module.make(importedModuleName), usingFunctionsOrClassMethods, usingDataConstructors, usingTypeConstructors, usingTypeClasses);
}
public static Import make(Name.Module importedModuleName) {
return new Import(importedModuleName, null, null);
}
public static Import make(ModuleName importedModuleName) {
return new Import(Name.Module.make(importedModuleName), null, null);
}
static Import makeAnnotated(Name.Module importedModuleName, UsingItem[] usingClauses, SourceRange sourceRange) {
return new Import(importedModuleName, usingClauses, sourceRange);
}
/**
* @return the name of the imported module.
*/
public Name.Module getImportedModuleName() {
return importedModuleName;
}
private boolean hasUsingClause () {
return usingItems.length > 0;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode importDeclarationNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_import, "import");
ParseTreeNode moduleNameNode = importedModuleName.toParseTreeNode();
if(hasUsingClause()) {
ParseTreeNode usingClauseNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_using, "using");
for (final UsingItem usingItem : usingItems) {
usingClauseNode.addChild(usingItem.toParseTreeNode());
}
moduleNameNode.setNextSibling(usingClauseNode);
}
importDeclarationNode.setFirstChild(moduleNameNode);
return importDeclarationNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Import(this, arg);
}
/**
* @return An array containing the items of the using clause of this import statement
*/
public UsingItem[] getUsingItems() {
if(usingItems.length == 0) {
return NO_USING_ITEMS;
}
return usingItems.clone();
}
}
/**
* Base class for modeling CAL local definitions (i.e. defined within a let expression).
* Currently these are local function definitions, local function type declarations,
* and pattern match declarations.
* <p>
* Note that a definition such as:
* <pre>
* let
* x = foo 1.0 "bar";
* in
* ...
* </pre>
* is considered a local function (and hence modeled with {@link SourceModel.LocalDefn.Function.Definition})
* rather than a local pattern match declaration.
*
* @author Bo Ilic
*/
public static abstract class LocalDefn extends SourceElement {
/**
* Base class for modeling CAL local definitions related to local functions.
* Currently these are local function definitions and local function type declarations.
*
* @author Bo Ilic
*/
public static abstract class Function extends LocalDefn {
/** The CALDoc comment associated with this local definition, or null if there is none. */
private final SourceModel.CALDoc.Comment.Function caldocComment;
/**
* CAL name of the local definition. The module name is not given, because it is assumed to be defined in the module in
* which it is defined in. In general, within CAL source, if the module name *must* be the name of the module in which
* the element is defined, then it is illegal to supply a qualified name.
*/
private final String name;
/**
* The optional position of this.name in the source code. May be null.
*/
private SourceRange functionNameSourceRange;
/**
* Models local function definitions i.e. enclosed within the scope of a let expression.
* For example, the "f x = x + 1" part of
* let
* f x = x + 1;
* in
* f 2;
*
* @author Bo Ilic
*/
public static final class Definition extends Function {
private final SourceRange sourceRangeExcludingCaldoc;
private final SourceModel.Parameter[] parameters;
private final SourceModel.Expr definingExpr;
public static final SourceModel.Parameter[] NO_PARAMETERS = new SourceModel.Parameter[0];
private Definition (SourceModel.CALDoc.Comment.Function caldocComment, String functionName, SourceRange functionNameSourceRange, SourceModel.Parameter[] parameters, SourceModel.Expr definingExpr, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc) {
super(caldocComment, functionName, functionNameSourceRange, sourceRange);
this.sourceRangeExcludingCaldoc = sourceRangeExcludingCaldoc;
if (parameters == null || parameters.length == 0) {
this.parameters = NO_PARAMETERS;
} else {
this.parameters = parameters.clone();
SourceModel.verifyArrayArg(this.parameters, "parameters");
}
SourceModel.verifyArg(definingExpr, "definingExpr");
this.definingExpr = definingExpr;
}
public static Definition make(String functionName, SourceModel.Parameter[] parameters, SourceModel.Expr definingExpr) {
return new Definition(null, functionName, null, parameters, definingExpr, null, null);
}
public static Definition make(SourceModel.CALDoc.Comment.Function caldocComment, String functionName, SourceModel.Parameter[] parameters, SourceModel.Expr definingExpr) {
return new Definition(caldocComment, functionName, null, parameters, definingExpr, null, null);
}
static Definition makeAnnotated(String functionName, SourceRange functionNameSourceRange, SourceModel.Parameter[] parameters, SourceModel.Expr definingExpr, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc) {
return new Definition(null, functionName, functionNameSourceRange, parameters, definingExpr, sourceRange, sourceRangeExcludingCaldoc);
}
static Definition makeAnnotated(SourceModel.CALDoc.Comment.Function caldocComment, String functionName, SourceRange functionNameSourceRange, SourceModel.Parameter[] parameters, SourceModel.Expr definingExpr, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc) {
return new Definition(caldocComment, functionName, functionNameSourceRange, parameters, definingExpr, sourceRange, sourceRangeExcludingCaldoc);
}
public SourceModel.Parameter[] getParameters() {
if (parameters.length == 0) {
return NO_PARAMETERS;
}
return parameters.clone();
}
/**
* Get the number of parameters.
* @return the number of parameters.
*/
public int getNParameters() {
return parameters.length;
}
/**
* Get the nth parameter.
* @param n the index of the parameter to return.
* @return the nth parameter.
*/
public SourceModel.Parameter getNthParameter(int n) {
return parameters[n];
}
public SourceModel.Expr getDefiningExpr() {
return definingExpr;
}
SourceRange getSourceRangeExcludingCaldoc() {
return sourceRangeExcludingCaldoc;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode localFunctionNode = new ParseTreeNode(CALTreeParserTokenTypes.LET_DEFN, "LET_DEFN");
ParseTreeNode optionalCALDocNode = SourceModel.makeOptionalCALDocNode(getCALDocComment());
ParseTreeNode functionNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, getName());
ParseTreeNode paramListNode = new ParseTreeNode(CALTreeParserTokenTypes.FUNCTION_PARAM_LIST, "FUNCTION_PARAM_LIST");
ParseTreeNode[] paramNodes = new ParseTreeNode[parameters.length];
for (int i = 0; i < parameters.length; i++) {
paramNodes[i] = parameters[i].toParseTreeNode();
}
paramListNode.addChildren(paramNodes);
ParseTreeNode exprNode = definingExpr.toParseTreeNode();
localFunctionNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(functionNameNode);
functionNameNode.setNextSibling(paramListNode);
paramListNode.setNextSibling(exprNode);
return localFunctionNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_LocalDefn_Function_Definition(this, arg);
}
}
/**
* Models local function type declarations i.e. the type declaration is enclosed within the scope of a let. For example,
* the "f :: Int -> Int;" in
* let
* f :: Int -> Int;
* f x = x + 1;
* in
* f 2;
* @author Bo Ilic
*/
public static final class TypeDeclaration extends Function {
private final SourceModel.TypeSignature declaredType;
private TypeDeclaration(SourceModel.CALDoc.Comment.Function caldocComment, String functionName, SourceRange functionNameSourceRange, SourceModel.TypeSignature declaredType, SourceRange sourceRange) {
super(caldocComment, functionName, functionNameSourceRange, sourceRange);
SourceModel.verifyArg(declaredType, "declaredType");
this.declaredType = declaredType;
}
public static TypeDeclaration make(String functionName, SourceModel.TypeSignature declaredType) {
return new TypeDeclaration(null, functionName, null, declaredType, null);
}
public static TypeDeclaration make(SourceModel.CALDoc.Comment.Function caldocComment, String functionName, SourceModel.TypeSignature declaredType) {
return new TypeDeclaration(caldocComment, functionName, null, declaredType, null);
}
static TypeDeclaration makeAnnotated(String functionName, SourceRange functionNameSourceRange, SourceModel.TypeSignature declaredType, SourceRange sourceRange) {
return new TypeDeclaration(null, functionName, functionNameSourceRange, declaredType, sourceRange);
}
static TypeDeclaration makeAnnotated(SourceModel.CALDoc.Comment.Function caldocComment, String functionName, SourceRange functionNameSourceRange, SourceModel.TypeSignature declaredType, SourceRange sourceRange) {
return new TypeDeclaration(caldocComment, functionName, functionNameSourceRange, declaredType, sourceRange);
}
public SourceModel.TypeSignature getDeclaredType() {
return declaredType;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode localDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.LET_DEFN_TYPE_DECLARATION, "LET_DEFN_TYPE_DECLARATION");
ParseTreeNode optionalCALDocNode = SourceModel.makeOptionalCALDocNode(getCALDocComment());
ParseTreeNode typeDeclarationNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_DECLARATION, "::");
ParseTreeNode functionNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, getName());
ParseTreeNode declaredTypeNode = declaredType.toParseTreeNode();
localDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(typeDeclarationNode);
typeDeclarationNode.setFirstChild(functionNameNode);
functionNameNode.setNextSibling(declaredTypeNode);
return localDefnNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_LocalDefn_Function_TypeDeclaration(this, arg);
}
}
private Function(SourceModel.CALDoc.Comment.Function caldocComment, String name, SourceRange functionNameSourceRange, SourceRange sourceRange) {
super(sourceRange);
this.caldocComment = caldocComment;
if (!LanguageInfo.isValidFunctionName(name)) {
throw new IllegalArgumentException();
}
this.name = name;
this.functionNameSourceRange = functionNameSourceRange;
}
/**
* @return the CALDoc comment associated with this function definition, or null if there is none.
*/
public SourceModel.CALDoc.Comment.Function getCALDocComment() {
return caldocComment;
}
/**
* @return the name of the function being defined or whose type is being declared.
*/
public String getName() {
return name;
}
/**
* @return the position of the name symbol in the source file. This may be null.
*/
// todo-jowong maybe the name can be encapsulated by its own source element
public SourceRange getNameSourceRange(){
return functionNameSourceRange;
}
}
/**
* Base class for modeling local pattern match declarations. A local pattern match
* declaration is used to introduce one or more pattern-bound variables in the
* scope of a let definition. For example, the follwoing is one such declaration (using
* a tuple pattern):
* <pre>
* let (x, y, z) = List.unzip3 listOfTriples; in ...
* </pre>
*
* @author Joseph Wong
*/
public static abstract class PatternMatch extends LocalDefn {
/**
* The expression that occurs on the right hand side of the "=" in a pattern match declaration.
*/
private final Expr definingExpr;
/**
* Models a local pattern match declaration using a data constructor pattern. For example, the following
* are all declarations of this kind:
* <pre>
* let Prelude.Cons x y = ['a', 'b', 'c']; in ...
* </pre>
* <pre>
* let Prelude.Cons {head, tail=y} = ['a', 'b', 'c']; in ...
* </pre>
*
* @author Joseph Wong
*/
public static final class UnpackDataCons extends PatternMatch {
/**
* The name of the data constructor used in the pattern.
*/
private final Name.DataCons dataConsName;
/**
* The pattern bindings (either positional or field-value pairs).
*/
private final ArgBindings argBindings;
/**
* Creates a new source model element for representing a local pattern match declaration using a data constructor pattern.
* @param dataConsName the name of the data constructor used in the pattern.
* @param argBindings the pattern bindings (either positional or field-value pairs).
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
*/
private UnpackDataCons(final Name.DataCons dataConsName, final ArgBindings argBindings, final Expr definingExpr, final SourceRange sourceRange) {
super(definingExpr, sourceRange);
this.argBindings = (argBindings == null) ? ArgBindings.NO_BINDINGS : argBindings;
verifyArg(dataConsName, "dataConsName");
this.dataConsName = dataConsName;
}
/**
* Factory method for constructing a new source model element for representing a local pattern match declaration using a data constructor pattern.
* @param dataConsName the name of the data constructor used in the pattern.
* @param argBindings the pattern bindings (either positional or field-value pairs).
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @return a new instance of this class.
*/
public static UnpackDataCons make(final Name.DataCons dataConsName, final ArgBindings argBindings, final Expr definingExpr) {
return new UnpackDataCons(dataConsName, argBindings, definingExpr, null);
}
/**
* Factory method for constructing a new source model element for representing a local pattern match declaration using a data constructor pattern.
* @param dataConsName the name of the data constructor used in the pattern.
* @param argBindings the pattern bindings (either positional or field-value pairs).
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
* @return a new instance of this class.
*/
static UnpackDataCons makeAnnotated(final Name.DataCons dataConsName, final ArgBindings argBindings, final Expr definingExpr, final SourceRange sourceRange) {
return new UnpackDataCons(dataConsName, argBindings, definingExpr, sourceRange);
}
/**
* Returns the name of the data constructor used in the pattern.
* @return the name of the data constructor used in the pattern.
*/
public Name.DataCons getDataConsName() {
return dataConsName;
}
/**
* Returns the pattern variable bindings (either positional or field-value pairs).
* @return the pattern variable bindings (either positional or field-value pairs).
*/
public ArgBindings getArgBindings() {
return argBindings;
}
/**
* {@inheritDoc}
*/
@Override
ParseTreeNode buildPatternParseTreeNode() {
final ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.PATTERN_CONSTRUCTOR, "PATTERN_CONSTURCTOR");
{
final ParseTreeNode dataConsNameListNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_NAME_LIST, "DATA_CONSTRUCTOR_NAME_LIST");
fullPatternNode.setFirstChild(dataConsNameListNode);
dataConsNameListNode.setFirstChild(dataConsName.toParseTreeNode());
final ParseTreeNode argBindingsNode = argBindings.toParseTreeNode();
dataConsNameListNode.setNextSibling(argBindingsNode);
}
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_LocalDefn_PatternMatch_UnpackDataCons(this, arg);
}
}
/**
* Models a local pattern match declaration using a tuple pattern. For example, the following
* are all declarations of this kind:
* <pre>
* let (x, y, z) = List.unzip3 listOfTriples; in ...
* </pre>
* <pre>
* let (_, y, _) = List.unzip3 listOfTriples; in ...
* </pre>
*
* @author Joseph Wong
*/
public static final class UnpackTuple extends PatternMatch {
/**
* The pattern bindings.
*/
private final Pattern[] patterns;
/**
* Creates a source model element for representing a local pattern match declaration using a tuple pattern.
* @param patterns the pattern bindings.
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
*/
private UnpackTuple(Pattern[] patterns, Expr definingExpr, SourceRange sourceRange) {
super(definingExpr, sourceRange);
if (patterns == null || patterns.length == 0) {
this.patterns = Pattern.NO_PATTERNS;
} else {
this.patterns = patterns.clone();
verifyArrayArg(this.patterns, "patterns");
}
}
/**
* Factory method for constructing a source model element for representing a local pattern match declaration using a tuple pattern.
* @param patterns the pattern bindings.
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @return a new instance of this class.
*/
public static UnpackTuple make(final Pattern[] patterns, final Expr definingExpr) {
return new UnpackTuple(patterns, definingExpr, null);
}
/**
* Factory method for constructing a source model element for representing a local pattern match declaration using a tuple pattern.
* @param patterns the pattern bindings.
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
* @return a new instance of this class.
*/
static UnpackTuple makeAnnotated(final Pattern[] patterns, final Expr definingExpr, final SourceRange sourceRange) {
return new UnpackTuple(patterns, definingExpr, sourceRange);
}
/**
* Returns the pattern bindings.
* @return the pattern bindings.
*/
public Pattern[] getPatterns() {
if (patterns.length == 0) {
return Pattern.NO_PATTERNS;
}
return patterns.clone();
}
/**
* Returns the number of pattern bindings.
* @return the number of pattern bindings.
*/
public int getNPatterns() {
return patterns.length;
}
/**
* Returns the pattern at the specified position in the array of pattern bindings.
* @param n the index of the pattern to return.
* @return the pattern at the specified position in the array of pattern bindings.
*/
public Pattern getNthPattern(int n) {
return patterns[n];
}
/**
* {@inheritDoc}
*/
@Override
ParseTreeNode buildPatternParseTreeNode() {
final ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR, "Tuple");
final ParseTreeNode[] patternNodes = new ParseTreeNode[patterns.length];
for (int i = 0; i < patterns.length; i++) {
patternNodes[i] = patterns[i].toParseTreeNode();
}
fullPatternNode.addChildren(patternNodes);
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_LocalDefn_PatternMatch_UnpackTuple(this, arg);
}
}
/**
* Models a local pattern match declaration using a list constructor pattern (:). For example, the following
* are all declarations of this kind:
* <pre>
* let x:y = ['a', 'b', 'c']; in ...
* </pre>
* <pre>
* let _:y = ['a', 'b', 'c']; in ...
* </pre>
* <pre>
* let x:_ = ['a', 'b', 'c']; in ...
* </pre>
*
* @author Joseph Wong
*/
public static final class UnpackListCons extends PatternMatch {
/** The pattern to the left of the ":". */
private final Pattern headPattern;
/** The pattern to the right of the ":". */
private final Pattern tailPattern;
/** The SourceRange of the ":". */
private final SourceRange operatorSourceRange;
/**
* Creates a new source model element for representing a local pattern match declaration using a list constructor pattern (:).
* @param headPattern the pattern to the left of the ":".
* @param tailPattern the pattern to the right of the ":".
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
* @param operatorSourceRange the SourceRange of the ":".
*/
private UnpackListCons(final Pattern headPattern, final Pattern tailPattern, final Expr definingExpr, final SourceRange sourceRange, final SourceRange operatorSourceRange) {
super (definingExpr, sourceRange);
verifyArg(headPattern, "headPattern");
verifyArg(tailPattern, "tailPattern");
this.headPattern = headPattern;
this.tailPattern = tailPattern;
this.operatorSourceRange = operatorSourceRange;
}
/**
* Factory method for constructing a new source model element for representing a local pattern match declaration using a list constructor pattern (:).
* @param headPattern the pattern to the left of the ":".
* @param tailPattern the pattern to the right of the ":".
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @return a new instance of this class.
*/
public static UnpackListCons make(final Pattern headPattern, final Pattern tailPattern, final Expr definingExpr) {
return new UnpackListCons(headPattern, tailPattern, definingExpr, null, null);
}
/**
* Factory method for constructing a new source model element for representing a local pattern match declaration using a list constructor pattern (:).
* @param headPattern the pattern to the left of the ":".
* @param tailPattern the pattern to the right of the ":".
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
* @param operatorSourceRange the SourceRange of the ":".
* @return a new instance of this class.
*/
static UnpackListCons makeAnnotated(final Pattern headPattern, final Pattern tailPattern, final Expr definingExpr, final SourceRange sourceRange, final SourceRange operatorSourceRange) {
return new UnpackListCons(headPattern, tailPattern, definingExpr, sourceRange, operatorSourceRange);
}
/**
* Returns the pattern to the left of the ":".
* @return the pattern to the left of the ":".
*/
public Pattern getHeadPattern() {
return headPattern;
}
/**
* Returns the pattern to the right of the ":".
* @return the pattern to the right of the ":".
*/
public Pattern getTailPattern() {
return tailPattern;
}
/**
* Returns the SourceRange of the ":".
* @return the SourceRange of the ":".
*/
// todo-jowong maybe the operator can be encapsulated by its own source element
SourceRange getOperatorSourceRange() {
return operatorSourceRange;
}
/**
* {@inheritDoc}
*/
@Override
ParseTreeNode buildPatternParseTreeNode() {
final ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.COLON, ":");
final ParseTreeNode headPatternNode = headPattern.toParseTreeNode();
final ParseTreeNode tailPatternNode = tailPattern.toParseTreeNode();
fullPatternNode.setFirstChild(headPatternNode);
headPatternNode.setNextSibling(tailPatternNode);
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_LocalDefn_PatternMatch_UnpackListCons(this, arg);
}
}
/**
* Models a local pattern match declaration using a record pattern. For example, the following
* are all declarations of this kind:
* <pre>
* let {x, y} = someRecord; in ...
* </pre>
* <pre>
* let {x=a, y=b} = someRecord; in ...
* </pre>
* <pre>
* let {_ | x=_, y} = someRecord; in ...
* </pre>
*
* Note that "{s | } = ..." is not equivalent to "{s} = ..."
* the first is doing a record polymorphic record match, the second is doing a case on a record with 1 field named "s"
* and using punning on the field name s.
*
* @author Joseph Wong
*/
public static final class UnpackRecord extends PatternMatch {
/**
* The base record pattern (to the left of the | in the pattern).
* <p>
* For example, the "r" in "{r | #1 = f1, #2 = f2} -> ...".
* May be null, to represent a non-record polymorphic pattern match e.g. "{#1 = f1, #2 = f3} -> ..."
* <p>
* Note that while it is syntactically valid to use a variable for the base record pattern, the compiler only permits
* the use of the local pattern match syntax with a wildcard (_) base record pattern.
*/
private final Pattern baseRecordPattern;
/**
* The field pattern bindings.
*/
private final FieldPattern[] fieldPatterns;
/**
* Creates a source model element for representing a local pattern match declaration using a record pattern.
* @param baseRecordPattern the base record pattern.
* @param fieldPatterns the field pattern bindings.
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
*/
private UnpackRecord(Pattern baseRecordPattern, FieldPattern[] fieldPatterns, Expr definingExpr, SourceRange sourceRange) {
super(definingExpr, sourceRange);
if (fieldPatterns == null || fieldPatterns.length == 0) {
this.fieldPatterns = FieldPattern.NO_FIELD_PATTERNS;
} else {
this.fieldPatterns = fieldPatterns.clone();
verifyArrayArg(this.fieldPatterns, "fieldPatterns");
}
this.baseRecordPattern = baseRecordPattern;
}
/**
* Factory method for constructing a source model element for representing a local pattern match declaration using a record pattern.
* @param baseRecordPattern the base record pattern.
* @param fieldPatterns the field pattern bindings.
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @return a new instance of this class.
*/
public static UnpackRecord make(Pattern baseRecordPattern, FieldPattern[] fieldPatterns, Expr definingExpr) {
return new UnpackRecord(baseRecordPattern, fieldPatterns, definingExpr, null);
}
/**
* Factory method for constructing a source model element for representing a local pattern match declaration using a record pattern.
* @param baseRecordPattern the base record pattern.
* @param fieldPatterns the field pattern bindings.
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
* @return a new instance of this class.
*/
static UnpackRecord makeAnnotated(Pattern baseRecordPattern, FieldPattern[] fieldPatterns, Expr definingExpr, SourceRange sourceRange) {
return new UnpackRecord(baseRecordPattern, fieldPatterns, definingExpr, sourceRange);
}
/**
* Returns the base record pattern (to the left of the | in the pattern).
* @return the base record pattern.
*/
public Pattern getBaseRecordPattern() {
return baseRecordPattern;
}
/**
* Returns the field pattern bindings.
* @return the field pattern bindings.
*/
public FieldPattern[] getFieldPatterns() {
if (fieldPatterns.length == 0) {
return FieldPattern.NO_FIELD_PATTERNS;
}
return fieldPatterns.clone();
}
/**
* Returns the number of field pattern bindings.
* @return the number of field pattern bindings.
*/
public int getNFieldPatterns() {
return fieldPatterns.length;
}
/**
* Returns the field pattern at the specified position in the array of field pattern bindings.
* @param n the index of the field pattern to return.
* @return the field pattern at the specified position in the array of field pattern bindings.
*/
public FieldPattern getNthFieldPattern(final int n) {
return fieldPatterns[n];
}
/**
* {@inheritDoc}
*/
@Override
ParseTreeNode buildPatternParseTreeNode() {
final ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.RECORD_PATTERN, "RECORD_PATTERN");
final ParseTreeNode baseRecordPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.BASE_RECORD_PATTERN, "BASE_RECORD_PATTERN");
final ParseTreeNode fieldBindingVarAssignmentListNode = new ParseTreeNode(CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT_LIST, "FIELD_BINDING_VAR_ASSIGNMENT_LIST");
if(baseRecordPattern != null) {
baseRecordPatternNode.setFirstChild(baseRecordPattern.toParseTreeNode());
}
final ParseTreeNode[] fieldPatternNodes = new ParseTreeNode[fieldPatterns.length];
for (int i = 0; i < fieldPatterns.length; i++) {
fieldPatternNodes[i] = fieldPatterns[i].toParseTreeNode();
}
fieldBindingVarAssignmentListNode.addChildren(fieldPatternNodes);
fullPatternNode.setFirstChild(baseRecordPatternNode);
baseRecordPatternNode.setNextSibling(fieldBindingVarAssignmentListNode);
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_LocalDefn_PatternMatch_UnpackRecord(this, arg);
}
}
/**
* Private constructor for this base class for local pattern match declarations. Intended only
* to be invoked by subclass constructors.
*
* @param definingExpr the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @param sourceRange
*/
private PatternMatch(final Expr definingExpr, final SourceRange sourceRange) {
super(sourceRange);
verifyArg(definingExpr, "definingExpr");
this.definingExpr = definingExpr;
}
/**
* Returns the expression that occurs on the right hand side of the "=" in a pattern match declaration.
* @return the expression that occurs on the right hand side of the "=" in a pattern match declaration.
*/
public Expr getDefiningExpr() {
return definingExpr;
}
/**
* @return a ParseTreeNode generated from the pattern associated with the pattern expression.
*/
abstract ParseTreeNode buildPatternParseTreeNode();
/**
* {@inheritDoc}
*/
@Override
final ParseTreeNode toParseTreeNode() {
final ParseTreeNode patternMatchDeclNode = new ParseTreeNode(CALTreeParserTokenTypes.LET_PATTERN_MATCH_DECL, "LET_PATTERN_MATCH_DECL");
final ParseTreeNode patternMatchPatternNode = buildPatternParseTreeNode();
final ParseTreeNode exprNode = getDefiningExpr().toParseTreeNode();
patternMatchDeclNode.addChild(patternMatchPatternNode);
patternMatchPatternNode.setNextSibling(exprNode);
return patternMatchDeclNode;
}
}
/**
* Private constructor for this base class for modeling CAL local definitions. Intended only
* to be invoked by subclass constructors.
* @param sourceRange
*/
private LocalDefn(final SourceRange sourceRange) {
super(sourceRange);
}
}
/**
* Base class for modeling CAL top-level function definitions.
* There are 3 kinds of CAL function definitions:
* -native CAL functions defined via CAL expressions.
* -foreign functions
* -primitive functions (i.e. built-in functions which have an explicit "primitive" declaration in the Prelude
*
* @author Bo Ilic
*/
public static abstract class FunctionDefn extends TopLevelSourceElement {
/** The CALDoc comment associated with this function definition, or null if there is none. */
private final CALDoc.Comment.Function caldocComment;
/** The SourceRange of the name of this function */
private final SourceRange nameSourceRange;
/** The SourceRange of the entire function decl, excluding any caldoc */
private final SourceRange sourceRangeExcludingCaldoc;
/**
* CAL name of the function. The module name is not given, because the function is assume to be defined in the module in
* which it is defined in. In general, within CAL source, if the module name *must* be the name of the module in which
* the element is defined, then it is illegal to supply a qualified name.
*/
private final String name;
/** The scope of the definition. */
private final Scope scope;
/** Whether the scope is explicitly specified in the source. */
private final boolean isScopeExplicitlySpecified;
/**
* Models a "regular" CAL function i.e. one defined by an expression in CAL rather than a foreign or primitive function.
* These are called algebraic because they use the algebra of CAL's expression syntax in their definitions.
* For example:
*
* f x y = x + y;
*
* @author Bo Ilic
*/
public static final class Algebraic extends FunctionDefn {
private final Parameter[] parameters;
private final Expr definingExpr;
public static final Parameter[] NO_PARAMETERS = new Parameter[0];
private Algebraic (CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, Parameter[] parameters, Expr definingExpr, boolean internalFunction, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
super (caldocComment, functionName, scope, isScopeExplicitlySpecified, internalFunction, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
if (parameters == null || parameters.length == 0) {
this.parameters = NO_PARAMETERS;
} else {
this.parameters = parameters.clone();
verifyArrayArg(this.parameters, "parameters");
}
verifyArg(definingExpr, "definingExpr");
this.definingExpr = definingExpr;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param functionName the name of the CAL function.
* @param scope the scope of the function.
* @param parameters the parameters of the function.
* @param definingExpr the defining expression of the function.
* @return a new instance of this class.
*/
public static Algebraic make (String functionName, Scope scope, Parameter[] parameters, Expr definingExpr) {
return new Algebraic(null, functionName, scope, true, parameters, definingExpr, false, null, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param functionName the name of the CAL function.
* @param scope the scope of the function.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param parameters the parameters of the function.
* @param definingExpr the defining expression of the function.
* @return a new instance of this class.
*/
public static Algebraic make (CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, Parameter[] parameters, Expr definingExpr) {
return new Algebraic(caldocComment, functionName, scope, isScopeExplicitlySpecified, parameters, definingExpr, false, null, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment and a source position.
* @param caldocComment the CALDoc comment.
* @param functionName the name of the CAL function.
* @param scope the scope of the function.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param parameters the parameters of the function.
* @param definingExpr the defining expression of the function.
* @param sourceRange the source position associated with this element.
* @param sourceRangeExcludingCaldoc
* @param functionNameSourceRange
* @return a new instance of this class.
*/
static Algebraic makeAnnotated (CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, Parameter[] parameters, Expr definingExpr, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
return new Algebraic(caldocComment, functionName, scope, isScopeExplicitlySpecified, parameters, definingExpr, false, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
}
/**
* Do not make this method public!!!
* An internal function in the source model for internal use by the compiler only.
* The main difference is that functionName is validated differently.
*
* @param functionName the name of the CAL function.
* @param scope the scope of the function.
* @param parameters the parameters of the function.
* @param definingExpr the defining expression of the function.
* @return Algebraic
*/
static Algebraic makeInternal (String functionName, Scope scope, Parameter[] parameters, Expr definingExpr) {
return new Algebraic(null, functionName, scope, true, parameters, definingExpr, true, null, null, null);
}
/**
* Do not make this method public!!!
* An internal function in the source model for internal use by the compiler only.
* The main difference is that functionName is validated differently.
*
* @param caldocComment the CALDoc comment.
* @param functionName the name of the CAL function.
* @param scope the scope of the function.
* @param parameters the parameters of the function.
* @param definingExpr the defining expression of the function.
* @return Algebraic
*/
static Algebraic makeInternal (CALDoc.Comment.Function caldocComment, String functionName, Scope scope, Parameter[] parameters, Expr definingExpr) {
return new Algebraic(caldocComment, functionName, scope, true, parameters, definingExpr, true, null, null, null);
}
public Parameter[] getParameters() {
if (parameters.length == 0) {
return NO_PARAMETERS;
}
return parameters.clone();
}
/**
* Get the number of parameters.
* @return the number of parameters.
*/
public int getNParameters() {
return parameters.length;
}
/**
* Get the nth parameter.
* @param n the index of the parameter to return.
* @return the nth parameter.
*/
public Parameter getNthParameter(int n) {
return parameters[n];
}
public Expr getDefiningExpr() {
return definingExpr;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode topLevelFunctionDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.TOP_LEVEL_FUNCTION_DEFN, "TOP_LEVEL_FUNCTION_DEFN");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(getCALDocComment());
ParseTreeNode accessModifierNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
ParseTreeNode functionNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, getName());
ParseTreeNode paramListNode = new ParseTreeNode(CALTreeParserTokenTypes.FUNCTION_PARAM_LIST, "FUNCTION_PARAM_LIST");
ParseTreeNode exprNode = getDefiningExpr().toParseTreeNode();
ParseTreeNode[] paramNodes = new ParseTreeNode[parameters.length];
for (int i = 0; i < parameters.length; i++) {
paramNodes[i] = parameters[i].toParseTreeNode();
}
paramListNode.addChildren(paramNodes);
topLevelFunctionDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(accessModifierNode);
accessModifierNode.setNextSibling(functionNameNode);
functionNameNode.setNextSibling(paramListNode);
paramListNode.setNextSibling(exprNode);
return topLevelFunctionDefnNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_FunctionDefn_Algebraic(this, arg);
}
}
/**
* Models a CAL foreign function definition such as:
* foreign unsafe import jvm "method getBlue" private getBlueFromColour :: Colour -> Int;
* @author Bo Ilic
*/
public static final class Foreign extends FunctionDefn {
/** for example, something like "java.lang.Math.sin" */
private final String externalName;
/** The position in the source of the external name. This maybe be null. */
private final SourceRange externalNameSourceRange;
private final TypeSignature declaredType;
private Foreign(CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, SourceRange externalNameSourceRange, TypeSignature declaredType, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
super(caldocComment, functionName, scope, isScopeExplicitlySpecified, false, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
verifyArg(externalName, "externalName");
verifyArg(declaredType, "declaredType");
this.externalName = externalName;
this.externalNameSourceRange = externalNameSourceRange;
this.declaredType = declaredType;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param functionName the name of the function.
* @param scope the scope of the function.
* @param externalName the external name of the function.
* @param declaredType the declared type of the function.
* @return a new instance of this class.
*/
public static Foreign make(String functionName, Scope scope, String externalName, TypeSignature declaredType) {
return new Foreign(null, functionName, scope, true, externalName, null, declaredType, null, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param functionName the name of the function.
* @param scope the scope of the function.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param externalName the external name of the function.
* @param declaredType the declared type of the function.
* @return a new instance of this class.
*/
public static Foreign make(CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, TypeSignature declaredType) {
return new Foreign(caldocComment, functionName, scope, isScopeExplicitlySpecified, externalName, null, declaredType, null, null, null);
}
static Foreign makeAnnotated(String functionName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, SourceRange externalNameSourceRange, TypeSignature declaredType, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
return new Foreign(null, functionName, scope, isScopeExplicitlySpecified, externalName, externalNameSourceRange, declaredType, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
}
static Foreign makeAnnotated(CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, SourceRange externalNameSourceRange, TypeSignature declaredType, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
return new Foreign(caldocComment, functionName, scope, isScopeExplicitlySpecified, externalName, externalNameSourceRange, declaredType, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
}
public String getExternalName() {
return externalName;
}
// todo-jowong maybe the name can be encapsulated by its own source element
public SourceRange getExternalNameSourceRange() {
return externalNameSourceRange;
}
public TypeSignature getDeclaredType() {
return declaredType;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode foreignFunctionDeclarationNode = new ParseTreeNode(CALTreeParserTokenTypes.FOREIGN_FUNCTION_DECLARATION, "foreignFunction");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(getCALDocComment());
ParseTreeNode externalNameNode = new ParseTreeNode(CALTreeParserTokenTypes.STRING_LITERAL, StringEncoder.encodeString(externalName));
ParseTreeNode accessModifierNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
ParseTreeNode typeDeclarationNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_DECLARATION, "::");
ParseTreeNode functionNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, getName());
ParseTreeNode typeSignatureNode = declaredType.toParseTreeNode();
foreignFunctionDeclarationNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(externalNameNode);
externalNameNode.setNextSibling(accessModifierNode);
accessModifierNode.setNextSibling(typeDeclarationNode);
typeDeclarationNode.setFirstChild(functionNameNode);
functionNameNode.setNextSibling(typeSignatureNode);
return foreignFunctionDeclarationNode;
}
/**
*
* @param accessibleObject A Method, Constructor, or Field, which you would like to refer to from CAL
* @return The CAL string that should be passed into the externalName argument of the FunctionDefn.Foreign constructor
*/
public static String makeExternalName(AccessibleObject accessibleObject) {
StringBuilder buf = new StringBuilder();
if (accessibleObject instanceof Method) {
Method method = (Method)accessibleObject;
if(Modifier.isStatic(method.getModifiers())) {
buf.append("static ");
}
buf.append("method ");
buf.append(method.getDeclaringClass().getName());
buf.append(".");
buf.append(method.getName());
} else if (accessibleObject instanceof Constructor) {
Constructor<?> constructor = (Constructor<?>)accessibleObject;
buf.append("constructor ");
buf.append(constructor.getName());
} else if (accessibleObject instanceof Field) {
Field field = (Field)accessibleObject;
if(Modifier.isStatic(field.getModifiers())) {
buf.append("static ");
}
buf.append("field ");
buf.append(field.getDeclaringClass().getName());
buf.append(".");
buf.append(field.getName());
} else {
throw new IllegalArgumentException();
}
return buf.toString();
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_FunctionDefn_Foreign(this, arg);
}
}
/**
* Models a CAL primitive function definition. These should never be created by external clients.
* An example is:
* primitive private equalsInt :: Int -> Int -> Boolean;
* @author Bo Ilic
*/
public static final class Primitive extends FunctionDefn {
private final TypeSignature declaredType;
private Primitive(CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, TypeSignature declaredType, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
super(caldocComment, functionName, scope, isScopeExplicitlySpecified, false, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
verifyArg(declaredType, "declaredType");
this.declaredType = declaredType;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param functionName the name of the function.
* @param scope the scope of the function.
* @param declaredType the declared type of the function.
* @return a new instance of this class.
*/
static Primitive make(String functionName, Scope scope, TypeSignature declaredType) {
return new Primitive(null, functionName, scope, true, declaredType, null, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param functionName the name of the function.
* @param scope the scope of the function.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param declaredType the declared type of the function.
* @return a new instance of this class.
*/
static Primitive make(CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, TypeSignature declaredType) {
return new Primitive(caldocComment, functionName, scope, isScopeExplicitlySpecified, declaredType, null, null, null);
}
static Primitive makeAnnotated(String functionName, Scope scope, boolean isScopeExplicitlySpecified, TypeSignature declaredType, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
return new Primitive(null, functionName, scope, isScopeExplicitlySpecified, declaredType, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
}
static Primitive makeAnnotated(CALDoc.Comment.Function caldocComment, String functionName, Scope scope, boolean isScopeExplicitlySpecified, TypeSignature declaredType, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange functionNameSourceRange) {
return new Primitive(caldocComment, functionName, scope, isScopeExplicitlySpecified, declaredType, sourceRange, sourceRangeExcludingCaldoc, functionNameSourceRange);
}
public TypeSignature getDeclaredType() {
return declaredType;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode primitiveFunctionNode = new ParseTreeNode(CALTreeParserTokenTypes.PRIMITIVE_FUNCTION_DECLARATION, "primitiveFunc");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(getCALDocComment());
ParseTreeNode accessModifierNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
ParseTreeNode typeDeclarationNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_DECLARATION, "::");
ParseTreeNode functionNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, getName());
ParseTreeNode typeSignatureNode = declaredType.toParseTreeNode();
primitiveFunctionNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(accessModifierNode);
accessModifierNode.setNextSibling(typeDeclarationNode);
typeDeclarationNode.setFirstChild(functionNameNode);
functionNameNode.setNextSibling(typeSignatureNode);
return primitiveFunctionNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_FunctionDefn_Primitive(this, arg);
}
}
private FunctionDefn(CALDoc.Comment.Function caldocComment, String name, Scope scope, boolean isScopeExplicitlySpecified, boolean internalFunction, SourceRange sourceRange, SourceRange sourceRangeExcludingCaldoc, SourceRange nameSourceRange) {
super(sourceRange);
this.nameSourceRange = nameSourceRange;
this.sourceRangeExcludingCaldoc = sourceRangeExcludingCaldoc;
this.caldocComment = caldocComment;
//internal functions are validated differently. This allows internal functions such as the instance
//functions for derived instances to use user-hidden names starting with a $ such as $equalsMaybe
if (internalFunction) {
if (name.charAt(0) != '$') {
throw new IllegalArgumentException("internal function names must start with a $.");
}
} else {
if (!LanguageInfo.isValidFunctionName(name)) {
throw new IllegalArgumentException();
}
}
verifyScopeArg(scope, isScopeExplicitlySpecified, "scope");
this.name = name;
this.scope = scope;
this.isScopeExplicitlySpecified = isScopeExplicitlySpecified;
}
/**
* @return the CALDoc comment associated with this function definition, or null if there is none.
*/
public CALDoc.Comment.Function getCALDocComment() {
return caldocComment;
}
public String getName() {
return name;
}
public Scope getScope() {
return scope;
}
/**
* @return whether the scope is explicitly specified in the source.
*/
public boolean isScopeExplicitlySpecified() {
return isScopeExplicitlySpecified;
}
/**
* @return An optional SourceRange specifying the range occupied by the name of the definition
* element in the original source text. May return null.
*/
// todo-jowong maybe the name can be encapsulated by its own source element
SourceRange getNameSourceRange() {
return nameSourceRange;
}
SourceRange getSourceRangeExcludingCaldoc() {
return sourceRangeExcludingCaldoc;
}
}
/**
* Models a formal parameter to a function (top-level, local or lambda),
* with a possible strictness annotation (indicated in CAL source by a pling !).
* @author Bo Ilic
*/
public static final class Parameter extends SourceElement {
private final String name;
private final boolean isStrict;
private Parameter(String name, boolean isStrict, SourceRange sourceRange) {
super(sourceRange);
if (!LanguageInfo.isValidFunctionName(name)) {
throw new IllegalArgumentException();
}
this.name = name;
this.isStrict = isStrict;
}
public static Parameter make(String name, boolean isStrict) {
return new Parameter(name, isStrict, null);
}
static Parameter makeAnnotated(String name, boolean isStrict, SourceRange sourceRange) {
return new Parameter(name, isStrict, sourceRange);
}
public String getName() {
return name;
}
public boolean isStrict() {
return isStrict;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfNameNotIncludingPotentialPling();
}
SourceRange getSourceRangeOfNameNotIncludingPotentialPling() {
return super.getSourceRange();
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode parameterNode;
if(isStrict) {
parameterNode = new ParseTreeNode(CALTreeParserTokenTypes.STRICT_PARAM, name);
} else {
parameterNode = new ParseTreeNode(CALTreeParserTokenTypes.LAZY_PARAM, name);
}
return parameterNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Parameter(this, arg);
}
}
/**
* Models a CAL expression occurring in the definition of regular CAL function. Note: type expressions are handled
* by a different hierarchy.
* @author Bo Ilic
*/
public static abstract class Expr extends SourceElement {
/**
* A helper class to mark expressions as either left, right or non-associative.
*
* @author Bo Ilic
*/
static final class Associativity {
private final String description;
static final Associativity LEFT = new Associativity("left associative");
static final Associativity NON = new Associativity("non associative");
static final Associativity RIGHT = new Associativity("right associative");
private Associativity(String description) {
this.description = description;
}
@Override
public String toString() {
return description;
}
}
/**
* Models a parenthesized expression
*
* @author Magnus Byne
*/
public static final class Parenthesized extends Expr {
private final Expr expr;
private Parenthesized(Expr expr) {
this(expr, null);
}
private Parenthesized(Expr expr, SourceRange sourceRange) {
super(sourceRange);
if (expr == null) {
throw new IllegalArgumentException("argument 'expr' cannot be null.");
}
this.expr = expr;
}
public static Parenthesized make(Expr expr) {
return new Parenthesized(expr);
}
static Parenthesized makeAnnotated(Expr expr, SourceRange sourceRange) {
return new Parenthesized(expr, sourceRange);
}
/**
* {@inheritDoc}
*/
@Override
boolean neverNeedsParentheses() {
return true;
}
/**
* {@inheritDoc}
*/
@Override
int precedenceLevel() {
return 100;
}
/**
* {@inheritDoc}
*/
@Override
Associativity associativity() {
return Associativity.NON;
}
/**
* Get the expression that is contained within Parentheses
* @return contents of the Parentheses
*/
public Expr getExpression() {
return expr;
}
/**
* {@inheritDoc}
*/
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode parenExprNode = new ParseTreeNode (CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR, "Tuple");
parenExprNode.addChildren(new ParseTreeNode[] {expr.toParseTreeNode()});
return parenExprNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Parenthesized(this, arg);
}
}
/**
* Models a function application expression. The application may have 1 or more arguments. Some examples: "f x", "List.map sin [1.0, 2.0]".
* @author Bo Ilic
*/
public static final class Application extends Expr {
/** for example, if the application is f x y this is [f, x, y]. */
private final Expr[] expressions;
/**
* If expressions is [e1, e2, e3], this is the application e1 e2 e3 i.e. (((e1) e2) e3)
* @param expressions the expressions defining the application. Must have length >=2, with each element non-null.
*/
private Application(Expr[] expressions) {
this(expressions, null);
}
/**
* If expressions is [e1, e2, e3], this is the application e1 e2 e3 i.e. (((e1) e2) e3)
* @param expressions the expressions defining the application. Must have length >=2, with each element non-null.
* @param sourceRange SourceRange that the application occurs at. May be null.
*/
private Application(Expr[] expressions, SourceRange sourceRange) {
super(sourceRange);
if (expressions == null || expressions.length < 2) {
throw new IllegalArgumentException("argument 'expressions' must have length >= 2.");
}
this.expressions = expressions.clone();
verifyArrayArg(this.expressions, "expressions");
}
/**
* If expressions is [e1, e2, e3], this is the application e1 e2 e3 i.e. (((e1) e2) e3)
* @param expressions the expressions defining the application. Must have length >=2, with each element non-null.
* @return an instance of Application
*/
public static Application make(Expr[] expressions) {
return new Application(expressions);
}
/**
* If expressions is [e1, e2, e3], this is the application e1 e2 e3 i.e. (((e1) e2) e3)
* @param expressions the expressions defining the application. Must have length >=2, with each element non-null.
* @param sourceRange Optional position that this application occurs at
* @return an instance of Application
*/
static Application makeAnnotated(Expr[] expressions, SourceRange sourceRange) {
return new Application(expressions, sourceRange);
}
@Override
int precedenceLevel() {
return 80;
}
@Override
Associativity associativity() {
return Associativity.LEFT;
}
@Override
boolean neverNeedsParentheses() {
//for example, 'f x y' is the same as (f x) y
//so if we want f (x y) then parentheses are needed.
return false;
}
/**
* @return Returns the expressions. For example, if the application is f x y this is [f, x, y]
*/
public Expr[] getExpressions() {
return expressions.clone();
}
/**
* Get the number of expressions.
* @return the number of expressions.
*/
public int getNExpressions() {
return expressions.length;
}
/**
* Get the nth expression.
* @param n the index of the expression to return.
* @return the nth expression.
*/
public Expr getNthExpression(int n) {
return expressions[n];
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode applicationExprNode = new ParseTreeNode (CALTreeParserTokenTypes.APPLICATION, "@");
ParseTreeNode[] exprNodes = new ParseTreeNode[expressions.length];
for (int i = 0; i < expressions.length; i++) {
exprNodes[i] = expressions[i].toParseTreeNode();
}
applicationExprNode.addChildren(exprNodes);
return applicationExprNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Application(this, arg);
}
}
/**
* Models a data constructor reference occurring in an expression in textual form. These can be
* either qualified or unqualified. If possible, supply the module qualified form- this speeds up later processing.
*
* @author Bo Ilic
*/
public static final class DataCons extends Expr {
private final Name.DataCons dataConsName;
private DataCons(Name.DataCons dataConsName, SourceRange sourceRange) {
super(sourceRange);
verifyArg(dataConsName, "dataConsName");
this.dataConsName = dataConsName;
}
public static DataCons make(Name.DataCons dataConsName) {
return new DataCons(dataConsName, null);
}
public static DataCons make(Name.Module moduleName, String dataConsName) {
return make(Name.DataCons.make(moduleName, dataConsName));
}
public static DataCons make(ModuleName moduleName, String dataConsName) {
return make(Name.Module.make(moduleName), dataConsName);
}
public static DataCons make(QualifiedName dataConsName) {
return make(dataConsName.getModuleName(), dataConsName.getUnqualifiedName());
}
/**
* @param unqualifiedDataConsName the unqualified data constructor name.
* @return an unqualified data constructor reference occurring in an expression.
*/
public static DataCons makeUnqualified(String unqualifiedDataConsName) {
return make((Name.Module)null, unqualifiedDataConsName);
}
static DataCons makeAnnotated(Name.DataCons dataConsName, SourceRange sourceRange) {
return new DataCons(dataConsName, sourceRange);
}
@Override
int precedenceLevel() {
return 100;
}
@Override
Associativity associativity() {
return Associativity.NON;
}
@Override
boolean neverNeedsParentheses() {
return true;
}
public Name.DataCons getDataConsName() {
return dataConsName;
}
@Override
ParseTreeNode toParseTreeNode() {
return dataConsName.toParseTreeNode();
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_DataCons(this, arg);
}
}
/**
* Models a variable, function or class method reference occurring in an expression in textual form. These can be
* either qualified or unqualified. If possible, supply the module qualified form- this speeds up later processing.
*
* @author Bo Ilic
*/
public static final class Var extends Expr {
private final Name.Function varName;
private Var(Name.Function varName, SourceRange sourceRange) {
super(sourceRange);
verifyArg(varName, "varName");
this.varName = varName;
}
public static Var make(Name.Function varName) {
return new Var(varName, null);
}
public static Var make(Name.Module moduleName, String varName) {
return make(Name.Function.make(moduleName, varName));
}
public static Var make(ModuleName moduleName, String varName) {
return make(Name.Module.make(moduleName), varName);
}
public static Var make(QualifiedName varName) {
return make(varName.getModuleName(), varName.getUnqualifiedName());
}
/**
* @param unqualifiedVarName the unqualified name for the variable, function or class method.
* @return an unqualified variable, function or class method reference occurring in an expression.
*/
public static Var makeUnqualified(String unqualifiedVarName) {
return make((Name.Module)null, unqualifiedVarName);
}
static Var makeAnnotated(Name.Function varName, SourceRange sourceRange) {
return new Var(varName, sourceRange);
}
/**
* Do not make this method public!!!
* An internal function in the source model for internal use by the compiler only.
* The main difference is that varName is validated differently.
*
* @param moduleName the name of the module.
* @param varName the name of the internal variable or function.
*
* @return a new Var instance representing a reference to an internal variable or function.
*/
static Var makeInternal(Name.Module moduleName, String varName) {
Name.Function name = new Name.Function(moduleName, varName, true, null, null);
return make(name);
}
@Override
int precedenceLevel() {
return 100;
}
@Override
Associativity associativity() {
return Associativity.NON;
}
@Override
boolean neverNeedsParentheses() {
return true;
}
@Override
ParseTreeNode toParseTreeNode() {
return varName.toParseTreeNode();
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Var(this, arg);
}
/**
* @return the variable name
*/
public Name.Function getVarName() {
return varName;
}
}
/**
* Models a let x in exp; expression in CAL source.
* @author Bo Ilic
*/
public static final class Let extends Expr {
private final LocalDefn[] localDefns;
/** expression following the 'in' part of the let. */
private final Expr inExpr;
private Let (LocalDefn[] localDefns, Expr inExpr) {
if (localDefns == null || localDefns.length < 1) {
throw new IllegalArgumentException("must have at least 1 local definition.");
}
this.localDefns = localDefns.clone();
verifyArrayArg(this.localDefns, "localFunctions");
verifyArg(inExpr, "inExpr");
this.inExpr = inExpr;
}
public static Let make(LocalDefn[] localDefns, Expr inExpr) {
return new Let(localDefns, inExpr);
}
@Override
int precedenceLevel() {
return 0;
}
@Override
Associativity associativity() {
return Associativity.NON;
}
@Override
boolean neverNeedsParentheses() {
return false;
}
/**
* @return Returns the array of local definition defined within the let.
*/
public LocalDefn[] getLocalDefinitions() {
return localDefns.clone();
}
/**
* Get the number of local definitions.
* @return the number of local definitions.
*/
public int getNLocalDefinitions() {
return localDefns.length;
}
/**
* Get the nth local definition.
* @param n the index of the local definition to return.
* @return the nth local definition.
*/
public LocalDefn getNthLocalDefinition(int n) {
return localDefns[n];
}
/**
* @return Returns expression following the 'in' part of the let.
*/
public Expr getInExpr() {
return inExpr;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode letExprNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_let, "let");
ParseTreeNode defnListNode = new ParseTreeNode(CALTreeParserTokenTypes.LET_DEFN_LIST, "LET_DEFN_LITS");
ParseTreeNode inExprNode = inExpr.toParseTreeNode();
ParseTreeNode[] defnNodes = new ParseTreeNode[localDefns.length];
for (int i = 0; i < localDefns.length; i++) {
defnNodes[i] = localDefns[i].toParseTreeNode();
}
defnListNode.addChildren(defnNodes);
letExprNode.setFirstChild(defnListNode);
defnListNode.setNextSibling(inExprNode);
return letExprNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Let(this, arg);
}
}
/**
* Models a case expression in CAL source.
* These are used for inspecting the value of a CAL expression and unpacking its components depending
* upon its particular format. For example, we can unpack data constructor or record values.
*
* @author Bo Ilic
*/
public static final class Case extends Expr {
private final Expr conditionExpr;
/** must have 1 or more alternatives. */
private final Alt[] caseAlts;
/**
* Base class for case alteratives. This consists of the pattern matching the particular case, along with the expression
* on the right hand side of the "->".
*
* @author Bo Ilic
*/
public static abstract class Alt extends SourceElement {
/** the expression that occurs on the right hand side of the "->" in a case alternative. */
private final Expr altExpr;
/**
* Models the unpacking of a group of general data constructors, where the data constructor's name is textual.
* (ie. not supported by special CAL syntax).
* For example, anything except an underscore on the lhs of an of an arrow in the following:
*
* public operatorPrecedence func =
* case func of
* (OpEq | OpLt | OpLtEq | OpGt | OpGtEq) -> 4;
* OpNotEq -> 4;
* (OpIsNull | OpIsNotNull) -> 8;
* _ -> 0; // Not an operator.
*
* @author Bo Ilic
*/
public static final class UnpackDataCons extends Alt {
private final Name.DataCons[] dataConsNames;
private final ArgBindings argBindings;
/** true if the datacons is parenthesized*/
private final boolean parenthesized;
private UnpackDataCons(Name.DataCons[] dataConsNames, ArgBindings argBindings, Expr altExpr, SourceRange sourceRange, boolean parenthesized) {
super(altExpr, sourceRange);
this.parenthesized = parenthesized;
this.argBindings = (argBindings == null) ? ArgBindings.NO_BINDINGS : argBindings;
verifyArrayArg(dataConsNames, "dataConsNames");
if (dataConsNames.length == 0) {
throw new IllegalArgumentException("dataConsNames must have at least one element.");
}
this.dataConsNames = dataConsNames.clone();
}
/** @return true if the data cons should be parenthesized*/
public boolean getParenthesized() {
return parenthesized;
}
public static UnpackDataCons make(Name.DataCons dataConsName, Expr altExpr) {
return new UnpackDataCons(new Name.DataCons[]{dataConsName}, null, altExpr, null, false);
}
public static UnpackDataCons make(Name.DataCons dataConsName, ArgBindings argBindings, Expr altExpr) {
return new UnpackDataCons(new Name.DataCons[]{dataConsName}, argBindings, altExpr, null, false);
}
public static UnpackDataCons make(Name.DataCons dataConsName, Pattern[] patterns, Expr altExpr) {
ArgBindings argBindings = ArgBindings.Positional.make(patterns);
return new UnpackDataCons(new Name.DataCons[]{dataConsName}, argBindings, altExpr, null, false);
}
public static UnpackDataCons make(Name.DataCons dataConsName, FieldPattern[] fieldPatterns, Expr altExpr) {
ArgBindings argBindings = ArgBindings.Matching.make(fieldPatterns);
return new UnpackDataCons(new Name.DataCons[]{dataConsName}, argBindings, altExpr, null, false);
}
public static UnpackDataCons make(Name.DataCons[] dataConsNames, Expr altExpr) {
return new UnpackDataCons(dataConsNames, null, altExpr, null, false);
}
public static UnpackDataCons make(Name.DataCons[] dataConsNames, ArgBindings argBindings, Expr altExpr) {
return new UnpackDataCons(dataConsNames, argBindings, altExpr, null, false);
}
public static UnpackDataCons make(Name.DataCons[] dataConsNames, Pattern[] patterns, Expr altExpr) {
ArgBindings argBindings = ArgBindings.Positional.make(patterns);
return new UnpackDataCons(dataConsNames, argBindings, altExpr, null, false);
}
public static UnpackDataCons make(Name.DataCons[] dataConsNames, FieldPattern[] fieldPatterns, Expr altExpr) {
ArgBindings argBindings = ArgBindings.Matching.make(fieldPatterns);
return new UnpackDataCons(dataConsNames, argBindings, altExpr, null, false);
}
static UnpackDataCons makeAnnotated(Name.DataCons dataConsName, Expr altExpr, SourceRange sourceRange) {
return new UnpackDataCons(new Name.DataCons[]{dataConsName}, null, altExpr, sourceRange, false);
}
static UnpackDataCons makeAnnotated(Name.DataCons[] dataConsNames, ArgBindings argBindings, Expr altExpr, SourceRange sourceRange) {
return new UnpackDataCons(dataConsNames, argBindings, altExpr, sourceRange, false);
}
static UnpackDataCons makeAnnotated(Name.DataCons[] dataConsNames, ArgBindings argBindings, Expr altExpr, SourceRange sourceRange, boolean parenthesized) {
return new UnpackDataCons(dataConsNames, argBindings, altExpr, sourceRange, parenthesized);
}
static UnpackDataCons makeAnnotated(Name.DataCons[] dataConsNames, Pattern[] patterns, Expr altExpr, SourceRange sourceRange) {
ArgBindings argBindings = ArgBindings.Positional.make(patterns);
return new UnpackDataCons(dataConsNames, argBindings, altExpr, sourceRange, false);
}
static UnpackDataCons makeAnnotated(Name.DataCons[] dataConsNames, FieldPattern[] fieldPatterns, Expr altExpr, SourceRange sourceRange) {
ArgBindings argBindings = ArgBindings.Matching.make(fieldPatterns);
return new UnpackDataCons(dataConsNames, argBindings, altExpr, sourceRange, false);
}
static UnpackDataCons makeAnnotated(Name.DataCons[] dataConsNames, Pattern[] patterns, Expr altExpr, SourceRange sourceRange, boolean parenthesized) {
ArgBindings argBindings = ArgBindings.Positional.make(patterns);
return new UnpackDataCons(dataConsNames, argBindings, altExpr, sourceRange, parenthesized);
}
static UnpackDataCons makeAnnotated(Name.DataCons[] dataConsNames, FieldPattern[] fieldPatterns, Expr altExpr, SourceRange sourceRange, boolean parenthesized) {
ArgBindings argBindings = ArgBindings.Matching.make(fieldPatterns);
return new UnpackDataCons(dataConsNames, argBindings, altExpr, sourceRange, parenthesized);
}
public Name.DataCons[] getDataConsNames() {
return dataConsNames.clone();
}
public int getNDataConsNames() {
return dataConsNames.length;
}
public Name.DataCons getNthDataConsName(int n) {
return dataConsNames[n];
}
public ArgBindings getArgBindings() {
return argBindings;
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.PATTERN_CONSTRUCTOR, "PATTERN_CONSTURCTOR");
{
ParseTreeNode dataConsNameListNode;
if (parenthesized || dataConsNames.length > 1) {
dataConsNameListNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_NAME_LIST, "DATA_CONSTRUCTOR_NAME_LIST");
} else {
dataConsNameListNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_NAME_SINGLETON, "DATA_CONSTRUCTOR_NAME_SINGLETON");
}
fullPatternNode.setFirstChild(dataConsNameListNode);
{
ParseTreeNode[] dataConsNameNodes = new ParseTreeNode[dataConsNames.length];
for (int i = 0; i < dataConsNames.length; i++) {
dataConsNameNodes[i] = dataConsNames[i].toParseTreeNode();
}
dataConsNameListNode.addChildren(dataConsNameNodes);
}
ParseTreeNode argBindingsNode = argBindings.toParseTreeNode();
dataConsNameListNode.setNextSibling(argBindingsNode);
}
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackDataCons(this, arg);
}
}
/**
* Models the unpacking of int values. For example,
* this is the "1 -> True;" or "(2|3) -> True;" part of the following function:
*
* public isTwoOrThree !intVal =
* case intVal of
* 1 -> True
* (2|3) -> True;
* _ -> False;
* ;
*
* @author Edward Lam
*/
public static final class UnpackInt extends Alt {
/** the int values */
private final BigInteger[] bigIntValues;
private UnpackInt(BigInteger[] intValues, Expr altExpr) {
super (altExpr, null);
this.bigIntValues = intValues.clone();
verifyArrayArg(intValues, "intValues");
if (intValues.length == 0) {
throw new IllegalArgumentException("intValues must have at least one element.");
}
}
public static UnpackInt make(BigInteger[] bigIntValues, Expr altExpr) {
return new UnpackInt(bigIntValues, altExpr);
}
public BigInteger[] getIntValues() {
return bigIntValues.clone();
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.INT_PATTERN, "INT_PATTERN");
{
ParseTreeNode intListNode = new ParseTreeNode(CALTreeParserTokenTypes.MAYBE_MINUS_INT_LIST, "MAYBE_MINUS_INT_LIST");
fullPatternNode.setFirstChild(intListNode);
{
ParseTreeNode maybeMinusNodes[] = new ParseTreeNode[bigIntValues.length];
for (int i = 0; i < bigIntValues.length; i++) {
BigInteger bigIntValue = bigIntValues[i];
if (bigIntValue.signum() < 0) {
maybeMinusNodes[i] = new ParseTreeNode(CALTreeParserTokenTypes.MINUS, "-");
maybeMinusNodes[i].setFirstChild(
new ParseTreeNode(CALTreeParserTokenTypes.INTEGER_LITERAL, bigIntValue.abs().toString()));
} else {
maybeMinusNodes[i] = new ParseTreeNode(CALTreeParserTokenTypes.INTEGER_LITERAL, bigIntValue.toString());
}
}
intListNode.addChildren(maybeMinusNodes);
}
}
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackInt(this, arg);
}
}
/**
* Models the unpacking of char values. For example,
* this is the "('A'|'B') -> True;" or "'d' -> True;" part of the following function:
*
* public isAorB !charVal =
* case charVal of
* ('A'|'B') -> True;
* 'd' -> True;
* _ -> False;
* ;
*
* @author Edward Lam
*/
public static final class UnpackChar extends Alt {
/** the char values */
private final char[] charValues;
private UnpackChar(char[] charValues, Expr altExpr) {
super (altExpr, null);
this.charValues = charValues.clone(); // npe if null.
if (charValues.length == 0) {
throw new IllegalArgumentException("charValues must have at least one element.");
}
}
public static UnpackChar make(char[] charValues, Expr altExpr) {
return new UnpackChar(charValues, altExpr);
}
public char[] getCharValues() {
return charValues.clone();
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.CHAR_PATTERN, "CHAR_PATTERN");
{
ParseTreeNode intListNode = new ParseTreeNode(CALTreeParserTokenTypes.CHAR_LIST, "CHAR_LIST");
fullPatternNode.setFirstChild(intListNode);
{
ParseTreeNode charNodes[] = new ParseTreeNode[charValues.length];
for (int i = 0; i < charValues.length; i++) {
char charValue = charValues[i];
String symbolText = StringEncoder.encodeChar(charValue);
charNodes[i] = new ParseTreeNode(CALTreeParserTokenTypes.CHAR_LITERAL, symbolText);
}
intListNode.addChildren(charNodes);
}
}
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackChar(this, arg);
}
}
/**
* Models the unpacking of a tuple data constructor in operator form.
* For example, the "(_, x, _) -> x;" part of the following function:
*
* public tuple3Field2 !t =
* case t of
* (_, x, _) -> x;
* ;
*
* @author Bo Ilic
*/
public static final class UnpackTuple extends Alt {
private final Pattern[] patterns;
private UnpackTuple(Pattern[] patterns, Expr altExpr) {
super(altExpr, null);
if (patterns == null || patterns.length == 0) {
this.patterns = Pattern.NO_PATTERNS;
} else {
this.patterns = patterns.clone();
verifyArrayArg(this.patterns, "patterns");
}
}
public static UnpackTuple make(Pattern[] patterns, Expr altExpr) {
return new UnpackTuple(patterns, altExpr);
}
public Pattern[] getPatterns() {
if (patterns.length == 0) {
return Pattern.NO_PATTERNS;
}
return patterns.clone();
}
/**
* Get the number of patterns.
* @return the number of patterns.
*/
public int getNPatterns() {
return patterns.length;
}
/**
* Get the nth pattern.
* @param n the index of the pattern to return.
* @return the nth pattern.
*/
public Pattern getNthPattern(int n) {
return patterns[n];
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR, "Tuple");
ParseTreeNode[] patternNodes = new ParseTreeNode[patterns.length];
for (int i = 0; i < patterns.length; i++) {
patternNodes[i] = patterns[i].toParseTreeNode();
}
fullPatternNode.addChildren(patternNodes);
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackTuple(this, arg);
}
}
/**
* Models the unpacking of the "()" data constructor (this is the operator form of Prelude.Unit).
* For example, the "() -> "unit"" part of the following function:
* unitToString x =
* case x of
* () -> "unit";
* ;
*
* @author Bo Ilic
*/
public static final class UnpackUnit extends Alt {
private UnpackUnit(Expr altExpr, SourceRange sourceRange) {
super(altExpr, sourceRange);
}
public static UnpackUnit make(Expr altExpr) {
return new UnpackUnit(altExpr, null);
}
static UnpackUnit makeAnnotated(Expr altExpr, SourceRange sourceRange) {
return new UnpackUnit(altExpr, sourceRange);
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR, "Tuple");
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackUnit(this, arg);
}
}
/**
* Models the unpacking of the "[]" data constructor (this is the operator form of Prelude.Nil). For example,
* this is the "[] -> error "List.init: empty list.";" part of the following function:
*
* public init !xs =
* case xs of
* a : as -> if isEmpty as then [] else a : init as;
* [] -> error "List.init: empty list.";
* ;
*
* @author Bo Ilic
*/
public static final class UnpackListNil extends Alt {
private UnpackListNil(Expr altExpr, SourceRange sourceRange) {
super(altExpr, sourceRange);
}
public static UnpackListNil make(Expr altExpr) {
return new UnpackListNil(altExpr, null);
}
static UnpackListNil makeAnnotated(Expr altExpr, SourceRange sourceRange) {
return new UnpackListNil(altExpr, sourceRange);
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.LIST_CONSTRUCTOR, CAL_Prelude.TypeConstructors.List.getUnqualifiedName());
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackListNil(this, arg);
}
}
/**
* Models the unpacking of the ":" data constructor (this is the operator form of Prelude.Cons). For example,
* this is the "a : as -> if isEmpty as then [] else a : init as;" part of the following function:
*
* public init !xs =
* case xs of
* a : as -> if isEmpty as then [] else a : init as;
* [] -> error "List.init: empty list.";
* ;
*
* @author Bo Ilic
*/
public static final class UnpackListCons extends Alt {
/** the pattern to the left of the ":" */
private final Pattern headPattern;
/** the pattern to the right of the ":" */
private final Pattern tailPattern;
/** The SourceRange of the ":" */
private final SourceRange operatorSourceRange;
private UnpackListCons(Pattern headPattern, Pattern tailPattern, Expr altExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super (altExpr, sourceRange);
verifyArg(headPattern, "headPattern");
verifyArg(tailPattern, "tailPattern");
this.headPattern = headPattern;
this.tailPattern = tailPattern;
this.operatorSourceRange = operatorSourceRange;
}
public static UnpackListCons make(Pattern headPattern, Pattern tailPattern, Expr altExpr) {
return new UnpackListCons(headPattern, tailPattern, altExpr, null, null);
}
static UnpackListCons makeAnnotated(Pattern headPattern, Pattern tailPattern, Expr altExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new UnpackListCons(headPattern, tailPattern, altExpr, sourceRange, operatorSourceRange);
}
public Pattern getHeadPattern() {
return headPattern;
}
public Pattern getTailPattern() {
return tailPattern;
}
// todo-jowong maybe the operator can be encapsulated by its own source element
SourceRange getOperatorSourceRange() {
return operatorSourceRange;
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.COLON, ":");
ParseTreeNode headPatternNode = headPattern.toParseTreeNode();
ParseTreeNode tailPatternNode = tailPattern.toParseTreeNode();
fullPatternNode.setFirstChild(headPatternNode);
headPatternNode.setNextSibling(tailPatternNode);
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackListCons(this, arg);
}
}
/**
* Models unpacking record values using a case expression.
*
* For example, the "{_ | #1 = f1, #2 = f2} -> (f1, f2);" part of the following function:
*
* public recordToTuple2 !r =
* case r of
* {_ | #1 = f1, #2 = f2} -> (f1, f2);
* ;
*
* Note that "case r of {s | } -> ..." is not equivalent to "case r of {s} -> ..."
* the first is doing a record polymorphic record match, the second is doing a case on a record with 1 field named "s"
* and using punning on the field name s.
*
* @author Bo Ilic
*/
public static final class UnpackRecord extends Alt {
/**
* The pattern to the left of the | in a record case.
* For example, the "r" in "{r | #1 = f1, #2 = f2} -> ...".
* May be null, to represent a non-record polymorphic pattern match e.g. "{#1 = f1, #2 = f3} -> ..."
*/
private final Pattern baseRecordPattern;
private final FieldPattern[] fieldPatterns;
private UnpackRecord(Pattern baseRecordPattern, FieldPattern[] fieldPatterns, Expr altExpr) {
super(altExpr, null);
if (fieldPatterns == null || fieldPatterns.length == 0) {
this.fieldPatterns = FieldPattern.NO_FIELD_PATTERNS;
} else {
this.fieldPatterns = fieldPatterns.clone();
verifyArrayArg(this.fieldPatterns, "fieldPatterns");
}
this.baseRecordPattern = baseRecordPattern;
}
public static UnpackRecord make(Pattern baseRecordPattern, FieldPattern[] fieldPatterns, Expr altExpr) {
return new UnpackRecord(baseRecordPattern, fieldPatterns, altExpr);
}
public Pattern getBaseRecordPattern() {
return baseRecordPattern;
}
public FieldPattern[] getFieldPatterns() {
if (fieldPatterns.length == 0) {
return FieldPattern.NO_FIELD_PATTERNS;
}
return fieldPatterns.clone();
}
/**
* Get the number of field patterns.
* @return the number of field patterns.
*/
public int getNFieldPatterns() {
return fieldPatterns.length;
}
/**
* Get the nth field pattern.
* @param n the index of the field pattern to return.
* @return the nth field pattern.
*/
public FieldPattern getNthFieldPattern(int n) {
return fieldPatterns[n];
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.RECORD_PATTERN, "RECORD_PATTERN");
ParseTreeNode baseRecordPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.BASE_RECORD_PATTERN, "BASE_RECORD_PATTERN");
ParseTreeNode fieldBindingVarAssignmentListNode = new ParseTreeNode(CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT_LIST, "FIELD_BINDING_VAR_ASSIGNMENT_LIST");
if(baseRecordPattern != null) {
baseRecordPatternNode.setFirstChild(baseRecordPattern.toParseTreeNode());
}
ParseTreeNode[] fieldPatternNodes = new ParseTreeNode[fieldPatterns.length];
for (int i = 0; i < fieldPatterns.length; i++) {
fieldPatternNodes[i] = fieldPatterns[i].toParseTreeNode();
}
fieldBindingVarAssignmentListNode.addChildren(fieldPatternNodes);
fullPatternNode.setFirstChild(baseRecordPatternNode);
baseRecordPatternNode.setNextSibling(fieldBindingVarAssignmentListNode);
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_UnpackRecord(this, arg);
}
}
/**
* Models the default or wildcard pattern "_ -> expr" that matches any of the cases not given explicitly as a case alternative.
*
* @author Bo Ilic
*/
public static final class Default extends Alt {
private Default(Expr altExpr, SourceRange range) {
super(altExpr, range);
}
public static Default make(Expr altExpr) {
return new Default(altExpr, null);
}
static Default makeAnnotated(Expr altExpr, SourceRange range) {
return new Default(altExpr, range);
}
@Override
ParseTreeNode buildPatternParseTreeNode() {
ParseTreeNode fullPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.UNDERSCORE, "_");
return fullPatternNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case_Alt_Default(this, arg);
}
}
private Alt(Expr altExpr, SourceRange sourceRange) {
super(sourceRange);
verifyArg(altExpr, "altExpr");
this.altExpr = altExpr;
}
/**
* @return Expr the expression that occurs on the right hand side of the "->" in a case alternative.
*/
public Expr getAltExpr() {
return altExpr;
}
/**
* @return A ParseTreeNode generated from the pattern associated with the pattern expression.
*/
abstract ParseTreeNode buildPatternParseTreeNode();
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode altNode = new ParseTreeNode(CALTreeParserTokenTypes.ALT, "ALT");
ParseTreeNode fullPatternNode = buildPatternParseTreeNode();
ParseTreeNode altExprNode = getAltExpr().toParseTreeNode();
altNode.addChild(fullPatternNode);
fullPatternNode.setNextSibling(altExprNode);
return altNode;
}
}
private Case(Expr conditionExpr, Alt[] caseAlts, SourceRange sourceRange) {
super(sourceRange);
if (caseAlts == null || caseAlts.length < 1) {
throw new IllegalArgumentException("the array argument 'caseAlts' must have at least 1 element.");
}
this.caseAlts = caseAlts.clone();
verifyArrayArg(this.caseAlts, "caseAlts");
verifyArg(conditionExpr, "conditionExpr");
this.conditionExpr = conditionExpr;
}
public static Case make(Expr conditionExpr, Alt[] caseAlts) {
return new Case(conditionExpr, caseAlts, null);
}
static Case makeAnnotated(Expr conditionExpr, Alt[] caseAlts, SourceRange sourceRange) {
return new Case(conditionExpr, caseAlts, sourceRange);
}
@Override
int precedenceLevel() {
return 0;
}
@Override
Associativity associativity() {
return Associativity.NON;
}
public Expr getConditionExpr() {
return conditionExpr;
}
public Case.Alt[] getCaseAlts() {
return caseAlts.clone();
}
/**
* Get the number of case alternatives.
* @return the number of case alternatives.
*/
public int getNCaseAlts() {
return caseAlts.length;
}
/**
* Get the nth case alternative.
* @param n the index of the case alternative to return.
* @return the nth case alternative.
*/
public Case.Alt getNthCaseAlt(int n) {
return caseAlts[n];
}
@Override
boolean neverNeedsParentheses() {
return false;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode caseExprNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_case, "case");
ParseTreeNode conditionExprNode = conditionExpr.toParseTreeNode();
ParseTreeNode altListNode = new ParseTreeNode(CALTreeParserTokenTypes.ALT_LIST, "ALT_LIST");
ParseTreeNode[] altNodes = new ParseTreeNode[caseAlts.length];
for(int i = 0; i < caseAlts.length; i++) {
altNodes[i] = caseAlts[i].toParseTreeNode();
}
altListNode.addChildren(altNodes);
caseExprNode.setFirstChild(conditionExprNode);
conditionExprNode.setNextSibling(altListNode);
return caseExprNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Case(this, arg);
}
}
/**
* Models a lambda expression such as:
* \x y z -> x + y + z
* or
* \!x x1 !x2 x3 -> map x [x1, x2, x3]
* @author Bo Ilic
*/
public static final class Lambda extends Expr {
private final Parameter[] parameters;
private final Expr definingExpr;
private Lambda (Parameter[] parameters, Expr definingExpr, SourceRange sourceRange) {
super(sourceRange);
if (parameters == null || parameters.length < 1) {
throw new IllegalArgumentException("lambda expressions cannot have 0 arguments.");
}
this.parameters = parameters.clone();
verifyArrayArg(this.parameters, "parameters");
verifyArg(definingExpr, "definingExpr");
this.definingExpr = definingExpr;
}
public static Lambda make(Parameter[] parameters, Expr definingExpr) {
return new Lambda(parameters, definingExpr, null);
}
static Lambda makeAnnotated(Parameter[] parameters, Expr definingExpr, SourceRange sourceRange) {
return new Lambda(parameters, definingExpr, sourceRange);
}
@Override
int precedenceLevel() {
return 0;
}
@Override
Associativity associativity() {
return Associativity.NON;
}
@Override
boolean neverNeedsParentheses() {
return false;
}
public Parameter[] getParameters() {
return parameters.clone();
}
/**
* Get the number of parameters.
* @return the number of parameters.
*/
public int getNParameters() {
return parameters.length;
}
/**
* Get the nth parameter.
* @param n the index of the parameter to return.
* @return the nth parameter.
*/
public Parameter getNthParameter(int n) {
return parameters[n];
}
public Expr getDefiningExpr() {
return definingExpr;
}
@Override
ParseTreeNode toParseTreeNode() {
ParseTreeNode lambdaExprNode = new ParseTreeNode(CALTreeParserTokenTypes.LAMBDA_DEFN, "\\");
ParseTreeNode paramListNode = new ParseTreeNode(CALTreeParserTokenTypes.FUNCTION_PARAM_LIST, "FUNCTION_PARAM_LIST");
ParseTreeNode exprNode = definingExpr.toParseTreeNode();
ParseTreeNode[] paramNodes = new ParseTreeNode[parameters.length];
for (int i = 0; i < parameters.length; i++) {
paramNodes[i] = parameters[i].toParseTreeNode();
}
paramListNode.addChildren(paramNodes);
lambdaExprNode.setFirstChild(paramListNode);
paramListNode.setNextSibling(exprNode);
return lambdaExprNode;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Lambda(this, arg);
}
}
/**
* Models an if-then-else expression.
* @author Bo Ilic
*/
public static final class If extends Expr {
private final Expr conditionExpr;
private final Expr thenExpr;
private final Expr elseExpr;
private If(Expr conditionExpr, Expr thenExpr, Expr elseExpr, SourceRange sourceRange) {
super(sourceRange);
verifyArg(conditionExpr, "conditionExpr");
verifyArg(thenExpr, "thenExpr");
verifyArg(elseExpr, "elseExpr");
this.conditionExpr = conditionExpr;
this.thenExpr = thenExpr;
this.elseExpr = elseExpr;
}
public static If make(Expr conditionExpr, Expr thenExpr, Expr elseExpr) {
return new If(conditionExpr, thenExpr, elseExpr, null);
}
static If makeAnnotated(Expr conditionExpr, Expr thenExpr, Expr elseExpr, SourceRange sourceRange) {
return new If(conditionExpr, thenExpr, elseExpr, sourceRange);
}
int precedenceLevel() {
return 0;
}
Associativity associativity() {
return Associativity.NON;
}
boolean neverNeedsParentheses() {
return false;
}
public Expr getConditionExpr() {
return conditionExpr;
}
public Expr getThenExpr() {
return thenExpr;
}
public Expr getElseExpr() {
return elseExpr;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode conditionExprNode = conditionExpr.toParseTreeNode();
ParseTreeNode thenExprNode = thenExpr.toParseTreeNode();
ParseTreeNode elseExprNode = elseExpr.toParseTreeNode();
ParseTreeNode ifExprNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_if, "if");
ifExprNode.setFirstChild(conditionExprNode);
conditionExprNode.setNextSibling(thenExprNode);
thenExprNode.setNextSibling(elseExprNode);
return ifExprNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_If(this, arg);
}
}
/**
* Base class for representing literals in CAL source.
* @author Bo Ilic
*/
public abstract static class Literal extends Expr {
private Literal(SourceRange sourceRange) {
super(sourceRange);
}
/**
* Models overloaded values of type "Num a => a" in CAL source. For example, 123. These look like integers, but
* in CAL, constants such as these really are shorthand for "Prelude.fromInteger 123" and so are overloaded values
* that can be specialized according to context as a Prelude.Int, Prelude.Integer, Prelude.Double etc.
* @author Bo Ilic
*/
public static final class Num extends Literal {
private final BigInteger value;
private Num(BigInteger value, SourceRange range) {
super(range);
verifyArg(value, "value");
this.value = value;
}
private Num(long value) {
this (BigInteger.valueOf(value), null);
}
public static Num make(BigInteger value) {
return new Num(value, null);
}
static Num makeAnnotated(BigInteger value, SourceRange range) {
return new Num(value, range);
}
public static Num make(long value) {
return new Num(value);
}
int precedenceLevel() {
if (value.compareTo(BigInteger.ZERO) < 0) {
//negative values have the precedence of unary negation.
return 70;
}
return 100;
}
public BigInteger getNumValue() {
return value;
}
boolean neverNeedsParentheses() {
//negative values may need to be parenthesized
return value.compareTo(BigInteger.ZERO) >= 0;
}
ParseTreeNode toParseTreeNode() {
if (value.compareTo(BigInteger.ZERO) < 0) {
Expr expr = Expr.UnaryOp.Negate.make(new Num(value.negate(), null));
ParseTreeNode exprNode = expr.toParseTreeNode();
return exprNode;
}
ParseTreeNode numLiteralNode = new ParseTreeNode(CALTreeParserTokenTypes.INTEGER_LITERAL, value.toString());
return numLiteralNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Literal_Num(this, arg);
}
}
/**
* Models literal values of type Prelude.Float in CAL source.
* @author Ray Cypher
*/
public static final class Float extends Literal {
private final float value;
private Float (float value, SourceRange range) {
super(range);
this.value = value;
}
public static Float make (float value) {
return new Float (value, null);
}
static Float makeAnnotated (float value, SourceRange range) {
return new Float (value, range);
}
int precedenceLevel() {
if (value < 0) {
//negative values have the precedence of unary negation.
return 70;
}
return 100;
}
public float getFloatValue() {
return value;
}
boolean neverNeedsParentheses() {
// because we are generating an application of Prelude.doubleToFloat
// it may need parentheses
return false;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode valNode;
if (java.lang.Double.isNaN(value)) {
Expr expr = Expr.Var.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.Functions.isNotANumber.getUnqualifiedName());
valNode = expr.toParseTreeNode();
} else
if (value == java.lang.Double.POSITIVE_INFINITY) {
Expr expr = Expr.Var.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.Functions.positiveInfinity.getUnqualifiedName());
valNode = expr.toParseTreeNode();
} else
if (value == java.lang.Double.NEGATIVE_INFINITY) {
Expr expr = Expr.Var.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.Functions.negativeInfinity.getUnqualifiedName());
valNode = expr.toParseTreeNode();
} else
if (value < 0) {
Expr expr = Expr.UnaryOp.Negate.make(makeDoubleValue(-value));
valNode = expr.toParseTreeNode();
} else {
valNode = new ParseTreeNode(CALTreeParserTokenTypes.FLOAT_LITERAL, java.lang.Double.toString(value));
}
ParseTreeNode appNode = new ParseTreeNode(CALTreeParserTokenTypes.APPLICATION, "@");
ParseTreeNode children[] =
new ParseTreeNode[]{
(Expr.Var.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.Functions.toFloat.getUnqualifiedName())).toParseTreeNode(),
valNode};
appNode.addChildren(children);
return appNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Literal_Float(this, arg);
}
}
/**
* Models literal values of type Prelude.Double in CAL source e.g. 1.23
* @author Bo Ilic
*/
public static final class Double extends Literal {
private final double value;
private Double(double value, SourceRange range) {
super(range);
this.value = value;
}
public static Double make(double value) {
return new Double(value, null);
}
static Double makeAnnotated(double value, SourceRange range) {
return new Double(value, range);
}
int precedenceLevel() {
if (value < 0) {
//negative values have the precedence of unary negation.
return 70;
}
return 100;
}
public double getDoubleValue() {
return value;
}
boolean neverNeedsParentheses() {
//negative values may need to be parenthesized
return value >= 0;
}
ParseTreeNode toParseTreeNode() {
if (java.lang.Double.isNaN(value)) {
Expr expr = Expr.Var.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.Functions.isNotANumber.getUnqualifiedName());
ParseTreeNode exprNode = expr.toParseTreeNode();
return exprNode;
}
if (value == java.lang.Double.POSITIVE_INFINITY) {
Expr expr = Expr.Var.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.Functions.positiveInfinity.getUnqualifiedName());
ParseTreeNode exprNode = expr.toParseTreeNode();
return exprNode;
}
if (value == java.lang.Double.NEGATIVE_INFINITY) {
Expr expr = Expr.Var.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.Functions.negativeInfinity.getUnqualifiedName());
ParseTreeNode exprNode = expr.toParseTreeNode();
return exprNode;
}
if (value < 0) {
Expr expr = Expr.UnaryOp.Negate.make(makeDoubleValue(-value));
ParseTreeNode exprNode = expr.toParseTreeNode();
return exprNode;
}
ParseTreeNode doubleLiteralNode = new ParseTreeNode(CALTreeParserTokenTypes.FLOAT_LITERAL, java.lang.Double.toString(value));
return doubleLiteralNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Literal_Double(this, arg);
}
}
/**
* Models literal values of type Prelude.Char in CAL source e.g. 'a', '\n'
* @author Bo Ilic
*/
public static final class Char extends Literal {
private final char value;
private Char(char value, SourceRange range) {
super(range);
this.value = value;
}
public static Char make(char value) {
return new Char(value, null);
}
static Char makeAnnotated(char value, SourceRange range) {
return new Char(value, range);
}
int precedenceLevel() {
return 100;
}
public char getCharValue() {
return value;
}
boolean neverNeedsParentheses() {
return true;
}
ParseTreeNode toParseTreeNode() {
String c = StringEncoder.encodeChar(value);
ParseTreeNode charLiteralNode = new ParseTreeNode(CALTreeParserTokenTypes.CHAR_LITERAL, c);
return charLiteralNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Literal_Char(this, arg);
}
}
/**
* Models literal values of type Prelude.String in CAL source e.g. "abc", "abc\ndef"
* @author Bo Ilic
*/
public static final class StringLit extends Literal {
private final String value;
private StringLit(String value, SourceRange range) {
super(range);
verifyArg(value, "value");
this.value = value;
}
public static StringLit make(String value) {
return new StringLit(value, null);
}
static StringLit makeAnnotated(String value, SourceRange range) {
return new StringLit(value, range);
}
int precedenceLevel() {
return 100;
}
public String getStringValue() {
return value;
}
boolean neverNeedsParentheses() {
return true;
}
ParseTreeNode toParseTreeNode() {
String encodedString = StringEncoder.encodeString(value);
ParseTreeNode stringLiteralNode = new ParseTreeNode(CALTreeParserTokenTypes.STRING_LITERAL, encodedString);
return stringLiteralNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Literal_StringLit(this, arg);
}
}
private Literal(){
}
Associativity associativity() {
return Associativity.NON;
}
}
/**
* Models a unary operator in operator form e.g. -2.0.
* Currently the only one is unary negate.
* @author Bo Ilic
*/
public abstract static class UnaryOp extends Expr {
/** the single argument expression of the unary operator */
private final Expr expr;
private final SourceRange operatorSourceRange;
/**
* Models the - unary operator (which is Prelude.negate in its textual form).
* @author Bo Ilic
*/
public static final class Negate extends UnaryOp {
private Negate(Expr expr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(expr, sourceRange, operatorSourceRange);
}
public static Negate make(Expr expr) {
return new Negate(expr, null, null);
}
static Negate makeAnnotated(Expr expr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Negate(expr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 70;
}
Associativity associativity() {
return Associativity.NON;
}
public String getOpText() {
return "-";
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode exprNode = new ParseTreeNode(CALTreeParserTokenTypes.UNARY_MINUS, getOpText());
exprNode.setFirstChild(getExpr().toParseTreeNode());
return exprNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_UnaryOp_Negate(this, arg);
}
}
private UnaryOp(Expr expr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(sourceRange);
verifyArg(expr, "expr");
this.expr = expr;
this.operatorSourceRange = operatorSourceRange;
}
/** @return The source range of the operator */
// todo-jowong maybe the operator can be encapsulated by its own source element
SourceRange getOperatorSourceRange() {
return operatorSourceRange;
}
/**
* @return representing the operator form in CAL source without its arguments e.g. "-".
*/
public abstract String getOpText();
boolean neverNeedsParentheses() {
//-3 + 7 is not the same as - (3 + 7)
return false;
}
/** @return the single argument expression of the unary operator */
public Expr getExpr() {
return expr;
}
}
/**
* Models binary operator expressions in operator form e.g. 2.0 + 3.0 (and not something like Prelude.add 2.0 3.0).
* @author Bo Ilic
*/
public abstract static class BinaryOp extends Expr {
/** the argument on the left hand side of the operator. */
private final Expr leftExpr;
/** the argument on the right hand side of the operator. */
private final Expr rightExpr;
/** The SourceRange of the operator */
private final SourceRange operatorSourceRange;
/**
* Models the && operator (which is Prelude.and in its textual form).
* @author Bo Ilic
*/
public static final class And extends BinaryOp {
private And(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static And make(Expr leftExpr, Expr rightExpr) {
return new And(leftExpr, rightExpr, null, null);
}
static And makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new And(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public String getOpText() {
return "&&";
}
int precedenceLevel() {
return 20;
}
Associativity associativity() {
return Associativity.RIGHT;
}
int getTokenType() {
return CALTreeParserTokenTypes.AMPERSANDAMPERSAND;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_And(this, arg);
}
}
/**
* Models the || operator (which is Prelude.or in its textual form).
* @author Bo Ilic
*/
public static final class Or extends BinaryOp {
private Or(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Or make(Expr leftExpr, Expr rightExpr) {
return new Or(leftExpr, rightExpr, null, null);
}
static Or makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Or(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public String getOpText() {
return "||";
}
int precedenceLevel() {
return 10;
}
Associativity associativity() {
return Associativity.RIGHT;
}
int getTokenType() {
return CALTreeParserTokenTypes.BARBAR;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Or(this, arg);
}
}
/**
* Models the == operator (which is Prelude.equals in its textual form).
* @author Bo Ilic
*/
public static final class Equals extends BinaryOp {
private Equals(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Equals make(Expr leftExpr, Expr rightExpr) {
return new Equals(leftExpr, rightExpr, null, null);
}
static Equals makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Equals(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 30;
}
Associativity associativity() {
return Associativity.NON;
}
public String getOpText() {
return "==";
}
int getTokenType() {
return CALTreeParserTokenTypes.EQUALSEQUALS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Equals(this, arg);
}
}
/**
* Models the != operator (which is Prelude.notEquals in its textual form).
* @author Bo Ilic
*/
public static final class NotEquals extends BinaryOp {
private NotEquals(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static NotEquals make(Expr leftExpr, Expr rightExpr) {
return new NotEquals(leftExpr, rightExpr, null, null);
}
static NotEquals makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new NotEquals(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 30;
}
Associativity associativity() {
return Associativity.NON;
}
public String getOpText() {
return "!=";
}
int getTokenType() {
return CALTreeParserTokenTypes.NOT_EQUALS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_NotEquals(this, arg);
}
}
/**
* Models the < operator (which is Prelude.lessThan in its textual form).
* @author Bo Ilic
*/
public static final class LessThan extends BinaryOp {
private LessThan(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static LessThan make(Expr leftExpr, Expr rightExpr) {
return new LessThan(leftExpr, rightExpr, null, null);
}
static LessThan makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new LessThan(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 30;
}
Associativity associativity() {
return Associativity.NON;
}
public String getOpText() {
return "<";
}
int getTokenType() {
return CALTreeParserTokenTypes.LESS_THAN;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_LessThan(this, arg);
}
}
/**
* Models the <= operator (which is Prelude.lessThanEquals in its textual form).
* @author Bo Ilic
*/
public static final class LessThanEquals extends BinaryOp {
private LessThanEquals(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static LessThanEquals make(Expr leftExpr, Expr rightExpr) {
return new LessThanEquals(leftExpr, rightExpr, null, null);
}
static LessThanEquals makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new LessThanEquals(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 30;
}
Associativity associativity() {
return Associativity.NON;
}
public String getOpText() {
return "<=";
}
int getTokenType() {
return CALTreeParserTokenTypes.LESS_THAN_OR_EQUALS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_LessThanEquals(this, arg);
}
}
/**
* Models the >= operator (which is Prelude.greaterThanEquals in its textual form).
* @author Bo Ilic
*/
public static final class GreaterThanEquals extends BinaryOp {
private GreaterThanEquals(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static GreaterThanEquals make(Expr leftExpr, Expr rightExpr) {
return new GreaterThanEquals(leftExpr, rightExpr, null, null);
}
static GreaterThanEquals makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new GreaterThanEquals(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 30;
}
Associativity associativity() {
return Associativity.NON;
}
public String getOpText() {
return ">=";
}
int getTokenType() {
return CALTreeParserTokenTypes.GREATER_THAN_OR_EQUALS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_GreaterThanEquals(this, arg);
}
}
/**
* Models the < operator (which is Prelude.lessThan in its textual form).
* @author Bo Ilic
*/
public static final class GreaterThan extends BinaryOp {
private GreaterThan(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static GreaterThan make(Expr leftExpr, Expr rightExpr) {
return new GreaterThan(leftExpr, rightExpr, null, null);
}
static GreaterThan makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new GreaterThan(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public String getOpText() {
return ">";
}
int precedenceLevel() {
return 30;
}
Associativity associativity() {
return Associativity.NON;
}
int getTokenType() {
return CALTreeParserTokenTypes.GREATER_THAN;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_GreaterThan(this, arg);
}
}
/**
* Models the + operator (which is Prelude.add in its textual form).
* @author Bo Ilic
*/
public static final class Add extends BinaryOp {
private Add(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Add make(Expr leftExpr, Expr rightExpr) {
return new Add(leftExpr, rightExpr, null, null);
}
static Add makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Add(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 50;
}
Associativity associativity() {
return Associativity.LEFT;
}
public String getOpText() {
return "+";
}
int getTokenType() {
return CALTreeParserTokenTypes.PLUS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Add(this, arg);
}
}
/**
* Models the - binary operator (which is Prelude.subtract in its textual form).
* @author Bo Ilic
*/
public static final class Subtract extends BinaryOp {
private Subtract(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Subtract make(Expr leftExpr, Expr rightExpr) {
return new Subtract(leftExpr, rightExpr, null, null);
}
static Subtract makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Subtract(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 50;
}
Associativity associativity() {
return Associativity.LEFT;
}
public String getOpText() {
return "-";
}
int getTokenType() {
return CALTreeParserTokenTypes.MINUS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Subtract(this, arg);
}
}
/**
* Models the * operator (which is Prelude.multiply in its textual form).
* @author Bo Ilic
*/
public static final class Multiply extends BinaryOp {
private Multiply(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Multiply make(Expr leftExpr, Expr rightExpr) {
return new Multiply(leftExpr, rightExpr, null, null);
}
static Multiply makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Multiply(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 60;
}
Associativity associativity() {
return Associativity.LEFT;
}
public String getOpText() {
return "*";
}
int getTokenType() {
return CALTreeParserTokenTypes.ASTERISK;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Multiply(this, arg);
}
}
/**
* Models the / operator (which is Prelude.divide in its textual form).
* @author Bo Ilic
*/
public static final class Divide extends BinaryOp {
private Divide(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Divide make(Expr leftExpr, Expr rightExpr) {
return new Divide(leftExpr, rightExpr, null, null);
}
static Divide makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Divide(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 60;
}
Associativity associativity() {
return Associativity.LEFT;
}
public String getOpText() {
return "/";
}
int getTokenType() {
return CALTreeParserTokenTypes.SOLIDUS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Divide(this, arg);
}
}
/**
* Models the % operator (which is Prelude.remainder in its textual form).
* @author Bo Ilic
*/
public static final class Remainder extends BinaryOp {
private Remainder(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Remainder make(Expr leftExpr, Expr rightExpr) {
return new Remainder(leftExpr, rightExpr, null, null);
}
static Remainder makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Remainder(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 60;
}
Associativity associativity() {
return Associativity.LEFT;
}
public String getOpText() {
return "%";
}
int getTokenType() {
return CALTreeParserTokenTypes.PERCENT;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Remainder(this, arg);
}
}
/**
* Models the `{Operator}` operator the back quoted operator application
* @author Greg McClement
* @author Joseph Wong
*/
public static abstract class BackquotedOperator extends BinaryOp
{
/**
* Models a backquoted operator containing a function/class method
* name between the backquotes.
* @author Joseph Wong
*/
public static final class Var extends BackquotedOperator {
/**
* The variable, function or class method reference appearing between the backquotes.
*/
private final Expr.Var operatorVarExpr;
/**
* Creates a source model element that represents a backquoted operator containing
* a function/class method name between the backquotes.
*
* @param operatorVarExpr the variable, function or class method reference appearing between the backquotes.
* @param leftExpr the left-hand-side expression.
* @param rightExpr the right-hand-side expression.
* @param sourceRange the position that this SourceElement begins at in the source text
* for this module.
* @param operatorSourceRange
*/
private Var(Expr.Var operatorVarExpr, Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
verifyArg(operatorVarExpr, "operatorVarExpr");
this.operatorVarExpr = operatorVarExpr;
}
/**
* Factory method for constructing a source model element that represents a backquoted operator containing
* a function/class method name between the backquotes.
*
* @param operatorVarExpr the variable, function or class method reference appearing between the backquotes.
* @param leftExpr the left-hand-side expression.
* @param rightExpr the right-hand-side expression.
* @return a new instance of this class.
*/
public static Var make(Expr.Var operatorVarExpr, Expr leftExpr, Expr rightExpr) {
return new Var(operatorVarExpr, leftExpr, rightExpr, null, null);
}
/**
* Factory method for constructing a source model element that represents a backquoted operator containing
* a function/class method name between the backquotes.
*
* @param operatorVarExpr the variable, function or class method reference appearing between the backquotes.
* @param leftExpr the left-hand-side expression.
* @param rightExpr the right-hand-side expression.
* @param sourceRange the position that this SourceElement begins at in the source text
* for this module.
* @param operatorSourceRange
* @return a new instance of this class.
*/
static Var makeAnnotated(Expr.Var operatorVarExpr, Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Var(operatorVarExpr, leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
/**
* @return the variable, function or class method reference appearing between the backquotes.
*/
public Expr.Var getOperatorVarExpr() {
return operatorVarExpr;
}
/**
* @return the string representing the operator form in CAL source without its arguments e.g. "`seq`".
*/
public String getOpText() {
return "`" + operatorVarExpr.toSourceText() + "`";
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeOperatorNode() {
return operatorVarExpr.toParseTreeNode();
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_BackquotedOperator_Var(this, arg);
}
}
/**
* Models a backquoted operator containing a data constructor
* name between the backquotes.
* @author Joseph Wong
*/
public static final class DataCons extends BackquotedOperator {
/**
* The data constructor reference appearing between the backquotes.
*/
private final Expr.DataCons operatorDataConsExpr;
/**
* Creates a source model element that represents a backquoted operator containing
* a data constructor name between the backquotes.
*
* @param operatorDataConsExpr the data constructor reference appearing between the backquotes.
* @param leftExpr the left-hand-side expression.
* @param rightExpr the right-hand-side expression.
* @param sourceRange the position that this SourceElement begins at in the source text
* for this module.
* @param operatorSourceRange
*/
private DataCons(Expr.DataCons operatorDataConsExpr, Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
verifyArg(operatorDataConsExpr, "operatorDataConsExpr");
this.operatorDataConsExpr = operatorDataConsExpr;
}
/**
* Factory method for constructing a source model element that represents a backquoted operator containing
* a data constructor name between the backquotes.
*
* @param operatorDataConsExpr the data constructor reference appearing between the backquotes.
* @param leftExpr the left-hand-side expression.
* @param rightExpr the right-hand-side expression.
* @return a new instance of this class.
*/
public static DataCons make(Expr.DataCons operatorDataConsExpr, Expr leftExpr, Expr rightExpr) {
return new DataCons(operatorDataConsExpr, leftExpr, rightExpr, null, null);
}
/**
* Factory method for constructing a source model element that represents a backquoted operator containing
* a data constructor name between the backquotes.
*
* @param operatorDataConsExpr the data constructor reference appearing between the backquotes.
* @param leftExpr the left-hand-side expression.
* @param rightExpr the right-hand-side expression.
* @param sourceRange the position that this SourceElement begins at in the source text
* for this module.
* @param operatorSourceRange
* @return a new instance of this class.
*/
static DataCons makeAnnotated(Expr.DataCons operatorDataConsExpr, Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new DataCons(operatorDataConsExpr, leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
/**
* @return the data constructor reference appearing between the backquotes.
*/
public Expr.DataCons getOperatorDataConsExpr() {
return operatorDataConsExpr;
}
/**
* @return the string representing the operator form in CAL source without its arguments e.g. "`Cons`".
*/
public String getOpText() {
return "`" + operatorDataConsExpr.toString() + "`";
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeOperatorNode() {
return operatorDataConsExpr.toParseTreeNode();
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_BackquotedOperator_DataCons(this, arg);
}
}
/**
* Private constructor for this base class for backquoted operator. Intended
* only to be invoked by subclass constructors.
*
* @param leftExpr the left-hand-side expression.
* @param rightExpr the right-hand-side expression.
* @param sourceRange the position that this SourceElement begins at in the source text
* for this module.
* @param operatorSourceRange
*/
private BackquotedOperator(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
/**
* {@inheritDoc}
*/
int precedenceLevel() {
return 75; // higher than unary negation, same as compose, lower than application
}
/**
* {@inheritDoc}
*/
Associativity associativity() {
return Associativity.LEFT;
}
/**
* {@inheritDoc}
*/
int getTokenType() {
return CALTreeParserTokenTypes.BACKQUOTE;
}
/**
* Creates an application node wrapping an expression.
* @param exprNode the ParseTreeNode of the expression.
* @return an application node wrapping the expression.
*/
private ParseTreeNode makeApplicationNode(ParseTreeNode exprNode){
ParseTreeNode applicationExprNode = new ParseTreeNode (CALTreeParserTokenTypes.APPLICATION, "@");
applicationExprNode.addChild( exprNode );
return applicationExprNode;
}
/**
* @return the qualified cons/var node for the backquoted operator.
*/
abstract ParseTreeNode makeOperatorNode();
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire operator, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the operator source range of the source element is its entirety, including backticks
// todo-jowong maybe the operator can be encapsulated by its own source element
@Deprecated
SourceRange getOperatorSourceRange() {
return getSourceRangeOfNameBetweenBackticks();
}
SourceRange getSourceRangeOfNameBetweenBackticks() {
return super.getOperatorSourceRange();
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode operatorNode = makeOperatorNode();
ParseTreeNode leftExprNode = makeApplicationNode(getLeftExpr().toParseTreeNode());
ParseTreeNode rightExprNode = makeApplicationNode(getRightExpr().toParseTreeNode());
ParseTreeNode applicationExprNode = new ParseTreeNode (CALTreeParserTokenTypes.APPLICATION, "@");
applicationExprNode.addChild( operatorNode );
applicationExprNode.addChild( leftExprNode );
applicationExprNode.addChild( rightExprNode );
ParseTreeNode exprNode = new ParseTreeNode (CALTreeParserTokenTypes.BACKQUOTE, "`");
exprNode.addChild( applicationExprNode );
return exprNode;
}
}
/**
* Models the # operator (which is Prelude.compose in its textual form).
* @author Joseph Wong
*/
public static final class Compose extends BinaryOp {
/**
* Private constructor for this class.
* @param leftExpr the left-hand-sidce operand.
* @param rightExpr the right-hand-sidce operand.
* @param sourceRange
* @param operatorSourceRange
*/
private Compose(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
/**
* Factory method for creating a new instance of this source model element.
* @param leftExpr the left-hand-sidce operand.
* @param rightExpr the right-hand-sidce operand.
* @return a new instance of SourceModel.Expr.BinaryOp.Compose.
*/
public static Compose make(Expr leftExpr, Expr rightExpr) {
return new Compose(leftExpr, rightExpr, null, null);
}
/**
* Internal factory method for creating a new instance of this source model element
* along with a SourceRange annotation.
* @param leftExpr the left-hand-sidce operand.
* @param rightExpr the right-hand-sidce operand.
* @param sourceRange The position in the source of the beginning of this element
* @param operatorSourceRange
* @return a new instance of SourceModel.Expr.BinaryOp.Compose.
*/
static Compose makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Compose(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
/**
* The higher the value, the greater the precedence level. For example, * would be higher than +.
* @return int precedence level. Has no absolute significance, only relative to the precedence
* level for other expressions.
*/
int precedenceLevel() {
return 75; // same as backquote operator, lower than application
}
/**
* @return the associativity of this operator.
*/
Associativity associativity() {
return Associativity.RIGHT;
}
/**
* @return representing the operator form in CAL source without its arguments e.g. "+".
*/
public String getOpText() {
return "#";
}
/**
* @return Int representing the token type of the operator.
*/
int getTokenType() {
return CALTreeParserTokenTypes.POUND;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Compose(this, arg);
}
}
/**
* Models the $ operator (which is Prelude.apply in its textual form).
* @author Joseph Wong
*/
public static final class Apply extends BinaryOp {
/**
* Private constructor for this class.
* @param leftExpr the left-hand-sidce operand.
* @param rightExpr the right-hand-sidce operand.
* @param sourceRange
* @param operatorSourceRange
*/
private Apply(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
/**
* Factory method for creating a new instance of this source model element.
* @param leftExpr the left-hand-sidce operand.
* @param rightExpr the right-hand-sidce operand.
* @return a new instance of SourceModel.Expr.BinaryOp.Apply.
*/
public static Apply make(Expr leftExpr, Expr rightExpr) {
return new Apply(leftExpr, rightExpr, null, null);
}
/**
* Internal factory method for creating a new instance of this source model element
* along with a SourceRange annotation.
* @param leftExpr the left-hand-sidce operand.
* @param rightExpr the right-hand-sidce operand.
* @param sourceRange The position in the source of the beginning of this element
* @param operatorSourceRange
* @return a new instance of SourceModel.Expr.BinaryOp.Apply.
*/
static Apply makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Apply(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
/**
* The higher the value, the greater the precedence level. For example, * would be higher than +.
* @return int precedence level. Has no absolute significance, only relative to the precedence
* level for other expressions.
*/
int precedenceLevel() {
return 5; // higher than :: operator, lower than || operator
}
/**
* @return the associativity of this operator.
*/
Associativity associativity() {
return Associativity.RIGHT;
}
/**
* @return representing the operator form in CAL source without its arguments e.g. "+".
*/
public String getOpText() {
return "$";
}
/**
* @return Int representing the token type of the operator.
*/
int getTokenType() {
return CALTreeParserTokenTypes.DOLLAR;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Apply(this, arg);
}
}
/**
* Models the : operator (which is Prelude.Cons in its textual form).
* @author Bo Ilic
*/
public static final class Cons extends BinaryOp {
private Cons(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Cons make(Expr leftExpr, Expr rightExpr) {
return new Cons(leftExpr, rightExpr, null, null);
}
static Cons makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Cons(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 40;
}
Associativity associativity() {
return Associativity.RIGHT;
}
public String getOpText() {
return ":";
}
int getTokenType() {
return CALTreeParserTokenTypes.COLON;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Cons(this, arg);
}
}
/**
* Models the ++ operator (which is Prelude.append in its textual form).
* @author Bo Ilic
*/
public static final class Append extends BinaryOp {
private Append(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
public static Append make(Expr leftExpr, Expr rightExpr) {
return new Append(leftExpr, rightExpr, null, null);
}
static Append makeAnnotated(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Append(leftExpr, rightExpr, sourceRange, operatorSourceRange);
}
int precedenceLevel() {
return 40;
}
Associativity associativity() {
return Associativity.RIGHT;
}
public String getOpText() {
return "++";
}
int getTokenType() {
return CALTreeParserTokenTypes.PLUSPLUS;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_BinaryOp_Append(this, arg);
}
}
private BinaryOp(Expr leftExpr, Expr rightExpr, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(sourceRange);
verifyArg(leftExpr, "leftExpr");
verifyArg(rightExpr, "rightExpr");
this.leftExpr = leftExpr;
this.rightExpr = rightExpr;
this.operatorSourceRange = operatorSourceRange;
}
/** @return The SourceRange of the operator (may be null) */
// todo-jowong maybe the operator can be encapsulated by its own source element
SourceRange getOperatorSourceRange() {
return operatorSourceRange;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode exprNode = new ParseTreeNode(getTokenType(), getOpText());
ParseTreeNode leftExprNode = getLeftExpr().toParseTreeNode();
ParseTreeNode rightExprNode = getRightExpr().toParseTreeNode();
exprNode.setFirstChild(leftExprNode);
leftExprNode.setNextSibling(rightExprNode);
return exprNode;
}
boolean neverNeedsParentheses() {
//for example, 'x + y * z' is the same as x + (y * z)
//so if we want (x + y) * z then parentheses are needed.
return false;
}
/**
* @return representing the operator form in CAL source without its arguments e.g. "+".
*/
public abstract String getOpText();
/**
* @return Int representing the token type of the operator.
*/
abstract int getTokenType();
/**
* @return the argument on the left hand side of the operator.
*/
public Expr getLeftExpr() {
return leftExpr;
}
/**
* @return the argument on the right hand side of the operator.
*/
public Expr getRightExpr() {
return rightExpr;
}
}
/**
* Models the notational form of the Prelude.Unit data constructor i.e. ().
* @author Bo Ilic
*/
public static final class Unit extends Expr {
private static final Unit UNIT = new Unit(null);
private Unit(SourceRange sourceRange) {
super(sourceRange);
}
public static Unit make() {
return UNIT;
}
static Unit makeAnnotated(SourceRange sourceRange) {
return new Unit(sourceRange);
}
int precedenceLevel() {
return 100;
}
Associativity associativity() {
return Associativity.NON;
}
boolean neverNeedsParentheses() {
return true;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode exprNode = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR, "Tuple");
return exprNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Unit(this, arg);
}
}
/**
* Models the notational form of tuples in CAL source (dimension 2 or greater) e.g. (2.0, 'a'), ("hello", sin 2.0, True)
* @author Bo Ilic
*/
public static final class Tuple extends Expr {
private final Expr[] components;
private Tuple(Expr[] components, SourceRange sourceRange) {
super(sourceRange);
if (components == null || components.length < 2) {
throw new IllegalArgumentException("tuples must have 2 or more components.");
}
this.components = components.clone();
verifyArrayArg(components, "components");
}
public static Tuple make(Expr[] components) {
return new Tuple(components, null);
}
static Tuple makeAnnotated(Expr[] components, SourceRange sourceRange) {
return new Tuple(components, sourceRange);
}
int precedenceLevel() {
return 100;
}
Associativity associativity() {
return Associativity.NON;
}
boolean neverNeedsParentheses() {
return true;
}
public Expr[] getComponents() {
return components.clone();
}
/**
* Get the number of components.
* @return the number of components.
*/
public int getNComponents() {
return components.length;
}
/**
* Get the nth component.
* @param n the index of the component to return.
* @return the nth component.
*/
public Expr getNthComponent(int n) {
return components[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode tupleNode = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR, "Tuple");
ParseTreeNode[] componentNodes = new ParseTreeNode[components.length];
for (int i = 0; i < components.length; i++) {
componentNodes[i] = components[i].toParseTreeNode();
}
tupleNode.addChildren(componentNodes);
return tupleNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Tuple(this, arg);
}
}
/**
* Models the notational form a list in CAL source e.g. ["dog", "cat", "horse"]
* @author Bo Ilic
*/
public static final class List extends Expr {
private final Expr[] elements;
private static final Expr[] NO_ELEMENTS = new Expr[0];
public static final List EMPTY_LIST = new List (NO_ELEMENTS, null);
private List(Expr[] elements, SourceRange sourceRange) {
super(sourceRange);
if (elements == null || elements.length == 0) {
this.elements = NO_ELEMENTS;
} else {
this.elements = elements.clone();
verifyArrayArg(this.elements, "elements");
}
}
private List(java.util.List<Expr> elementList, SourceRange sourceRange) {
super(sourceRange);
if (elementList == null || elementList.isEmpty()) {
this.elements = NO_ELEMENTS;
} else {
this.elements = elementList.toArray(new Expr[elementList.size()]);
verifyArrayArg(this.elements, "elements");
}
}
public static List make(Expr[] elements) {
return new List(elements, null);
}
public static List make (java.util.List<Expr> elementList) {
return new List(elementList, null);
}
static List makeAnnotated(Expr[] elements, SourceRange sourceRange) {
return new List(elements, sourceRange);
}
int precedenceLevel() {
return 100;
}
Associativity associativity() {
return Associativity.NON;
}
boolean neverNeedsParentheses() {
return true;
}
public Expr[] getElements() {
if (elements.length == 0) {
return NO_ELEMENTS;
}
return elements.clone();
}
/**
* Get the number of elements.
* @return the number of elements.
*/
public int getNElements() {
return elements.length;
}
/**
* Get the nth element.
* @param n the index of the element to return.
* @return the nth element.
*/
public Expr getNthElement(int n) {
return elements[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode listNode = new ParseTreeNode(CALTreeParserTokenTypes.LIST_CONSTRUCTOR, CAL_Prelude.TypeConstructors.List.getUnqualifiedName());
ParseTreeNode[] elementNodes = new ParseTreeNode[elements.length];
for (int i = 0; i < elements.length; i++) {
elementNodes[i] = elements[i].toParseTreeNode();
}
listNode.addChildren(elementNodes);
return listNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_List(this, arg);
}
}
/**
* Models record expressions using the brace notation such as
* {r | field1 = "abc", #2 = 100.0}
* {}
* {f x | }
*
* This includes both record literals, as well as record modifications (which can include field extensions or
* field value updates) e.g.
* {r | #1 := "abc", foo = "bar", name := "Fred", age = 2.0}
*
* @author Bo Ilic
*/
public static final class Record extends Expr {
private final Expr baseRecordExpr;
private final FieldModification[] fieldModifications;
public static final FieldModification[] NO_FIELD_MODIFICATIONS = new FieldModification[0];
/**
* Models an element of the field modification list (the right hand side of the "|" in a record expression.
* Currently these are either field extensions such as "foo = 2.0" or field value updates such as "bar := 10.0".
*
* @author Bo Ilic
*/
public static abstract class FieldModification extends SourceElement {
private final Name.Field fieldName;
private final Expr valueExpr;
public static final class Extension extends FieldModification {
private Extension(Name.Field fieldName, Expr valueExpr) {
super(fieldName, valueExpr);
}
public static Extension make(Name.Field fieldName, Expr valueExpr) {
return new Extension(fieldName, valueExpr);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Record_FieldModification_Extension(this, arg);
}
/** {@inheritDoc} */
ParseTreeNode makeFieldModificationNode () {
return new ParseTreeNode(CALTreeParserTokenTypes.FIELD_EXTENSION, "FIELD_EXTENSION");
}
}
public static final class Update extends FieldModification {
private Update(Name.Field fieldName, Expr valueExpr) {
super(fieldName, valueExpr);
}
public static Update make(Name.Field fieldName, Expr valueExpr) {
return new Update(fieldName, valueExpr);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Record_FieldModification_Update(this, arg);
}
/** {@inheritDoc} */
ParseTreeNode makeFieldModificationNode () {
return new ParseTreeNode(CALTreeParserTokenTypes.FIELD_VALUE_UPDATE, "FIELD_VALUE_UPDATE");
}
}
private FieldModification(Name.Field fieldName, Expr valueExpr) {
verifyArg(fieldName, "fieldName");
verifyArg(valueExpr, "valueExpr");
this.fieldName = fieldName;
this.valueExpr = valueExpr;
}
public Name.Field getFieldName() {
return fieldName;
}
public Expr getValueExpr() {
return valueExpr;
}
abstract ParseTreeNode makeFieldModificationNode();
/** {@inheritDoc} */
ParseTreeNode toParseTreeNode() {
ParseTreeNode fieldModificationNode = makeFieldModificationNode();
ParseTreeNode fieldNameNode = fieldName.toParseTreeNode();
ParseTreeNode assignmentNode = valueExpr.toParseTreeNode();
fieldModificationNode.setFirstChild(fieldNameNode);
fieldNameNode.setNextSibling(assignmentNode);
return fieldModificationNode;
}
}
/**
* If extensionFields is [(field1, expr1), ..., (fieldN, exprN)] then this models the record extension
* {baseRecordExpr | field1 = expr1, field2 = expr2, ..., fieldN = exprN}
*
* if baseRecordExpr is null, this is just
* {field1 = expr1, field2 = expr2, ..., fieldN = exprN}
*
* if extensionField is empty and baseRecordExpr is null, this is the empty record {}.
*
* @param baseRecordExpr Expr may be null to indicate a record with a non-polymorphic
* @param extensionFields May not be null, nor can any of its elements be null.
*/
private Record (Expr baseRecordExpr, FieldModification[] extensionFields) {
if (extensionFields == null || extensionFields.length == 0) {
this.fieldModifications = NO_FIELD_MODIFICATIONS;
} else {
this.fieldModifications = extensionFields.clone();
verifyArrayArg(this.fieldModifications, "extensionFields");
}
this.baseRecordExpr = baseRecordExpr;
}
/**
* If extensionFields is [(field1, expr1), ..., (fieldN, exprN)] then this models the record extension
* {baseRecordExpr | field1 = expr1, field2 = expr2, ..., fieldN = exprN}
*
* if baseRecordExpr is null, this is just
* {field1 = expr1, field2 = expr2, ..., fieldN = exprN}
*
* if extensionField is empty and baseRecordExpr is null, this is the empty record {}.
*
* @param baseRecordExpr Expr may be null to indicate a record with a non-polymorphic
* @param extensionFields May not be null, nor can any of its elements be null.
* @return an instance of Record
*/
public static Record make(Expr baseRecordExpr, FieldModification[] extensionFields) {
return new Record(baseRecordExpr, extensionFields);
}
int precedenceLevel() {
return 100;
}
Associativity associativity() {
return Associativity.NON;
}
boolean neverNeedsParentheses() {
return true;
}
public Expr getBaseRecordExpr() {
return baseRecordExpr;
}
public FieldModification[] getExtensionFields() {
if (fieldModifications.length == 0) {
return NO_FIELD_MODIFICATIONS;
}
return fieldModifications.clone();
}
/**
* Get the number of extension fields.
* @return the number of extension fields.
*/
public int getNExtensionFields() {
return fieldModifications.length;
}
/**
* Get the nth extension field.
* @param n the index of the extension field to return.
* @return the nth extension field.
*/
public FieldModification getNthExtensionField(int n) {
return fieldModifications[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode recordExprNode = new ParseTreeNode(CALTreeParserTokenTypes.RECORD_CONSTRUCTOR, "Record");
ParseTreeNode baseRecordNode = new ParseTreeNode(CALTreeParserTokenTypes.BASE_RECORD, "BASE_RECORD");
ParseTreeNode fieldModificationListNode = new ParseTreeNode(CALTreeParserTokenTypes.FIELD_MODIFICATION_LIST, "FIELD_MODIFICATION_LIST");
if (baseRecordExpr != null) {
ParseTreeNode baseRecordExprNode = baseRecordExpr.toParseTreeNode();
baseRecordNode.setFirstChild(baseRecordExprNode);
}
ParseTreeNode[] fieldValueAssignmentNodes = new ParseTreeNode[fieldModifications.length];
for (int i = 0; i < fieldModifications.length; i++) {
fieldValueAssignmentNodes[i] = fieldModifications[i].toParseTreeNode();
}
fieldModificationListNode.addChildren(fieldValueAssignmentNodes);
recordExprNode.setFirstChild(baseRecordNode);
baseRecordNode.setNextSibling(fieldModificationListNode);
return recordExprNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_Record(this, arg);
}
}
/**
* Models field selection from a record or record expression (the . operator) e.g. "r.name", "r.#2"
* @author Bo Ilic
*/
public static final class SelectRecordField extends Expr {
private final Expr recordValuedExpr;
private final Name.Field fieldName;
/**
* Constructs the model for "recordValuedExpr.fieldName".
* @param recordValuedExpr Expr
* @param fieldName FieldName
*/
private SelectRecordField(Expr recordValuedExpr, Name.Field fieldName) {
if (recordValuedExpr == null || fieldName == null) {
throw new IllegalArgumentException();
}
this.recordValuedExpr = recordValuedExpr;
this.fieldName = fieldName;
}
/**
* Constructs the model for "recordValuedExpr.fieldName".
* @param recordValuedExpr Expr
* @param fieldName FieldName
* @return an instance of SelectRecordField
*/
public static SelectRecordField make(Expr recordValuedExpr, Name.Field fieldName) {
return new SelectRecordField(recordValuedExpr, fieldName);
}
int precedenceLevel() {
return 90;
}
Associativity associativity() {
return Associativity.LEFT;
}
boolean neverNeedsParentheses() {
return true;
}
public Expr getRecordValuedExpr() {
return recordValuedExpr;
}
public Name.Field getFieldName() {
return fieldName;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode selectFieldNode = new ParseTreeNode(CALTreeParserTokenTypes.SELECT_RECORD_FIELD, "SELECT_RECORD_FIELD");
ParseTreeNode exprNode = recordValuedExpr.toParseTreeNode();
ParseTreeNode fieldNameNode = fieldName.toParseTreeNode();
selectFieldNode.setFirstChild(exprNode);
exprNode.setNextSibling(fieldNameNode);
return selectFieldNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_SelectRecordField(this, arg);
}
}
/**
* Models field selection from an expression which evaluates to a data constructor (the . operator) e.g. "(expr).Cons.head".
* @author Edward Lam
*/
public static final class SelectDataConsField extends Expr {
private final Expr dataConsValuedExpr;
private final Name.DataCons dataConsName;
private final Name.Field fieldName;
/**
* Constructs the model for "dataConsValuedExpr.dataConsName.fieldName".
* @param dataConsValuedExpr
* @param dataConsName
* @param fieldName
* @param sourceRange
*/
private SelectDataConsField(Expr dataConsValuedExpr, Name.DataCons dataConsName, Name.Field fieldName, SourceRange sourceRange) {
super(sourceRange);
if (dataConsValuedExpr == null || dataConsName == null || fieldName == null) {
throw new IllegalArgumentException();
}
this.dataConsValuedExpr = dataConsValuedExpr;
this.dataConsName = dataConsName;
this.fieldName = fieldName;
}
/**
* Constructs the model for "dataConsValuedExpr.dataConsName.fieldName".
* @param dataConsValuedExpr
* @param dataConsName
* @param fieldName
* @return an instance of SelectDataConsField
*/
public static SelectDataConsField make(Expr dataConsValuedExpr, Name.DataCons dataConsName, Name.Field fieldName) {
return new SelectDataConsField(dataConsValuedExpr, dataConsName, fieldName, null);
}
static SelectDataConsField makeAnnotated(Expr dataConsValuedExpr, Name.DataCons dataConsName, Name.Field fieldName, SourceRange sourceRange) {
return new SelectDataConsField(dataConsValuedExpr, dataConsName, fieldName, sourceRange);
}
int precedenceLevel() {
return 90;
}
Associativity associativity() {
return Associativity.LEFT;
}
boolean neverNeedsParentheses() {
return true;
}
public Expr getDataConsValuedExpr() {
return dataConsValuedExpr;
}
public Name.DataCons getDataConsName() {
return dataConsName;
}
public Name.Field getFieldName() {
return fieldName;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode selectFieldNode = new ParseTreeNode(CALTreeParserTokenTypes.SELECT_DATA_CONSTRUCTOR_FIELD, "SELECT_DATA_CONSTRUCTOR_FIELD");
ParseTreeNode exprNode = dataConsValuedExpr.toParseTreeNode();
ParseTreeNode dataConsNameNode = dataConsName.toParseTreeNode();
ParseTreeNode fieldNameNode = fieldName.toParseTreeNode();
selectFieldNode.setFirstChild(exprNode);
exprNode.setNextSibling(dataConsNameNode);
dataConsNameNode.setNextSibling(fieldNameNode);
return selectFieldNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_SelectDataConsField(this, arg);
}
}
/**
* Models expression type signatures such as "1 + 3 :: Prelude.Int", "[] :: [Char]".
* @author Bo Ilic
*/
public static final class ExprTypeSignature extends Expr {
private final Expr expr;
private final TypeSignature typeSignature;
private ExprTypeSignature (Expr expr, TypeSignature typeSignature) {
verifyArg(expr, "expr");
verifyArg(typeSignature, "typeSignature");
this.expr = expr;
this.typeSignature = typeSignature;
}
public static ExprTypeSignature make (Expr expr, TypeSignature typeSignature) {
return new ExprTypeSignature(expr, typeSignature);
}
int precedenceLevel() {
return 0;
}
Associativity associativity() {
return Associativity.NON;
}
boolean neverNeedsParentheses() {
return false;
}
public Expr getExpr() {
return expr;
}
public TypeSignature getTypeSignature() {
return typeSignature;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode selectFieldNode = new ParseTreeNode(CALTreeParserTokenTypes.EXPRESSION_TYPE_SIGNATURE, "::");
ParseTreeNode exprNode = expr.toParseTreeNode();
ParseTreeNode signatureNode = typeSignature.toParseTreeNode();
selectFieldNode.setFirstChild(exprNode);
exprNode.setNextSibling(signatureNode);
return selectFieldNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Expr_ExprTypeSignature(this, arg);
}
}
private Expr () {
}
private Expr(SourceRange sourceRange) {
super(sourceRange);
}
/**
* The higher the value, the greater the precedence level. For example, * would be higher than +.
* @return int precedence level. Has no absolute significance, only relative to the precedence
* level for other expressions.
*/
abstract int precedenceLevel();
abstract Associativity associativity();
abstract boolean neverNeedsParentheses();
/**
* Makes a literal-like value of type Prelude.Boolean.
* @param value
* @return Expr
*/
public static Expr makeBooleanValue(boolean value) {
QualifiedName name = value ? CAL_Prelude.DataConstructors.True : CAL_Prelude.DataConstructors.False;
return Expr.makeGemCall(name);
}
/**
* Makes a literal-like value of type Prelude.Int.
*
* For example, for the argument value 3, this produces the expression "3 :: Prelude.Int". Effectively, this is the
* way to make Int literal values in CAL since the raw value 3 is an overloaded value of type Num a => a.
*
* @param value int
* @return Expr value of type Prelude.Int
*/
public static Expr makeIntValue(int value) {
return new ExprTypeSignature(new Literal.Num(value), new TypeSignature(TypeExprDefn.TypeCons.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.TypeConstructors.Int.getUnqualifiedName())));
}
/**
* Makes a literal-like value of type Prelude.Short.
*
* For example, for the argument value 3, this produces the expression "3 :: Prelude.Short". Effectively, this is the
* way to make Int literal values in CAL since the raw value 3 is an overloaded value of type Num a => a.
*
* @param value short
* @return Expr value of type Prelude.Short
*/
public static Expr makeShortValue (short value) {
return new ExprTypeSignature(new Literal.Num(value), new TypeSignature(TypeExprDefn.TypeCons.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.TypeConstructors.Short.getUnqualifiedName())));
}
/**
* Makes a literal-like value of type Prelude.Byte.
*
* For example, for the argument value 3, this produces the expression "3 :: Prelude.Byte". Effectively, this is the
* way to make Int literal values in CAL since the raw value 3 is an overloaded value of type Num a => a.
*
* @param value byte
* @return Expr value of type Prelude.Byte
*/
public static Expr makeByteValue (byte value) {
return new ExprTypeSignature(new Literal.Num(value), new TypeSignature(TypeExprDefn.TypeCons.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.TypeConstructors.Byte.getUnqualifiedName())));
}
/**
* Makes a literal-like value of type Prelude.Long.
*
* For example, for the argument value 3, this produces the expression "3 :: Prelude.Long". Effectively, this is the
* way to make Long literal values in CAL since the raw value 3 is an overloaded value of type Num a => a.
*
* @param value long
* @return Expr value of type Prelude.Long
*/
public static Expr makeLongValue(long value) {
return new ExprTypeSignature(new Literal.Num(value), new TypeSignature(TypeExprDefn.TypeCons.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.TypeConstructors.Long.getUnqualifiedName())));
}
/**
* Makes a literal-like value of type Prelude.Integer (which is the arbitrary precision integer type in CAL).
*
* For example, for the argument value 3, this produces the expression "3 :: Prelude.Integer". Effectively, this is the
* way to make Integer literal values in CAL since the raw value 3 is an overloaded value of type Num a => a.
*
* @param value BigInteger
* @return Expr value of type Prelude.Integer
*/
public static Expr makeIntegerValue(BigInteger value) {
return new ExprTypeSignature(new Literal.Num(value, null), new TypeSignature(TypeExprDefn.TypeCons.make(CAL_Prelude.MODULE_NAME, CAL_Prelude.TypeConstructors.Integer.getUnqualifiedName())));
}
/**
* A convenience method for creating a Double literal value instead of calling the Expr.Literal.Double constructor.
*
* @param value double
* @return Expr value of type Prelude.Double
*/
public static Expr makeDoubleValue(double value) {
return new Literal.Double(value, null);
}
/**
* A convenience method for creating a Float literal value instead of calling the Expr.Literal.Float constructor.
*
* @param value float
* @return Expr value of type Prelude.Float
*/
public static Expr makeFloatValue(float value) {
return new Literal.Float(value, null);
}
/**
* A convenience method for creating a String literal value instead of calling the Expr.Literal.StringLit constructor.
*
* @param value String
* @return Expr value of type Prelude.String
*/
public static Expr makeStringValue(String value) {
return new Literal.StringLit(value, null);
}
/**
* A convenience method for creating a Char literal value instead of calling the Expr.Literal.Char constructor.
*
* @param value char
* @return Expr value of type Prelude.Char
*/
public static Expr makeCharValue(char value) {
return new Literal.Char(value, null);
}
/**
* A helper used to create a call to Prelude.error with an error message
*
* @param msg the error message
* @return Expr a call to Prelude.error with the supplied error message
*/
public static Expr makeErrorCall(String msg) {
return makeGemCall(CAL_Prelude.Functions.error, new Literal.StringLit(msg, null));
}
/**
* A helper used to create a reference to a gem in an expression, where no arguments are supplied e.g.
* Prelude.Nothing
* Prelude.pi
*
* In this context, "gem" means a function, class method or data constructor.
*
* @param gemName a non-null lexically valid gem name.
* @return Expr reference to the gem as an Expr.
*/
public static Expr makeGemCall(QualifiedName gemName) {
if (gemName.lowercaseFirstChar()) {
return Expr.Var.make(gemName);
} else {
return Expr.DataCons.make(gemName);
}
}
/**
* Used to create an application of a gem to a single argument such as
* Prelude.sin 2.0
* or
* Prelude.Just "abc"
*
* In this context, "gem" means a function, class method or data constructor.
*
* @param gemName a non-null lexically valid gem name.
* @param arg1 non-null argument to be applied.
* @return the application of the gem to the argument arg1.
*/
public static Expr makeGemCall(QualifiedName gemName, Expr arg1) {
return makeGemCall(gemName, new Expr[] {arg1});
}
/**
* Used to create an application of a gem to a single argument such as
* Prelude.add 2.0 3.0
* or
* Prelude.Tuple2 "abc" 'a'
*
* In this context, "gem" means a function, class method or data constructor.
*
* @param gemName a non-null lexically valid gem name.
* @param arg1 non-null argument to be applied.
* @param arg2 non-null argument to be applied.
* @return the application of the gem to the argument arg1.
*/
public static Expr makeGemCall(QualifiedName gemName, Expr arg1, Expr arg2) {
return makeGemCall(gemName, new Expr[] {arg1, arg2});
}
public static Expr makeGemCall(QualifiedName gemName, Expr arg1, Expr arg2, Expr arg3) {
return makeGemCall(gemName, new Expr[] {arg1, arg2, arg3});
}
public static Expr makeGemCall(QualifiedName gemName, Expr arg1, Expr arg2, Expr arg3, Expr arg4) {
return makeGemCall(gemName, new Expr[] {arg1, arg2, arg3, arg4});
}
public static Expr makeGemCall(QualifiedName gemName, Expr[] args) {
if (args == null) {
return makeGemCall(gemName);
}
int nArgs = args.length;
if (nArgs == 0) {
return makeGemCall(gemName);
}
Expr[] exprs = new Expr[nArgs + 1];
exprs[0] = makeGemCall(gemName);
System.arraycopy(args, 0, exprs, 1, nArgs);
return new Application(exprs);
}
}
/**
* Models a type expression with a context (possible empty) such as
* Num a => a -> a -> a
* r\field1 => {r : field1 :: Int} -> Int
*
* the context part is the part of the type signature to the left of the "=>" in the CAL source.
* type typeExprDefn part is the part of the type signature to the right of the "=>".
*
* @author Bo Ilic
*/
public static final class TypeSignature extends SourceElement {
private final Constraint[] constraints;
private final TypeExprDefn typeExprDefn;
/** this field is used to indicate if the constraints should be contained within parens*/
private final boolean parenthesizedConstraints;
public static final Constraint[] NO_CONSTRAINTS = new Constraint[0];
private TypeSignature(Constraint[] constraints, TypeExprDefn typeExprDefn, boolean parenthesizedConstraints) {
if (constraints == null || constraints.length == 0) {
this.constraints = NO_CONSTRAINTS;
} else {
this.constraints = constraints.clone();
verifyArrayArg(this.constraints, "constraints");
}
this.parenthesizedConstraints = parenthesizedConstraints;
verifyArg(typeExprDefn, "typeExprDefn");
this.typeExprDefn = typeExprDefn;
}
/**
* Constructs a type expression definition with no context part (i.e. no type class or lacks constraints).
* @param typeExprDefn TypeExprDefn
*/
private TypeSignature(TypeExprDefn typeExprDefn, boolean parenthesizedConstraints) {
this (NO_CONSTRAINTS, typeExprDefn, parenthesizedConstraints);
}
/**
* Constructs a type expression definition with no context part (i.e. no type class or lacks constraints).
* @param typeExprDefn TypeExprDefn
*/
private TypeSignature(TypeExprDefn typeExprDefn) {
this (NO_CONSTRAINTS, typeExprDefn, false);
}
public static TypeSignature make(Constraint[] constraints, TypeExprDefn typeExprDefn) {
return new TypeSignature(constraints, typeExprDefn, false);
}
static TypeSignature make(Constraint[] constraints, TypeExprDefn typeExprDefn, boolean parens) {
return new TypeSignature(constraints, typeExprDefn, parens);
}
/**
* Constructs a type expression definition with no context part (i.e. no type class or lacks constraints).
* @param typeExprDefn TypeExprDefn
* @return an instance of TypeSignature
*/
public static TypeSignature make(TypeExprDefn typeExprDefn) {
return new TypeSignature(typeExprDefn, false);
}
public Constraint[] getConstraints() {
if (constraints.length == 0) {
return NO_CONSTRAINTS;
}
return constraints.clone();
}
/**this is true if the constraints are parenthesized*/
public boolean getConstraintsHaveParen() {
return parenthesizedConstraints;
}
/**
* Get the number of constraints.
* @return the number of constraints.
*/
public int getNConstraints() {
return constraints.length;
}
/**
* Get the nth constraint.
* @param n the index of the constraint to return.
* @return the nth constraint.
*/
public Constraint getNthConstraint(int n) {
return constraints[n];
}
public TypeExprDefn getTypeExprDefn() {
return typeExprDefn;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode typeSignatureNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_SIGNATURE, "TYPE_SIGNATURE");
final ParseTreeNode contextListNode;
if (parenthesizedConstraints || constraints.length > 1) {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_CONTEXT_LIST, "TYPE_CONTEXT_LIST");
} else if (constraints.length == 1) {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_CONTEXT_SINGLETON, "TYPE_CONTEXT_SINGLETON");
} else {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_CONTEXT_NOTHING, "TYPE_CONTEXT_NOTHING");
}
ParseTreeNode typeExprNode = typeExprDefn.toParseTreeNode();
ParseTreeNode[] contextNodes = new ParseTreeNode[constraints.length];
for (int i = 0; i < constraints.length; i++) {
contextNodes[i] = constraints[i].toParseTreeNode();
}
contextListNode.addChildren(contextNodes);
typeSignatureNode.setFirstChild(contextListNode);
contextListNode.setNextSibling(typeExprNode);
return typeSignatureNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeSignature(this, arg);
}
}
/**
* Models the part of a type definition to the right of the context symbol (=>). For example:
* Int -> Char
* (a -> b) -> a -> b
* [(Int, String)]
* {#1 :: [a], #2 :: Boolean} -> Maybe Char
*
* @author Bo Ilic
*/
public static abstract class TypeExprDefn extends SourceElement {
/**
* Models a parenthesized type expression
*
* @author Magnus Byne
*/
public static final class Parenthesized extends TypeExprDefn {
private final TypeExprDefn expr;
private Parenthesized(TypeExprDefn typeExpr) {
this(typeExpr, null);
}
private Parenthesized(TypeExprDefn typeExpr, SourceRange range) {
super(range);
expr=typeExpr;
}
/**
* Get the type definition that has been parenthesized
*/
public TypeExprDefn getTypeExprDefn() {
return expr;
}
public static Parenthesized make(TypeExprDefn typeExpr) {
return new Parenthesized(typeExpr);
}
static Parenthesized makeAnnotated(TypeExprDefn typeExpr, SourceRange sourceRange) {
return new Parenthesized(typeExpr, sourceRange);
}
/**
* {@inheritDoc}
*/
boolean neverNeedsParentheses() {
return true;
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode parenthesized = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_TYPE_CONSTRUCTOR, "Tuple");
parenthesized.addChildren(new ParseTreeNode[] {expr.toParseTreeNode()});
return parenthesized;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_Parenthesized(this, arg);
}
}
/**
* Models types made out of "->", which is the Prelude.Function type constructor in operator form.
* In particular, Prelude.Function must be fully saturated.
*
* @author Bo Ilic
*/
public static final class Function extends TypeExprDefn {
private final TypeExprDefn domain;
private final TypeExprDefn codomain;
private final SourceRange operatorSourceRange;
private Function (TypeExprDefn domain, TypeExprDefn codomain, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(sourceRange);
verifyArg(domain, "domain");
verifyArg(codomain, "codomain");
this.domain = domain;
this.codomain = codomain;
this.operatorSourceRange = operatorSourceRange;
}
public static Function make(TypeExprDefn domain, TypeExprDefn codomain) {
return new Function(domain, codomain, null, null);
}
static Function makeAnnotated(TypeExprDefn domain, TypeExprDefn codomain, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Function(domain, codomain, sourceRange, operatorSourceRange);
}
// todo-jowong maybe the operator can be encapsulated by its own source element
SourceRange getOperatorSourceRange() {
return operatorSourceRange;
}
boolean neverNeedsParentheses() {
return false;
}
public TypeExprDefn getDomain() {
return domain;
}
public TypeExprDefn getCodomain() {
return codomain;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode functionTypeDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.FUNCTION_TYPE_CONSTRUCTOR, "->");
ParseTreeNode domainNode = domain.toParseTreeNode();
ParseTreeNode codomainNode = codomain.toParseTreeNode();
functionTypeDefnNode.setFirstChild(domainNode);
domainNode.setNextSibling(codomainNode);
return functionTypeDefnNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_Function(this, arg);
}
}
/**
* Models the notational form of the Prelude.Unit type constructor i.e. ().
* Note this is different from the Prelude.Unit data constructor, which is also
* indicated by () in CAL source, but is used differently in the CAL grammar.
*
* @author Bo Ilic
*/
public static final class Unit extends TypeExprDefn {
private static final Unit UNIT = new Unit(null);
private Unit(SourceRange sourceRange) {
super(sourceRange);
}
public static Unit make() {
return UNIT;
}
static Unit makeAnnotated(SourceRange sourceRange) {
return new Unit(sourceRange);
}
boolean neverNeedsParentheses() {
return true;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode parseTree = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_TYPE_CONSTRUCTOR, "Tuple");
return parseTree;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_Unit(this, arg);
}
}
public static final class Tuple extends TypeExprDefn {
private final TypeExprDefn[] components;
private Tuple(TypeExprDefn[] components, SourceRange sourceRange) {
super(sourceRange);
if (components == null || components.length < 2) {
throw new IllegalArgumentException("tuple types must have 2 or more components.");
}
this.components = components.clone();
verifyArrayArg(this.components, "components");
}
public static Tuple make(TypeExprDefn[] components) {
return new Tuple(components, null);
}
static Tuple makeAnnotated(TypeExprDefn[] components, SourceRange sourceRange) {
return new Tuple(components, sourceRange);
}
boolean neverNeedsParentheses() {
return true;
}
public TypeExprDefn[] getComponents() {
return components.clone();
}
/**
* Get the number of components.
* @return the number of components.
*/
public int getNComponents() {
return components.length;
}
/**
* Get the nth component.
* @param n the index of the component to return.
* @return the nth component.
*/
public TypeExprDefn getNthComponent(int n) {
return components[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode tupleTypeDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.TUPLE_TYPE_CONSTRUCTOR, "Tuple");
ParseTreeNode[] componentNodes = new ParseTreeNode[components.length];
for (int i = 0; i < components.length; i++) {
componentNodes[i] = components[i].toParseTreeNode();
}
tupleTypeDefnNode.addChildren(componentNodes);
return tupleTypeDefnNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_Tuple(this, arg);
}
}
/**
* Models types made out of "[]", which is the Prelude.List type constructor in notational form.
* In particular, Prelude.List must be fully saturated i.e. applied to a type argument.
*
* @author Bo Ilic
*/
public static final class List extends TypeExprDefn {
private final TypeExprDefn element;
private List(TypeExprDefn element, SourceRange sourceRange) {
super(sourceRange);
verifyArg(element, "element");
this.element = element;
}
public static List make(TypeExprDefn element) {
return new List(element, null);
}
static List makeAnnotated(TypeExprDefn element, SourceRange sourceRange) {
return new List(element, sourceRange);
}
boolean neverNeedsParentheses() {
return true;
}
public TypeExprDefn getElement() {
return element;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode listTypeNode = new ParseTreeNode(CALTreeParserTokenTypes.LIST_TYPE_CONSTRUCTOR, CAL_Prelude.TypeConstructors.List.getUnqualifiedName());
listTypeNode.setFirstChild(element.toParseTreeNode());
return listTypeNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_List(this, arg);
}
}
public static final class Record extends TypeExprDefn {
private final TypeVar baseRecordVar;
private final FieldTypePair[] extensionFields;
public static final FieldTypePair[] NO_EXTENSION_FIELDS = new FieldTypePair[0];
public static final class FieldTypePair extends SourceElement {
private final Name.Field fieldName;
private final TypeExprDefn fieldType;
private FieldTypePair (Name.Field fieldName, TypeExprDefn fieldType) {
verifyArg(fieldName, "fieldName");
verifyArg(fieldType, "fieldType");
this.fieldName = fieldName;
this.fieldType = fieldType;
}
public static FieldTypePair make(Name.Field fieldName, TypeExprDefn fieldType) {
return new FieldTypePair(fieldName, fieldType);
}
public Name.Field getFieldName() {
return fieldName;
}
public TypeExprDefn getFieldType() {
return fieldType;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode fieldTypeAssignmentNode = new ParseTreeNode(CALTreeParserTokenTypes.FIELD_TYPE_ASSIGNMENT, "FIELD_TYPE_ASSIGNMENT");
ParseTreeNode fieldNameNode = fieldName.toParseTreeNode();
ParseTreeNode typeNode = fieldType.toParseTreeNode();
fieldTypeAssignmentNode.setFirstChild(fieldNameNode);
fieldNameNode.setNextSibling(typeNode);
return fieldTypeAssignmentNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_Record_FieldTypePair(this, arg);
}
}
/**
* If extensionFields is [(field1, type1), ..., (fieldN, typeN)] then this models the record type
* {baseRecordVar | field1 :: type1, field2 :: type2, ..., fieldN :: typeN}
*
* if baseRecordVar is null, this is just
* {field1 :: type1, field2 :: type2, ..., fieldN :: typeN}
*
* if extensionFields is empty and baseRecordVar is null, this is the empty record type {}.
*
* @param baseRecordVar Expr may be null to indicate a record with a non-polymorphic
* @param extensionFields May not be null, nor can any of its elements be null.
* @param sourceRange May be null, indicates the source position of this source element
*/
private Record (TypeVar baseRecordVar, FieldTypePair[] extensionFields, SourceRange sourceRange) {
super(sourceRange);
if (extensionFields == null || extensionFields.length == 0) {
this.extensionFields = NO_EXTENSION_FIELDS;
} else {
this.extensionFields = extensionFields.clone();
verifyArrayArg(this.extensionFields, "extensionFields");
}
this.baseRecordVar = baseRecordVar;
}
/**
* If extensionFields is [(field1, type1), ..., (fieldN, typeN)] then this models the record type
* {baseRecordVar | field1 :: type1, field2 :: type2, ..., fieldN :: typeN}
*
* if baseRecordVar is null, this is just
* {field1 :: type1, field2 :: type2, ..., fieldN :: typeN}
*
* if extensionFields is empty and baseRecordVar is null, this is the empty record type {}.
*
* @param baseRecordVar Expr may be null to indicate a record with a non-polymorphic
* @param extensionFields May not be null, nor can any of its elements be null.
* @return an instance of Record
*/
public static Record make(TypeVar baseRecordVar, FieldTypePair[] extensionFields) {
return new Record(baseRecordVar, extensionFields, null);
}
static Record makeAnnotated(TypeVar baseRecordVar, FieldTypePair[] extensionFields, SourceRange sourceRange) {
return new Record(baseRecordVar, extensionFields, sourceRange);
}
boolean neverNeedsParentheses() {
return true;
}
public TypeExprDefn.TypeVar getBaseRecordVar() {
return baseRecordVar;
}
public FieldTypePair[] getExtensionFields() {
if (extensionFields.length == 0) {
return NO_EXTENSION_FIELDS;
}
return extensionFields.clone();
}
/**
* Get the number of extension fields.
* @return the number of extension fields.
*/
public int getNExtensionFields() {
return extensionFields.length;
}
/**
* Get the nth extension field.
* @param n the index of the extension field to return.
* @return the nth extension field.
*/
public FieldTypePair getNthExtensionField(int n) {
return extensionFields[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode recordTypeNode = new ParseTreeNode(CALTreeParserTokenTypes.RECORD_TYPE_CONSTRUCTOR, "Record");
ParseTreeNode recordVarNode = new ParseTreeNode(CALTreeParserTokenTypes.RECORD_VAR, "RECORD_VAR");
ParseTreeNode fieldTypeAssignmentListNode = new ParseTreeNode(CALTreeParserTokenTypes.FIELD_TYPE_ASSIGNMENT_LIST, "FIELD_TYPE_ASSIGNMENT_LIST");
if (baseRecordVar != null) {
ParseTreeNode recordVarNameNode = baseRecordVar.toParseTreeNode();
recordVarNode.setFirstChild(recordVarNameNode);
}
ParseTreeNode[] fieldTypeAssignmentNodes = new ParseTreeNode[extensionFields.length];
for (int i = 0; i < extensionFields.length; i++) {
fieldTypeAssignmentNodes[i] = extensionFields[i].toParseTreeNode();
}
fieldTypeAssignmentListNode.addChildren(fieldTypeAssignmentNodes);
recordTypeNode.setFirstChild(recordVarNode);
recordVarNode.setNextSibling(fieldTypeAssignmentListNode);
return recordTypeNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_Record(this, arg);
}
}
public static final class Application extends TypeExprDefn {
private final TypeExprDefn[] typeExpressions;
/**
* If expressions is [e1, e2, e3], this is the application e1 e2 e3 i.e. (((e1) e2) e3)
* @param typeExpressions the expressions defining the application. Must have length >=2, with each element non-null.
* @param sourceRange may be null. Represents the source position of this source element.
*/
private Application(TypeExprDefn[] typeExpressions, SourceRange sourceRange) {
super(sourceRange);
if (typeExpressions == null || typeExpressions.length < 2) {
throw new IllegalArgumentException("argument 'typeExpressions' must have length >= 2.");
}
this.typeExpressions = typeExpressions.clone();
verifyArrayArg(this.typeExpressions, "typeExpressions");
}
/**
* If expressions is [e1, e2, e3], this is the application e1 e2 e3 i.e. (((e1) e2) e3)
* @param typeExpressions the expressions defining the application. Must have length >=2, with each element non-null.
* @return an instance of Application
*/
public static Application make(TypeExprDefn[] typeExpressions) {
return new Application(typeExpressions, null);
}
static Application makeAnnotated(TypeExprDefn[] typeExpressions, SourceRange sourceRange) {
return new Application(typeExpressions, sourceRange);
}
boolean neverNeedsParentheses() {
//for example, 'Maybe Maybe Int is the same as (Maybe Maybe) Int
//so if we want Maybe (Maybe Int) then parentheses are needed.
return false;
}
public TypeExprDefn[] getTypeExpressions() {
return typeExpressions.clone();
}
/**
* Get the number of type expressions.
* @return the number of type expressions.
*/
public int getNTypeExpressions() {
return typeExpressions.length;
}
/**
* Get the nth type expression.
* @param n the index of the type expression to return.
* @return the nth type expression.
*/
public TypeExprDefn getNthTypeExpression(int n) {
return typeExpressions[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode applicationTypeNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_APPLICATION, "@");
ParseTreeNode[] exprNodes = new ParseTreeNode[typeExpressions.length];
for (int i = 0; i < exprNodes.length; i++) {
exprNodes[i] = typeExpressions[i].toParseTreeNode();
}
applicationTypeNode.addChildren(exprNodes);
return applicationTypeNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_Application(this, arg);
}
}
/**
* Reference to a non-operator form type constructor (such as Prelude.Just or Prelude.Left)
* within a type expression definition.
*
* @author Bo Ilic
*/
public static final class TypeCons extends TypeExprDefn {
private final Name.TypeCons typeConsName;
private TypeCons(Name.TypeCons typeConsName, SourceRange sourceRange) {
super(sourceRange);
verifyArg(typeConsName, "typeConsName");
this.typeConsName = typeConsName;
}
public static TypeCons make(Name.TypeCons typeConsName) {
return new TypeCons(typeConsName, null);
}
/**
* @param moduleName String may be null, in which case the type constructor name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeConsName String must be a non-null syntactically valid type constructor name.
* @return an instance of TypeCons
*/
public static TypeCons make(ModuleName moduleName, String typeConsName) {
return new TypeCons(Name.TypeCons.make(moduleName, typeConsName), null);
}
public static TypeCons make(QualifiedName typeConsName) {
return make(typeConsName.getModuleName(), typeConsName.getUnqualifiedName());
}
static TypeCons makeAnnotated(Name.TypeCons typeConsName, SourceRange sourceRange) {
return new TypeCons(typeConsName, sourceRange);
}
boolean neverNeedsParentheses() {
return true;
}
public Name.TypeCons getTypeConsName() {
return typeConsName;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode qualifiedTypeConsNameNode = typeConsName.toParseTreeNode();
return qualifiedTypeConsNameNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_TypeCons(this, arg);
}
}
public static final class TypeVar extends TypeExprDefn {
private final Name.TypeVar typeVarName;
/**
* @param typeVarName String must be a non-null syntactically valid type variable name.
* @param sourceRange
*/
private TypeVar(Name.TypeVar typeVarName, SourceRange sourceRange) {
super(sourceRange);
this.typeVarName = typeVarName;
}
/**
* @param typeVarName String must be a non-null syntactically valid type variable name.
* @return an instance of TypeVar
*/
public static TypeVar make(Name.TypeVar typeVarName) {
return new TypeVar(typeVarName, null);
}
static TypeVar makeAnnotated(Name.TypeVar typeVarName, SourceRange sourceRange) {
return new TypeVar(typeVarName, sourceRange);
}
boolean neverNeedsParentheses() {
return true;
}
public Name.TypeVar getTypeVarName() {
return typeVarName;
}
ParseTreeNode toParseTreeNode() {
return typeVarName.toParseTreeNode();
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeExprDefn_TypeVar(this, arg);
}
}
private TypeExprDefn(SourceRange sourceRange) {
super(sourceRange);
}
abstract boolean neverNeedsParentheses();
}
/**
* Models a CAL type class definition. For example, below is the definition of the Ord type class
* in the Prelude module.
*
* public class Eq a => Ord a where
* public lessThan :: a -> a -> Boolean;
* public lessThanEquals :: a -> a -> Boolean;
* public greaterThanEquals :: a -> a -> Boolean;
* public greaterThan :: a -> a -> Boolean;
* public compare :: a -> a -> Ordering;
* public max :: a -> a -> a;
* public min :: a -> a -> a;
* ;
*
* Currently, type classes define a condition on a single type variable ("a" above) and we think of
* a type as "belonging to the set of types defined by the class". However, in the future we may support
* multi-parameter type classes such as:
* class (Ord a, Outputable b) => MyMap a b where ...
* in which we then think of the MyMap type class as being a relationship satisfied by 2 types which take the place
* of the type variables "a" and "b".
*
* @author Bo Ilic
*/
public static final class TypeClassDefn extends TopLevelSourceElement {
/** The CALDoc comment associated with this type class definition, or null if there is none. */
private final CALDoc.Comment.TypeClass caldocComment;
/** this field is used to indicate if the constraints should be contained within parens*/
private final boolean parenthesizeConstraints;
private final String typeClassName;
/** For example, for "class Eq a => Ord a where..." this is the "a" following the Ord. */
private final Name.TypeVar typeVar;
/** The scope of the definition. */
private final Scope scope;
/** Whether the scope is explicitly specified in the source. */
private final boolean isScopeExplicitlySpecified;
/** For example, for "class Eq a => Ord a where..." this is "Eq a". A type class may have 0 or more parent class constraints. */
private final Constraint.TypeClass[] parentClassConstraints;
public static final Constraint.TypeClass[] NO_CONSTRAINTS = new Constraint.TypeClass[0];
private final ClassMethodDefn[] classMethodDefns;
public static final ClassMethodDefn[] NO_CLASS_METHOD_DEFNS = new ClassMethodDefn[0];
/** The source range for the entire type def statement. */
private final SourceRange sourceRangeOfDefn;
/**
* Models a class method definition in CAL source. For example, in the definition of the "Ord" type class above there are 7
* class methods, one of which is:
* "public greaterThan :: a -> a -> Boolean"
*
* @author Bo Ilic
*/
public static final class ClassMethodDefn extends SourceElement {
/** The CALDoc comment associated with this class method definition, or null if there is none. */
private final CALDoc.Comment.ClassMethod caldocComment;
private final String methodName;
/** The scope of the definition. */
private final Scope scope;
/** Whether the scope is explicitly specified in the source. */
private final boolean isScopeExplicitlySpecified;
private final TypeSignature typeSignature;
/** the default class method name, if there is one. If the method does not have a default, this is null. */
private final Name.Function defaultClassMethodName;
private final SourceRange sourceRangeOfClassDefn;
private ClassMethodDefn(
CALDoc.Comment.ClassMethod caldocComment,
String methodName,
Scope scope, boolean isScopeExplicitlySpecified,
TypeSignature typeSignature,
Name.Function defaultClassMethodName,
SourceRange sourceRange,
SourceRange sourceRangeOfClassDefn) {
super(sourceRange);
this.caldocComment = caldocComment;
this.sourceRangeOfClassDefn = sourceRangeOfClassDefn;
if (!LanguageInfo.isValidClassMethodName(methodName)) {
throw new IllegalArgumentException();
}
verifyScopeArg(scope, isScopeExplicitlySpecified, "scope");
verifyArg(typeSignature, "typeSignature");
this.methodName = methodName;
this.scope = scope;
this.isScopeExplicitlySpecified = isScopeExplicitlySpecified;
this.typeSignature = typeSignature;
this.defaultClassMethodName = defaultClassMethodName;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param methodName the name of the class method.
* @param scope the scope of the class method.
* @param typeSignature the type signature of the class method.
* @param defaultClassMethodName
* @return a new instance of this class.
*/
public static ClassMethodDefn make(String methodName, Scope scope, TypeSignature typeSignature, Name.Function defaultClassMethodName) {
return new ClassMethodDefn(null, methodName, scope, true, typeSignature, defaultClassMethodName, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param methodName the name of the class method.
* @param scope the scope of the class method.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param typeSignature the type signature of the class method.
* @param defaultClassMethodName
* @return a new instance of this class.
*/
public static ClassMethodDefn make(CALDoc.Comment.ClassMethod caldocComment, String methodName, Scope scope, boolean isScopeExplicitlySpecified, TypeSignature typeSignature, Name.Function defaultClassMethodName) {
return new ClassMethodDefn(caldocComment, methodName, scope, isScopeExplicitlySpecified, typeSignature, defaultClassMethodName, null, null);
}
static ClassMethodDefn makeAnnotated(String methodName, Scope scope, boolean isScopeExplicitlySpecified, TypeSignature typeSignature, Name.Function defaultClassMethodName, SourceRange sourceRange, SourceRange sourceRangeOfClassDefn) {
return new ClassMethodDefn(null, methodName, scope, isScopeExplicitlySpecified, typeSignature, defaultClassMethodName, sourceRange, sourceRangeOfClassDefn);
}
static ClassMethodDefn makeAnnotated(CALDoc.Comment.ClassMethod caldocComment, String methodName, Scope scope, boolean isScopeExplicitlySpecified, TypeSignature typeSignature, Name.Function defaultClassMethodName, SourceRange sourceRange, SourceRange sourceRangeOfClassDefn) {
return new ClassMethodDefn(caldocComment, methodName, scope, isScopeExplicitlySpecified, typeSignature, defaultClassMethodName, sourceRange, sourceRangeOfClassDefn);
}
// todo-jowong this should be refactored - the class method should not have knowledge about its enclosing type class definition!!
SourceRange getSourceRangeOfClassDefn(){
return sourceRangeOfClassDefn;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
/**
* @return the CALDoc comment associated with this class method definition, or null if there is none.
*/
public CALDoc.Comment.ClassMethod getCALDocComment() {
return caldocComment;
}
public String getMethodName() {
return methodName;
}
public Scope getScope() {
return scope;
}
/**
* @return whether the scope is explicitly specified in the source.
*/
public boolean isScopeExplicitlySpecified() {
return isScopeExplicitlySpecified;
}
public TypeSignature getTypeSignature() {
return typeSignature;
}
/**
* @return the default class method name, or null if there is no default.
*/
public Name.Function getDefaultClassMethodName() {
return defaultClassMethodName;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode classMethodNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_METHOD, "CLASS_METHOD");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(caldocComment);
ParseTreeNode accessModifierNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
ParseTreeNode classMethodNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, methodName);
ParseTreeNode typeSignatureNode = typeSignature.toParseTreeNode();
classMethodNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(accessModifierNode);
accessModifierNode.setNextSibling(classMethodNameNode);
classMethodNameNode.setNextSibling(typeSignatureNode);
if (defaultClassMethodName != null) {
typeSignatureNode.setNextSibling(defaultClassMethodName.toParseTreeNode());
}
return classMethodNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeClassDefn_ClassMethodDefn(this, arg);
}
}
private TypeClassDefn(CALDoc.Comment.TypeClass caldocComment, String typeClassName, Name.TypeVar typeVar, Scope scope, boolean isScopeExplicitlySpecified,
Constraint.TypeClass[] parentClassConstraints, ClassMethodDefn[] classMethodDefns,
SourceRange sourceRange,
SourceRange sourceRangeOfDefn,
boolean parenthesizeConstraints) {
super(sourceRange);
this.caldocComment = caldocComment;
this.sourceRangeOfDefn = sourceRangeOfDefn;
if (!LanguageInfo.isValidTypeClassName(typeClassName)) {
throw new IllegalArgumentException();
}
if (parentClassConstraints == null || parentClassConstraints.length == 0) {
this.parentClassConstraints = NO_CONSTRAINTS;
} else {
this.parentClassConstraints = parentClassConstraints.clone();
verifyArrayArg(this.parentClassConstraints, "parentClassConstraints");
}
if (classMethodDefns == null || classMethodDefns.length == 0) {
this.classMethodDefns = NO_CLASS_METHOD_DEFNS;
} else {
this.classMethodDefns = classMethodDefns.clone();
verifyArrayArg(this.classMethodDefns, "classMethodDefns");
}
verifyScopeArg(scope, isScopeExplicitlySpecified, "scope");
this.typeClassName = typeClassName;
this.scope = scope;
this.isScopeExplicitlySpecified = isScopeExplicitlySpecified;
this.typeVar = typeVar;
this.parenthesizeConstraints = parenthesizeConstraints;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param typeClassName the name of the type class.
* @param typeVar the type variable.
* @param scope the scope of the type class.
* @param parentClassConstraints the parent class constraints of the type class.
* @param classMethodDefns the class methods for the type class.
* @return a new instance of this class.
*/
public static TypeClassDefn make(String typeClassName, Name.TypeVar typeVar, Scope scope,
Constraint.TypeClass[] parentClassConstraints, ClassMethodDefn[] classMethodDefns) {
return new TypeClassDefn(null, typeClassName, typeVar, scope, true, parentClassConstraints, classMethodDefns, null, null, false);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param typeClassName the name of the type class.
* @param typeVar the type variable.
* @param scope the scope of the type class.
* @param isScopeExplicitlySpecified scope is explicitly specified in the source.
* @param parentClassConstraints the parent class constraints of the type class.
* @param classMethodDefns the class methods for the type class.
* @return a new instance of this class.
*/
public static TypeClassDefn make(CALDoc.Comment.TypeClass caldocComment, String typeClassName, Name.TypeVar typeVar, Scope scope, boolean isScopeExplicitlySpecified,
Constraint.TypeClass[] parentClassConstraints, ClassMethodDefn[] classMethodDefns) {
return new TypeClassDefn(caldocComment, typeClassName, typeVar, scope, isScopeExplicitlySpecified, parentClassConstraints, classMethodDefns, null, null, false);
}
static TypeClassDefn makeAnnotated(CALDoc.Comment.TypeClass caldocComment, String typeClassName, Name.TypeVar typeVar, Scope scope, boolean isScopeExplicitlySpecified,
Constraint.TypeClass[] parentClassConstraints, ClassMethodDefn[] classMethodDefns, SourceRange sourceRange, SourceRange sourceRangeOfStatement, boolean parenthesizeConstraints) {
return new TypeClassDefn(caldocComment, typeClassName, typeVar, scope, isScopeExplicitlySpecified, parentClassConstraints, classMethodDefns, sourceRange, sourceRangeOfStatement, parenthesizeConstraints);
}
/**
* @return the range of the entire type def statement.
*/
SourceRange getSourceRangeOfDefn(){
return sourceRangeOfDefn;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
/**
* @return the CALDoc comment associated with this type class definition, or null if there is none.
*/
public CALDoc.Comment.TypeClass getCALDocComment() {
return caldocComment;
}
public String getTypeClassName() {
return typeClassName;
}
public Name.TypeVar getTypeVar() {
return typeVar;
}
public Scope getScope() {
return scope;
}
/**
* @return whether the scope is explicitly specified in the source.
*/
public boolean isScopeExplicitlySpecified() {
return isScopeExplicitlySpecified;
}
public Constraint.TypeClass[] getParentClassConstraints() {
if (parentClassConstraints.length == 0) {
return NO_CONSTRAINTS;
}
return parentClassConstraints.clone();
}
/**
* Get the number of parent class constraints.
* @return the number of parent class constraints.
*/
public int getNParentClassConstraints() {
return parentClassConstraints.length;
}
/**
* @return True if the constraints are parenthesized
*/
public boolean getParenthesizeConstraints() {
return parenthesizeConstraints;
}
/**
* Get the nth parent class constraint.
* @param n the index of the parent class constraint to return.
* @return the nth parent class constraint.
*/
public Constraint.TypeClass getNthParentClassConstraint(int n) {
return parentClassConstraints[n];
}
public ClassMethodDefn[] getClassMethodDefns() {
if (classMethodDefns.length == 0) {
return NO_CLASS_METHOD_DEFNS;
}
return classMethodDefns.clone();
}
/**
* Get the number of class method definitions.
* @return the number of class method definitions.
*/
public int getNClassMethodDefns() {
return classMethodDefns.length;
}
/**
* Get the nth class method definition.
* @param n the index of the class method definition to return.
* @return the nth class method definition.
*/
public ClassMethodDefn getNthClassMethodDefn(int n) {
return classMethodDefns[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode typeClassDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_CLASS_DEFN, "class");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(caldocComment);
ParseTreeNode scopeNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
final ParseTreeNode contextListNode;
if (parenthesizeConstraints || parentClassConstraints.length > 1) {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT_LIST, "CLASS_CONTEXT_LIST");
} else if (parentClassConstraints.length == 1) {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT_SINGLETON, "CLASS_CONTEXT_SINGLETON");
} else {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT_NOTHING, "CLASS_CONTEXT_NOTHING");
}
ParseTreeNode typeClassNameNode = new ParseTreeNode(CALTreeParserTokenTypes.CONS_ID, typeClassName);
ParseTreeNode typeVarNode = typeVar.toParseTreeNode();
ParseTreeNode classMethodList = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_METHOD_LIST, "CLASS_METHOD_LIST");
ParseTreeNode[] contextNodes = new ParseTreeNode[parentClassConstraints.length];
for (int i = 0; i < parentClassConstraints.length; i++) {
contextNodes[i] = parentClassConstraints[i].toParseTreeNode();
}
contextListNode.addChildren(contextNodes);
ParseTreeNode[] classMethodNodes = new ParseTreeNode[classMethodDefns.length];
for (int i = 0; i < classMethodDefns.length; i++) {
classMethodNodes[i] = classMethodDefns[i].toParseTreeNode();
}
classMethodList.addChildren(classMethodNodes);
typeClassDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(scopeNode);
scopeNode.setNextSibling(contextListNode);
contextListNode.setNextSibling(typeClassNameNode);
typeClassNameNode.setNextSibling(typeVarNode);
typeVarNode.setNextSibling(classMethodList);
return typeClassDefnNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeClassDefn(this, arg);
}
}
/**
* Base class for all CAL constructs that define new type constructors.
* Currently this can be done through data declarations or through foreign data declarations.
*
* @author Bo Ilic
*/
public static abstract class TypeConstructorDefn extends TopLevelSourceElement {
/** The CALDoc comment associated with this type constructor definition, or null if there is none. */
private final CALDoc.Comment.TypeCons caldocComment;
/** name of the type constructor. Some examples from the core are "Maybe", "Map" and "JList". */
private final String typeConsName;
/** the scope of the type constructor */
private final Scope scope;
/** Whether the scope is explicitly specified in the source. */
private final boolean isScopeExplicitlySpecified;
/** The source range of the definition body */
private final SourceRange sourceRangeOfDefn;
/**
* a foreign or algebraic data type definition can have a "deriving" clause which specifies a list of
* type classes for which an instance is automatically generated by the compiler for the type.
*/
private final Name.TypeClass[] derivingClauseTypeClassNames;
public static final Name.TypeClass[] NO_DERIVING_CLAUSE = new Name.TypeClass[0];
/**
* Models a CAL foreign data declaration such as:
*
* data foreign unsafe import jvm public "java.util.List" public JList;
*
* In CAL source, the scope in front of the external name ("java.util.List") is the implementation scope while
* the scope in from of the CAL name (JList) is the scope of the type constructor (JList).
*
* @author Bo Ilic
*/
public static final class ForeignType extends TypeConstructorDefn {
/** external name for the type e.g. "java.util.List" */
private final String externalName;
/** The position in the source of the external name. This maybe be null. */
private final SourceRange externalNameSourceRange;
/**
* the scope of the fact that this type is in fact a foreign type e.g. if the implementation scope is private
* then other modules cannot declare a foreign function that has arguments of this CAL type.
*/
private final Scope implementationScope;
/** Whether the implementation scope is explicitly specified in the source. */
private final boolean isImplementationScopeExplicitlySpecified;
private ForeignType(CALDoc.Comment.TypeCons caldocComment, String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, SourceRange externalNameSourceRange, Scope implementationScope, boolean isImplementationScopeExplicitlySpecified, Name.TypeClass[] derivingClauseTypeClassNames, SourceRange sourceRange, SourceRange sourceRangeOfBody) {
super(caldocComment, typeConsName, scope, isScopeExplicitlySpecified, derivingClauseTypeClassNames, sourceRange, sourceRangeOfBody);
verifyArg(externalName, "externalName");
verifyScopeArg(implementationScope, isImplementationScopeExplicitlySpecified, "implementationScope");
this.externalName = externalName;
this.externalNameSourceRange = externalNameSourceRange;
this.implementationScope = implementationScope;
this.isImplementationScopeExplicitlySpecified = isImplementationScopeExplicitlySpecified;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param typeConsName the name of the type constructor.
* @param scope the scope of the type constructor.
* @param externalName the external name of the type constructor.
* @param implementationScope the scope of the fact that this type is in fact a foreign type.
* @param derivingClauseTypeClassNames the class names in the deriving clause.
* @return a new instance of this class.
*/
public static ForeignType make(String typeConsName, Scope scope, String externalName, Scope implementationScope, Name.TypeClass[] derivingClauseTypeClassNames) {
return new ForeignType(null, typeConsName, scope, true, externalName, null, implementationScope, true, derivingClauseTypeClassNames, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param typeConsName the name of the type constructor.
* @param scope the scope of the type constructor.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param externalName the external name of the type constructor.
* @param implementationScope the scope of the fact that this type is in fact a foreign type.
* @param derivingClauseTypeClassNames the class names in the deriving clause.
* @param isImplementationScopeExplicitlySpecified
* @return a new instance of this class.
*/
public static ForeignType make(CALDoc.Comment.TypeCons caldocComment, String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, Scope implementationScope, boolean isImplementationScopeExplicitlySpecified, Name.TypeClass[] derivingClauseTypeClassNames) {
return new ForeignType(caldocComment, typeConsName, scope, isScopeExplicitlySpecified, externalName, null, implementationScope, isImplementationScopeExplicitlySpecified, derivingClauseTypeClassNames, null, null);
}
static ForeignType makeAnnotated(String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, SourceRange externalNameSourceRange, Scope implementationScope, boolean isImplementationScopeExplicitlySpecified, Name.TypeClass[] derivingClauseTypeClassNames, SourceRange sourceRange, SourceRange sourceRangeOfBody) {
return new ForeignType(null, typeConsName, scope, isScopeExplicitlySpecified, externalName, externalNameSourceRange, implementationScope, isImplementationScopeExplicitlySpecified, derivingClauseTypeClassNames, sourceRange, sourceRangeOfBody);
}
static ForeignType makeAnnotated(CALDoc.Comment.TypeCons caldocComment, String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, String externalName, SourceRange externalNameSourceRange, Scope implementationScope, boolean isImplementationScopeExplicitlySpecified, Name.TypeClass[] derivingClauseTypeClassNames, SourceRange sourceRange, SourceRange sourceRangeOfBody) {
return new ForeignType(caldocComment, typeConsName, scope, isScopeExplicitlySpecified, externalName, externalNameSourceRange, implementationScope, isImplementationScopeExplicitlySpecified, derivingClauseTypeClassNames, sourceRange, sourceRangeOfBody);
}
public String getExternalName() {
return externalName;
}
// todo-jowong maybe the name can be encapsulated by its own source element
public SourceRange getExternalNameSourceRange() {
return externalNameSourceRange;
}
public Scope getImplementationScope() {
return implementationScope;
}
/**
* @return whether the implementation scope is explicitly specified in the source.
*/
public boolean isImplementationScopeExplicitlySpecified() {
return isImplementationScopeExplicitlySpecified;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode foreignTypeDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.FOREIGN_DATA_DECLARATION, "foreignData");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(getCALDocComment());
ParseTreeNode implementationScopeNode = SourceModel.makeAccessModifierNode(implementationScope, isImplementationScopeExplicitlySpecified);
ParseTreeNode externalNameNode = new ParseTreeNode(CALTreeParserTokenTypes.STRING_LITERAL, StringEncoder.encodeString(externalName));
ParseTreeNode accessModifierNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
ParseTreeNode typeNameNode = new ParseTreeNode(CALTreeParserTokenTypes.CONS_ID, getTypeConsName());
foreignTypeDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(implementationScopeNode);
implementationScopeNode.setNextSibling(externalNameNode);
externalNameNode.setNextSibling(accessModifierNode);
accessModifierNode.setNextSibling(typeNameNode);
typeNameNode.setNextSibling(derivingClauseToParseTreeNode());
return foreignTypeDefnNode;
}
/**
* Generates the required "externalName" string necessary in order to refer to this class as a foreign data type in CAL
* @param classObject The class that is desired to be used as a foreign type
* @return The CAL string that should be passed into the externalName argument of the ForeignType constructor
*/
public static String makeExternalName(Class<?> classObject) {
return classObject.getName();
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeConstructorDefn_ForeignType(this, arg);
}
}
/**
* Models a CAL algebraic type definition i.e. a "regular" data declaration such as:
*
* data public Maybe a = public Nothing | public Just a;
*
* data public Map k a =
* private Tip |
* private Bin
* size :: !Int
* key :: !k
* value :: a
* leftMap :: !(Map k a)
* rightMap :: !(Map k a);
*
* @author Bo Ilic
*/
public static final class AlgebraicType extends TypeConstructorDefn {
/** for example, for "data public Either a b = ..." this would be ["a", "b"]. */
private final Name.TypeVar[] typeParameters;
public static final Name.TypeVar[] NO_TYPE_PARAMETERS = new Name.TypeVar[0];
private final DataConsDefn[] dataConstructors;
/**
* Models the part of an algebraic type definition where the data constructor is being defined.
*
* For example, the "public Nothing" and "public Just a" parts of
* data public Maybe a = public Nothing | public Just a;
*
* For example, the "private Tip" and "private Bin !Int !k a !(Map k a) !(Map k a)"
* parts of the type definition of the Map type:
* data public Map k a =
* private Tip |
* private Bin
* size :: !Int
* key :: !k
* value :: a
* leftMap :: !(Map k a)
* rightMap :: !(Map k a);
*
* @author Bo Ilic
*/
public static final class DataConsDefn extends SourceElement {
/** The CALDoc comment associated with this data constructor definition, or null if there is none. */
private final CALDoc.Comment.DataCons caldocComment;
private final String dataConsName;
/** The scope of the definition. */
private final Scope scope;
/** Whether the scope is explicitly specified in the source. */
private final boolean isScopeExplicitlySpecified;
private final TypeArgument[] typeArgs;
public static final TypeArgument[] NO_TYPE_ARGS = new TypeArgument[0];
private final SourceRange sourceRangeOfDefn;
/**
* Models the arguments of a data constructor, including whether they are annotated as strict.
*
* For example, Tip has 0 type arguments.
* Bin has 5 type arguments: "size :: !Int", "key :: !k", "value :: a", "leftMap :: !(Map k a)", "rightMap :: !(Map k a)"
* of which all but "a" are strict.
*
* data public Map k a =
* private Tip |
* private Bin
* size :: !Int
* key :: !k
* value :: a
* leftMap :: !(Map k a)
* rightMap :: !(Map k a);
*
* @author Bo Ilic
*/
public static final class TypeArgument extends SourceElement {
private final Name.Field fieldName;
private final TypeExprDefn typeExprDefn;
private final boolean isStrict;
private TypeArgument(Name.Field fieldName, TypeExprDefn typeExprDefn, boolean isStrict, SourceRange range) {
super(range);
verifyArg(typeExprDefn, "typeExprDefn");
verifyArg(fieldName, "fieldName");
this.fieldName = fieldName;
this.typeExprDefn = typeExprDefn;
this.isStrict = isStrict;
}
public static TypeArgument make(Name.Field fieldName, TypeExprDefn typeExprDefn, boolean isStrict) {
return new TypeArgument(fieldName, typeExprDefn, isStrict, null);
}
static TypeArgument makeAnnotated(Name.Field fieldName, TypeExprDefn typeExprDefn, boolean isStrict, SourceRange range) {
return new TypeArgument(fieldName, typeExprDefn, isStrict, range);
}
public Name.Field getFieldName() {
return fieldName;
}
public TypeExprDefn getTypeExprDefn() {
return typeExprDefn;
}
public boolean isStrict() {
return isStrict;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode typeExprNode = typeExprDefn.toParseTreeNode();
ParseTreeNode maybePlingTypeExprNode;
if (isStrict) {
maybePlingTypeExprNode = new ParseTreeNode(CALTreeParserTokenTypes.STRICT_ARG, "!");
maybePlingTypeExprNode.setFirstChild(typeExprNode);
} else {
maybePlingTypeExprNode = typeExprNode;
}
ParseTreeNode typeArgumentNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_NAMED_ARG, "::");
ParseTreeNode dcArgNameNode = fieldName.toParseTreeNode();
typeArgumentNode.setFirstChild(dcArgNameNode);
dcArgNameNode.setNextSibling(maybePlingTypeExprNode);
return typeArgumentNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeConstructorDefn_AlgebraicType_DataConsDefn_TypeArgument(this, arg);
}
}
private DataConsDefn(CALDoc.Comment.DataCons caldocComment, String dataConsName, Scope scope, boolean isScopeExplicitlySpecified, TypeArgument[] typeArgs, SourceRange sourceRange, SourceRange sourceRangeOfDefn) {
super(sourceRange);
this.caldocComment = caldocComment;
this.sourceRangeOfDefn = sourceRangeOfDefn;
if (!LanguageInfo.isValidDataConstructorName(dataConsName)) {
throw new IllegalArgumentException();
}
if (typeArgs == null || typeArgs.length == 0) {
this.typeArgs = NO_TYPE_ARGS;
} else {
this.typeArgs = typeArgs.clone();
verifyArrayArg(this.typeArgs, "typeArgs");
}
verifyScopeArg(scope, isScopeExplicitlySpecified, "scope");
this.dataConsName = dataConsName;
this.scope = scope;
this.isScopeExplicitlySpecified = isScopeExplicitlySpecified;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param dataConsName the name of the data constructor.
* @param scope the scope of the data constructor.
* @param typeArgs the type arguments of the data constructor.
* @return a new instance of this class.
*/
public static DataConsDefn make(String dataConsName, Scope scope, TypeArgument[] typeArgs) {
return new DataConsDefn(null, dataConsName, scope, true, typeArgs, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param dataConsName the name of the data constructor.
* @param scope the scope of the data constructor.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param typeArgs the type arguments of the data constructor.
* @return a new instance of this class.
*/
public static DataConsDefn make(CALDoc.Comment.DataCons caldocComment, String dataConsName, Scope scope, boolean isScopeExplicitlySpecified, TypeArgument[] typeArgs) {
return new DataConsDefn(caldocComment, dataConsName, scope, isScopeExplicitlySpecified, typeArgs, null, null);
}
static DataConsDefn makeAnnotated(String dataConsName, Scope scope, boolean isScopeExplicitlySpecified, TypeArgument[] typeArgs, SourceRange sourceRange, SourceRange sourceRangeOfDefn) {
return new DataConsDefn(null, dataConsName, scope, isScopeExplicitlySpecified, typeArgs, sourceRange, sourceRangeOfDefn);
}
static DataConsDefn makeAnnotated(CALDoc.Comment.DataCons caldocComment, String dataConsName, Scope scope, boolean isScopeExplicitlySpecified, TypeArgument[] typeArgs, SourceRange sourceRange, SourceRange sourceRangeOfDefn) {
return new DataConsDefn(caldocComment, dataConsName, scope, isScopeExplicitlySpecified, typeArgs, sourceRange, sourceRangeOfDefn);
}
/**
* @return get the source range of the definition.
*/
SourceRange getSourceRangeOfDefn(){
return sourceRangeOfDefn;
}
/**
* @return the CALDoc comment associated with this data constructor definition, or null if there is none.
*/
public CALDoc.Comment.DataCons getCALDocComment() {
return caldocComment;
}
public String getDataConsName() {
return dataConsName;
}
public Scope getScope() {
return scope;
}
/**
* @return whether the scope is explicitly specified in the source.
*/
public boolean isScopeExplicitlySpecified() {
return isScopeExplicitlySpecified;
}
public TypeArgument[] getTypeArgs() {
if (typeArgs.length == 0) {
return NO_TYPE_ARGS;
}
return typeArgs.clone();
}
/**
* Get the number of type arguments.
* @return the number of type arguments.
*/
public int getNTypeArgs() {
return typeArgs.length;
}
/**
* Get the nth type argument.
* @param n the index of the type argument to return.
* @return the nth type argument.
*/
public TypeArgument getNthTypeArg(int n) {
return typeArgs[n];
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode dataConsDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_DEFN, "DATA_CONSTRUCTOR_DEFN");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(caldocComment);
ParseTreeNode scopeNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
ParseTreeNode dataConsNameNode = new ParseTreeNode(CALTreeParserTokenTypes.CONS_ID, dataConsName);
ParseTreeNode dataConsArgListNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_ARG_LIST, "DATA_CONSTRUCTOR_ARG_LIST");
ParseTreeNode[] dataConsArgNodes = new ParseTreeNode[typeArgs.length];
for (int i = 0; i < typeArgs.length; i++) {
dataConsArgNodes[i] = typeArgs[i].toParseTreeNode();
}
dataConsArgListNode.addChildren(dataConsArgNodes);
dataConsDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(scopeNode);
scopeNode.setNextSibling(dataConsNameNode);
dataConsNameNode.setNextSibling(dataConsArgListNode);
return dataConsDefnNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeConstructorDefn_AlgebraicType_DataConsDefn(this, arg);
}
}
private AlgebraicType(CALDoc.Comment.TypeCons caldocComment, String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, Name.TypeVar[] typeParameters, DataConsDefn[] dataConstructors, Name.TypeClass[] derivingClauseTypeClassNames, SourceRange sourceRange, SourceRange sourceRangeOfBody) {
super(caldocComment, typeConsName, scope, isScopeExplicitlySpecified, derivingClauseTypeClassNames, sourceRange, sourceRangeOfBody);
if (typeParameters == null || typeParameters.length == 0) {
this.typeParameters = NO_TYPE_PARAMETERS;
} else {
this.typeParameters = typeParameters.clone();
verifyArrayArg(this.typeParameters, "typeParameters");
}
if (dataConstructors == null || dataConstructors.length < 1) {
throw new IllegalArgumentException("An algebraic type definition must define at least 1 data constructor.");
}
this.dataConstructors = dataConstructors.clone();
verifyArrayArg(dataConstructors, "dataConstructors");
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param typeConsName the name of the type constructor.
* @param scope the scope of the type constructor.
* @param typeParameters the type parameters of the type constructor.
* @param dataConstructors the data constructor definitions.
* @param derivingClauseTypeClassNames the class names in the deriving clause.
* @return a new isntance of this class.
*/
public static AlgebraicType make(String typeConsName, Scope scope, Name.TypeVar[] typeParameters, DataConsDefn[] dataConstructors, Name.TypeClass[] derivingClauseTypeClassNames) {
return new AlgebraicType(null, typeConsName, scope, true, typeParameters, dataConstructors, derivingClauseTypeClassNames, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param typeConsName the name of the type constructor.
* @param scope the scope of the type constructor.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param typeParameters the type parameters of the type constructor.
* @param dataConstructors the data constructor definitions.
* @param derivingClauseTypeClassNames the class names in the deriving clause.
* @return a new instance of this class.
*/
public static AlgebraicType make(CALDoc.Comment.TypeCons caldocComment, String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, Name.TypeVar[] typeParameters, DataConsDefn[] dataConstructors, Name.TypeClass[] derivingClauseTypeClassNames) {
return new AlgebraicType(caldocComment, typeConsName, scope, isScopeExplicitlySpecified, typeParameters, dataConstructors, derivingClauseTypeClassNames, null, null);
}
static AlgebraicType makeAnnotated(String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, Name.TypeVar[] typeParameters, DataConsDefn[] dataConstructors, Name.TypeClass[] derivingClauseTypeClassNames, SourceRange sourceRange, SourceRange sourceRangeOfBody) {
return new AlgebraicType(null, typeConsName, scope, isScopeExplicitlySpecified, typeParameters, dataConstructors, derivingClauseTypeClassNames, sourceRange, sourceRangeOfBody);
}
static AlgebraicType makeAnnotated(CALDoc.Comment.TypeCons caldocComment, String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, Name.TypeVar[] typeParameters, DataConsDefn[] dataConstructors, Name.TypeClass[] derivingClauseTypeClassNames, SourceRange sourceRange, SourceRange sourceRangeOfBody) {
return new AlgebraicType(caldocComment, typeConsName, scope, isScopeExplicitlySpecified, typeParameters, dataConstructors, derivingClauseTypeClassNames, sourceRange, sourceRangeOfBody);
}
public Name.TypeVar[] getTypeParameters() {
if (typeParameters.length == 0) {
return NO_TYPE_PARAMETERS;
}
return typeParameters.clone();
}
/**
* Get the number of type parameters.
* @return the number of type parameters.
*/
public int getNTypeParameters() {
return typeParameters.length;
}
/**
* Get the nth type parameter.
* @param n the index of the type parameter to return.
* @return the nth type parameter.
*/
public Name.TypeVar getNthTypeParameter(int n) {
return typeParameters[n];
}
public DataConsDefn[] getDataConstructors() {
return dataConstructors.clone();
}
/**
* Get the number of data constructors.
* @return the number of data constructors.
*/
public int getNDataConstructors() {
return dataConstructors.length;
}
/**
* Get the nth data constructor.
* @param n the index of the data constructor to return.
* @return the nth data constructor.
*/
public DataConsDefn getNthDataConstructor(int n) {
return dataConstructors[n];
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode algebraicTypeDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_DECLARATION, "data");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(getCALDocComment());
ParseTreeNode accessModifierNode = SourceModel.makeAccessModifierNode(getScope(), isScopeExplicitlySpecified());
ParseTreeNode typeNameNode = new ParseTreeNode(CALTreeParserTokenTypes.CONS_ID, getTypeConsName());
ParseTreeNode typeParamListNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_CONS_PARAM_LIST, "TYPE_CONS_PARAM_LIST");
ParseTreeNode dataConsDefnListNode = new ParseTreeNode(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_DEFN_LIST, "DATA_CONSTRUCTOR_DEFN_LIST");
ParseTreeNode[] typeVarNodes = new ParseTreeNode[typeParameters.length];
for (int i = 0; i < typeParameters.length; i++) {
typeVarNodes[i] = typeParameters[i].toParseTreeNode();
}
typeParamListNode.addChildren(typeVarNodes);
ParseTreeNode[] dataConsDefnNodes = new ParseTreeNode[dataConstructors.length];
for (int i = 0; i < dataConstructors.length; i++) {
dataConsDefnNodes[i] = dataConstructors[i].toParseTreeNode();
}
dataConsDefnListNode.addChildren(dataConsDefnNodes);
algebraicTypeDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(accessModifierNode);
accessModifierNode.setNextSibling(typeNameNode);
typeNameNode.setNextSibling(typeParamListNode);
typeParamListNode.setNextSibling(dataConsDefnListNode);
dataConsDefnListNode.setNextSibling(derivingClauseToParseTreeNode());
return algebraicTypeDefnNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_TypeConstructorDefn_AlgebraicType(this, arg);
}
}
private TypeConstructorDefn(CALDoc.Comment.TypeCons caldocComment, String typeConsName, Scope scope, boolean isScopeExplicitlySpecified, Name.TypeClass[] derivingClauseTypeClassNames, SourceRange sourceRange, SourceRange sourceRangeOfDefn) {
super(sourceRange);
this.caldocComment = caldocComment;
this.sourceRangeOfDefn = sourceRangeOfDefn;
if (!LanguageInfo.isValidTypeConstructorName(typeConsName)) {
throw new IllegalArgumentException();
}
verifyScopeArg(scope, isScopeExplicitlySpecified, "scope");
if (derivingClauseTypeClassNames == null || derivingClauseTypeClassNames.length == 0) {
this.derivingClauseTypeClassNames = NO_DERIVING_CLAUSE;
} else {
this.derivingClauseTypeClassNames = derivingClauseTypeClassNames.clone();
verifyArrayArg(this.derivingClauseTypeClassNames, "derivingClauseTypeClassNames");
}
this.typeConsName = typeConsName;
this.scope = scope;
this.isScopeExplicitlySpecified = isScopeExplicitlySpecified;
}
/**
* @return An optional SourceRange specifying the range occupied by the body
* element in the original source text. May return null.
*/
final SourceRange getSourceRangeOfDefn() {
return sourceRangeOfDefn;
}
/**
* @return the CALDoc comment associated with this type constructor definition, or null if there is none.
*/
public CALDoc.Comment.TypeCons getCALDocComment() {
return caldocComment;
}
public String getTypeConsName() {
return typeConsName;
}
// todo-jowong maybe the name can be encapsulated by its own source element
abstract SourceRange getSourceRangeOfName();
public Scope getScope() {
return scope;
}
/**
* @return whether the scope is explicitly specified in the source.
*/
public boolean isScopeExplicitlySpecified() {
return isScopeExplicitlySpecified;
}
public int getNDerivingClauseTypeClassNames() {
return derivingClauseTypeClassNames.length;
}
public Name.TypeClass getDerivingClauseTypeClassName(int n) {
return derivingClauseTypeClassNames[n];
}
public Name.TypeClass[] getDerivingClauseTypeClassNames() {
if (derivingClauseTypeClassNames.length == 0) {
return NO_DERIVING_CLAUSE;
}
return derivingClauseTypeClassNames.clone();
}
ParseTreeNode derivingClauseToParseTreeNode() {
int nDerivingClauseTypeClassNames = getNDerivingClauseTypeClassNames();
if (nDerivingClauseTypeClassNames == 0) {
return null;
}
ParseTreeNode derivingClauseNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_deriving, "deriving");
ParseTreeNode[] derivingClauseTypeClassNames = new ParseTreeNode[nDerivingClauseTypeClassNames];
for (int i = 0; i < nDerivingClauseTypeClassNames; ++i) {
derivingClauseTypeClassNames[i] = getDerivingClauseTypeClassName(i).toParseTreeNode();
}
derivingClauseNode.addChildren(derivingClauseTypeClassNames);
return derivingClauseNode;
}
}
/**
* Models a class instance definition in CAL.
* This includes constrained instances.
*
* An example of a instance declaration:
* instance Eq Integer where
* equals = equalsInteger;
* notEquals = notEqualsInteger;
* ;
* This can be read as saying "the type Integer is a member of the set of types Eq"
*
* An example of a constrained instance declaration:
* instance Eq a => Eq (Maybe a) where
* equals = equalsMaybe;
* notEquals = notEqualsMaybe;
* ;
* This can be read as saying "the type 'Maybe a' is a member of the set of types Eq provided that
* 'a' is a member of the set of types Eq".
*
* @author Bo Ilic
*/
public static final class InstanceDefn extends TopLevelSourceElement {
/** The CALDoc comment associated with this instance definition, or null if there is none. */
private final CALDoc.Comment.Instance caldocComment;
private final Name.TypeClass typeClassName;
private final InstanceTypeCons instanceTypeCons;
/** used for defining constrained instances such as "instance Eq a => Eq [a] where ..." or "instance (Ord a, Ord b) => Ord (a, b) where ..." */
private final Constraint.TypeClass[] constraints;
/** used to indicate if the constraints should be parenthesized*/
private final boolean parenthesizeConstraints;
public static final Constraint.TypeClass[] NO_CONSTRAINTS = new Constraint.TypeClass[0];
private final InstanceMethod[] instanceMethods;
public static final InstanceMethod[] NO_INSTANCE_METHODS = new InstanceMethod[0];
/**
* An instance declaration must name a type constructor that it is being applied to, along with
* its type variables. These type variables then may be constrained by the constraints. In the
* instance "instance Eq Integer where ..." the instance type cons is "Integer". In the instance
* "instance Eq a => Eq (Maybe a) where ..." the instance type cons is "Maybe a".
*
* @author Bo Ilic
*/
public static abstract class InstanceTypeCons extends SourceElement {
public static final class TypeCons extends InstanceTypeCons {
private final Name.TypeCons typeConsName;
private final Name.TypeVar[] typeVars;
public static final Name.TypeVar[] NO_TYPE_VARS = new Name.TypeVar[0];
private final SourceRange sourceRangeOfDefn;
/** This is true if the typecons is explicitly parenthesized*/
private final boolean parenthesised;
private TypeCons(Name.TypeCons typeConsName, Name.TypeVar[] typeVars, SourceRange sourceRange, SourceRange sourceRangeOfDefn, boolean parenthesized) {
super(sourceRange);
this.sourceRangeOfDefn = sourceRangeOfDefn;
verifyArg(typeConsName, "typeConsName");
this.typeConsName = typeConsName;
this.parenthesised = parenthesized;
if (typeVars == null || typeVars.length == 0) {
this.typeVars = NO_TYPE_VARS;
} else {
this.typeVars = typeVars.clone();
verifyArrayArg(this.typeVars, "typeVars");
}
}
public static TypeCons make(Name.TypeCons typeConsName, Name.TypeVar[] typeVars) {
return new TypeCons(typeConsName, typeVars, null, null, false);
}
static TypeCons makeAnnotated(Name.TypeCons typeConsName, Name.TypeVar[] typeVars, SourceRange sourceRange, SourceRange sourceRangeOfDefn, boolean parenthesized) {
return new TypeCons(typeConsName, typeVars, sourceRange, sourceRangeOfDefn, parenthesized);
}
/** @return true if the type constructor is explicitly parenthesized*/
boolean getParenthesized() {
return parenthesised;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode instanceTypeConsNode;
if (!parenthesised && typeVars.length == 0) {
instanceTypeConsNode = new ParseTreeNode(CALTreeParserTokenTypes.UNPARENTHESIZED_TYPE_CONSTRUCTOR, "UNPARENTHESIZED_TYPE_CONSTRUCTOR");
} else {
instanceTypeConsNode = new ParseTreeNode(CALTreeParserTokenTypes.GENERAL_TYPE_CONSTRUCTOR, "GENERAL_TYPE_CONSTRUCTOR");
}
ParseTreeNode typeConsNameNode = typeConsName.toParseTreeNode();
ParseTreeNode[] typeVarNodes = new ParseTreeNode[typeVars.length];
for (int i = 0; i < typeVars.length; i++) {
typeVarNodes[i] = typeVars[i].toParseTreeNode();
}
instanceTypeConsNode.setFirstChild(typeConsNameNode);
instanceTypeConsNode.addChildren(typeVarNodes);
return instanceTypeConsNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_InstanceDefn_InstanceTypeCons_TypeCons(this, arg);
}
/**
* @return the type constructor name
*/
public Name.TypeCons getTypeConsName() {
return typeConsName;
}
SourceRange getSourceRangeOfDefn(){
return sourceRangeOfDefn;
}
/**
* @return the type variables
*/
public Name.TypeVar[] getTypeVars() {
if (typeVars.length == 0) {
return NO_TYPE_VARS;
}
return typeVars.clone();
}
}
public static final class Function extends InstanceTypeCons {
private final Name.TypeVar domainTypeVar;
private final Name.TypeVar codomainTypeVar;
private final SourceRange operatorSourceRange;
private Function(Name.TypeVar domainTypeVar, Name.TypeVar codomainTypeVar, SourceRange sourceRange, SourceRange operatorSourceRange) {
super(sourceRange);
this.domainTypeVar = domainTypeVar;
this.codomainTypeVar = codomainTypeVar;
this.operatorSourceRange = operatorSourceRange;
}
public static Function make(Name.TypeVar domainTypeVar, Name.TypeVar codomainTypeVar) {
return new Function(domainTypeVar, codomainTypeVar, null, null);
}
static Function makeAnnotated(Name.TypeVar domainTypeVar, Name.TypeVar codomainTypeVar, SourceRange sourceRange, SourceRange operatorSourceRange) {
return new Function(domainTypeVar, codomainTypeVar, sourceRange, operatorSourceRange);
}
// todo-jowong maybe the operator can be encapsulated by its own source element
SourceRange getOperatorSourceRange() {
return operatorSourceRange;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode instanceTypeConsNode = new ParseTreeNode(CALTreeParserTokenTypes.FUNCTION_TYPE_CONSTRUCTOR, "->");
ParseTreeNode domainTypeVarNode = domainTypeVar.toParseTreeNode();
ParseTreeNode codomainTypeVarNode = codomainTypeVar.toParseTreeNode();
instanceTypeConsNode.setFirstChild(domainTypeVarNode);
domainTypeVarNode.setNextSibling(codomainTypeVarNode);
return instanceTypeConsNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_InstanceDefn_InstanceTypeCons_Function(this, arg);
}
/**
* @return the domain type variable
*/
public Name.TypeVar getDomainTypeVar() {
return domainTypeVar;
}
/**
* @return the codomain type variable
*/
public Name.TypeVar getCodomainTypeVar() {
return codomainTypeVar;
}
}
public static final class Unit extends InstanceTypeCons {
private static final Unit UNIT = new Unit(null);
private Unit (SourceRange sourceRange) {
super(sourceRange);
}
public static Unit make() {
return UNIT;
}
static Unit makeAnnotated(SourceRange sourceRange) {
return new Unit(sourceRange);
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode instanceTypeConsNode = new ParseTreeNode(CALTreeParserTokenTypes.UNIT_TYPE_CONSTRUCTOR, "Unit");
return instanceTypeConsNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_InstanceDefn_InstanceTypeCons_Unit(this, arg);
}
}
public static final class List extends InstanceTypeCons {
private final Name.TypeVar elemTypeVar;
private List(Name.TypeVar elemTypeVar, SourceRange sourceRange) {
super(sourceRange);
this.elemTypeVar = elemTypeVar;
}
public static List make(Name.TypeVar elemTypeVar) {
return new List(elemTypeVar, null);
}
static List makeAnnotated(Name.TypeVar elemTypeVar, SourceRange sourceRange) {
return new List(elemTypeVar, sourceRange);
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode instanceTypeConsNode = new ParseTreeNode(CALTreeParserTokenTypes.LIST_TYPE_CONSTRUCTOR, CAL_Prelude.TypeConstructors.List.getUnqualifiedName());
ParseTreeNode elemTypeVarNode = elemTypeVar.toParseTreeNode();
instanceTypeConsNode.setFirstChild(elemTypeVarNode);
return instanceTypeConsNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_InstanceDefn_InstanceTypeCons_List(this, arg);
}
/**
* @return the element's type variable
*/
public Name.TypeVar getElemTypeVar() {
return elemTypeVar;
}
}
public static final class Record extends InstanceTypeCons {
private final Name.TypeVar elemTypeVar;
private final SourceRange sourceRangeOfDefn;
private Record(Name.TypeVar elemTypeVar, SourceRange sourceRange, SourceRange sourceRangeOfDefn) {
super(sourceRange);
this.sourceRangeOfDefn = sourceRangeOfDefn;
this.elemTypeVar = elemTypeVar;
}
public static Record make(Name.TypeVar elemTypeVar) {
return new Record(elemTypeVar, null, null);
}
static Record makeAnnotated(Name.TypeVar elemTypeVar, SourceRange sourceRange, SourceRange sourceRangeOfDefn) {
return new Record(elemTypeVar, sourceRange, sourceRangeOfDefn);
}
SourceRange getSourceRangeOfDefn(){
return sourceRangeOfDefn;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode instanceTypeConsNode = new ParseTreeNode(CALTreeParserTokenTypes.RECORD_TYPE_CONSTRUCTOR, "Record");
ParseTreeNode elemTypeVarNode = elemTypeVar.toParseTreeNode();
instanceTypeConsNode.setFirstChild(elemTypeVarNode);
return instanceTypeConsNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_InstanceDefn_InstanceTypeCons_Record(this, arg);
}
/**
* @return the element's type variable
*/
public Name.TypeVar getElemTypeVar() {
return elemTypeVar;
}
}
private InstanceTypeCons(SourceRange sourceRange) {
super(sourceRange);
}
}
/**
* Associates a class method to a particular resolving function for the type that the
* instance is an instance for.
*
* For example, in the Eq Int instance in the Prelude, one of the instance methods is
* "equals = equalsInt;"
*
* @author Bo Ilic
*/
public static final class InstanceMethod extends SourceElement {
/** The CALDoc comment associated with this instance method definition, or null if there is none. */
private final CALDoc.Comment.InstanceMethod caldocComment;
/**
* name of the instance method. This belongs to the same module as the module of the
* instance type constructor of the enclosing instance definition.
*/
private final String classMethodName;
private final SourceRange classMethodNameSourceRange;
private final Name.Function resolvingFunctionName;
private InstanceMethod(CALDoc.Comment.InstanceMethod caldocComment, String classMethodName, Name.Function resolvingFunctionName, SourceRange sourceRange, SourceRange classMethodNameSourceRange) {
super(sourceRange);
this.caldocComment = caldocComment;
if (!LanguageInfo.isValidClassMethodName(classMethodName)) {
throw new IllegalArgumentException();
}
verifyArg(resolvingFunctionName, "resolvingFunctionName");
this.classMethodName = classMethodName;
this.classMethodNameSourceRange = classMethodNameSourceRange;
this.resolvingFunctionName = resolvingFunctionName;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param classMethodName the name of the class method.
* @param resolvingFunctionName the name of the resolving function.
* @return a new instance of this class.
*/
public static InstanceMethod make(String classMethodName, Name.Function resolvingFunctionName) {
return new InstanceMethod(null, classMethodName, resolvingFunctionName, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param classMethodName the name of the class method.
* @param resolvingFunctionName the name of the resolving function.
* @return a new instance of this class.
*/
public static InstanceMethod make(CALDoc.Comment.InstanceMethod caldocComment, String classMethodName, Name.Function resolvingFunctionName) {
return new InstanceMethod(caldocComment, classMethodName, resolvingFunctionName, null, null);
}
static InstanceMethod makeAnnotated(String classMethodName, Name.Function resolvingFunctionName, SourceRange sourceRange, SourceRange classMethodNameSourceRange) {
return new InstanceMethod(null, classMethodName, resolvingFunctionName, sourceRange, classMethodNameSourceRange);
}
static InstanceMethod makeAnnotated(CALDoc.Comment.InstanceMethod caldocComment, String classMethodName, Name.Function resolvingFunctionName, SourceRange sourceRange, SourceRange classMethodNameSourceRange) {
return new InstanceMethod(caldocComment, classMethodName, resolvingFunctionName, sourceRange, classMethodNameSourceRange);
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode instanceMethodNode = new ParseTreeNode(CALTreeParserTokenTypes.INSTANCE_METHOD, "INSTANCE_METHOD");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(caldocComment);
ParseTreeNode instanceMethodNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, classMethodName);
ParseTreeNode instanceMethodDefnNode = resolvingFunctionName.toParseTreeNode();
instanceMethodNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(instanceMethodNameNode);
instanceMethodNameNode.setNextSibling(instanceMethodDefnNode);
return instanceMethodNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_InstanceDefn_InstanceMethod(this, arg);
}
/**
* @return the CALDoc comment associated with this instance method definition, or null if there is none.
*/
public CALDoc.Comment.InstanceMethod getCALDocComment() {
return caldocComment;
}
/**
* @return the resolving function name
*/
public Name.Function getResolvingFunctionName() {
return resolvingFunctionName;
}
/**
* @return the class method name
*/
public String getClassMethodName() {
return classMethodName;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfResolvingFunctionName();
}
SourceRange getSourceRangeOfResolvingFunctionName() {
return super.getSourceRange();
}
/**
* @return SourceRange of the class method name (may be null)
*/
// todo-jowong maybe the name can be encapsulated by its own source element
SourceRange getClassMethodNameSourceRange() {
return classMethodNameSourceRange;
}
}
private InstanceDefn(CALDoc.Comment.Instance caldocComment, Name.TypeClass typeClassName, InstanceTypeCons instanceTypeCons,
Constraint.TypeClass[] constraints, InstanceMethod[] instanceMethods, SourceRange sourceRange, boolean parenthesizeConstraints) {
super(sourceRange);
this.caldocComment = caldocComment;
verifyArg(typeClassName, "typeClassName");
verifyArg(instanceTypeCons, "instanceTypeCons");
if (constraints == null || constraints.length == 0) {
this.constraints = NO_CONSTRAINTS;
} else {
this.constraints = constraints.clone();
verifyArrayArg(this.constraints, "constraints");
}
if (instanceMethods == null || instanceMethods.length == 0) {
this.instanceMethods = NO_INSTANCE_METHODS;
} else {
this.instanceMethods = instanceMethods.clone();
verifyArrayArg(this.instanceMethods, "instanceMethods");
}
this.typeClassName = typeClassName;
this.instanceTypeCons = instanceTypeCons;
this.parenthesizeConstraints = parenthesizeConstraints;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param typeClassName the name of the type class.
* @param instanceTypeCons the instance type.
* @param constraints the constraints on the instance.
* @param instanceMethods the instance methods associated with the instance.
* @return a new instance of this class.
*/
public static InstanceDefn make(Name.TypeClass typeClassName, InstanceTypeCons instanceTypeCons,
Constraint.TypeClass[] constraints, InstanceMethod[] instanceMethods) {
return new InstanceDefn(null, typeClassName, instanceTypeCons, constraints, instanceMethods, null, false);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param typeClassName the name of the type class.
* @param instanceTypeCons the instance type.
* @param constraints the constraints on the instance.
* @param instanceMethods the instance methods associated with the instance.
* @return a new instance of this class.
*/
public static InstanceDefn make(CALDoc.Comment.Instance caldocComment, Name.TypeClass typeClassName, InstanceTypeCons instanceTypeCons,
Constraint.TypeClass[] constraints, InstanceMethod[] instanceMethods) {
return new InstanceDefn(caldocComment, typeClassName, instanceTypeCons, constraints, instanceMethods, null, false);
}
static InstanceDefn makeAnnotated(Name.TypeClass typeClassName, InstanceTypeCons instanceTypeCons,
Constraint.TypeClass[] constraints, InstanceMethod[] instanceMethods, SourceRange sourceRange) {
return new InstanceDefn(null, typeClassName, instanceTypeCons, constraints, instanceMethods, sourceRange, false);
}
static InstanceDefn makeAnnotated(CALDoc.Comment.Instance caldocComment, Name.TypeClass typeClassName, InstanceTypeCons instanceTypeCons,
Constraint.TypeClass[] constraints, InstanceMethod[] instanceMethods, SourceRange sourceRange) {
return new InstanceDefn(caldocComment, typeClassName, instanceTypeCons, constraints, instanceMethods, sourceRange, false);
}
static InstanceDefn makeAnnotated(CALDoc.Comment.Instance caldocComment, Name.TypeClass typeClassName, InstanceTypeCons instanceTypeCons,
Constraint.TypeClass[] constraints, InstanceMethod[] instanceMethods, SourceRange sourceRange, boolean parenthesizeConstraints) {
return new InstanceDefn(caldocComment, typeClassName, instanceTypeCons, constraints, instanceMethods, sourceRange, parenthesizeConstraints);
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode instanceDefnNode = new ParseTreeNode(CALTreeParserTokenTypes.INSTANCE_DEFN, "instance");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(caldocComment);
ParseTreeNode instanceNameNode = new ParseTreeNode(CALTreeParserTokenTypes.INSTANCE_NAME, "INSTANCE_NAME");
ParseTreeNode instanceMethodListNode = new ParseTreeNode(CALTreeParserTokenTypes.INSTANCE_METHOD_LIST, "INSTANCE_METHOD_LIST");
//ParseTreeNode contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT_LIST, "CLASS_CONTEXT_LIST");
final ParseTreeNode contextListNode;
if (parenthesizeConstraints || constraints.length > 1) {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT_LIST, "CLASS_CONTEXT_LIST");
} else if (constraints.length == 1) {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT_SINGLETON, "CLASS_CONTEXT_SINGLETON");
} else {
contextListNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT_NOTHING, "CLASS_CONTEXT_NOTHING");
}
ParseTreeNode typeClassNameNode = typeClassName.toParseTreeNode();
ParseTreeNode instanceTypeConsNode = instanceTypeCons.toParseTreeNode();
ParseTreeNode[] contextNodes = new ParseTreeNode[constraints.length];
for (int i = 0; i < constraints.length; i++) {
contextNodes[i] = constraints[i].toParseTreeNode();
}
contextListNode.addChildren(contextNodes);
instanceNameNode.setFirstChild(contextListNode);
contextListNode.setNextSibling(typeClassNameNode);
typeClassNameNode.setNextSibling(instanceTypeConsNode);
ParseTreeNode[] instanceMethodNodes = new ParseTreeNode[instanceMethods.length];
for (int i = 0; i < instanceMethods.length; i++) {
instanceMethodNodes[i] = instanceMethods[i].toParseTreeNode();
}
instanceMethodListNode.addChildren(instanceMethodNodes);
instanceDefnNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(instanceNameNode);
instanceNameNode.setNextSibling(instanceMethodListNode);
return instanceDefnNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_InstanceDefn(this, arg);
}
// todo-jowong maybe the name can be encapsulated by its own source element
SourceRange getSourceRangeOfName(){
if (typeClassName.getSourceRange() == null || instanceTypeCons.getSourceRangeOfDefn() ==null) {
return null;
}
SourcePosition start = this.typeClassName.getSourceRange().getStartSourcePosition();
SourcePosition end = this.instanceTypeCons.getSourceRangeOfDefn().getEndSourcePosition();
return new SourceRange(start, end);
}
/**
* @return the constraints
*/
public Constraint.TypeClass[] getConstraints() {
if (constraints.length == 0) {
return NO_CONSTRAINTS;
}
return constraints.clone();
}
/**
* Get the number of constraints.
* @return the number of constraints.
*/
public int getNConstraints() {
return constraints.length;
}
/**
* @return True if the constraints are parenthesized
*/
public boolean getParenthesizeConstraints() {
return parenthesizeConstraints;
}
/**
* Get the nth constraint.
* @param n the index of the constraint to return.
* @return the nth constraint.
*/
public Constraint.TypeClass getNthConstraint(int n) {
return constraints[n];
}
/**
* @return the instance methods
*/
public InstanceMethod[] getInstanceMethods() {
if (instanceMethods.length == 0) {
return NO_INSTANCE_METHODS;
}
return instanceMethods.clone();
}
/**
* Get the number of instance methods.
* @return the number of instance methods.
*/
public int getNInstanceMethods() {
return instanceMethods.length;
}
/**
* Get the nth instance method.
* @param n the index of the instance method to return.
* @return the nth instance method.
*/
public InstanceMethod getNthInstanceMethod(int n) {
return instanceMethods[n];
}
/**
* @return the instance type constructor
*/
public InstanceTypeCons getInstanceTypeCons() {
return instanceTypeCons;
}
/**
* @return the CALDoc comment associated with this instance definition, or null if there is none.
*/
public CALDoc.Comment.Instance getCALDocComment() {
return caldocComment;
}
/**
* @return the type class name
*/
public Name.TypeClass getTypeClassName() {
return typeClassName;
}
}
/**
* Models a type declaration for a top-level (algebraic) function.
* @author Bo Ilic
*/
public static final class FunctionTypeDeclaration extends TopLevelSourceElement {
/** The CALDoc comment associated with this function type declaration, or null if there is none. */
private final CALDoc.Comment.Function caldocComment;
private final String functionName;
private final TypeSignature typeSignature;
private final SourceRange sourceRangeOfDefn;
private FunctionTypeDeclaration(CALDoc.Comment.Function caldocComment, String functionName, TypeSignature typeSignature, SourceRange sourceRange, SourceRange sourceRangeOfDefn) {
super(sourceRange);
this.caldocComment = caldocComment;
this.sourceRangeOfDefn = sourceRangeOfDefn;
verifyArg(functionName, "functionName");
verifyArg(typeSignature, "typeSignature");
this.functionName = functionName;
this.typeSignature = typeSignature;
}
/**
* Create an instance of this class without an associated CALDoc comment.
* @param functionName the name of the function.
* @param typeSignature the declared type signature of the function.
* @return a new instance of this class.
*/
public static FunctionTypeDeclaration make(String functionName, TypeSignature typeSignature) {
return new FunctionTypeDeclaration(null, functionName, typeSignature, null, null);
}
/**
* Create an instance of this class with an associated CALDoc comment.
* @param caldocComment the CALDoc comment.
* @param functionName the name of the function.
* @param typeSignature the declared type signature of the function.
* @return a new instance of this class.
*/
public static FunctionTypeDeclaration make(CALDoc.Comment.Function caldocComment, String functionName, TypeSignature typeSignature) {
return new FunctionTypeDeclaration(caldocComment, functionName, typeSignature, null, null);
}
static FunctionTypeDeclaration makeAnnotated(String functionName, TypeSignature typeSignature, SourceRange sourceRange, SourceRange sourceRangeOfDeclaration) {
return new FunctionTypeDeclaration(null, functionName, typeSignature, sourceRange, sourceRangeOfDeclaration);
}
static FunctionTypeDeclaration makeAnnotated(CALDoc.Comment.Function caldocComment, String functionName, TypeSignature typeSignature, SourceRange sourceRange, SourceRange sourceRangeOfDeclaration) {
return new FunctionTypeDeclaration(caldocComment, functionName, typeSignature, sourceRange, sourceRangeOfDeclaration);
}
/**
* @return the CALDoc comment associated with this function definition, or null if there is none.
*/
public CALDoc.Comment.Function getCALDocComment() {
return caldocComment;
}
public String getFunctionName() {
return functionName;
}
public TypeSignature getTypeSignature() {
return typeSignature;
}
SourceRange getSourceRangeOfDefn(){
return sourceRangeOfDefn;
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfName();
}
SourceRange getSourceRangeOfName() {
return super.getSourceRange();
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode topLevelTypeDeclarationNode = new ParseTreeNode(CALTreeParserTokenTypes.TOP_LEVEL_TYPE_DECLARATION, "TOP_LEVEL_TYPE_DECLARATION");
ParseTreeNode optionalCALDocNode = makeOptionalCALDocNode(caldocComment);
ParseTreeNode typeDeclarationNode = new ParseTreeNode(CALTreeParserTokenTypes.TYPE_DECLARATION, "::");
ParseTreeNode functionNameNode = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, functionName);
ParseTreeNode declaredTypeNode = typeSignature.toParseTreeNode();
topLevelTypeDeclarationNode.setFirstChild(optionalCALDocNode);
optionalCALDocNode.setNextSibling(typeDeclarationNode);
typeDeclarationNode.setFirstChild(functionNameNode);
functionNameNode.setNextSibling(declaredTypeNode);
return topLevelTypeDeclarationNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_FunctionTypeDeclaraction(this, arg);
}
}
/**
* Models a constraint on a type variable. Currently there are type class constraints such as "Eq a" and
* lacks constraints such as "r\orderDate".
*
* Constraints are used in the context part of a type declaration, and in type class and class instance definitions.
*
* @author Bo Ilic
*/
public static abstract class Constraint extends SourceElement {
private final Name.TypeVar typeVarName;
/**
* Models the constraint that a type variable belongs to a particular type class.
* For example,
* Prelude.Ord a
* Eq b
*
* @author Bo Ilic
*/
public static final class TypeClass extends Constraint {
private final Name.TypeClass typeClassName;
private TypeClass(Name.TypeClass typeClassName, Name.TypeVar typeVarName, SourceRange sourceRange) {
super(typeVarName, sourceRange);
verifyArg(typeClassName, "typeClassName");
this.typeClassName = typeClassName;
}
public static TypeClass make(Name.TypeClass typeClassName, Name.TypeVar typeVarName) {
return new TypeClass(typeClassName, typeVarName, null);
}
static TypeClass makeAnnotated(Name.TypeClass typeClassName, Name.TypeVar typeVarName, SourceRange sourceRange) {
return new TypeClass(typeClassName, typeVarName, sourceRange);
}
public Name.TypeClass getTypeClassName() {
return typeClassName;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode contextNode = new ParseTreeNode(CALTreeParserTokenTypes.CLASS_CONTEXT, "CLASS_CONTEXT");
ParseTreeNode typeClassNameNode = typeClassName.toParseTreeNode();
ParseTreeNode varNameNode = getTypeVarName().toParseTreeNode();
contextNode.setFirstChild(typeClassNameNode);
typeClassNameNode.setNextSibling(varNameNode);
return contextNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Constraint_TypeClass(this, arg);
}
}
/**
* Models the constraint that a record variable lacks a specific field e.g
* r\orderDate
* s\#4
*
* @author Bo Ilic
*/
public static final class Lacks extends Constraint {
private final Name.Field lacksField;
private Lacks(Name.TypeVar typeVarName, Name.Field lacksField, SourceRange sourceRange) {
super (typeVarName, sourceRange);
verifyArg(lacksField, "lacksField");
this.lacksField = lacksField;
}
public static Lacks make(Name.TypeVar typeVarName, Name.Field lacksField) {
return new Lacks(typeVarName, lacksField, null);
}
static Lacks makeAnnotated(Name.TypeVar typeVarName, Name.Field lacksField, SourceRange sourceRange) {
return new Lacks(typeVarName, lacksField, sourceRange);
}
public Name.Field getLacksField() {
return lacksField;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode contextNode = new ParseTreeNode(CALTreeParserTokenTypes.LACKS_FIELD_CONTEXT, "LACKS_FIELD_CONTEXT");
ParseTreeNode recordVarNameNode = getTypeVarName().toParseTreeNode();
ParseTreeNode lacksFieldNameNode = lacksField.toParseTreeNode();
contextNode.setFirstChild(recordVarNameNode);
recordVarNameNode.setNextSibling(lacksFieldNameNode);
return contextNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Constraint_Lacks(this, arg);
}
}
private Constraint(Name.TypeVar typeVarName, SourceRange sourceRange) {
super(sourceRange);
this.typeVarName = typeVarName;
}
public Name.TypeVar getTypeVarName() {
return typeVarName;
}
}
/**
* Models a name in CAL source.
*
* @author Bo Ilic
*/
public static abstract class Name extends SourceElement {
/**
* Models a module name in CAL source. Note that a module name may contain zero
* or more dots, and whitespace (including comments) can appear on either side
* of these dots. For example, it is possible for a module name to span multiple lines.
*
* @author Joseph Wong
*/
public static final class Module extends Name {
/**
* The qualifier portion of the module name. This cannot be null, but
* can represent an empty qualifier if it has zero components.
*/
private final Qualifier qualifier;
/**
* The unqualified portion of the module name - the component after the last dot.
*/
private final String unqualifiedModuleName;
/**
* Models a module name qualifier. A module name may have an empty qualifier
* (e.g. the module name Gamma), or it may have a non-empty qualifier
* (e.g. the qualifier Beta in the module name Beta.Gamma, or the
* qualifier Alpha.Beta in the module name Alpha.Beta.Gamma).
*
* @author Joseph Wong
*/
public static final class Qualifier extends SourceElement {
/**
* The components of the qualifier which are lexically separated by dots.
* This array can be empty to represent an empty qualifier.
*/
private final String[] components;
public static final String[] NO_COMPONENTS = new String[0];
/**
* Creates a source model element for representing a module name qualifier.
* @param components the components of the qualifier which are lexically separated by dots.
* @param sourceRange the source range which encompasses the entire qualifier.
*/
private Qualifier(String[] components, SourceRange sourceRange) {
super(sourceRange);
if (components == null || components.length == 0) {
this.components = NO_COMPONENTS;
} else {
this.components = components.clone();
verifyArrayArg(this.components, "components");
}
for (int i = 0, n = this.components.length; i < n; i++) {
if (!LanguageInfo.isValidModuleNameComponent(this.components[i])) {
throw new IllegalArgumentException();
}
}
}
/**
* Factory method for constructing a source model element for representing a module name qualifier.
*
* @param qualifier
* the qualifier as a string, with the components separated by dots (no whitespace allowed
* on either side of the dots).
* @return a new instance of this class.
*/
public static Qualifier make(String qualifier) {
return new Qualifier(qualifier.split("\\."), null);
}
/**
* Factory method for constructing a source model element for representing a module name qualifier.
* @param components the components of the qualifier which are lexically separated by dots.
* @return a new instance of this class.
*/
public static Qualifier make(String[] components) {
return new Qualifier(components, null);
}
/**
* Factory method for constructing a source model element for representing a module name qualifier from
* the module name qualifier of a {@link ModuleName}.
* @param moduleName the module name whose qualifier is to be represented.
* @return a new instance of this class.
*/
public static Qualifier makeFromQualifierOfModuleName(ModuleName moduleName) {
return new Qualifier(moduleName.getComponents(0, moduleName.getNComponents() - 1), null);
}
/**
* Factory method for constructing a source model element for representing a module name qualifier.
* @param components the components of the qualifier which are lexically separated by dots.
* @param sourceRange the source range which encompasses the entire qualifier.
* @return a new instance of this class.
*/
static Qualifier makeAnnotated(String[] components, SourceRange sourceRange) {
return new Qualifier(components, sourceRange);
}
/**
* @return the components of the qualifier which are lexically separated by dots.
* This array can be empty to represent an empty qualifier.
*/
public String[] getComponents() {
if (components.length == 0) {
return NO_COMPONENTS;
}
return components.clone();
}
/**
* @return the number of components in the qualifier.
*/
public int getNComponents() {
return components.length;
}
/**
* Returns the component at the specified position in the array
* of components.
*
* @param n the index of the component to return.
* @return the component at the specified position in the array
* of components.
*/
public String getNthComponents(int n) {
return components[n];
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode hierarchicalModuleNameNode = new ParseTreeNode(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER, "HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER");
for (final String component : components) {
ParseTreeNode qualifierNode = hierarchicalModuleNameNode;
hierarchicalModuleNameNode = new ParseTreeNode(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME, "HIERARCHICAL_MODULE_NAME");
ParseTreeNode unqualifiedModuleNameNode = new ParseTreeNode(CALTreeParserTokenTypes.CONS_ID, component);
hierarchicalModuleNameNode.setFirstChild(qualifierNode);
qualifierNode.setNextSibling(unqualifiedModuleNameNode);
}
return hierarchicalModuleNameNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_Module_Qualifier(this, arg);
}
}
/**
* Creates a source model element for representing a module name.
*
* @param qualifier
* the qualifier portion of the module name. This cannot be null, but can represent
* an empty qualifier if it has zero components.
* @param unqualifiedModuleName
* the unqualified portion of the module name - the component after the last dot.
* @param sourceRange
* the source range which encompasses the entire module name including the qualifier.
*/
private Module(Qualifier qualifier, String unqualifiedModuleName, SourceRange sourceRange) {
super(sourceRange);
verifyArg(qualifier, "qualifier");
verifyArg(unqualifiedModuleName, "unqualifiedName");
if (!LanguageInfo.isValidModuleNameComponent(unqualifiedModuleName)) {
throw new IllegalArgumentException();
}
this.qualifier = qualifier;
this.unqualifiedModuleName = unqualifiedModuleName;
}
/**
* Factory method for constructing a source model element for representing a module name.
*
* @param qualifiedModuleName
* the qualified module name as a ModuleName, with the components separated by dots.
* @return a new instance of this class.
*/
public static Module make(ModuleName qualifiedModuleName) {
if (qualifiedModuleName == null) {
return null;
}
return new Module(
Qualifier.makeFromQualifierOfModuleName(qualifiedModuleName),
qualifiedModuleName.getLastComponent(),
null);
}
/**
* Factory method for constructing a source model element for representing a module name.
*
* @param qualifier
* the qualifier portion of the module name. This cannot be null, but can represent
* an empty qualifier if it has zero components.
* @param unqualifiedModuleName
* the unqualified portion of the module name - the component after the last dot.
* @return a new instance of this class.
*/
public static Module make(Qualifier qualifier, String unqualifiedModuleName) {
return new Module(qualifier, unqualifiedModuleName, null);
}
/**
* Factory method for constructing a source model element for representing a module name.
*
* @param qualifier
* the qualifier portion of the module name. This cannot be null, but can represent
* an empty qualifier if it has zero components.
* @param unqualifiedModuleName
* the unqualified portion of the module name - the component after the last dot.
* @param sourceRange
* the source range which encompasses the entire module name including the qualifier.
* @return a new instance of this class.
*/
static Module makeAnnotated(Qualifier qualifier, String unqualifiedModuleName, SourceRange sourceRange) {
return new Module(qualifier, unqualifiedModuleName, sourceRange);
}
/**
* Factory method for constructing an instance of ModuleName.
* @param module a Name.Module. Cannot be null.
* @return an instance of ModuleName.
*/
public static ModuleName toModuleName(Module module) {
String[] moduleQualifierComponents = module.qualifier.components;
String[] components = new String[moduleQualifierComponents.length + 1];
System.arraycopy(moduleQualifierComponents, 0, components, 0, moduleQualifierComponents.length);
components[moduleQualifierComponents.length] = module.unqualifiedModuleName;
return ModuleName.make(components);
}
/**
* Factory method for constructing an instance of ModuleName which accepts nulls.
* @param maybeModuleName a module name. <em>Can</em> be null.
* @return an instance of ModuleName. If moduleName is null, then null is returned.
*/
public static ModuleName maybeToModuleName(final Module maybeModuleName) {
if (maybeModuleName == null) {
return null;
} else {
return toModuleName(maybeModuleName);
}
}
/**
* @return the qualifier portion of the module name. This cannot be null, but
* can represent an empty qualifier if it has zero components.
*/
public Qualifier getQualifier() {
return qualifier;
}
/**
* @return true if the qualifier of this module name is non-empty (i.e. the module name contains
* dots, such as Foo.Bar); false otherwise.
*/
public boolean isQualified() {
return qualifier.getNComponents() > 0;
}
/**
* @return the unqualified portion of the module name - the component after the last dot.
*/
public String getUnqualifiedModuleName() {
return unqualifiedModuleName;
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode hierarchicalModuleNameNode = new ParseTreeNode(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME, "HIERARCHICAL_MODULE_NAME");
ParseTreeNode qualifierNode = qualifier.toParseTreeNode();
ParseTreeNode unqualifiedModuleNameNode = new ParseTreeNode(CALTreeParserTokenTypes.CONS_ID, unqualifiedModuleName);
hierarchicalModuleNameNode.setFirstChild(qualifierNode);
qualifierNode.setNextSibling(unqualifiedModuleNameNode);
return hierarchicalModuleNameNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_Module(this, arg);
}
}
/**
* Models a potentially qualified name in CAL source. What this means is that it is a name where an explicit
* module qualification is able to be given, but may or may not have actually been given.
* <p>
* In general in CAL, user can only provide a qualification if and only if it is possible for the symbol to be defined in another module.
* That is why for a function definition such as:
* <pre>
* f x y = x + y;
* </pre>
* it is not legal to supply qualifications to any of the 3 symbols on the left hand side "f", "x", "y", but it is legal
* to qualify the x or y on the right hand side.
* Note that <code>f x y = M.x + M.y;</code>
* the x and y on the right hand side do not refer to the local arguments x and y but rather to the top-level symbols M.x and M.y.
*
* @author Bo Ilic
*/
public static abstract class Qualifiable extends Name {
/**
* Name of the module in which the name is defined. May be null, in which case the name is unqualified.
* For efficiency, it is better to supply the explicit qualification if available.
* Local names must have null module part.
* If non-null, it must be a syntactically valid module name.
*/
private final Name.Module moduleName;
private Qualifiable(Name.Module moduleName, SourceRange sourceRange) {
super(sourceRange);
this.moduleName = moduleName;
}
/**
* @return the module name, or null if the name is unqualified.
*/
public Name.Module getModuleName() {
return moduleName;
}
/**
* @return true if this name is qualified (i.e. it has a module name); false otherwise.
*/
public boolean isQualified() {
return moduleName != null;
}
/**
* @return the part of the name not including the module qualification. For example, for "List.filter" this is "filter".
*/
public abstract String getUnqualifiedName();
/**
* Constructs a parse tree for a potentially qualified name in CAL source.
* @param qualifiedNameNodeType the node type for the qualified name.
* @param qualifiedNameNodeTypeString the string representation of the node type for the qualified name.
* @param unqualifiedNameNodeType the node type for the unqualified name.
* @param unqualifiedName the unqualified name as a string.
* @return the corresponding parse tree.
*/
final ParseTreeNode toParseTreeNode(int qualifiedNameNodeType, String qualifiedNameNodeTypeString, int unqualifiedNameNodeType, String unqualifiedName) {
ParseTreeNode qualifiedNode = new ParseTreeNode(qualifiedNameNodeType, qualifiedNameNodeTypeString);
ParseTreeNode moduleNameNode;
ParseTreeNode functionNameNode = new ParseTreeNode(unqualifiedNameNodeType, unqualifiedName);
if (moduleName == null) {
moduleNameNode = new ParseTreeNode(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER, "HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER");
} else {
moduleNameNode = moduleName.toParseTreeNode();
}
qualifiedNode.setFirstChild(moduleNameNode);
moduleNameNode.setNextSibling(functionNameNode);
return qualifiedNode;
}
}
/**
* Models a potentially qualified function name in CAL source. It also is used for modeling class method and
* local variable names when they can be potentially qualified (i.e. for any symbol that shares the namespace
* of CAL functions).
*
* @author Bo Ilic
*/
public static final class Function extends Qualifiable {
private final String functionName;
/** SourceRange of the unqualifiedName portion */
private final SourceRange unqualifiedNameSourceRange;
/**
* @param moduleName may be null, in which case Var is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. Local names must have null module part. If non-null, it must be a syntactically valid module name.
* @param functionName must be a non-null syntactically valid function, class method or local variable name, or an internal function name.
* @param internalName whether the name is one for an internal function.
* @param sourceRange
* @param unqualifiedNameSourceRange
*/
private Function(Name.Module moduleName, String functionName, boolean internalName, SourceRange sourceRange, SourceRange unqualifiedNameSourceRange) {
super(moduleName, sourceRange);
//internal names are validated differently. This allows internal functions such as the instance
//functions for derived instances to use user-hidden names starting with a $ such as $equalsMaybe
if (internalName) {
if (functionName.charAt(0) != '$') {
throw new IllegalArgumentException("internal function names must start with a $.");
}
} else {
if (!LanguageInfo.isValidFunctionName(functionName)) {
throw new IllegalArgumentException("Invalid function name: " + functionName);
}
}
this.functionName = functionName;
this.unqualifiedNameSourceRange = unqualifiedNameSourceRange;
}
/**
* @param moduleName may be null, in which case Var is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. Local names must have null module part. If non-null, it must be a syntactically valid module name.
* @param functionName must be a non-null syntactically valid function, class method or local variable name, or an internal function name.
* @param internalName whether the name is one for an internal function.
* @param sourceRange
* @param unqualifiedNameSourceRange
*/
private Function(ModuleName moduleName, String functionName, boolean internalName, SourceRange sourceRange, SourceRange unqualifiedNameSourceRange) {
this(Name.Module.make(moduleName), functionName, internalName, sourceRange, unqualifiedNameSourceRange);
}
private Function(QualifiedName functionName, SourceRange sourceRange, SourceRange unqualifiedNameSourceRange) {
this(functionName.getModuleName(), functionName.getUnqualifiedName(), false, sourceRange, unqualifiedNameSourceRange);
}
/**
* @param moduleName may be null, in which case Var is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. Local names must have null module part. If non-null, it must be a syntactically valid module name.
* @param functionName must be a non-null syntactically valid function, class method or local variable name.
* @return Function
*/
public static Function make(Name.Module moduleName, String functionName) {
return new Function(moduleName, functionName, false, null, null);
}
/**
* @param moduleName may be null, in which case Var is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. Local names must have null module part. If non-null, it must be a syntactically valid module name.
* @param functionName must be a non-null syntactically valid function, class method or local variable name.
* @return Function
*/
public static Function make(ModuleName moduleName, String functionName) {
return new Function(moduleName, functionName, false, null, null);
}
public static Function make(QualifiedName functionName) {
return new Function(functionName, null, null);
}
/**
* @param unqualifiedFunctionName the unqualified name for a function or class method.
* @return an unqualified function or class method name.
*/
public static Function makeUnqualified(String unqualifiedFunctionName) {
return make((Name.Module)null, unqualifiedFunctionName);
}
static Function makeAnnotated(Name.Module moduleName, String functionName, SourceRange sourceRange, SourceRange unqualifiedNameSourceRange) {
return new Function(moduleName, functionName, false, sourceRange, unqualifiedNameSourceRange);
}
public String getUnqualifiedName() {
return functionName;
}
// todo-jowong maybe the unqualified name can be encapsulated by its own source element
SourceRange getUnqualifiedNameSourceRange() {
return unqualifiedNameSourceRange;
}
ParseTreeNode toParseTreeNode() {
return toParseTreeNode(CALTreeParserTokenTypes.QUALIFIED_VAR, "QUALIFIED_VAR", CALTreeParserTokenTypes.VAR_ID, functionName);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_Function(this, arg);
}
}
/**
* Models a potentially qualified data constructor name in CAL source.
* @author Bo Ilic
*/
public static final class DataCons extends Qualifiable {
private final String dataConsName;
/**
* @param moduleName may be null, in which case Cons is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param dataConsName must be a non-null syntactically valid data constructor name.
* @param sourceRange may be null.
*/
private DataCons(Name.Module moduleName, String dataConsName, SourceRange sourceRange) {
super(moduleName, sourceRange);
if (!LanguageInfo.isValidDataConstructorName(dataConsName)) {
throw new IllegalArgumentException();
}
this.dataConsName = dataConsName;
}
/**
* @param moduleName may be null, in which case Cons is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param dataConsName must be a non-null syntactically valid data constructor name.
* @param sourceRange may be null.
*/
private DataCons(ModuleName moduleName, String dataConsName, SourceRange sourceRange) {
this(Name.Module.make(moduleName), dataConsName, sourceRange);
}
private DataCons(QualifiedName dataConsName, SourceRange sourceRange) {
this(dataConsName.getModuleName(), dataConsName.getUnqualifiedName(), sourceRange);
}
/**
* @param moduleName may be null, in which case Cons is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param dataConsName must be a non-null syntactically valid data constructor name.
* @return an instance of DataCons
*/
public static DataCons make(Name.Module moduleName, String dataConsName) {
return new DataCons(moduleName, dataConsName, null);
}
/**
* @param moduleName may be null, in which case Cons is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param dataConsName must be a non-null syntactically valid data constructor name.
* @return an instance of DataCons
*/
public static DataCons make(ModuleName moduleName, String dataConsName) {
return new DataCons(moduleName, dataConsName, null);
}
public static DataCons make(QualifiedName dataConsName) {
return new DataCons(dataConsName, null);
}
/**
* @param unqualifiedDataConsName the unqualified name for a data constructor.
* @return an unqualified data constructor name.
*/
public static DataCons makeUnqualified(String unqualifiedDataConsName) {
return make((Name.Module)null, unqualifiedDataConsName);
}
static DataCons makeAnnotated(Name.Module moduleName, String dataConsName, SourceRange sourceRange) {
return new DataCons(moduleName, dataConsName, sourceRange);
}
public String getUnqualifiedName() {
return dataConsName;
}
ParseTreeNode toParseTreeNode() {
return toParseTreeNode(CALTreeParserTokenTypes.QUALIFIED_CONS, "QUALIFIED_CONS", CALTreeParserTokenTypes.CONS_ID, dataConsName);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_DataCons(this, arg);
}
}
/**
* Models a potentially qualified type class name such as "Prelude.Eq" or "Ord".
*
* @author Bo Ilic
*/
public static final class TypeClass extends Qualifiable {
private final String typeClassName;
/**
* @param moduleName may be null, in which case the type class name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeClassName must be a non-null syntactically valid type constructor name.
* @param sourceRange the position of the beginning of this TypeClass name
*/
private TypeClass(Name.Module moduleName, String typeClassName, SourceRange sourceRange) {
super(moduleName, sourceRange);
if (!LanguageInfo.isValidTypeClassName(typeClassName)) {
throw new IllegalArgumentException();
}
this.typeClassName = typeClassName;
}
/**
* @param moduleName may be null, in which case the type class name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeClassName must be a non-null syntactically valid type constructor name.
* @param sourceRange the position of the beginning of this TypeClass name
*/
private TypeClass(ModuleName moduleName, String typeClassName, SourceRange sourceRange) {
this(Name.Module.make(moduleName), typeClassName, sourceRange);
}
private TypeClass(QualifiedName typeClassName, SourceRange sourceRange) {
this(typeClassName.getModuleName(), typeClassName.getUnqualifiedName(), sourceRange);
}
/**
* @param moduleName may be null, in which case the type class name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeClassName must be a non-null syntactically valid type constructor name.
* @return an instance of TypeClass
*/
public static TypeClass make(Name.Module moduleName, String typeClassName) {
return new TypeClass(moduleName, typeClassName, null);
}
/**
* @param moduleName may be null, in which case the type class name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeClassName must be a non-null syntactically valid type constructor name.
* @return an instance of TypeClass
*/
public static TypeClass make(ModuleName moduleName, String typeClassName) {
return new TypeClass(moduleName, typeClassName, null);
}
public static TypeClass make(QualifiedName typeClassName) {
return new TypeClass(typeClassName, null);
}
/**
* @param unqualifiedTypeClassName the unqualified name for a type class.
* @return an unqualified type class name.
*/
public static TypeClass makeUnqualified(String unqualifiedTypeClassName) {
return make((Name.Module)null, unqualifiedTypeClassName);
}
static TypeClass makeAnnotated(Name.Module moduleName, String typeClassName, SourceRange sourceRange) {
return new TypeClass(moduleName, typeClassName, sourceRange);
}
public String getUnqualifiedName() {
return typeClassName;
}
ParseTreeNode toParseTreeNode() {
return toParseTreeNode(CALTreeParserTokenTypes.QUALIFIED_CONS, "QUALIFIED_CONS", CALTreeParserTokenTypes.CONS_ID, typeClassName);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_TypeClass(this, arg);
}
}
public static final class TypeCons extends Qualifiable {
private final String typeConsName;
/**
* @param moduleName may be null, in which case the type constructor name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeConsName must be a non-null syntactically valid type constructor name.
* @param sourceRange
*/
private TypeCons(Name.Module moduleName, String typeConsName, SourceRange sourceRange) {
super(moduleName, sourceRange);
if (!LanguageInfo.isValidTypeConstructorName(typeConsName)) {
throw new IllegalArgumentException();
}
this.typeConsName = typeConsName;
}
/**
* @param moduleName may be null, in which case the type constructor name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeConsName must be a non-null syntactically valid type constructor name.
* @param sourceRange
*/
private TypeCons(ModuleName moduleName, String typeConsName, SourceRange sourceRange) {
this(Name.Module.make(moduleName), typeConsName, sourceRange);
}
private TypeCons(QualifiedName typeConsName, SourceRange sourceRange) {
this(typeConsName.getModuleName(), typeConsName.getUnqualifiedName(), sourceRange);
}
/**
* @param moduleName may be null, in which case the type constructor name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeConsName must be a non-null syntactically valid type constructor name.
* @return an instance of TypeCons
*/
public static TypeCons make(Name.Module moduleName, String typeConsName) {
return new TypeCons(moduleName, typeConsName, null);
}
/**
* @param moduleName may be null, in which case the type constructor name is unqualified. For efficiency, it is better to supply the
* explicit qualification if available. If non-null, it must be a syntactically valid module name.
* @param typeConsName must be a non-null syntactically valid type constructor name.
* @return an instance of TypeCons
*/
public static TypeCons make(ModuleName moduleName, String typeConsName) {
return new TypeCons(moduleName, typeConsName, null);
}
public static TypeCons make(QualifiedName typeConsName) {
return new TypeCons(typeConsName, null);
}
/**
* @param unqualifiedTypeConsName the unqualified name for a type constructor.
* @return an unqualified type constructor name.
*/
public static TypeCons makeUnqualified(String unqualifiedTypeConsName) {
return make((Name.Module)null, unqualifiedTypeConsName);
}
static TypeCons makeAnnotated(Name.Module moduleName, String typeConsName, SourceRange sourceRange) {
return new TypeCons(moduleName, typeConsName, sourceRange);
}
public String getUnqualifiedName() {
return typeConsName;
}
ParseTreeNode toParseTreeNode() {
return toParseTreeNode(CALTreeParserTokenTypes.QUALIFIED_CONS, "QUALIFIED_CONS", CALTreeParserTokenTypes.CONS_ID, typeConsName);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_TypeCons(this, arg);
}
}
/**
* Models a potentially qualified name such as "Prelude", "Prelude.Eq", "Maybe", or "Nothing",
* appearing in the source where the 'context' of the name is undetermined: it may be a
* module name, a type constructor name, a data constructor name, or a type class name.
*
* Such a name may appear in a CALDoc comment, as in:
* {at-link Cal.Prelude at-} - a module reference without context
* {at-link Nothing at-} - a data constructor reference without context
* at-see Prelude.Int - a type constructor reference without context
* at-see Eq - a type class reference without context
*
* (Replace at- with @ in the descriptions above)
*
* @author Joseph Wong
*/
public static final class WithoutContextCons extends Qualifiable {
/**
* The "unqualified name" portion of the name. Note that if the name represents a module name,
* the module name's unqualified portion will in fact be stored in this field, and the moduleName field in the
* superclass will store the module name's qualifier. This is a consequence of the inability to tell the context
* of the name at parsing-time.
* <p>
* This must be a non-null syntactically valid constructor name, i.e. one that starts with an uppercase character.
*/
private final String unqualifiedName;
/**
* @param moduleName the "module name", which represents the module name portion of a qualified name. If the
* instance is meant to represent a true module name, this parameter represents the module name's qualifier.
* If non-null, it must be a syntactically valid module name.
* @param unqualifiedName must be a non-null syntactically valid constructor name, i.e. one that starts with an uppercase character.
* @param sourceRange
*/
private WithoutContextCons(Name.Module moduleName, String unqualifiedName, SourceRange sourceRange) {
super(moduleName, sourceRange);
if (!LanguageInfo.isValidTypeConstructorName(unqualifiedName)) {
throw new IllegalArgumentException();
}
this.unqualifiedName = unqualifiedName;
}
/**
* @param moduleName the "module name", which represents the module name portion of a qualified name. If the
* instance is meant to represent a true module name, this parameter represents the module name's qualifier.
* If non-null, it must be a syntactically valid module name.
* @param unqualifiedName must be a non-null syntactically valid constructor name, i.e. one that starts with an uppercase character.
* @param sourceRange
*/
private WithoutContextCons(ModuleName moduleName, String unqualifiedName, SourceRange sourceRange) {
this(Name.Module.make(moduleName), unqualifiedName, sourceRange);
}
/**
* Constructs an instance of this class using the module and unqualified names from the specified QualifiedName.
* @param qualifiedName the qualified name whose components will form the "module name" and "unqualified name"
* of this WithoutContextCons instance.
* @param sourceRange
*/
private WithoutContextCons(QualifiedName qualifiedName, SourceRange sourceRange) {
this(qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName(), sourceRange);
}
/**
* Factory method for constructing a new source model element for representing a potentially qualified name
* such as "Prelude", "Prelude.Eq", "Maybe", or "Nothing", appearing in the source where the 'context' of the
* name is undetermined.
*
* @param maybeQualifiedName a string representing either a qualified name or an unqualified name.
* @return a new instance of this class.
*/
public static WithoutContextCons make(String maybeQualifiedName) {
int lastDotPos = maybeQualifiedName.lastIndexOf('.');
if (lastDotPos < 0) {
// no dot - so no qualifier
return new WithoutContextCons((Name.Module)null, maybeQualifiedName, null);
} else if (lastDotPos == 0) {
// dot as the first character - illegal
throw new IllegalArgumentException();
} else {
// there is a dot, after the first character
String qualifier = maybeQualifiedName.substring(0, lastDotPos);
String unqualifiedName = maybeQualifiedName.substring(lastDotPos + 1);
return new WithoutContextCons(Name.Module.make(ModuleName.make(qualifier)), unqualifiedName, null);
}
}
/**
* @param moduleName the "module name", which represents the module name portion of a qualified name. If the
* instance is meant to represent a true module name, this parameter represents the module name's qualifier.
* If non-null, it must be a syntactically valid module name.
* @param unqualifiedName must be a non-null syntactically valid constructor name, i.e. one that starts with an uppercase character.
* @return an instance of WithoutContextCons
*/
public static WithoutContextCons make(Name.Module moduleName, String unqualifiedName) {
return new WithoutContextCons(moduleName, unqualifiedName, null);
}
/**
* @param moduleName the "module name", which represents the module name portion of a qualified name. If the
* instance is meant to represent a true module name, this parameter represents the module name's qualifier.
* If non-null, it must be a syntactically valid module name.
* @param unqualifiedName must be a non-null syntactically valid constructor name, i.e. one that starts with an uppercase character.
* @return an instance of WithoutContextCons
*/
public static WithoutContextCons make(ModuleName moduleName, String unqualifiedName) {
return new WithoutContextCons(moduleName, unqualifiedName, null);
}
/**
* Factory method for constructing an instance of this class using the module and unqualified names from the specified QualifiedName.
* @param qualifiedName the qualified name whose components will form the "module name" and "unqualified name"
* of this WithoutContextCons instance.
* @return an instance of WithoutContextCons
*/
public static WithoutContextCons make(QualifiedName qualifiedName) {
return new WithoutContextCons(qualifiedName, null);
}
static WithoutContextCons makeAnnotated(Name.Module moduleName, String unqualifiedName, SourceRange sourceRange) {
return new WithoutContextCons(moduleName, unqualifiedName, sourceRange);
}
/**
* @return the part of the name not including the module qualification. For example, for "List.filter" this is "filter".
*/
public String getUnqualifiedName() {
return unqualifiedName;
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
return toParseTreeNode(CALTreeParserTokenTypes.QUALIFIED_CONS, "QUALIFIED_CONS", CALTreeParserTokenTypes.CONS_ID, unqualifiedName);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_WithoutContextCons(this, arg);
}
}
/**
* Models a field name in CAL, e.g. {@code value} (a textual field name) or {@code #3}
* (an ordinal field name).
*
* @author Joseph Wong
*/
public static final class Field extends Name {
/** The name of the field. */
private final FieldName fieldName;
/**
* Constructs a new source model element for representing a field name.
* @param fieldName the name of the field.
* @param sourceRange the associated source range.
*/
private Field(final FieldName fieldName, final SourceRange sourceRange) {
super(sourceRange);
verifyArg(fieldName, "fieldName");
this.fieldName = fieldName;
}
/**
* Factory method for constructing a new source model element for representing a field name.
* @param fieldName the name of the field.
* @return a new instance of this class.
*/
public static Field make(final FieldName fieldName) {
return new Field(fieldName, null);
}
/**
* Factory method for constructing a new source model element for representing a field name.
* @param fieldName the name of the field.
* @param sourceRange the associated source range.
* @return a new instance of this class.
*/
static Field makeAnnotated(final FieldName fieldName, final SourceRange sourceRange) {
return new Field(fieldName, sourceRange);
}
/**
* @return the name of the field.
*/
public FieldName getName() {
return fieldName;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_Field(this, arg);
}
/**
* {@inheritDoc}
*/
@Override
ParseTreeNode toParseTreeNode() {
return SourceModel.makeFieldNameExpr(fieldName);
}
}
/**
* Models a type variable name in CAL.
*
* @author Joseph Wong
*/
public static final class TypeVar extends Name {
/** The name of the type variable. */
private final String typeVarName;
/**
* Constructs a new source model element for representing a type variable name.
* @param typeVarName the name of the type variable
* @param sourceRange the associated source range.
*/
private TypeVar(final String typeVarName, final SourceRange sourceRange) {
super(sourceRange);
verifyArg(typeVarName, "typeVarName");
if (!LanguageInfo.isValidTypeVariableName(typeVarName)) {
throw new IllegalArgumentException();
}
this.typeVarName = typeVarName;
}
/**
* Factory method for constructing a new source model element for representing a type variable name.
* @param typeVarName the name of the type variable
* @return a new instance of this class.
*/
public static TypeVar make(final String typeVarName) {
return new TypeVar(typeVarName, null);
}
/**
* Factory method for constructing a new source model element for representing a type variable name.
* @param typeVarName the name of the type variable
* @param sourceRange the associated source range.
* @return a new instance of this class.
*/
static TypeVar makeAnnotated(final String typeVarName, final SourceRange sourceRange) {
return new TypeVar(typeVarName, sourceRange);
}
/**
* @return the name of the type variable.
*/
public String getName() {
return typeVarName;
}
/**
* {@inheritDoc}
*/
@Override
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Name_TypeVar(this, arg);
}
/**
* {@inheritDoc}
*/
@Override
ParseTreeNode toParseTreeNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, typeVarName);
}
}
/**
* @param sourceRange
*/
private Name(SourceRange sourceRange) {
super(sourceRange);
}
}
/**
* Base class for all source elements that constitute a CALDoc comment. CALDoc is the documentation comment
* format for CAL.
*
* @author Joseph Wong
*/
public static abstract class CALDoc extends SourceElement {
private CALDoc(SourceRange sourceRange) {
super(sourceRange);
}
/**
* Models a CALDoc comment, which consists of a description block followed by a list
* of tagged blocks.
*
* @author Joseph Wong
*/
public static abstract class Comment extends CALDoc {
/** The description block at the start of the comment. */
private final TextBlock description;
/**
* The tagged blocks in the latter part of the comment. This can be
* an empty array if the comment contains no tags.
*/
private final TaggedBlock[] taggedBlocks;
public static final TaggedBlock[] NO_TAGGED_BLOCKS = new TaggedBlock[0];
/**
* Private constructor for this base class for CALDoc comments. Intended
* only to be invoked by subclass constructors.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
*/
private Comment(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(range);
verifyArg(description, "description");
this.description = description;
if (taggedBlocks == null || taggedBlocks.length == 0) {
this.taggedBlocks = NO_TAGGED_BLOCKS;
} else {
this.taggedBlocks = taggedBlocks.clone();
verifyArrayArg(this.taggedBlocks, "taggedBlocks");
}
}
/**
* @return the description block at the start of the comment.
*/
public TextBlock getDescription() {
return description;
}
/**
* @return the tagged blocks in the latter part of the comment. This
* can be an empty array if the comment contains no tags.
*/
public TaggedBlock[] getTaggedBlocks() {
if (taggedBlocks.length == 0) {
return NO_TAGGED_BLOCKS;
}
return taggedBlocks.clone();
}
/**
* @return the number of tagged blocks contained this the comment.
*/
public int getNTaggedBlocks() {
return taggedBlocks.length;
}
/**
* Returns the tagged block at the specified position in the array
* of tagged blocks.
*
* @param n
* the index of the tagged block to return
* @return the tagged block at the specified position in the array
* of tagged blocks.
*/
public TaggedBlock getNthTaggedBlock(int n) {
return taggedBlocks[n];
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode commentNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_COMMENT, "CALDOC_COMMENT");
ParseTreeNode descriptionNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_DESCRIPTION_BLOCK, "CALDOC_DESCRIPTION_BLOCK");
ParseTreeNode descriptionTextNode = description.toParseTreeNode();
ParseTreeNode taggedBlocksNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TAGGED_BLOCKS, "CALDOC_TAGGED_BLOCKS");
ParseTreeNode[] taggedBlockNodeList = new ParseTreeNode[taggedBlocks.length];
for (int i = 0; i < taggedBlocks.length; i++) {
taggedBlockNodeList[i] = taggedBlocks[i].toParseTreeNode();
}
taggedBlocksNode.addChildren(taggedBlockNodeList);
commentNode.setFirstChild(descriptionNode);
descriptionNode.setFirstChild(descriptionTextNode);
descriptionNode.setNextSibling(taggedBlocksNode);
return commentNode;
}
/**
* Models a CALDoc comment associated with a module definition.
*
* @author Joseph Wong
*/
public static final class Module extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with a module definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source range for this element
*/
private Module(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a module definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
public static Module make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new Module(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a module definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source range of this element
* @return a new instance of this class.
*/
static Module makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new Module(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_Module(this, arg);
}
}
/**
* Models a CALDoc comment associated with a function definition.
*
* @author Joseph Wong
*/
public static final class Function extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with a function definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source range of this element
*/
private Function(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a function definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
public static Function make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new Function(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a function definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source range of this element
* @return a new instance of this class.
*/
static Function makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new Function(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_Function(this, arg);
}
}
/**
* Models a CALDoc comment associated with a type constructor definition.
*
* @author Joseph Wong
*/
public static final class TypeCons extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with a type constructor definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
*/
private TypeCons(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a type constructor definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instace of this class.
*/
public static TypeCons make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new TypeCons(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a type constructor definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instace of this class.
*/
static TypeCons makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new TypeCons(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_TypeCons(this, arg);
}
}
/**
* Models a CALDoc comment associated with a data constructor definition.
*
* @author Joseph Wong
*/
public static final class DataCons extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with a data constructor definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source range of this element
*/
private DataCons(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a data constructor definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
public static DataCons make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new DataCons(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a data constructor definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source range of this element
* @return a new instance of this class.
*/
static DataCons makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new DataCons(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_DataCons(this, arg);
}
}
/**
* Models a CALDoc comment associated with a type class definition.
*
* @author Joseph Wong
*/
public static final class TypeClass extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with a type class definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source range of this element
*/
private TypeClass(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a type class definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
public static TypeClass make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new TypeClass(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a type class definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @param range the source element range
* @return a new instance of this class.
*/
static TypeClass makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new TypeClass(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_TypeClass(this, arg);
}
}
/**
* Models a CALDoc comment associated with a class method definition.
*
* @author Joseph Wong
*/
public static final class ClassMethod extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with a class method definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
*/
private ClassMethod(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a class method definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
public static ClassMethod make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new ClassMethod(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with a class method definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
static ClassMethod makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new ClassMethod(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_ClassMethod(this, arg);
}
}
/**
* Models a CALDoc comment associated with an instance definition.
*
* @author Joseph Wong
*/
public static final class Instance extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with an instance definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
*/
private Instance(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with an instance definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
public static Instance make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new Instance(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with an instance definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
static Instance makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new Instance(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_Instance(this, arg);
}
}
/**
* Models a CALDoc comment associated with an instance method definition.
*
* @author Joseph Wong
*/
public static final class InstanceMethod extends Comment {
/**
* Creates a new source model element for representing a CALDoc comment associated
* with an instance method definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
*/
private InstanceMethod(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
super(description, taggedBlocks, range);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with an instance method definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
public static InstanceMethod make(TextBlock description, TaggedBlock[] taggedBlocks) {
return new InstanceMethod(description, taggedBlocks, null);
}
/**
* Factory method for constructing a new source model element for representing a CALDoc comment associated
* with an instance method definition.
*
* @param description the description block at the start of the comment.
* @param taggedBlocks an array of tagged blocks in the latter part of the comment.
* @return a new instance of this class.
*/
static InstanceMethod makeAnnotated(TextBlock description, TaggedBlock[] taggedBlocks, SourceRange range) {
return new InstanceMethod(description, taggedBlocks, range);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_Comment_InstanceMethod(this, arg);
}
}
}
/**
* Models a reference in a list of references in a CALDoc "@see" block or "@link" inline block.
* A reference can either be checked or unchecked. An unchecked reference
* is represented in source by surrounding the name in double quotes.
*
* @author Joseph Wong
*/
public static abstract class CrossReference extends SourceElement {
/**
* Base class for a reference in a CALDoc "@see" block or "@link" inline block that can appear without
* the context keyword.
*
* @author Joseph Wong
*/
public static abstract class CanAppearWithoutContext extends CrossReference {
/**
* Private constructor for this base class for a reference in a CALDoc "@see" block or "@link"
* inline block that can appear without the context keyword. Intended to be invoked only by subclass
* constructors.
*
* @param checked
* whether the reference is to be statically checked and
* resolved during compilation.
* @param sourceRange
*/
private CanAppearWithoutContext(boolean checked, SourceRange sourceRange) {
super(checked, sourceRange);
}
}
/**
* Models a (checked/unchecked) function name reference in a CALDoc "@see function = ..." block.
*
* @author Joseph Wong
*/
public static final class Function extends CanAppearWithoutContext {
/** The function name encapsulated by this reference. */
private final Name.Function name;
/**
* Creates a source model element for representing a function name reference
* in a CALDoc "@see function = ..." block.
*
* @param name the function name.
* @param checked whether the name is to be checked and resolved statically during compilation.
*/
private Function(Name.Function name, boolean checked) {
super(checked, null);
verifyArg(name, "name");
this.name = name;
}
/**
* Factory method for constructing a source model element for representing a function name reference
* in a CALDoc "@see function = ..." block.
*
* @param name the function name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @return a new instance of this class.
*/
public static Function make(Name.Function name, boolean checked) {
return new Function(name, checked);
}
/**
* @return the function name encapsulated by this reference.
*/
public Name.Function getName() {
return name;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_CrossReference_Function(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode refNode;
if (isChecked()) {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_VAR, "CALDOC_CHECKED_QUALIFIED_VAR");
} else {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_VAR, "CALDOC_UNCHECKED_QUALIFIED_VAR");
}
refNode.setFirstChild(name.toParseTreeNode());
return refNode;
}
}
/**
* Models a (checked/unchecked) module name reference in a CALDoc "@see module = ..." block.
*
* @author Joseph Wong
*/
public static final class Module extends CrossReference {
/** The module name encapsulated by this reference. */
private final Name.Module name;
/**
* Creates a source model element for representing a module name reference
* in a CALDoc "@see module = ..." block.
*
* @param name the module name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @param sourceRange
*/
private Module(Name.Module name, boolean checked, SourceRange sourceRange) {
super(checked, sourceRange);
verifyArg(name, "name");
this.name = name;
}
/**
* Factory method for constructing a source model element for representing a module name reference
* in a CALDoc "@see module = ..." block.
*
* @param name the module name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @return a new instance of this class.
*/
public static Module make(Name.Module name, boolean checked) {
return new Module(name, checked, null);
}
/**
* @return the module name encapsulated by this reference.
*/
public Name.Module getName() {
return name;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_CrossReference_Module(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode refNode;
if (isChecked()) {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_CHECKED_MODULE_NAME, "CALDOC_CHECKED_MODULE_NAME");
} else {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_UNCHECKED_MODULE_NAME, "CALDOC_UNCHECKED_MODULE_NAME");
}
refNode.setFirstChild(name.toParseTreeNode());
return refNode;
}
}
/**
* Models a (checked/unchecked) type constructor name reference in a CALDoc "@see typeConstructor = ..." block.
*
* @author Joseph Wong
*/
public static final class TypeCons extends CrossReference {
/** The type constructor name encapsulated by this reference. */
private final Name.TypeCons name;
/**
* Creates a source model element for representing a type constructor name reference
* in a CALDoc "@see typeConstructor = ..." block.
*
* @param name the type constructor name.
* @param checked whether the name is to be checked and resolved statically during compilation.
*/
private TypeCons(Name.TypeCons name, boolean checked) {
super(checked, null);
verifyArg(name, "name");
this.name = name;
}
/**
* Factory method for constructing a source model element for representing a type constructor name reference
* in a CALDoc "@see typeConstructor = ..." block.
*
* @param name the type constructor name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @return a new instance of this class.
*/
public static TypeCons make(Name.TypeCons name, boolean checked) {
return new TypeCons(name, checked);
}
/**
* @return the tyep constructor name encapsulated by this reference.
*/
public Name.TypeCons getName() {
return name;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_CrossReference_TypeCons(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode refNode;
if (isChecked()) {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS, "CALDOC_CHECKED_QUALIFIED_CONS");
} else {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS, "CALDOC_UNCHECKED_QUALIFIED_CONS");
}
refNode.setFirstChild(name.toParseTreeNode());
return refNode;
}
}
/**
* Models a (checked/unchecked) data constructor name reference in a CALDoc "@see dataConstructor = ..." block.
*
* @author Joseph Wong
*/
public static final class DataCons extends CrossReference {
/** The data constructor name encapsulated by this reference. */
private final Name.DataCons name;
/**
* Creates a source model element for representing a data constructor name reference
* in a CALDoc "@see dataConstructor = ..." block.
*
* @param name the data constructor name.
* @param checked whether the name is to be checked and resolved statically during compilation.
*/
private DataCons(Name.DataCons name, boolean checked) {
super(checked, null);
verifyArg(name, "name");
this.name = name;
}
/**
* Factory method for constructing a source model element for representing a data constructor name reference
* in a CALDoc "@see dataConstructor = ..." block.
*
* @param name the data constructor name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @return a new instance of this class.
*/
public static DataCons make(Name.DataCons name, boolean checked) {
return new DataCons(name, checked);
}
/**
* @return the data constructor name encapsulated by this reference.
*/
public Name.DataCons getName() {
return name;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_CrossReference_DataCons(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode refNode;
if (isChecked()) {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS, "CALDOC_CHECKED_QUALIFIED_CONS");
} else {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS, "CALDOC_UNCHECKED_QUALIFIED_CONS");
}
refNode.setFirstChild(name.toParseTreeNode());
return refNode;
}
}
/**
* Models a (checked/unchecked) type class name reference in a CALDoc "@see typeClass = ..." block.
*
* @author Joseph Wong
*/
public static final class TypeClass extends CrossReference {
/** The type class name encapsulated by this reference. */
private final Name.TypeClass name;
/**
* Creates a source model element for representing a type class name reference
* in a CALDoc "@see typeClass = ..." block.
*
* @param name the type class name.
* @param checked whether the name is to be checked and resolved statically during compilation.
*/
private TypeClass(Name.TypeClass name, boolean checked) {
super(checked, null);
verifyArg(name, "name");
this.name = name;
}
/**
* Factory method for constructing a source model element for representing a type class name reference
* in a CALDoc "@see typeClass = ..." block.
*
* @param name the type class name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @return a new instance of this class.
*/
public static TypeClass make(Name.TypeClass name, boolean checked) {
return new TypeClass(name, checked);
}
/**
* @return the type class name encapsulated by this reference.
*/
public Name.TypeClass getName() {
return name;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_CrossReference_TypeClass(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode refNode;
if (isChecked()) {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS, "CALDOC_CHECKED_QUALIFIED_CONS");
} else {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS, "CALDOC_UNCHECKED_QUALIFIED_CONS");
}
refNode.setFirstChild(name.toParseTreeNode());
return refNode;
}
}
/**
* Models a (checked/unchecked) constructor/module name reference in a CALDoc "@see"/"@link" block without
* the context keyword.
*
* @author Joseph Wong
*/
public static final class WithoutContextCons extends CanAppearWithoutContext {
/** The constructor/module name encapsulated by this reference. */
private final Name.WithoutContextCons name;
/**
* Creates a source model element for representing a constructor/module name reference in a CALDoc
* "@see"/"@link" block without the context keyword.
*
* @param name the type class name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @param sourceRange
*/
private WithoutContextCons(Name.WithoutContextCons name, boolean checked, SourceRange sourceRange) {
super(checked, sourceRange);
verifyArg(name, "name");
this.name = name;
}
/**
* Factory method for constructing a source model element for representing a constructor/module name
* reference in a CALDoc "@see"/"@link" block without the context keyword.
*
* @param name the type class name.
* @param checked whether the name is to be checked and resolved statically during compilation.
* @return a new instance of this class.
*/
public static WithoutContextCons make(Name.WithoutContextCons name, boolean checked) {
return new WithoutContextCons(name, checked, null);
}
static WithoutContextCons makeAnnotated(Name.WithoutContextCons name, boolean checked, SourceRange sourceRange) {
return new WithoutContextCons(name, checked, sourceRange);
}
/**
* @return the type class name encapsulated by this reference.
*/
public Name.WithoutContextCons getName() {
return name;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_CrossReference_WithoutContextCons(this, arg);
}
/**
* @deprecated this is deprecated to signify that the returned source range is not the entire definition, but
* rather a portion thereof.
*/
// todo-jowong refactor this so that the primary source range of the source element is its entire source range
@Deprecated
SourceRange getSourceRange() {
return getSourceRangeOfReference();
}
SourceRange getSourceRangeOfReference() {
return super.getSourceRange();
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode refNode;
if (isChecked()) {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS, "CALDOC_CHECKED_QUALIFIED_CONS");
} else {
refNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS, "CALDOC_UNCHECKED_QUALIFIED_CONS");
}
refNode.setFirstChild(name.toParseTreeNode());
return refNode;
}
}
/** Indicates whether the reference is to be statically checked and resolved during compilation. */
private final boolean checked;
/**
* Private constructor for this base class for a reference in a list of
* references in an "@see"/"@link" block. Intended to be invoked only by subclass
* constructors.
*
* @param checked
* whether the reference is to be statically checked and
* resolved during compilation.
* @param sourceRange
*/
private CrossReference(boolean checked, SourceRange sourceRange) {
super(sourceRange);
this.checked = checked;
}
/**
* @return true if the reference is to be statically checked and resolved during compilation; false otherwise.
*/
public boolean isChecked() {
return checked;
}
}
/**
* Base class for CALDoc comment elements that can be indented in the source on the
* right hand side of the decorative '*' on the left-edge of the comment.
*
* @author Joseph Wong
*/
public static abstract class InteriorIndentable extends CALDoc {
private InteriorIndentable(SourceRange sourceRange) {
super(sourceRange);
}
}
/**
* Base class for a text segment in a CALDoc comment.
*
* @author Joseph Wong
*/
public static abstract class TextSegment extends InteriorIndentable {
/**
* Base class for a top-level text segment in a CALDoc comment, i.e. one that
* can be a child of a text paragraph. In contrast, a text segment that is not
* top-level cannot be a direct child of a text paragraph.
*
* @author Joseph Wong
*/
public static abstract class TopLevel extends TextSegment {
private TopLevel(SourceRange sourceRange) {
super(sourceRange);
}
/** An empty TopLevel array. */
public static final TopLevel[] NO_SEGMENTS = new TopLevel[0];
}
/**
* Models a plain text segment in a CALDoc comment, i.e. a segment consisting of
* a simple string of characters.
*
* @author Joseph Wong
*/
public static final class Plain extends TopLevel {
/**
* The text that constitutes this plain text segment.
*/
private final String text;
/**
* Creates a new source model element for representing a plain text segment in a CALDoc comment.
*
* @param text the text that constitues this plain text segment.
*/
private Plain(String text) {
super(null);
verifyArg(text, "text");
this.text = text;
}
/**
* Factory method for constructing a new source model element for representing a plain text
* segment in a CALDoc comment.
*
* @param text the text that constitues this plain text segment.
* @return a new instance of this class.
*/
public static Plain make(String text) {
return new Plain(text);
}
/**
* @return the text that constitues this plain text segment.
*/
public String getText() {
return text;
}
/**
* Escapes the specified string for inclusion in the source representation of a CALDoc comment.
* @param string the stirng to be escaped.
* @return the escaped version of the specified string.
*/
private static String caldocEscape(String string) {
String augmentedString = '\n' + string; // augment the string so that the @-escaping can be uniformly applied to even the first @ after leading spaces
String augmentedStringWithEscapedAtSigns = augmentedString.replaceAll("@", "\\\\@");
String augmentedEscapedString = augmentedStringWithEscapedAtSigns.replaceAll("\\{@", "\\\\{@"); // the first arg is the regular expression '{@', the second arg the replacement string '\{@'
return augmentedEscapedString.substring(1);
}
/**
* {@inheritDoc}
*/
void addToParseTree(ParseTreeNode parentNode) {
String escapedText = caldocEscape(text);
String textWithNormalizedNewlines = escapedText.replaceAll("\r\n|\r", "\n");
StringTokenizer tokenizer = new StringTokenizer(textWithNormalizedNewlines, "\n", true);
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (token.equals("\n")) {
parentNode.addChild(new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINE_BREAK, "CALDOC_TEXT_LINE_BREAK"));
} else {
if (CALDocLexer.isCALDocWhitespaceString(token)) {
parentNode.addChild(new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_BLANK_TEXT_LINE, token));
} else {
parentNode.addChild(new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINE, token));
}
}
}
}
/**
* {@inheritDoc}
*/
boolean spansMultipleLines() {
return (text.indexOf('\n') >= 0) || (text.indexOf('\r') >= 0);
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_Plain(this, arg);
}
}
/**
* Models a preformatted text segment in a CALDoc comment. Whitespace characters
* contained within such a segment is respected and preserved in the formatted output
* (e.g. when converted to HTML).
*
* @author Joseph Wong
*/
public static final class Preformatted extends TextSegment {
/**
* The segments which constitute this preformatted segment. Note that inline tag
* segments can appear within a preformatted segment.
*/
private final TopLevel[] segments;
/**
* Creates a new source model element for representing a preformatted text segment in a CALDoc comment.
*
* @param segments the segments which constitute this preformatted segment.
*/
private Preformatted(TopLevel[] segments) {
super(null);
if (segments == null || segments.length == 0) {
this.segments = TopLevel.NO_SEGMENTS;
} else {
this.segments = segments.clone();
verifyArrayArg(this.segments, "segments");
}
}
/**
* Factory method for constructing a new source model element for representing a preformatted text segment
* in a CALDoc comment.
*
* @param segments the segments which constitute this preformatted segment.
* @return a new instance of this class.
*/
public static Preformatted make(TopLevel[] segments) {
return new Preformatted(segments);
}
/**
* @return the segments which constitute this preformatted segment.
*/
public TextSegment.TopLevel[] getSegments() {
if (segments.length == 0) {
return TextSegment.TopLevel.NO_SEGMENTS;
}
return segments.clone();
}
/**
* @return the number of segments which constitute this preformatted segment.
*/
public int getNSegments() {
return segments.length;
}
/**
* Returns the segment at the specified position in the array of constituent segments.
* @param n the index of the segment to return.
* @return the segment at the specified position in the array of constituent segments.
*/
public TextSegment.TopLevel getNthSegment(int n) {
return segments[n];
}
/**
* {@inheritDoc}
*/
void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode wrapperNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_PREFORMATTED_BLOCK, "CALDOC_TEXT_PREFORMATTED_BLOCK");
parentNode.addChild(wrapperNode);
for (final TopLevel segment : segments) {
segment.addToParseTree(wrapperNode);
}
}
/**
* {@inheritDoc}
*/
boolean spansMultipleLines() {
for (final TopLevel segment : segments) {
if (segment.spansMultipleLines()) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_Preformatted(this, arg);
}
}
/**
* Base class for an inline tag segment in a CALDoc comment.
*
* @author Joseph Wong
*/
public static abstract class InlineTag extends TopLevel {
/**
* Base class for an inline tag segment whose content is simply a TextBlock. This represents
* a common kind of inline tag segments in CALDoc.
*
* @author Joseph Wong
*/
public static abstract class InlineTagWithTextBlockContent extends InlineTag {
/**
* The text block which forms the content of this segment.
*/
private final TextBlock content;
/**
* Private constructor for this base class for inline tag segments whose content is simply
* a TextBlock. Intended only to be invoked by subclass constructors.
*
* @param content the text block which forms the content of this segment.
*/
private InlineTagWithTextBlockContent(TextBlock content) {
super(null);
verifyArg(content, "content");
this.content = content;
}
/**
* @return the text block which forms the content of this segment.
*/
public final TextBlock getContent() {
return content;
}
/**
* @return the name of the inline tag.
*/
public abstract String getTagName();
/**
* @return the parse tree node for the inline tag itself.
* (In particular the first child of the CALDOC_TEXT_INLINE_BLOCK node.)
*/
abstract ParseTreeNode makeInlineTagNode();
/**
* {@inheritDoc}
*/
final void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode inlineBlockNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK, "CALDOC_TEXT_INLINE_BLOCK");
ParseTreeNode inlineTagNode = makeInlineTagNode();
ParseTreeNode contentNode = content.toParseTreeNode();
parentNode.addChild(inlineBlockNode);
inlineBlockNode.setFirstChild(inlineTagNode);
inlineTagNode.setFirstChild(contentNode);
}
/**
* {@inheritDoc}
*/
final boolean spansMultipleLines() {
return content.spansMultipleLines();
}
}
/**
* Base class for an inline tag segment whose content is simply a preformatted text segment.
*
* @author Joseph Wong
*/
public static abstract class InlineTagWithPreformattedContent extends InlineTag {
/**
* The preformatted text segment which forms the content of this segment.
*/
private final Preformatted content;
/**
* Private constructor for this base class for inline tag segments whose content is simply
* a preformatted text segment. Intended only to be invoked by subclass constructors.
*
* @param content the preformatted text segment which forms the content of this segment.
*/
private InlineTagWithPreformattedContent(Preformatted content) {
super(null);
verifyArg(content, "content");
this.content = content;
}
/**
* @return the preformatted text segment which forms the content of this segment.
*/
public final Preformatted getContent() {
return content;
}
/**
* @return the name of the inline tag.
*/
public abstract String getTagName();
/**
* @return the parse tree node for the inline tag itself.
* (In particular the first child of the CALDOC_TEXT_INLINE_BLOCK node.)
*/
abstract ParseTreeNode makeInlineTagNode();
/**
* {@inheritDoc}
*/
final void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode inlineBlockNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK, "CALDOC_TEXT_INLINE_BLOCK");
ParseTreeNode inlineTagNode = makeInlineTagNode();
parentNode.addChild(inlineBlockNode);
inlineBlockNode.setFirstChild(inlineTagNode);
content.addToParseTree(inlineTagNode);
}
/**
* {@inheritDoc}
*/
final boolean spansMultipleLines() {
return content.spansMultipleLines();
}
}
/**
* Models a "@url" CALDoc inline tag segment. This represents a hyperlinkable URL in a CALDoc comment.
*
* @author Joseph Wong
*/
public static final class URL extends InlineTag {
/**
* The plain text content of the inline tag segment.
*/
private final Plain content;
/**
* Creates a new source model element for representing a "@url" CALDoc inline tag segment.
*
* @param content the plain text content of the inline tag segment.
*/
private URL(Plain content) {
super(null);
verifyArg(content, "content");
this.content = content;
}
/**
* Factory method for constructing a new source model element for representing a "@url" CALDoc
* inline tag segment.
*
* @param content the plain text content of the inline tag segment.
* @return a new instance of this class.
*/
public static URL make(Plain content) {
return new URL(content);
}
/**
* @return the plain text content of the inline tag segment.
*/
public Plain getContent() {
return content;
}
/**
* {@inheritDoc}
*/
void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode inlineBlockNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK, "CALDOC_TEXT_INLINE_BLOCK");
ParseTreeNode urlNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_URL, "CALDOC_TEXT_URL");
ParseTreeNode withoutInlineTagsNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_BLOCK_WITHOUT_INLINE_TAGS, "CALDOC_TEXT_BLOCK_WITHOUT_INLINE_TAGS");
parentNode.addChild(inlineBlockNode);
inlineBlockNode.setFirstChild(urlNode);
urlNode.setFirstChild(withoutInlineTagsNode);
content.addToParseTree(withoutInlineTagsNode);
}
/**
* {@inheritDoc}
*/
final boolean spansMultipleLines() {
return content.spansMultipleLines();
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_URL(this, arg);
}
}
/**
* Models a "@link" CALDoc inline tag segment. This represents an inline cross-reference in a CALDoc comment.
* There are several different varieties of this inline tag segment. For "@link" segments with context,
* each of the varieties correspond to a different context under which the name is to be resolved, e.g. "{at-link module = Prelude at-}",
* or "{at-link typeClass = Prelude.Eq at-}". (Replace 'at-' with '@' in preceding examples.)
*
* @author Joseph Wong
*/
public static abstract class Link extends InlineTag {
/**
* Models a "@link" CALDoc inline tag segment without a context.
*
* e.g {at-link Nothing at-}, {at-link Prelude.Int at-}, {at-link compare at-}, {at-link "List.map" at-}
*/
public static abstract class WithoutContext extends Link {
private WithoutContext(SourceRange sourceRange) {
super(sourceRange);
}
/**
* {@inheritDoc}
*/
final void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode inlineBlockNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK, "CALDOC_TEXT_INLINE_BLOCK");
ParseTreeNode linkNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK, "CALDOC_TEXT_LINK");
ParseTreeNode contextNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK_WITHOUT_CONTEXT, "CALDOC_TEXT_LINK_WITHOUT_CONTEXT");
ParseTreeNode refNode = getAbstractCrossReference().toParseTreeNode();
parentNode.addChild(inlineBlockNode);
inlineBlockNode.setFirstChild(linkNode);
linkNode.setFirstChild(contextNode);
contextNode.setFirstChild(refNode);
}
/**
* {@inheritDoc}
*/
final boolean spansMultipleLines() {
return false;
}
/**
* @return the cross-reference encapsualted by this instance.
*/
abstract CrossReference getAbstractCrossReference();
}
/**
* Models a "@link" CALDoc inline tag segment without a context and containing an identifier
* starting with an uppercase character.
*
* e.g {at-link Nothing at-}, {at-link Prelude.Int at-}, {at-link "Dynamic.Dynamic" at-}
*
* @author Joseph Wong
*/
public static final class ConsNameWithoutContext extends WithoutContext {
/**
* The cross-reference encapsulated by this instance.
*/
private final CrossReference.WithoutContextCons reference;
/**
* Creates a new source model element for representing a "@link" CALDoc inline tag segment
* without a context and containing an identifier starting with an uppercase character.
*
* @param reference the cross-reference encapsulated by this instance.
* @param sourceRange
*/
private ConsNameWithoutContext(CrossReference.WithoutContextCons reference, SourceRange sourceRange) {
super(sourceRange);
verifyArg(reference, "reference");
this.reference = reference;
}
/**
* Factory method for constructing a new source model element for representing a
* "@link" CALDoc inline tag segment without a context and containing an identifier
* starting with an uppercase character.
*
* @param reference the cross-reference encapsulated by this instance.
* @return a new instance of this class.
*/
public static ConsNameWithoutContext make(CrossReference.WithoutContextCons reference) {
return new ConsNameWithoutContext(reference, null);
}
static ConsNameWithoutContext makeAnnotated(CrossReference.WithoutContextCons reference, SourceRange sourceRange) {
return new ConsNameWithoutContext(reference, sourceRange);
}
/**
* @return the cross-reference encapsualted by this instance.
*/
public CrossReference.WithoutContextCons getReference() {
return reference;
}
/**
* {@inheritDoc}
*/
CrossReference getAbstractCrossReference() {
return reference;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Link_ConsNameWithoutContext(this, arg);
}
}
/**
* Models a "@link" CALDoc inline tag segment without a context and containing an identifier
* starting with a lowercase character.
*
* e.g {at-link compare at-}, {at-link Prelude.greaterThan at-}, {at-link "Debug.trace" at-}
*
* @author Joseph Wong
*/
public static final class FunctionWithoutContext extends WithoutContext {
/**
* The cross-reference encapsulated by this instance.
*/
private final CrossReference.Function reference;
/**
* Creates a new source model element for representing a "@link" CALDoc inline tag segment
* without a context and containing an identifier starting with a lowercase character.
*
* @param reference the cross-reference encapsulated by this instance.
*/
private FunctionWithoutContext(CrossReference.Function reference) {
super(null);
verifyArg(reference, "reference");
this.reference = reference;
}
/**
* Factory method for constructing a new source model element for representing a
* "@link" CALDoc inline tag segment without a context and containing an identifier
* starting with a lowercase character.
*
* @param reference the cross-reference encapsulated by this instance.
* @return a new instance of this class.
*/
public static FunctionWithoutContext make(CrossReference.Function reference) {
return new FunctionWithoutContext(reference);
}
/**
* @return the cross-reference encapsualted by this instance.
*/
public CrossReference.Function getReference() {
return reference;
}
/**
* {@inheritDoc}
*/
CrossReference getAbstractCrossReference() {
return reference;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Link_FunctionWithoutContext(this, arg);
}
}
/**
* Models a "@link" CALDoc inline tag segment with a context, i.e. currently one of:
* module, function, typeConstructor, dataConstructor, typeClass.
*
* There are several different varieties of this inline tag segment, each corresponding to a different context
* under which the name is to be resolved, e.g. "{at-link module = Prelude at-}",
* or "{at-link typeClass = Prelude.Eq at-}". (Replace 'at-' with '@' in preceding examples.)
*
* @author Joseph Wong
*/
public static abstract class WithContext extends Link {
private WithContext() {
super(null);
}
/**
* {@inheritDoc}
*/
final void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode inlineBlockNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK, "CALDOC_TEXT_INLINE_BLOCK");
ParseTreeNode linkNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK, "CALDOC_TEXT_LINK");
ParseTreeNode contextNode = makeContextNode();
ParseTreeNode refNode = getAbstractCrossReference().toParseTreeNode();
parentNode.addChild(inlineBlockNode);
inlineBlockNode.setFirstChild(linkNode);
linkNode.setFirstChild(contextNode);
contextNode.setFirstChild(refNode);
}
/**
* {@inheritDoc}
*/
final boolean spansMultipleLines() {
return false;
}
/**
* @return the parse tree node for the context.
*/
abstract ParseTreeNode makeContextNode();
/**
* @return the context keyword.
*/
abstract String getContextKeyword();
/**
* @return the cross-reference encapsualted by this instance.
*/
abstract CrossReference getAbstractCrossReference();
}
/**
* Models a "@link function = ..." CALDoc inline tag segment.
*
* @author Joseph Wong
*/
public static final class Function extends WithContext {
/**
* The cross-reference encapsulated by this instance.
*/
private final CrossReference.Function reference;
/**
* Creates a new source model element for representing a "@link function = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
*/
private Function(CrossReference.Function reference) {
verifyArg(reference, "reference");
this.reference = reference;
}
/**
* Factory method for constructing a new source model element for representing a
* "@link function = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
* @return a new instance of this class.
*/
public static Function make(CrossReference.Function reference) {
return new Function(reference);
}
/**
* @return the cross-reference encapsualted by this instance.
*/
public CrossReference.Function getReference() {
return reference;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeContextNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK_FUNCTION, "CALDOC_TEXT_LINK_FUNCTION");
}
/**
* {@inheritDoc}
*/
String getContextKeyword() {
return "function";
}
/**
* {@inheritDoc}
*/
CrossReference getAbstractCrossReference() {
return reference;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Link_Function(this, arg);
}
}
/**
* Models a "@link module = ..." CALDoc inline tag segment.
*
* @author Joseph Wong
*/
public static final class Module extends WithContext {
/**
* The cross-reference encapsulated by this instance.
*/
private final CrossReference.Module reference;
/**
* Creates a new source model element for representing a "@link module = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
*/
private Module(CrossReference.Module reference) {
verifyArg(reference, "reference");
this.reference = reference;
}
/**
* Factory method for constructing a new source model element for representing a
* "@link module = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
* @return a new instance of this class.
*/
public static Module make(CrossReference.Module reference) {
return new Module(reference);
}
/**
* @return the cross-reference encapsualted by this instance.
*/
public CrossReference.Module getReference() {
return reference;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeContextNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK_MODULE, "CALDOC_TEXT_LINK_MODULE");
}
/**
* {@inheritDoc}
*/
String getContextKeyword() {
return "module";
}
/**
* {@inheritDoc}
*/
CrossReference getAbstractCrossReference() {
return reference;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Link_Module(this, arg);
}
}
/**
* Models a "@link typeConstructor = ..." CALDoc inline tag segment.
*
* @author Joseph Wong
*/
public static final class TypeCons extends WithContext {
/**
* The cross-reference encapsulated by this instance.
*/
private final CrossReference.TypeCons reference;
/**
* Creates a new source model element for representing a "@link typeConstructor = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
*/
private TypeCons(CrossReference.TypeCons reference) {
verifyArg(reference, "reference");
this.reference = reference;
}
/**
* Factory method for constructing a new source model element for representing a
* "@link typeConstructor = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
* @return a new instance of this class.
*/
public static TypeCons make(CrossReference.TypeCons reference) {
return new TypeCons(reference);
}
/**
* @return the cross-reference encapsualted by this instance.
*/
public CrossReference.TypeCons getReference() {
return reference;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeContextNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK_TYPECONS, "CALDOC_TEXT_LINK_TYPECONS");
}
/**
* {@inheritDoc}
*/
String getContextKeyword() {
return "typeConstructor";
}
/**
* {@inheritDoc}
*/
CrossReference getAbstractCrossReference() {
return reference;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Link_TypeCons(this, arg);
}
}
/**
* Models a "@link dataConstructor = ..." CALDoc inline tag segment.
*
* @author Joseph Wong
*/
public static final class DataCons extends WithContext {
/**
* The cross-reference encapsulated by this instance.
*/
private final CrossReference.DataCons reference;
/**
* Creates a new source model element for representing a "@link dataConstructor = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
*/
private DataCons(CrossReference.DataCons reference) {
verifyArg(reference, "reference");
this.reference = reference;
}
/**
* Factory method for constructing a new source model element for representing a
* "@link dataConstructor = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
* @return a new instance of this class.
*/
public static DataCons make(CrossReference.DataCons reference) {
return new DataCons(reference);
}
/**
* @return the cross-reference encapsualted by this instance.
*/
public CrossReference.DataCons getReference() {
return reference;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeContextNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK_DATACONS, "CALDOC_TEXT_LINK_DATACONS");
}
/**
* {@inheritDoc}
*/
String getContextKeyword() {
return "dataConstructor";
}
/**
* {@inheritDoc}
*/
CrossReference getAbstractCrossReference() {
return reference;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Link_DataCons(this, arg);
}
}
/**
* Models a "@link typeClass = ..." CALDoc inline tag segment.
*
* @author Joseph Wong
*/
public static final class TypeClass extends WithContext {
/**
* The cross-reference encapsulated by this instance.
*/
private final CrossReference.TypeClass reference;
/**
* Creates a new source model element for representing a "@link typeClass = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
*/
private TypeClass(CrossReference.TypeClass reference) {
verifyArg(reference, "reference");
this.reference = reference;
}
/**
* Factory method for constructing a new source model element for representing a
* "@link typeClass = ..." CALDoc inline tag segment.
*
* @param reference the cross-reference encapsulated by this instance.
* @return a new instance of this class.
*/
public static TypeClass make(CrossReference.TypeClass reference) {
return new TypeClass(reference);
}
/**
* @return the cross-reference encapsualted by this instance.
*/
public CrossReference.TypeClass getReference() {
return reference;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeContextNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LINK_TYPECLASS, "CALDOC_TEXT_LINK_TYPECLASS");
}
/**
* {@inheritDoc}
*/
String getContextKeyword() {
return "typeClass";
}
/**
* {@inheritDoc}
*/
CrossReference getAbstractCrossReference() {
return reference;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Link_TypeClass(this, arg);
}
}
private Link(SourceRange sourceRange) {
super(sourceRange);
}
}
/**
* Base class for an inline tag segment for text formatting in CALDoc.
*
* @author Joseph Wong
*/
public static abstract class TextFormatting extends InlineTagWithTextBlockContent {
/**
* Private constructor for this base class for inline tag segments for text formatting.
* Intended only to be invoked by subclass constructors.
*
* @param content the text block which forms the content of this segment.
*/
private TextFormatting(TextBlock content) {
super(content);
}
/**
* Models an "@em" CALDoc inline tag segment. This represents an emphasized piece of text.
*
* @author Joseph Wong
*/
public static final class Emphasized extends TextFormatting {
/**
* The name of the "@em" tag.
*/
public static final String EM_TAG = "em";
/**
* Creates a new source model element for representing an "@em" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
*/
private Emphasized(TextBlock content) {
super(content);
}
/**
* Factory method for constructing a new source model element for representing
* an "@em" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
* @return a new instance of this class.
*/
public static Emphasized make(TextBlock content) {
return new Emphasized(content);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return EM_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_EMPHASIZED_TEXT, "CALDOC_TEXT_EMPHASIZED_TEXT");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_TextFormatting_Emphasized(this, arg);
}
}
/**
* Models a "@strong" CALDoc inline tag segment. This represents a strongly emphasized piece of text.
*
* @author Joseph Wong
*/
public static final class StronglyEmphasized extends TextFormatting {
/**
* The name of the "@strong" tag.
*/
public static final String STRONG_TAG = "strong";
/**
* Creates a new source model element for representing a "@strong" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
*/
private StronglyEmphasized(TextBlock content) {
super(content);
}
/**
* Factory method for constructing a new source model element for representing
* a "@strong" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
* @return a new instance of this class.
*/
public static StronglyEmphasized make(TextBlock content) {
return new StronglyEmphasized(content);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return STRONG_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_STRONGLY_EMPHASIZED_TEXT, "CALDOC_TEXT_STRONGLY_EMPHASIZED_TEXT");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_TextFormatting_StronglyEmphasized(this, arg);
}
}
/**
* Models a "@sup" CALDoc inline tag segment. This represents a superscripted piece of text.
*
* @author Joseph Wong
*/
public static final class Superscript extends TextFormatting {
/**
* The name of the "@sup" tag.
*/
public static final String SUP_TAG = "sup";
/**
* Creates a new source model element for representing a "@sup" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
*/
private Superscript(TextBlock content) {
super(content);
}
/**
* Factory method for constructing a new source model element for representing
* a "@sup" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
* @return a new instance of this class.
*/
public static Superscript make(TextBlock content) {
return new Superscript(content);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return SUP_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_SUPERSCRIPT_TEXT, "CALDOC_TEXT_SUPERSCRIPT_TEXT");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_TextFormatting_Superscript(this, arg);
}
}
/**
* Models a "@sub" CALDoc inline tag segment. This represents a subscripted piece of text.
*
* @author Joseph Wong
*/
public static final class Subscript extends TextFormatting {
/**
* The name of the "@sub" tag.
*/
public static final String SUB_TAG = "sub";
/**
* Creates a new source model element for representing a "@sub" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
*/
private Subscript(TextBlock content) {
super(content);
}
/**
* Factory method for constructing a new source model element for representing
* a "@sub" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
* @return a new instance of this class.
*/
public static Subscript make(TextBlock content) {
return new Subscript(content);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return SUB_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_SUBSCRIPT_TEXT, "CALDOC_TEXT_SUBSCRIPT_TEXT");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_TextFormatting_Subscript(this, arg);
}
}
}
/**
* Models a "@summary" CALDoc inline tag segment. This represents a piece of text to be included in the
* CALDoc comment's summary.
*
* @author Joseph Wong
*/
public static final class Summary extends InlineTagWithTextBlockContent {
/**
* The name of the "@summary" tag.
*/
public static final String SUMMARY_TAG = "summary";
/**
* Creates a new source model element for representing a "@summary" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
*/
private Summary(TextBlock content) {
super(content);
}
/**
* Factory method for constructing a new source model element for representing
* a "@summary" CALDoc inline tag segment.
*
* @param content the text block which forms the content of this segment.
* @return a new instance of this class.
*/
public static Summary make(TextBlock content) {
return new Summary(content);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return SUMMARY_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_SUMMARY, "CALDOC_TEXT_SUMMARY");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Summary(this, arg);
}
}
/**
* Models a "@code" CALDoc inline tag segment. This represents a block of preformatted code in a CALDoc comment.
*
* @author Joseph Wong
*/
public static final class Code extends InlineTagWithPreformattedContent {
/**
* The name of the "@code" tag.
*/
public static final String CODE_TAG = "code";
/**
* Creates a new source model element for representing a "@code" CALDoc inline tag segment.
*
* @param content the preformatted text segment which forms the content of this segment.
*/
private Code(Preformatted content) {
super(content);
}
/**
* Factory method for constructing a new source model element for representing
* a "@code" CALDoc inline tag segment.
*
* @param content the preformatted text segment which forms the content of this segment.
* @return a new instance of this class.
*/
public static Code make(Preformatted content) {
return new Code(content);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return CODE_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_CODE_BLOCK, "CALDOC_TEXT_CODE_BLOCK");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_Code(this, arg);
}
}
/**
* Base class for an inline tag segment for representing a list in a CALDoc comment.
*
* @author Joseph Wong
*/
public static abstract class List extends InlineTag {
/**
* The items contained in the list.
*/
private final Item[] items;
/** An empty Item array. */
public static final Item[] NO_ITEMS = new Item[0];
/**
* Models an unordered list in a CALDoc comment.
*
* @author Joseph Wong
*/
public static final class Unordered extends List {
/**
* The name of the inline tag.
*/
public static final String UNORDERED_LIST_TAG = "unorderedList";
/**
* Creates a new source model element for representing an unordered list in a CALDoc comment.
*
* @param items the items contained in the list.
*/
private Unordered(Item[] items) {
super(items);
}
/**
* Factory method for constructing a new source model element for representing an unordered list
* in a CALDoc comment.
*
* @param items the items contained in the list.
* @return a new instance of this class.
*/
public static Unordered make(Item[] items) {
return new Unordered(items);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return UNORDERED_LIST_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_UNORDERED_LIST, "CALDOC_TEXT_UNORDERED_LIST");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_List_Unordered(this, arg);
}
}
/**
* Models an ordered list in a CALDoc comment.
*
* @author Joseph Wong
*/
public static final class Ordered extends List {
/**
* The name of the inline tag.
*/
public static final String ORDERED_LIST_TAG = "orderedList";
/**
* Creates a new source model element for representing an ordered list in a CALDoc comment.
*
* @param items the items contained in the list.
*/
private Ordered(Item[] items) {
super(items);
}
/**
* Factory method for constructing a new source model element for representing an ordered list
* in a CALDoc comment.
*
* @param items the items contained in the list.
* @return a new instance of this class.
*/
public static Ordered make(Item[] items) {
return new Ordered(items);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return ORDERED_LIST_TAG;
}
/**
* {@inheritDoc}
*/
ParseTreeNode makeInlineTagNode() {
return new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_ORDERED_LIST, "CALDOC_TEXT_ORDERED_LIST");
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_List_Ordered(this, arg);
}
}
/**
* Models a list item in a CALDoc comment.
*
* @author Joseph Wong
*/
public static final class Item extends TextSegment {
/**
* The text block which forms the content of this list item.
*/
private final TextBlock content;
/**
* Creates a new source model element for representing a list item in a CALDoc comment.
*
* @param content the text block which forms the content of this list item.
*/
private Item(TextBlock content) {
super(null);
verifyArg(content, "content");
this.content = content;
}
/**
* Factory method for constructing a new source model element for representing a list item
* in a CALDoc comment.
*
* @param content the text block which forms the content of this list item.
* @return a new instance of this class.
*/
public static Item make(TextBlock content) {
return new Item(content);
}
/**
* @return the text block which forms the content of this segment.
*/
public TextBlock getContent() {
return content;
}
/**
* {@inheritDoc}
*/
void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode itemNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_LIST_ITEM, "CALDOC_TEXT_LIST_ITEM");
ParseTreeNode contentNode = content.toParseTreeNode();
parentNode.addChild(itemNode);
itemNode.setFirstChild(contentNode);
}
/**
* {@inheritDoc}
*/
boolean spansMultipleLines() {
return content.spansMultipleLines();
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextSegment_InlineTag_List_Item(this, arg);
}
}
/**
* Private constructor for this base class for inline tag segments representing lists
* in a CALDoc comment. Intended only to be invoked by subclass constructors.
*
* @param items the items contained in the list.
*/
private List(Item[] items) {
super(null);
if (items == null || items.length == 0) {
this.items = NO_ITEMS;
} else {
this.items = items.clone();
verifyArrayArg(this.items, "items");
}
}
/**
* @return the items in the list.
*/
public final Item[] getItems() {
if (items.length == 0) {
return NO_ITEMS;
}
return items.clone();
}
/**
* @return the number of items in the list.
*/
public final int getNItems() {
return items.length;
}
/**
* Returns the item at the specified position in the array of items.
* @param n the index of the item to return.
* @return the item at the specified position in the array of items.
*/
public final Item getNthItem(int n) {
return items[n];
}
/**
* @return the name of the inline tag.
*/
public abstract String getTagName();
/**
* @return the parse tree node for the inline tag itself.
* (In particular the first child of the CALDOC_TEXT_INLINE_BLOCK node.)
*/
abstract ParseTreeNode makeInlineTagNode();
/**
* {@inheritDoc}
*/
final void addToParseTree(ParseTreeNode parentNode) {
ParseTreeNode inlineBlockNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK, "CALDOC_TEXT_INLINE_BLOCK");
ParseTreeNode inlineTagNode = makeInlineTagNode();
parentNode.addChild(inlineBlockNode);
inlineBlockNode.setFirstChild(inlineTagNode);
for (final Item item : items) {
item.addToParseTree(inlineTagNode);
}
}
/**
* {@inheritDoc}
*/
final boolean spansMultipleLines() {
return true;
}
}
private InlineTag(SourceRange sourceRange) {
super(sourceRange);
}
}
private TextSegment(SourceRange sourceRange) {
super(sourceRange);
}
/**
* {@inheritDoc}
*/
final ParseTreeNode toParseTreeNode() {
ParseTreeNode listNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT, "CALDOC_TEXT");
addToParseTree(listNode);
return listNode.firstChild();
}
/**
* Adds to the given parse tree node the subtree representing this instance.
* @param parentNode the node to which the subtree is to be added as a child.
*/
abstract void addToParseTree(ParseTreeNode parentNode);
/**
* @return whether the comment text spans multiple source lines.
*/
abstract boolean spansMultipleLines();
}
/**
* Models a block of text segments within a CALDoc comment. The description block of
* a CALDoc comment is a TextBlock, and so are the descriptions contained with
* a number of the tagged blocks.
*
* @author Joseph Wong
*/
public static final class TextBlock extends InteriorIndentable {
/**
* The text segments which constitute this text block.
*/
private final TextSegment.TopLevel[] segments;
/**
* Creates a new source model element for representing a block of text segments within a CALDoc comment.
*
* @param segments the segments which constitute this text block.
*/
private TextBlock(TextSegment.TopLevel[] segments) {
super(null);
if (segments == null || segments.length == 0) {
this.segments = TextSegment.TopLevel.NO_SEGMENTS;
} else {
this.segments = segments.clone();
verifyArrayArg(this.segments, "segments");
}
}
/**
* Factory method for constructing a new source model element for representing a block of text segments
* within a CALDoc comment.
*
* @param segments the segments which constitute this text block.
* @return a new instance of this class.
*/
public static TextBlock make(TextSegment.TopLevel[] segments) {
return new TextBlock(segments);
}
/**
* @return the text segments which constitute this text block.
*/
public TextSegment.TopLevel[] getSegments() {
if (segments.length == 0) {
return TextSegment.TopLevel.NO_SEGMENTS;
}
return segments.clone();
}
/**
* @return the number of text segments in this text block.
*/
public int getNSegments() {
return segments.length;
}
/**
* Returns the text segment at the specified position in the array of constituent segments.
* @param n the index of the segment to return.
* @return the text segment at the specified position in the array of constituent segments.
*/
public TextSegment.TopLevel getNthSegment(int n) {
return segments[n];
}
/**
* @return whether the comment text spans multiple source lines.
*/
public boolean spansMultipleLines() {
for (final TopLevel segment : segments) {
if (segment.spansMultipleLines()) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode textNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_TEXT, "CALDOC_TEXT");
for (final TopLevel segment : segments) {
segment.addToParseTree(textNode);
}
return textNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TextBlock(this, arg);
}
}
/**
* Models a tagged block in a CALDoc comment. A tagged block is a special block
* which starts with a tag, and a tag is one of a few special keywords within the
* CALDoc grammar, and all tags start with the character '@'.
*
* @author Joseph Wong
*/
public static abstract class TaggedBlock extends CALDoc {
private TaggedBlock(SourceRange sourceRange) {
super(sourceRange);
}
/**
* @return the string representation of the tag encapsulated by this class.
*/
public abstract String getTagName();
/**
* Models a common kind of tagged blocks in CALDoc: one which ends with a text block.
*
* @author Joseph Wong
*/
public static abstract class TaggedBlockWithText extends TaggedBlock {
/** The text block that forms the trailing portion of this tagged block. */
private final TextBlock textBlock;
/**
* Private constructor for this base class for tagged blocks in
* CALDoc that ends with a text block. Intended only to be
* invoked by subclass constructors.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
*/
private TaggedBlockWithText(TextBlock textBlock) {
super(null);
verifyArg(textBlock, "textBlock");
this.textBlock = textBlock;
}
/**
* @return the text block that forms the trailing portion of this tagged block.
*/
public TextBlock getTextBlock() {
return textBlock;
}
}
/**
* Models the "@author" CALDoc tag.
*
* @author Joseph Wong
*/
public static final class Author extends TaggedBlockWithText {
/** The string representation of the "@author" tag. */
public static final String AUTHOR_TAG = "@author";
/**
* Creates a source model element that represents an "@author"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
*/
private Author(TextBlock textBlock) {
super(textBlock);
}
/**
* Factory method for constructing a source model element that represents an "@author"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
* @return a new instance of this class.
*/
public static Author make(TextBlock textBlock) {
return new Author(textBlock);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return AUTHOR_TAG;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_Author(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode authorNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_AUTHOR_BLOCK, "CALDOC_AUTHOR_BLOCK");
authorNode.setFirstChild(getTextBlock().toParseTreeNode());
return authorNode;
}
}
/**
* Models the "@deprecated" CALDoc tag.
*
* @author Joseph Wong
*/
public static final class Deprecated extends TaggedBlockWithText {
/** The string representation of the "@deprecated" tag. */
public static final String DEPRECATED_TAG = "@deprecated";
/**
* Creates a source model element that represents an "@deprecated"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
*/
private Deprecated(TextBlock textBlock) {
super(textBlock);
}
/**
* Factory method for constructing a source model element that represents an "@deprecated"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
* @return a new instance of this class.
*/
public static Deprecated make(TextBlock textBlock) {
return new Deprecated(textBlock);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return DEPRECATED_TAG;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_Deprecated(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode deprecatedNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_DEPRECATED_BLOCK, "CALDOC_DEPRECATED_BLOCK");
deprecatedNode.setFirstChild(getTextBlock().toParseTreeNode());
return deprecatedNode;
}
}
/**
* Models the "@return" CALDoc tag.
*
* @author Joseph Wong
*/
public static final class Return extends TaggedBlockWithText {
/** The string representation of the "@return" tag. */
public static final String RETURN_TAG = "@return";
/**
* Creates a source model element that represents an "@return"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
*/
private Return(TextBlock textBlock) {
super(textBlock);
}
/**
* Factory method for constructing a source model element that represents an "@return"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
* @return a new instance of this class.
*/
public static Return make(TextBlock textBlock) {
return new Return(textBlock);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return RETURN_TAG;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_Return(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode returnNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_RETURN_BLOCK, "CALDOC_RETURN_BLOCK");
returnNode.setFirstChild(getTextBlock().toParseTreeNode());
return returnNode;
}
}
/**
* Models the "@version" CALDoc tag.
*
* @author Joseph Wong
*/
public static final class Version extends TaggedBlockWithText {
/** The string representation of the "@version" tag. */
public static final String VERSION_TAG = "@version";
/**
* Creates a source model element that represents an "@version"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
*/
private Version(TextBlock textBlock) {
super(textBlock);
}
/**
* Factory method for constructing a source model element that represents an "@version"
* block in a CALDoc comment.
*
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
* @return a new instance of this class.
*/
public static Version make(TextBlock textBlock) {
return new Version(textBlock);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return VERSION_TAG;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_Version(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode versionNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_VERSION_BLOCK, "CALDOC_VERSION_BLOCK");
versionNode.setFirstChild(getTextBlock().toParseTreeNode());
return versionNode;
}
}
/**
* Models the "@arg" CALDoc tag. The tagged block contains a reference to an argument name,
* and is therefore valid only for a CALDoc function comment or a CALDoc data constructor
* comment.
*
* @author Joseph Wong
*/
public static final class Arg extends TaggedBlockWithText {
/** The string representation of the "@arg" tag. */
public static final String ARG_TAG = "@arg";
/** The name of the argument referenced by this "@arg" tag. */
private final Name.Field argName;
/**
* Creates a source model element that represents an "@arg"
* block in a CALDoc comment.
*
* @param argName
* the name of the argument referenced by this tagged block.
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
*/
private Arg(Name.Field argName, TextBlock textBlock) {
super(textBlock);
this.argName = argName;
}
/**
* Factory method for constructing a source model element that represents an "@arg"
* block in a CALDoc comment.
*
* @param argName
* the name of the argument referenced by this tagged block.
* @param textBlock
* the text block that forms the trailing portion of
* this tagged block.
* @return a new instance of this class.
*/
public static Arg make(Name.Field argName, TextBlock textBlock) {
return new Arg(argName, textBlock);
}
/**
* {@inheritDoc}
*/
public String getTagName() {
return ARG_TAG;
}
/**
* @return the name of the argument referenced by this "@arg" tag.
*/
public Name.Field getArgName() {
return argName;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_Arg(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode argNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_ARG_BLOCK, "CALDOC_ARG_BLOCK");
ParseTreeNode argNameNode = argName.toParseTreeNode();
argNode.setFirstChild(argNameNode);
argNameNode.setNextSibling(getTextBlock().toParseTreeNode());
return argNode;
}
}
/**
* Models the "@see" CALDoc tag. There are several different varieties of this
* tagged block, each corresponding to a different context under which
* the listed names are to be resolved, e.g. "@see module = Prelude, Debug",
* or "@see typeClass = Prelude.Eq, Debug.Show". A "@see" block can also appear
* without the context keyword, e.g. "@see List.map".
*
* @author Joseph Wong
*/
public static abstract class See extends TaggedBlock {
private See(SourceRange sourceRange) {
super(sourceRange);
}
/** The string representation of the "@see" tag. */
public static final String SEE_TAG = "@see";
/**
* {@inheritDoc}
*/
public String getTagName() {
return SEE_TAG;
}
/**
* Models a CALDoc "@see function = ..." block.
*
* @author Joseph Wong
*/
public static final class Function extends See {
/**
* The non-empty array of function names.
*/
private final CrossReference.Function[] functionNames;
/**
* Creates a source model element for representing a CALDoc "@see function = ..." block.
*
* @param functionNames a non-empty array of function names referenced by this "@see" block.
*/
private Function(CrossReference.Function[] functionNames) {
super(null);
if (functionNames.length == 0) {
throw new IllegalArgumentException("Must have at least one name in the @see function list");
}
this.functionNames = functionNames.clone();
verifyArrayArg(this.functionNames, "functionNames");
}
/**
* Factory method for constructing a source model element for representing a CALDoc "@see function = ..." block.
*
* @param functionNames a non-empty array of function names referenced by this "@see" block.
* @return a new instance of this class.
*/
public static Function make(CrossReference.Function[] functionNames) {
return new Function(functionNames);
}
/**
* @return the non-empty array of function names referenced by this "@see" block.
*/
public CrossReference.Function[] getFunctionNames() {
return functionNames.clone();
}
/**
* @return the number of function names referenced by this "@see" block.
*/
public int getNFunctionNames() {
return functionNames.length;
}
/**
* Returns the function name at the specified position in this "@see" block.
* @param n index of the function name to return.
* @return the function name at the specified position in this "@see" block.
*/
public CrossReference.Function getNthFunctionName(int n) {
return functionNames[n];
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_See_Function(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode seeNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_BLOCK, "CALDOC_SEE_BLOCK");
ParseTreeNode functionNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_FUNCTION_BLOCK, "CALDOC_SEE_FUNCTION_BLOCK");
ParseTreeNode[] children = new ParseTreeNode[functionNames.length];
for (int i = 0; i < functionNames.length; i++) {
children[i] = functionNames[i].toParseTreeNode();
}
functionNode.addChildren(children);
seeNode.setFirstChild(functionNode);
return seeNode;
}
}
/**
* Models a CALDoc "@see module = ..." block.
*
* @author Joseph Wong
*/
public static final class Module extends See {
/**
* The non-empty array of module names.
*/
private final CrossReference.Module[] moduleNames;
/**
* Creates a source model element for representing a CALDoc "@see module = ..." block.
*
* @param moduleNames a non-empty array of module names referenced by this "@see" block.
*/
private Module(CrossReference.Module[] moduleNames) {
super(null);
if (moduleNames.length == 0) {
throw new IllegalArgumentException("Must have at least one name in the @see module list");
}
this.moduleNames = moduleNames.clone();
verifyArrayArg(this.moduleNames, "moduleNames");
}
/**
* Factory method for constructing a source model element for representing a CALDoc "@see module = ..." block.
*
* @param moduleNames a non-empty array of module names referenced by this "@see" block.
* @return a new instance of this class.
*/
public static Module make(CrossReference.Module[] moduleNames) {
return new Module(moduleNames);
}
/**
* @return the non-empty array of module names referenced by this "@see" block.
*/
public CrossReference.Module[] getModuleNames() {
return moduleNames.clone();
}
/**
* @return the number of module names referenced by this "@see" block.
*/
public int getNModuleNames() {
return moduleNames.length;
}
/**
* Returns the module name at the specified position in this "@see" block.
* @param n index of the module name to return.
* @return the module name at the specified position in this "@see" block.
*/
public CrossReference.Module getNthModuleName(int n) {
return moduleNames[n];
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_See_Module(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode seeNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_BLOCK, "CALDOC_SEE_BLOCK");
ParseTreeNode moduleNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_MODULE_BLOCK, "CALDOC_SEE_MODULE_BLOCK");
ParseTreeNode[] children = new ParseTreeNode[moduleNames.length];
for (int i = 0; i < moduleNames.length; i++) {
children[i] = moduleNames[i].toParseTreeNode();
}
moduleNode.addChildren(children);
seeNode.setFirstChild(moduleNode);
return seeNode;
}
}
/**
* Models a CALDoc "@see typeConstructor = ..." block.
*
* @author Joseph Wong
*/
public static final class TypeCons extends See {
/**
* The non-empty array of type constructor names.
*/
private final CrossReference.TypeCons[] typeConsNames;
/**
* Creates a source model element for representing a CALDoc "@see typeConstructor = ..." block.
*
* @param typeConsNames a non-empty array of type constructor names referenced by this "@see" block.
*/
private TypeCons(CrossReference.TypeCons[] typeConsNames) {
super(null);
if (typeConsNames.length == 0) {
throw new IllegalArgumentException("Must have at least one name in the @see typeConstructor list");
}
this.typeConsNames = typeConsNames.clone();
verifyArrayArg(this.typeConsNames, "typeConsNames");
}
/**
* Factory method for constructing a source model element for representing a CALDoc "@see typeConstructor = ..." block.
*
* @param typeConsNames a non-empty array of type constructor names referenced by this "@see" block.
* @return a new instance of this class.
*/
public static TypeCons make(CrossReference.TypeCons[] typeConsNames) {
return new TypeCons(typeConsNames);
}
/**
* @return the non-empty array of type constructor names referenced by this "@see" block.
*/
public CrossReference.TypeCons[] getTypeConsNames() {
return typeConsNames.clone();
}
/**
* @return the number of type constructor names referenced by this "@see" block.
*/
public int getNTypeConsNames() {
return typeConsNames.length;
}
/**
* Returns the type constructor name at the specified position in this "@see" block.
* @param n index of the type constructor name to return.
* @return the type constructor name at the specified position in this "@see" block.
*/
public CrossReference.TypeCons getNthTypeConsName(int n) {
return typeConsNames[n];
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_See_TypeCons(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode seeNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_BLOCK, "CALDOC_SEE_BLOCK");
ParseTreeNode typeConsNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_TYPECONS_BLOCK, "CALDOC_SEE_TYPECONS_BLOCK");
ParseTreeNode[] children = new ParseTreeNode[typeConsNames.length];
for (int i = 0; i < typeConsNames.length; i++) {
children[i] = typeConsNames[i].toParseTreeNode();
}
typeConsNode.addChildren(children);
seeNode.setFirstChild(typeConsNode);
return seeNode;
}
}
/**
* Models a CALDoc "@see dataConstructor = ..." block.
*
* @author Joseph Wong
*/
public static final class DataCons extends See {
/**
* The non-empty array of data constructor names.
*/
private final CrossReference.DataCons[] dataConsNames;
/**
* Creates a source model element for representing a CALDoc "@see dataConstructor = ..." block.
*
* @param dataConsNames a non-empty array of data constructor names referenced by this "@see" block.
*/
private DataCons(CrossReference.DataCons[] dataConsNames) {
super(null);
if (dataConsNames.length == 0) {
throw new IllegalArgumentException("Must have at least one name in the @see dataCons list");
}
this.dataConsNames = dataConsNames.clone();
verifyArrayArg(this.dataConsNames, "dataConsNames");
}
/**
* Factory method for constructing a source model element for representing a CALDoc "@see dataConstructor = ..." block.
*
* @param dataConsNames a non-empty array of data constructor names referenced by this "@see" block.
* @return a new instance of this class.
*/
public static DataCons make(CrossReference.DataCons[] dataConsNames) {
return new DataCons(dataConsNames);
}
/**
* @return the non-empty array of data constructor names referenced by this "@see" block.
*/
public CrossReference.DataCons[] getDataConsNames() {
return dataConsNames.clone();
}
/**
* @return the number of data constructor names referenced by this "@see" block.
*/
public int getNDataConsNames() {
return dataConsNames.length;
}
/**
* Returns the data constructor name at the specified position in this "@see" block.
* @param n index of the data constructor name to return.
* @return the data constructor name at the specified position in this "@see" block.
*/
public CrossReference.DataCons getNthDataConsName(int n) {
return dataConsNames[n];
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_See_DataCons(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode seeNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_BLOCK, "CALDOC_SEE_BLOCK");
ParseTreeNode dataConsNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_DATACONS_BLOCK, "CALDOC_SEE_DATACONS_BLOCK");
ParseTreeNode[] children = new ParseTreeNode[dataConsNames.length];
for (int i = 0; i < dataConsNames.length; i++) {
children[i] = dataConsNames[i].toParseTreeNode();
}
dataConsNode.addChildren(children);
seeNode.setFirstChild(dataConsNode);
return seeNode;
}
}
/**
* Models a CALDoc "@see typeClass = ..." block.
*
* @author Joseph Wong
*/
public static final class TypeClass extends See {
/**
* The non-empty array of type class names.
*/
private final CrossReference.TypeClass[] typeClassNames;
/**
* Creates a source model element for representing a CALDoc "@see typeClass = ..." block.
*
* @param typeClassNames a non-empty array of type class names referenced by this "@see" block.
*/
private TypeClass(CrossReference.TypeClass[] typeClassNames) {
super(null);
if (typeClassNames.length == 0) {
throw new IllegalArgumentException("Must have at least one name in the @see typeClass list");
}
this.typeClassNames = typeClassNames.clone();
verifyArrayArg(this.typeClassNames, "typeClassNames");
}
/**
* Factory method for constructing a source model element for representing a CALDoc "@see typeClass = ..." block.
*
* @param typeClassNames a non-empty array of type class names referenced by this "@see" block.
* @return a new instance of this class.
*/
public static TypeClass make(CrossReference.TypeClass[] typeClassNames) {
return new TypeClass(typeClassNames);
}
/**
* @return the non-empty array of type class names referenced by this "@see" block.
*/
public CrossReference.TypeClass[] getTypeClassNames() {
return typeClassNames.clone();
}
/**
* @return the number of type class names referenced by this "@see" block.
*/
public int getNTypeClassNames() {
return typeClassNames.length;
}
/**
* Returns the type class name at the specified position in this "@see" block.
* @param n index of the type class name to return.
* @return the type class name at the specified position in this "@see" block.
*/
public CrossReference.TypeClass getNthTypeClassName(int n) {
return typeClassNames[n];
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_See_TypeClass(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode seeNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_BLOCK, "CALDOC_SEE_BLOCK");
ParseTreeNode typeClassNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_TYPECLASS_BLOCK, "CALDOC_SEE_TYPECLASS_BLOCK");
ParseTreeNode[] children = new ParseTreeNode[typeClassNames.length];
for (int i = 0; i < typeClassNames.length; i++) {
children[i] = typeClassNames[i].toParseTreeNode();
}
typeClassNode.addChildren(children);
seeNode.setFirstChild(typeClassNode);
return seeNode;
}
}
/**
* Models a CALDoc "@see" block without the context keyword.
*
* @author Joseph Wong
*/
public static final class WithoutContext extends See {
/**
* The non-empty array of referenced names.
*/
private final CrossReference.CanAppearWithoutContext[] referencedNames;
/**
* Creates a source model element for representing a CALDoc "@see" block without the context keyword.
*
* @param referencedNames a non-empty array of names referenced by this "@see" block.
* @param sourceRange
*/
private WithoutContext(CrossReference.CanAppearWithoutContext[] referencedNames, SourceRange sourceRange) {
super(sourceRange);
if (referencedNames.length == 0) {
throw new IllegalArgumentException("Must have at least one name in the @see list");
}
this.referencedNames = referencedNames.clone();
verifyArrayArg(this.referencedNames, "referencedNames");
}
/**
* Factory method for constructing a source model element for representing a CALDoc "@see" block without the context keyword.
*
* @param referencedNames a non-empty array of names referenced by this "@see" block.
* @return a new instance of this class.
*/
public static WithoutContext make(CrossReference.CanAppearWithoutContext[] referencedNames) {
return new WithoutContext(referencedNames, null);
}
static WithoutContext makeAnnotated(CrossReference.CanAppearWithoutContext[] referencedNames, SourceRange sourceRange) {
return new WithoutContext(referencedNames, sourceRange);
}
/**
* @return the non-empty array of names referenced by this "@see" block.
*/
public CrossReference.CanAppearWithoutContext[] getReferencedNames() {
return referencedNames.clone();
}
/**
* @return the number of names referenced by this "@see" block.
*/
public int getNReferencedNames() {
return referencedNames.length;
}
/**
* Returns the referenced name at the specified position in this "@see" block.
* @param n index of the function name to return.
* @return the referenced name at the specified position in this "@see" block.
*/
public CrossReference.CanAppearWithoutContext getNthReferencedName(int n) {
return referencedNames[n];
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_CALDoc_TaggedBlock_See_WithoutContext(this, arg);
}
/**
* {@inheritDoc}
*/
ParseTreeNode toParseTreeNode() {
ParseTreeNode seeNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_BLOCK, "CALDOC_SEE_BLOCK");
ParseTreeNode withoutContextNode = new ParseTreeNode(CALTreeParserTokenTypes.CALDOC_SEE_BLOCK_WITHOUT_CONTEXT, "CALDOC_SEE_BLOCK_WITHOUT_CONTEXT");
ParseTreeNode[] children = new ParseTreeNode[referencedNames.length];
for (int i = 0; i < referencedNames.length; i++) {
children[i] = referencedNames[i].toParseTreeNode();
}
withoutContextNode.addChildren(children);
seeNode.setFirstChild(withoutContextNode);
return seeNode;
}
}
}
}
}
/**
* Models the arguments in the unpacking of a general data constructor.
* @author Edward Lam
*/
public static abstract class ArgBindings extends SourceElement {
public static final ArgBindings NO_BINDINGS = ArgBindings.Positional.make(Pattern.NO_PATTERNS);
/**
* Models the arguments in the unpacking of a general data constructor, where the argument notation is matching.
*
* For instance, if we have the data type Foo:
* data public Foo a b = Bar bar::a barbar::a | Baz baz::b bazbaz::b;
*
* ... and the function blah:
* public blah !foo =
* case foo of
* Bar bar barbar -> 1.0;
* Baz {baz} -> 2.0;
* ;
*
* ... in function "blah", the unpacking of Bar is positional, and the unpacking of Baz is matching.
*
* @author Edward Lam
*/
public static final class Matching extends ArgBindings {
private final FieldPattern[] fieldPatterns;
private Matching(FieldPattern[] fieldPatterns) {
if (fieldPatterns == null || fieldPatterns.length == 0) {
this.fieldPatterns = FieldPattern.NO_FIELD_PATTERNS;
} else {
this.fieldPatterns = fieldPatterns.clone();
verifyArrayArg(this.fieldPatterns, "patterns");
}
}
public static Matching make(FieldPattern[] patterns) {
return new Matching(patterns);
}
public FieldPattern[] getFieldPatterns() {
if (fieldPatterns.length == 0) {
return FieldPattern.NO_FIELD_PATTERNS;
}
return fieldPatterns.clone();
}
/**
* Get the number of field patterns.
* @return the number of field patterns.
*/
public int getNFieldPatterns() {
return fieldPatterns.length;
}
/**
* Get the nth field pattern.
* @param n the index of the field pattern to return.
* @return the nth field pattern.
*/
public FieldPattern getNthFieldPattern(int n) {
return fieldPatterns[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode fieldBindingVarAssignmentListNode =
new ParseTreeNode(CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT_LIST, "FIELD_BINDING_VAR_ASSIGNMENT_LIST");
ParseTreeNode[] fieldPatternNodes = new ParseTreeNode[fieldPatterns.length];
for (int i = 0; i < fieldPatterns.length; i++) {
fieldPatternNodes[i] = fieldPatterns[i].toParseTreeNode();
}
fieldBindingVarAssignmentListNode.addChildren(fieldPatternNodes);
return fieldBindingVarAssignmentListNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_ArgBindings_Matching(this, arg);
}
}
/**
* Models the unpacking of a general data constructor, where the argument notation is positional.
*
* For instance, if we have the data type Foo:
* data public Foo a b = Bar bar::a barbar::a | Baz baz::b bazbaz::b;
*
* ... and the function blah:
* public blah !foo =
* case foo of
* Bar bar barbar -> 1.0;
* Baz {baz} -> 2.0;
* ;
*
* ... in function "blah", the unpacking of Bar is positional, and the unpacking of Baz is matching.
*
* @author Bo Ilic
* @author Edward Lam
*/
public static final class Positional extends ArgBindings {
private final Pattern[] patterns;
private Positional(Pattern[] patterns) {
if (patterns == null || patterns.length == 0) {
this.patterns = Pattern.NO_PATTERNS;
} else {
this.patterns = patterns.clone();
verifyArrayArg(this.patterns, "patterns");
}
}
public static Positional make(Pattern[] patterns) {
return new Positional(patterns);
}
public Pattern[] getPatterns() {
if (patterns.length == 0) {
return Pattern.NO_PATTERNS;
}
return patterns.clone();
}
/**
* Get the number of patterns.
* @return the number of patterns.
*/
public int getNPatterns() {
return patterns.length;
}
/**
* Get the nth pattern.
* @param n the index of the pattern to return.
* @return the nth pattern.
*/
public Pattern getNthPattern(int n) {
return patterns[n];
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode patternListNode = new ParseTreeNode(CALTreeParserTokenTypes.PATTERN_VAR_LIST, "PATTERN_VAR_LIST");
ParseTreeNode[] patternNodes = new ParseTreeNode[patterns.length];
for (int i = 0; i < patterns.length; i++) {
patternNodes[i] = patterns[i].toParseTreeNode();
}
patternListNode.addChildren(patternNodes);
return patternListNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_ArgBindings_Positional(this, arg);
}
}
}
/**
* Models a variable that occurs in a case pattern (i.e. on the left hand side of the "->"). These
* correspond either to actual variable or the wildcard pattern "_" which is used to indicate
* that the variable will not be used on the right hand side of the "->" and so a name is not
* explicitly given.
*
* @author Bo Ilic
*/
public static abstract class Pattern extends SourceElement {
public static final Pattern[] NO_PATTERNS = new Pattern[0];
public static final class Var extends Pattern {
private final String name;
private Var(final String name, final SourceRange sourceRange) {
super(sourceRange);
if (!LanguageInfo.isValidFunctionName(name)) {
throw new IllegalArgumentException();
}
this.name = name;
}
public static Var make(String name) {
return new Var(name, null);
}
static Var makeAnnotated(final String name, final SourceRange sourceRange) {
return new Var(name, sourceRange);
}
public String getName() {
return name;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode patternVar = new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, name);
return patternVar;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Pattern_Var(this, arg);
}
}
/**
* Models the wildcard pattern variable, which is "_" in CAL text. Note that this
* is distinct from the default pattern, which is also "_" in CAL text but stands in
* for the whole pattern and not just a pattern variable.
*
* @author Bo Ilic
*/
public static final class Wildcard extends Pattern {
private static final Wildcard WILDCARD = new Wildcard();
private Wildcard() {
super(null);
}
public static Wildcard make() {
return WILDCARD;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode patternVar = new ParseTreeNode(CALTreeParserTokenTypes.UNDERSCORE, "_");
return patternVar;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_Pattern_Wildcard(this, arg);
}
}
private Pattern(final SourceRange sourceRange) {
super(sourceRange);
}
}
/**
* Models a fieldName/pattern pair, where the patternVar may be missing due to punning. For example,
*
* the parts "#1 = x", "#2", "#3 = _", "orderDate = od", "shipDate", and "receivedDate = _" in the fragement below:
*
* case r of
* {#1 = x, #2, #3 = _, orderDate = od, shipDate, receivedDate = _} -> ...
*
* @author Bo Ilic
*/
public static final class FieldPattern extends SourceElement {
public static final FieldPattern[] NO_FIELD_PATTERNS = new FieldPattern[0];
private final Name.Field fieldName;
/**
* may be null to indicate punning where the fieldName is used to supply a "default" pattern.
*
* In the case of textual field names:
* orderDate
* is semantically equivalent to
* orderDate = orderDate
*
* In the case of ordinal field names:
* #1
* is semantically equivalent to
* #1 = _
*
*/
private final Pattern pattern;
/**
* @param fieldName FieldName
* @param pattern Pattern may be null to indicate punning where the fieldName is used to supply a "default" pattern.
*/
private FieldPattern(Name.Field fieldName, Pattern pattern) {
verifyArg(fieldName, "fieldName");
this.fieldName = fieldName;
this.pattern = pattern;
}
/**
* @param fieldName FieldName
* @param pattern Pattern may be null to indicate punning where the fieldName is used to supply a "default" pattern.
* @return an instance of FieldPattern
*/
public static FieldPattern make(Name.Field fieldName, Pattern pattern) {
return new FieldPattern(fieldName, pattern);
}
/**
* @param fieldName FieldName
* @param pattern Pattern may be null to indicate punning where the fieldName is used to supply a "default" pattern.
* @return an instance of FieldPattern
*/
static FieldPattern makeAnnotated(Name.Field fieldName, Pattern pattern) {
return new FieldPattern(fieldName, pattern);
}
public Name.Field getFieldName() {
return fieldName;
}
public Pattern getPattern() {
return pattern;
}
ParseTreeNode toParseTreeNode() {
ParseTreeNode fieldPatternNode = new ParseTreeNode(CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT, "FIELD_BINDING_VAR_ASSIGNMENT");
ParseTreeNode fieldNameNode = fieldName.toParseTreeNode();
if (pattern != null) {
ParseTreeNode patternNode = pattern.toParseTreeNode();
fieldNameNode.setNextSibling(patternNode);
}
fieldPatternNode.setFirstChild(fieldNameNode);
return fieldPatternNode;
}
/**
* {@inheritDoc}
*/
public <T, R> R accept(final SourceModelVisitor<T, R> visitor, final T arg) {
return visitor.visit_FieldPattern(this, arg);
}
}
/**
* Throws an exception if the array is null or has any null elements.
* @param array Object[]
* @param argName String name of the array for display in the error text of any generated exception
* @throws NullPointerException if array is null, or any of its elements are null
*/
static void verifyArrayArg(Object[] array, String argName) {
verifyArg(array, argName);
for (int i = 0, nElems = array.length; i < nElems; ++i) {
if (array[i] == null) {
throw new NullPointerException(argName + "[" + i + "] is null.");
}
}
}
/**
* Throws an exception if arg is null.
* @param arg Object
* @param argName String name of the arg to display in the error text of any generated exception
* @throws NullPointerException if 'arg' is null
*/
static void verifyArg(Object arg, String argName) {
if (arg == null) {
throw new NullPointerException("The argument '" + argName + "' cannot be null.");
}
}
/**
* Verifies the scope argument as non-null and as valid (either explicitly specified, or implicitly private).
* @param scope the scope argument to check.
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @param argName name of the arg to display in the error text of any generated exception.
*/
static void verifyScopeArg(Scope scope, boolean isScopeExplicitlySpecified, String argName) {
verifyArg(scope, argName);
if (!isScopeExplicitlySpecified && scope != Scope.PRIVATE) {
throw new IllegalArgumentException("For the argument '" + argName + "', the non-private scope " + scope + " must be explicitly specified in the source.");
}
}
static String space(int nSpaces) {
StringBuilder sb = new StringBuilder(nSpaces);
for (int i = 0; i < nSpaces; ++i) {
sb.append(' ');
}
return sb.toString();
}
/**
* A helper function that creates the parseTree for a scope expression.
* Creation date: (12/06/04)
* @param scope
* @param isScopeExplicitlySpecified whether the scope is explicitly specified in the source.
* @return ParseTreeNode
*/
static ParseTreeNode makeAccessModifierNode(Scope scope, boolean isScopeExplicitlySpecified) {
ParseTreeNode accessModifierNode = new ParseTreeNode(CALTreeParserTokenTypes.ACCESS_MODIFIER, "ACCESS_MODIFIER");
ParseTreeNode scopeNode;
if (scope.isPublic()) {
scopeNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_public, "public");
} else if (scope.isPrivate()) {
scopeNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_private, "private");
} else if (scope.isProtected()) {
scopeNode = new ParseTreeNode(CALTreeParserTokenTypes.LITERAL_protected, "protected");
} else {
throw new IllegalArgumentException("unrecognized scope " + scope);
}
if (isScopeExplicitlySpecified) {
accessModifierNode.setFirstChild(scopeNode);
}
return accessModifierNode;
}
/**
* A helper function that creates the parseTree for a FieldName expression.
* Creation date: (5/31/01 7:43:14 AM)
* @param fieldName
* @return ParseTreeNode
*/
static ParseTreeNode makeFieldNameExpr(FieldName fieldName) {
if(fieldName instanceof FieldName.Ordinal) {
return new ParseTreeNode(CALTreeParserTokenTypes.ORDINAL_FIELD_NAME, fieldName.getCalSourceForm());
} else {
return new ParseTreeNode(CALTreeParserTokenTypes.VAR_ID, fieldName.getCalSourceForm());
}
}
/**
* A helper function that creates the parseTree for an optional CALDoc comment.
* @param commentOrNull the comment to be represented by the parse tree, or null.
* @return ParseTreeNode a parse tree whose root is of the type OPTIONAL_CALDOC_COMMENT.
*/
static ParseTreeNode makeOptionalCALDocNode(CALDoc.Comment commentOrNull) {
ParseTreeNode optionalCALDocNode = new ParseTreeNode(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT, "OPTIONAL_CALDOC_COMMENT");
if (commentOrNull != null) {
optionalCALDocNode.setFirstChild(commentOrNull.toParseTreeNode());
}
return optionalCALDocNode;
}
}