/* * 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. */ /* * OverloadingInfo.java * Creation date: (April 9, 2001) * By: Bo Ilic */ package org.openquark.cal.compiler; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.openquark.cal.module.Cal.Core.CAL_Record; /** * This class is a helper class used during type checking. Its purpose is to store information needed * to add the extra dictionary arguments to functions and applications necessary to resolve overloading. * * Creation date: (4/9/01 4:35:56 PM) * @author Bo Ilic */ class OverloadingInfo { /** entity for the function whose defining equation is undergoing overload resolution. */ private final Function function; /** * the top-level or local function that is being defined. Extra dictionary arguments may * need to be added here. */ private final ParseTreeNode functionNode; /** * (PolymorphicVar Set i.e. each element either a TypeVar or RecordVar) * the generic, type-class constrained type and record variables occurring in the type expression of the function after it * has been type checked. Note that for a local function, this can be tricky. For example, * g x = let f y = x + y; in (f 3.0, f 5.0) * f cannot be used polymorphically in the "in" part. Replacing the call to f 5.0 by f (idInt 5) * results in a type checking error. So, in particular, the type for f for the purpose of * overload resolution is Double -> Double and not Num a => a -> a. * The basic idea is that overload resolution must add dictionary variables only for the *generic* * type-class constrained type and record variables. * The set is ordered by first occurrence of the type var in the type expression. */ private Set<PolymorphicVar> genericClassConstrainedPolymorphicVars; private final TypeExpr functionTypeExpr; /** * (ApplicationInfo) information on applications of functions that occur within the definition of the * function given by functionNode. Extra arguments may need to be added at the application site to * call the operator of the application. */ private final List<ApplicationInfo> applicationsList; /** * OverloadingInfo object associated with the parent function of this OverloadingInfo object. * null if this is a top level function. */ private final OverloadingInfo parent; /** * (PolymorphicVar -> TypeClass -> String) For example, for an (Eq a) type constraint on the type variable a, * the name of the dictionary variable will be something like $dictvar14Eq. */ private Map<PolymorphicVar, Map<TypeClass, String>> dictionaryVariablesMap; /** * OverloadingInfo constructor comment. * @param function * @param functionNode * @param functionTypeExpr * @param parent */ OverloadingInfo(Function function, ParseTreeNode functionNode, TypeExpr functionTypeExpr, OverloadingInfo parent) { if (function == null || functionTypeExpr == null) { throw new NullPointerException(); } switch (functionNode.getType()) { case CALTreeParserTokenTypes.TOP_LEVEL_FUNCTION_DEFN : case CALTreeParserTokenTypes.LET_DEFN : break; default : throw new IllegalArgumentException("functionNode has an invalid node type."); } this.function = function; this.functionNode = functionNode; this.functionTypeExpr = functionTypeExpr; this.parent = parent; applicationsList = new ArrayList<ApplicationInfo>(); } /** * Add the application info if it may be needed in the future for overloading resolution. * Creation date: (4/9/01 4:59:40 PM) * @param apInfo */ void addApplication(ApplicationInfo apInfo) { //there is no need to add applications for overload resolution if we know for sure that //it will not be needed. if (apInfo.isPolymorphic()) { if (apInfo.getGenericClassConstrainedPolymorphicVars().isEmpty() && // the overloading resolver must take action for the uses of the dictionary function !apInfo.getAppliedFunctionalAgent().getName().equals(CAL_Record.Functions.dictionary)) { return; } applicationsList.add(apInfo); return; } //add the application to the overloading info object having the same nesting level. int apNestingLevel = apInfo.getNestingLevel(); OverloadingInfo oi = this; while (oi.function.getNestingLevel() > apNestingLevel) { oi = oi.getParent(); } oi.applicationsList.add(apInfo); } /** * Call this method when type checking for this function is finished, and then * constrainedTypeVarList needs to be calculated. * Creation date: (4/19/01 10:01:38 AM) * @param nonGenericVars the non-generic variables at the point where the body of * all functions in the function's declaration group have been type checked. * Can be null to indicate an empty list. */ void finishedTypeCheckingFunction(NonGenericVars nonGenericVars) { genericClassConstrainedPolymorphicVars = functionTypeExpr.getGenericClassConstrainedPolymorphicVars(nonGenericVars); for (int i = 0, nApplications = getNApplications(); i < nApplications; ++i) { ApplicationInfo ai = getApplication(i); if (!ai.isPolymorphic()) { ai.finishedTypeCheckingFunction(nonGenericVars); } } } /** * Insert the method's description here. * Creation date: (4/9/01 5:01:43 PM) * @return OverloadingInfo.ApplicationInfo * @param index */ ApplicationInfo getApplication(int index) { return applicationsList.get(index); } /** * Note that finishedTypeCheckingFunction must be called before this method is called. * @return Set the generic, class constrained type or record variables occurring within the type expression. These are the ones for which * dictionary variables constants must be added to the function's definition in order to resolve overloading. */ Set<PolymorphicVar> getGenericClassConstrainedPolymorphicVars() { //finishedTypeCheckingFunction must be called before calling this method is valid. if (genericClassConstrainedPolymorphicVars == null) { throw new IllegalStateException(); } return genericClassConstrainedPolymorphicVars; } /** * Insert the method's description here. * Creation date: (5/31/01 11:48:20 AM) * @return ParseTreeNode */ ParseTreeNode getFunctionArgsNode() { switch (functionNode.getType()) { case CALTreeParserTokenTypes.LET_DEFN : return functionNode.getChild(2); case CALTreeParserTokenTypes.TOP_LEVEL_FUNCTION_DEFN : return functionNode.getChild(3); default : throw new IllegalStateException("Programming error in OverloadingInfo.getFunctionArgsNode."); } } /** * Insert the method's description here. * Creation date: (5/31/01 12:15:51 PM) * @return String */ String getFunctionName() { switch (functionNode.getType()) { case CALTreeParserTokenTypes.LET_DEFN : return functionNode.getChild(1).getText(); case CALTreeParserTokenTypes.TOP_LEVEL_FUNCTION_DEFN : return functionNode.getChild(2).getText(); default : throw new IllegalStateException("Programming error in OverloadingInfo.getFunctionName."); } } /** * @return ParseTreeNode the top-level or local function that is being defined. */ ParseTreeNode getFunctionNode() { return functionNode; } /** * @return TypeExpr */ TypeExpr getFunctionTypeExpr() { return functionTypeExpr; } /** * @return int number of applications that may need overload resolution occurring in the definition of this function. * Note: all these applications will be such that the operator is a simple function rather than an application itself. */ int getNApplications() { return applicationsList.size(); } /** * @return OverloadingInfo object associated with the parent function of this OverloadingInfo object. * null if this is a top level function. */ OverloadingInfo getParent() { return parent; } void setDictionaryVariablesMap(Map<PolymorphicVar, Map<TypeClass, String>> dictionaryVariablesMap) { this.dictionaryVariablesMap = dictionaryVariablesMap; } String getDictionaryVariableName(PolymorphicVar polymorphicVar, TypeClass typeClass) { return dictionaryVariablesMap.get(polymorphicVar).get(typeClass); } /** * @param polymorphicVar * @return OverloadingInfo the dictionary variable needed to satisfy the polymorphicVar constraint or null * if there is not any (which implies an ambiguous type). */ OverloadingInfo getResolvingOverloadingInfo(PolymorphicVar polymorphicVar) { if (genericClassConstrainedPolymorphicVars.contains(polymorphicVar)) { return this; } if (parent == null) { return null; } return parent.getResolvingOverloadingInfo(polymorphicVar); } @Override public String toString() { return getFunctionName(); } }