/*
* 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.
*/
/*
* OptimizerHelper.java
* Created: ??
* By: Greg McClement
*/
package org.openquark.cal.compiler;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.openquark.cal.compiler.Expression.ErrorInfo;
import org.openquark.cal.compiler.ExpressionAnalyzer.Visitor;
import org.openquark.cal.foreignsupport.module.Prelude.AlgebraicValue;
import org.openquark.cal.internal.machine.MachineFunctionImpl;
import org.openquark.cal.internal.module.Cal.Internal.CAL_Optimizer_Expression_internal;
import org.openquark.cal.machine.MachineFunction;
import org.openquark.cal.machine.Program;
import org.openquark.cal.machine.Program.ProgramException;
import org.openquark.cal.module.Cal.Collections.CAL_Array;
import org.openquark.cal.module.Cal.Collections.CAL_List;
import org.openquark.cal.module.Cal.Core.CAL_Debug;
import org.openquark.cal.module.Cal.Core.CAL_Dynamic;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
import org.openquark.cal.module.Cal.Core.CAL_String;
import org.openquark.cal.services.WorkspaceManager;
import org.openquark.cal.util.FixedSizeList;
import org.openquark.util.UnsafeCast;
/**
* Warning- this class should only be used by the CAL compiler implementation. It is not part of the
* external API of the CAL platform.
* <P>
* Helper functions that are called from the CAL global optimizer (written in CAL itself).
*
* @author GMCCLEMENT
*/
public final class OptimizerHelper {
/**
* Used by getLiteralType to tell the CAL code the type of a literal.
*/
public final static int Literal_String = 1;
public final static int Literal_Int = 2;
public final static int Literal_Boolean = 3;
public final static int Literal_Double = 4;
public final static int Literal_Char = 5;
public final static int Literal_Byte = 6;
public final static int Literal_Long = 7;
public final static int Literal_Opaque = 8;
public final static int Literal_Integer = 9;
public final static int Literal_Short = 10;
public final static int Literal_Float = 11;
/**
* Used by getFieldNameType to tell the compiler the type of the field name.
*/
public final static int FieldName_Ordinal = 1;
public final static int FieldName_Textual = 2;
/**
* Used by getExpressionType to tell the CAL code the type of the expression.
*/
public final static int Expression_Appl = 1;
public final static int Expression_Cast = 2;
public final static int Expression_DataConsSelection = 3;
public final static int Expression_ErrorInfo = 4;
public final static int Expression_LetRec = 5;
public final static int Expression_Literal = 6;
public final static int Expression_PackCons = 7;
public final static int Expression_RecordCase = 8;
public final static int Expression_RecordExtension = 9;
public final static int Expression_RecordSelection = 10;
public final static int Expression_Switch = 11;
public final static int Expression_TailRecursiveCall = 12;
public final static int Expression_Var = 13;
public final static int Expression_LetNonRec = 14;
public final static int Expression_RecordUpdate = 15;
/**
* Used by getAltType to tell the CAL optimizer the type of a switch alt.
*/
public final static int Alt_Matching = 1;
public final static int Alt_Positional = 2;
/**
* Used by var_getType to tell the CAL optimizer the type of the var.
*/
public final static int Var_Type_DataConstructor = 1;
public final static int Var_Type_FunctionEntity = 2;
public final static int Var_Type_Name = 3;
/**
* Used by getTypeType to tell the CAL optimizer the type of the type expression.
*/
public static final int TypeExpr_TypeConstructor = 1;
public static final int TypeExpr_TypeVar = 2;
public static final int TypeExpr_Other = 3;
/**
* Used by getTypeConstructorType to tell the CAL optimizer the type of the type constructor.
*/
public final static int TypeConstructor_Function = 1;
public final static int TypeConstructor_List = 2;
public final static int TypeConstructor_Other = 3;
/**
* This will only be initialized if the optimizer is enabled.
*/
private static PreludeTypeConstants preludeTypeConstants = null;
/** This class is not intended to be instantiated */
private OptimizerHelper() {}
public static void setPreludeTypeConstants(PreludeTypeConstants preludeTypeConstants){
OptimizerHelper.preludeTypeConstants = preludeTypeConstants;
}
/**
* Make a list type expression with elements of the given type.
*
* @param elementType The type of the list elements
* @return A type expression for lists with the given element type.
*/
public static TypeExpr makeListType(TypeExpr elementType){
return preludeTypeConstants.makeListType(elementType);
}
/**
* The optimizer currently does not support certain types of expressions. This exception
* is thrown when an expression with components of unacceptable type are passed to the optimizer.
* This is temporary.
*
* @author GMCCLEMENT
*
*/
public static class UnsupportedExpressionTypeException extends RuntimeException {
/**
* Fix a warning
*/
private static final long serialVersionUID = 4888880848260406510L;
private final String reason;
UnsupportedExpressionTypeException(String reason){
this.reason = reason;
}
public String getReason(){
return reason;
}
}
/**
* Used to get a type code number for the literal by code that inputs the Java object
* into CAL.
*
* @param literal The literal to get the type code for.
* @return An integer indicating the type of the literal.
*/
public static int getLiteralType(Expression.Literal literal){
Object value = literal.getLiteral();
if (value instanceof String){
return Literal_String;
}
if (value instanceof Integer){
return Literal_Int;
}
if (value instanceof Boolean){
return Literal_Boolean;
}
if (value instanceof Double){
return Literal_Double;
}
if (value instanceof Character){
return Literal_Char;
}
if (value instanceof Byte){
return Literal_Byte;
}
if (value instanceof Long){
return Literal_Long;
}
if (value instanceof BigInteger){
return Literal_Integer;
}
if (value instanceof Short){
return Literal_Short;
}
if (value instanceof Float){
return Literal_Float;
}
return Literal_Opaque;
}
/**
* Used to get a type code number for the field name by code that inputs the Java object
* into CAL.
*
* @param fieldName The field name to get the type code for.
* @return An integer indicating the type of the field name.
*/
public static int getFieldNameType(FieldName fieldName){
if (fieldName instanceof FieldName.Ordinal){
return FieldName_Ordinal;
}
if (fieldName instanceof FieldName.Textual){
return FieldName_Textual;
}
throw new IllegalStateException();
}
/**
* Get the ordinal of the given field name. If the field name is not
* of type FieldName.Ordinal then an error will be throw.
*
* @param fn The FieldName.Ordinal to get the ordinal of.
* @return The ordinal of the field name.
*/
public static int fieldName_getOrdinal(FieldName fn){
FieldName.Ordinal ordinal = (FieldName.Ordinal) fn;
return ordinal.getOrdinal();
}
/**
* Used to get a type code number for the expression by code that inputs the Java object
* into CAL.
*
* @param expression The field name to get the type code for.
* @return An integer indicating the type of the field name.
*/
public static int getExpressionType(Expression expression){
if (expression instanceof Expression.Appl){
return Expression_Appl;
}
else if (expression instanceof Expression.Cast){
return Expression_Cast;
}
else if (expression instanceof Expression.DataConsSelection){
return Expression_DataConsSelection;
}
else if (expression instanceof Expression.ErrorInfo){
return Expression_ErrorInfo;
}
else if (expression instanceof Expression.LetNonRec){
return Expression_LetNonRec;
}
else if (expression instanceof Expression.LetRec){
if ( ((Expression.Let) expression).getDefns().length > 1){
// TODO fix this
throw new UnsupportedExpressionTypeException("LetRec with more than once definition.");
}
return Expression_LetRec;
}
else if (expression instanceof Expression.Literal){
return Expression_Literal;
}
else if (expression instanceof Expression.PackCons){
return Expression_PackCons;
}
else if (expression instanceof Expression.RecordCase){
return Expression_RecordCase;
}
else if (expression instanceof Expression.RecordUpdate) {
return Expression_RecordUpdate;
}
else if (expression instanceof Expression.RecordExtension){
return Expression_RecordExtension;
}
else if (expression instanceof Expression.RecordSelection){
return Expression_RecordSelection;
}
else if (expression instanceof Expression.Switch){
return Expression_Switch;
}
else if (expression instanceof Expression.TailRecursiveCall){
return Expression_TailRecursiveCall;
}
else if (expression instanceof Expression.Var){
return Expression_Var;
}
throw new IllegalStateException();
}
/**
* Construct a new Expression.Var from a qualified name;
* @param name The name of the variable.
* @return The Var for the given name.
*/
public static Expression expression_new_var_name(QualifiedName name){
return new Expression.Var(name);
}
/**
* Construct a new Expression.Var from an FunctionalAgent
* @param entity The entity to use to construct the Var.
* @return The Var constructed.
*/
public static Expression expression_new_var_entity(FunctionalAgent entity){
return new Expression.Var(entity);
}
/**
* Construct an Expression.Literal from the given java object.
* @param literal The java object to put in the literal.
* @return The literal for the given java object.
*/
public static Expression expression_new_literal(Object literal){
return new Expression.Literal(literal);
}
/**
* Construct an Expression.Appl from the given expressions.
* @param expr1 The first expression to use.
* @param expr2 The second expression to use.
* @return The application for the given expressions.
*/
public static Expression expression_new_appl(Expression expr1, Expression expr2){
return new Expression.Appl(expr1, expr2);
}
/**
* Construct an Expression.Let object.
*
* @param unqualifiedName The name of the let variable.
* @param defExpr The expression that defined the let variable.
* @param bodyExpr The body of the let expression.
* @param isRecursive True if the expression being defined is recursive.
* @return The new Let expression object.
*/
public static Expression expression_new_let(String unqualifiedName, Expression defExpr, Expression bodyExpr, boolean isRecursive, TypeExpr varType){
Expression.Let.LetDefn defns[] = { new Expression.Let.LetDefn(unqualifiedName, defExpr, varType) };
if (isRecursive){
return new Expression.LetRec(defns, bodyExpr);
}
else{
return new Expression.LetNonRec(defns[0], bodyExpr);
}
}
/**
* Create a new Switch expression for the given parameters.
* @param expression The case expression for the switch.
* @param altsObject A list of the SwitchAlts for the switch.
* @return The Switch expression.
*/
public static Expression expression_new_switch(Expression expression, Object altsObject){
List<Expression.Switch.SwitchAlt> altsList = UnsafeCast.unsafeCast(altsObject);
Expression.Switch.SwitchAlt alts[] = new Expression.Switch.SwitchAlt[altsList.size()];
int iAlts = 0;
for(Iterator<Expression.Switch.SwitchAlt> i = altsList.iterator(); i.hasNext();){
alts[iAlts++] = i.next();
}
/* TODO Add the error info back in */
return new Expression.Switch(expression, alts, new ErrorInfo(QualifiedName.make(ModuleName.make("OptimizerHelper"), "todo"), 1, 1));
}
public static Expression expression_new_opaque(Object expression){
return (Expression) expression;
}
/**
* Construct a new Expression.Var for the given data constructor.
* @param dataConstructor The data constructor that the Var will hold.
* @return A new Var for the given data constructor.
*/
public static Expression expression_new_dataConstructor(Object dataConstructor){
return new Expression.Var( (DataConstructor) dataConstructor);
}
/**
* Construct a SwitchAlt object for the given CAL object values.
* @param switchTag The tag of the switch alt.
* @param isPositional A flag indicating if the alt is positional.
* @param varsObject A list of the vars.
* @param altExpr The expression body.
* @return A SwitchAlt for the given CAL parameters.
*/
public static Expression.Switch.SwitchAlt alt_new(Object switchTag, boolean isPositional, Object varsObject, Expression altExpr){
SortedMap<FieldName, String> fieldNameToVarNameMap = new TreeMap<FieldName, String>();
SortedMap<Integer, String> ordinalToVarNameMap = new TreeMap<Integer, String>();
{
List<List<Object>> varsList = UnsafeCast.unsafeCast(varsObject);
for(Iterator<List<Object>> iVarsList = (varsList).iterator(); iVarsList.hasNext();){
List<Object> fieldNameQualifiedName = iVarsList.next();
Iterator<Object> fieldNameQualifiedNameIterator = fieldNameQualifiedName.iterator();
FieldName fn = (FieldName) fieldNameQualifiedNameIterator.next();
QualifiedName qn = (QualifiedName) fieldNameQualifiedNameIterator.next();
String name = qn.getUnqualifiedName();
if (fn instanceof FieldName.Ordinal){
FieldName.Ordinal ordinal = (FieldName.Ordinal) fn;
// Ordinals start at zero but field name start at one so we have to
// take the number back one.
ordinalToVarNameMap.put(Integer.valueOf(ordinal.getOrdinal() - 1), name);
isPositional = true;
}
else{
// TODO GregM Rethink if this is the right way to handle positional versus matching.
fieldNameToVarNameMap.put(fn, name);
isPositional = false;
}
}
}
if (isPositional){
return new Expression.Switch.SwitchAlt.Positional(switchTag, ordinalToVarNameMap, altExpr);
}
else{
return new Expression.Switch.SwitchAlt.Matching(switchTag, fieldNameToVarNameMap, altExpr);
}
}
/**
* Used to get a type code number for the alt by code that inputs the Java object
* into CAL.
*
* @param alt The alt to get the type code for.
* @return An integer indicating the type of the alt.
*/
public static int getAltType(Expression.Switch.SwitchAlt alt){
if (alt instanceof Expression.Switch.SwitchAlt.Matching){
return Alt_Matching;
}
else if (alt instanceof Expression.Switch.SwitchAlt.Positional){
return Alt_Positional;
}
throw new IllegalStateException();
}
/**
* Is the tag of the alt a data constructor.
* @param alt The alt to check the tag of.
* @return True if the first tag is a data constructor.
*/
public static boolean alt_tagIsDataConstructor(Expression.Switch.SwitchAlt alt){
Object tag = alt.getFirstAltTag();
if (tag instanceof DataConstructor){
return true;
}
else{
return false;
}
}
/**
* Is the given object a data constructor.
* @param object The object to perform the check on.
* @return True if the object is a data constructor.
*/
public static boolean object_isDataConstructor(Object object){
if (object instanceof DataConstructor){
return true;
}
else{
return false;
}
}
/**
* The first tag of the alt.
* @param alt The alt to get the tag of.
* @return The first tag.
*/
public static FunctionalAgent alt_getFirstTag_asJFunctionalAgent(Expression.Switch.SwitchAlt alt){
return (FunctionalAgent) alt.getFirstAltTag();
}
/**
* The first tag of the alt.
* @param alt The alt to get the tag of.
* @return The first tag.
*/
public static Expression.Literal alt_getFirstTag_asJLiteral(Expression.Switch.SwitchAlt alt){
return new Expression.Literal(alt.getFirstAltTag());
}
/**
* Used for converting from a Java Var expression to a CAL expression.
* @param var The var object to get the type of
* @return A code indicating the type of the Var.
*/
public static int var_getType(Expression.Var var){
Object entity = var.getFunctionalAgent();
if (entity != null){
if (entity instanceof DataConstructor){
return Var_Type_DataConstructor;
}
else if (entity instanceof Function){
return Var_Type_FunctionEntity;
}
else{
throw new IllegalStateException();
}
}
else{
return Var_Type_Name;
}
}
/**
* Construct a new unconstrained type var.
* @return The new type var.
*/
public static TypeVar newTypeVar(){
return new TypeVar();
}
/**
* Get the number of arguments for the alt pattern.
*
* @param alt The SwitchAlt object
* @return The number of arguments for this alt pattern.
*/
public static int alt_getNArguments(Expression.Switch.SwitchAlt alt){
Object tag = alt.getFirstAltTag();
if (tag instanceof DataConstructor){
DataConstructor dctag = (DataConstructor) tag;
return dctag.getArity();
}
else {
return 0;
}
}
/**
* Get the Nth argument from the position to var map for a Positional switch alt.
* @param altObject
* @param index The index of the argument to get.
* @return The nth argument.
*/
public static String alt_getPositionArgument(Expression.Switch.SwitchAlt altObject, int index){
Expression.Switch.SwitchAlt.Positional alt = (Expression.Switch.SwitchAlt.Positional) altObject;
SortedMap<Integer, String> map = alt.getPositionToVarNameMap();
String varName = map.get(Integer.valueOf(index));
if (varName == null){
return "";
}
else{
return varName;
}
}
public static Expression let_getDef(Expression.Let letObject, int index){
return letObject.getDefns()[index].getExpr();
}
public static String let_getVar(Expression.Let letObject, int index){
return letObject.getDefns()[index].getVar();
}
public static TypeExpr let_getDefType(Expression.Let letObject, int index){
return letObject.getDefns()[index].getVarType();
}
public static TypeExpr objectAsTypeExpr(TypeVar object){
return object;
}
/**
* Used to get a type code number for the TypeExpr by code that inputs the Java object
* into CAL.
*
* @param type The type expression to get the type code for.
* @return An integer indicating the type of the type expression.
*/
public static int getTypeType(TypeExpr type){
if (type instanceof TypeConsApp) {
return TypeExpr_TypeConstructor;
} else if (type instanceof TypeVar) {
return TypeExpr_TypeVar;
} else {
return TypeExpr_Other;
}
}
public static TypeVar typeExprAsJTypeVar(TypeExpr type){
return (TypeVar) type;
}
public static Object typeExprAsJObject(TypeExpr type){
return type;
}
public static String typeExpr_getName(TypeExpr type){
if (type == null){
return "null";
}
else{
return type.toString();
}
}
/**
* Used to get a type code number for the TypeConsApp by code that inputs the Java object
* into CAL.
*
* @param type The type constructor expression to get the type code for.
* @return An integer indicating the type of the type constructor expression.
*/
public static int getTypeConstructorType(TypeConsApp type){
QualifiedName typeName = type.getRoot().getName();
if (typeName.equals(CAL_Prelude.TypeConstructors.Function)) {
if (TypeConstructor.FUNCTION != type.getRoot()){
System.out.println("Doesn't Match Root");
}
return TypeConstructor_Function;
} else if (typeName.equals(CAL_Prelude.TypeConstructors.List)) {
return TypeConstructor_List;
}
else{
return TypeConstructor_Other;
}
}
public static TypeConsApp typeExpr_asTypeConstructor(TypeExpr typeExpr){
return (TypeConsApp) typeExpr;
}
public static boolean typeVar_hasClassConstraints(TypeVar typeVar){
return !typeVar.noClassConstraints();
}
public static TypeExpr functionalAgent_getTypeExprExact(FunctionalAgent functionalAgent){
return (functionalAgent).getTypeExprExact();
}
/**
* Construct a new Expression.RecordSelection.
* @param expression The record expression.
* @param fieldName The field name.
* @return A new record selection expression for the given record expression and field name.
*/
public static Expression expression_new_recordSelection(Expression expression, FieldName fieldName){
return new Expression.RecordSelection(expression, fieldName);
}
/**
* Construct a new Expression.RecordSelection.
* @param conditionExpr The record case expression.
* @param baseRecordPatternVarName The pattern var name for the record case.
* @param fieldBindingVars The map from FieldName to Var name.
* @param resultExpr The result expression for the record case.
* @return A new record case expression for the given record expression and field name.
*/
public static Expression expression_new_recordCase(Expression conditionExpr, String baseRecordPatternVarName, Object fieldBindingVars, Expression resultExpr){
List<List<Object>> fieldsList = UnsafeCast.unsafeCast(fieldBindingVars);
return new Expression.RecordCase(conditionExpr, baseRecordPatternVarName, getFieldBindingVarMap(fieldsList), resultExpr);
}
private static SortedMap<FieldName, String> getFieldBindingVarMap(List<List<Object>> extensionFieldsList){
SortedMap<FieldName, String> extensionFieldsMap = new TreeMap<FieldName, String>();
for (final List<Object> ef : extensionFieldsList) {
Iterator<Object> efIterator = ef.iterator();
FieldName fieldName = (FieldName) efIterator.next();
String varName = (String) efIterator.next();
extensionFieldsMap.put(fieldName, varName);
}
return extensionFieldsMap;
}
public static RecordType type_asRecordType(TypeExpr type){
return (RecordType) type;
}
public static FunctionalAgent dataConstructor_asFunctionalAgent(DataConstructor functionalAgent){
return functionalAgent;
}
public static DataConstructor functionalAgent_asDataConstructor(FunctionalAgent functionalAgent){
return (DataConstructor) functionalAgent;
}
/**
* Construct a new Expression.DataConsSelection.
* @param dcValueExpr The expression.
* @param dataConstructor
* @param fieldIndex
* @param errorInfo
* @return The new DataConsSelection.
*/
public static Expression expression_new_dataConsSelection(Expression dcValueExpr, FunctionalAgent dataConstructor, int fieldIndex, ErrorInfo errorInfo){
return new Expression.DataConsSelection(dcValueExpr, (DataConstructor) dataConstructor, fieldIndex, errorInfo);
}
private static SortedMap<FieldName, Expression> getExtensionFieldsMap(List<List<Object>> extensionFieldsList){
SortedMap<FieldName, Expression> extensionFieldsMap = new TreeMap<FieldName, Expression>();
for (final List<Object> ef : extensionFieldsList) {
Iterator<Object> efIterator = ef.iterator();
FieldName fieldName = (FieldName) efIterator.next();
Expression expression = (Expression) efIterator.next();
extensionFieldsMap.put(fieldName, expression);
}
return extensionFieldsMap;
}
public static Expression expression_new_recordExtensionLiteral(Object extensionFields){
List<List<Object>> efList = UnsafeCast.unsafeCast(extensionFields);
return new Expression.RecordExtension(null, getExtensionFieldsMap( efList));
}
public static Expression expression_new_recordExtensionPolymorphic(Expression baseRecordExpr, Object extensionFields){
List<List<Object>> efList = UnsafeCast.unsafeCast(extensionFields);
return new Expression.RecordExtension(baseRecordExpr, getExtensionFieldsMap(efList));
}
public static FieldName fieldName_ordinal_new(int ordinal){
return FieldName.makeOrdinalField(ordinal);
}
public static FieldName fieldName_textual_new(String text){
return FieldName.makeTextualField(text);
}
/**
* Checks if the expression contains Expression types no supported by the CAL optimizer.
* @param expr The expression to check
* @return True if the expression contains unsupported types.
*/
static boolean hasExcludedTypes(Expression expr) {
class HasExcludedTypes extends Visitor {
public boolean found = false;
HasExcludedTypes(){
}
@Override
void enterPackCons(Expression.PackCons packCons) {
found = true;
}
@Override
void enterRecordCase(Expression.RecordCase recordCase) {
found = true;
}
@Override
void enterCast(Expression.Cast cast) {
found = true;
}
}
HasExcludedTypes collector = new HasExcludedTypes();
expr.walk(collector);
return collector.found;
}
/**
* Converts the given core function into an algebraic value usable within the CAL optimizer.
*
* @param cf The core function to get the algebraic value for.
* @return An algebraic value corresponing to the given core function.
*/
static AlgebraicValue getAlgebraicValue(CoreFunction cf){
if (hasExcludedTypes(cf.getExpression())){
return null;
}
// Initialize the type list
TypeExpr calTypesArray[] = cf.getType();
// If the arguments have null for a type then skip this body.
for(int i = 0; i < calTypesArray.length; ++i){
if (calTypesArray[i] == null){
return null;
}
}
List<TypeExpr> calType = new ArrayList<TypeExpr>(calTypesArray.length);
for(int i = 0; i < calTypesArray.length; ++i){
calType.add(calTypesArray[i]);
}
boolean[] strictness = cf.getParameterStrictness();
List<Boolean> calStrictness = new ArrayList<Boolean>(strictness.length);
{
for(int i = 0; i < strictness.length; ++i){
calStrictness.add(Boolean.valueOf(strictness[i]));
}
}
boolean[] argIsWHNF = cf.getParameterStrictness();
List<Boolean> calArgIsWHNF = new ArrayList<Boolean>(argIsWHNF.length);
{
for(int i = 0; i < strictness.length; ++i){
calArgIsWHNF.add(Boolean.valueOf(false));
}
}
ArrayList<QualifiedName> calParameters = new ArrayList<QualifiedName>(cf.getFormalParameters().length);
for(int i = 0; i < cf.getFormalParameters().length; ++i){
calParameters.add(QualifiedName.make(cf.getName().getModuleName(), cf.getFormalParameters()[i]));
}
// create the helper functions using the name to
// type map
QualifiedName bodyVar = cf.getName();
Expression calExpr = cf.getExpression();
final int Optimizer_calType_CF = 0;
return AlgebraicValue.makeGeneralAlgebraicValue(
CAL_Optimizer_Expression_internal.DataConstructors.CoreFunction,
Optimizer_calType_CF,
FixedSizeList.make(
bodyVar,
calParameters,
calExpr,
calType,
calStrictness,
calArgIsWHNF
)
);
}
/**
* Lookup the given function name and return an algebraic value based of the function definition.
* @param workspaceManager The workspace to look for the function definition in.
* @param var The name of the function to look for.
* @return An algebraic value for the core function that is usable by the optimizer.
*/
public static AlgebraicValue getCoreFunction(WorkspaceManager workspaceManager, QualifiedName var){
MachineFunction mf = null;
try {
mf = workspaceManager.getMachineFunction(var);
} catch (ProgramException e) {
// TODO FIX THIS
e.printStackTrace();
}
if (mf == null){
// Fix your test app so it does not have unhandled expression types.
throw new IllegalStateException();
}
return getAlgebraicValue(((MachineFunctionImpl)mf).getCoreFunction());
}
/**
* Lookup the given function name and return an algebraic value based of the function definition.
* @param workspaceManager The workspace to look for the function definition in.
* @param var The name of the function to look for.
* @return An algebraic value for the core function that is usable by the optimizer.
*/
public static AlgebraicValue getTestInput(WorkspaceManager workspaceManager, QualifiedName var){
MachineFunction mf = null;
try {
mf = workspaceManager.getMachineFunction(var);
} catch (ProgramException e) {
// TODO FIX THIS
e.printStackTrace();
}
if (mf == null){
// Fix your test app so it does not have unhandled expression types.
throw new IllegalStateException();
}
CoreFunction cf = ((MachineFunctionImpl)mf).getCoreFunction();
AlgebraicValue coreFunction = getAlgebraicValue(cf);
if (coreFunction == null){
// Fix your test app so it does not have unhandled expression types.
throw new IllegalStateException();
}
List<List<Object>> nameToTypeExpr = new LinkedList<List<Object>>();
LinkedList<AlgebraicValue> helperFunctions = new LinkedList<AlgebraicValue>();
List<QualifiedName> nonCalFunctions = new ArrayList<QualifiedName>();
try {
OptimizerHelper.getHelperFunctions(null, workspaceManager, new HashMap<QualifiedName, CoreFunction>(), cf, nameToTypeExpr, helperFunctions, nonCalFunctions);
} catch (ProgramException e) {
// TODO FIX THIS
e.printStackTrace();
}
/*
* Make a list of the parameter strictness flags.
*/
boolean strictness[] = cf.getParameterStrictness();
List<Boolean> strictnessList = new ArrayList<Boolean>(strictness.length);
{
for( int i = 0; i < strictness.length; ++i){
strictnessList.add(Boolean.valueOf(strictness[i]));
}
}
/*
* Make a list of the formal parameters of the expression.
*/
String formalParameters[] = cf.getFormalParameters();
List<QualifiedName> formalParametersList = new ArrayList<QualifiedName>(formalParameters.length);
ModuleName optimizerTestModule = ModuleName.make("Cal.Test.Internal.Optimizer_Test");
for(int i = 0; i < formalParameters.length; ++i){
formalParametersList.add(QualifiedName.make(optimizerTestModule, formalParameters[i]));
}
// return new TestInput(nameToTypeExpr, helperFunctions, cf.getExpression());
return AlgebraicValue.makeGeneralAlgebraicValue(
QualifiedName.make(optimizerTestModule, "TestInput"),
0,
FixedSizeList.make(
nameToTypeExpr,
helperFunctions,
nonCalFunctions,
formalParametersList,
strictnessList,
cf.getExpression()
));
}
private static final QualifiedName PRELUDE_SEQ = CAL_Prelude.Functions.seq;
/**
* @param program
* @param workspace
* @param inlinableFunctions A list of extra functions to look at when searching for a given function. Map of QualifiedName to CoreFunction
* @param cf
* @param nameToTypeExpr
* @param helperFunctions
* @param nonCalFunctions
* @throws ProgramException
*/
static void getHelperFunctions(Program program, WorkspaceManager workspace, Map<QualifiedName, CoreFunction> inlinableFunctions, CoreFunction cf, List<List<Object>> nameToTypeExpr, LinkedList<AlgebraicValue> helperFunctions, List<QualifiedName> nonCalFunctions) throws ProgramException{
QualifiedName name = cf.getName();
Expression body = cf.getExpression();
Set<Object> varsDone = variables(body);
LinkedList<Object> varsUsed = new LinkedList<Object>(varsDone);
varsUsed.add(PRELUDE_SEQ); // The optimizer can add calls to this
// Keep track of the types already in the nameToTypeList
Set<QualifiedName> alreadyGotTypes = new HashSet<QualifiedName>();
int numberOfFunctionsNeeded = 0;
// initialize name to type map
while (varsUsed.size() > 0) {
QualifiedName var = (QualifiedName) varsUsed.removeFirst();
CoreFunction iBody = null;
// Look for the function the the previously compiled modules.
MachineFunction iMF = program == null ? workspace.getMachineFunction(var) : program.getCodeLabel(var);
if (iMF != null){
iBody = ((MachineFunctionImpl)iMF).getCoreFunction();
}
if (iBody == null){
// Look for the function in the module currently being compiled.
iBody = inlinableFunctions.get(var);
}
// if iBody is still null then the symbol found was perhaps an argument and not a function name.
if (iBody != null) {
if (
iBody.isCALFunction() &&
!iBody.getHadUnsafeCoerce() &&
// iBody.getFormalParameters().length > 0 &&
// if the function calls itself don't include itself in the helper functions
// since we are optimizing that function already.
iBody.getName() != name &&
iBody.getExpression() != null){
getCALTypes(iBody, nameToTypeExpr, alreadyGotTypes);
AlgebraicValue coreFunction = OptimizerHelper.getAlgebraicValue(iBody);
if (coreFunction == null){
continue;
}
if (iBody.getName().getQualifiedName().startsWith("$dict")){
continue;
}
/*
* What I really want to do is not use functions that call unsafe coerce in the body
* this is just temporary so I can get some timings
*/
if (iBody.getName().getQualifiedName().equals(CAL_Array.Functions.subscript.getQualifiedName())){
continue;
}
helperFunctions.addFirst(coreFunction);
// add the functions used by this body to the
// inlined list iff the function is defined
// in this module since the functions in this
// module are not optimized yet. The hard coded
// names are here because the optimizer currently
// does not optimize these functions.
if (iBody.getName().getModuleName().equals(name.getModuleName()) ||
iBody.getName().getModuleName().equals(CAL_Prelude.MODULE_NAME) ||
iBody.getName().getModuleName().equals(CAL_List.MODULE_NAME) ||
iBody.getName().getModuleName().equals(CAL_String.MODULE_NAME) ||
iBody.getName().getModuleName().equals(CAL_Dynamic.MODULE_NAME) ||
iBody.getName().getModuleName().equals(CAL_Debug.MODULE_NAME)
){
Set<Object> moreVars = variables(iBody.getExpression());
for (final Object mv : moreVars) {
if (varsDone.contains(mv)) {
continue; // already done
} else {
varsDone.add(mv);
varsUsed.add(mv);
}
}
}
else{
{
// Add type information for any variables used by this function.
Set<Object> moreVars = variables(iBody.getExpression());
for (final Object object : moreVars) {
QualifiedName mv = (QualifiedName) object;
if (varsDone.contains(mv) || varsUsed.contains(mv)) {
continue; // already done or is going to be done
} else {
CoreFunction mvBody = null;
// Look for the function the the previously compiled modules.
MachineFunction mvMF = program == null ? workspace.getMachineFunction(mv) : program.getCodeLabel(mv);
if (mvMF != null){
mvBody = ((MachineFunctionImpl)mvMF).getCoreFunction();
}
if (mvBody == null){
// Look for the function in the module currently being compiled.
mvBody = inlinableFunctions.get(mv);
}
// if mvBody is still null then the symbol found was perhaps an argument and not a function name.
if (mvBody != null) {
getCALType(mvBody, nameToTypeExpr, alreadyGotTypes);
}
}
}
}
}
numberOfFunctionsNeeded++;
}
else{
// Add an entry for the type of this function for any recursive calls.
getCALType(iBody, nameToTypeExpr, alreadyGotTypes);
if (!iBody.isCALFunction()){
nonCalFunctions.add(iBody.getName());
}
}
}
else{
}
}
// Add an entry for the type of this function for any recursive calls.
getCALTypes(cf, nameToTypeExpr, alreadyGotTypes);
}
/**
* Build a list of all the Expression.Var objects in the given expression.
*
* @param expr
* The expression to get all the variable in.
* @return A list of Expression.Var objects that appear in the given
* expression.
*/
private static Set<Object> variables(Expression expr) {
class VariableCollector extends Visitor {
private Set<Object> variables = new HashSet<Object>();
@Override
void enterVar(Expression.Var var) {
QualifiedName name = var.getName();
if (name != null) {
variables.add(name);
}
}
Set<Object> getVariables() {
return variables;
}
}
VariableCollector collector = new VariableCollector();
expr.walk(collector);
return collector.getVariables();
}
/**
* Returns the function type of the given core function in a form that can be passed to the CAL Optimizer.
*
* @param cf The core function to get the type for.
* @param nameToTypeList The list of name to type objects.
* @param alreadySeenTypes The list of objects names already in the nameToTypeList
* return The function type in a form that can be passed to the CAL optimizer.
*/
private static void getCALType(CoreFunction cf, List<List<Object>> nameToTypeList, Set<QualifiedName> alreadySeenTypes){
if (alreadySeenTypes.contains(cf.getName())){
return;
}
else{
alreadySeenTypes.add(cf.getName());
}
List<Object> nameToType = new ArrayList<Object>(3);
// Name
nameToType.add(cf.getName());
// Type
TypeExpr calTypesArray[] = cf.getType();
List<Object> calType = new ArrayList<Object>(calTypesArray.length);
for(int i = 0; i < calTypesArray.length; ++i){
calType.add(calTypesArray[i]);
}
nameToType.add(calType);
// Strictness
boolean[] strictness = cf.getParameterStrictness();
List<Object> calStrictness = new ArrayList<Object>(strictness.length);
{
for(int i = 0; i < strictness.length; ++i){
calStrictness.add(Boolean.valueOf(strictness[i]));
}
}
nameToType.add(calStrictness);
nameToTypeList.add(nameToType);
}
/**
* Add mappings of symbols to type for the core function and all of its arguments.
*
* @param cf The core function to get the types from.
* @param nameToTypeList List to add the name to type tuples to.
* @param alreadySeenTypes A list of the names already in the nameToTypeList.
*/
private static void getCALTypes(CoreFunction cf, List<List<Object>> nameToTypeList, Set<QualifiedName> alreadySeenTypes){
getCALType(cf, nameToTypeList, alreadySeenTypes);
final ModuleName moduleName = cf.getName().getModuleName();
// Get name to type tuples for the parameters.
String[] parameterNames = cf.getFormalParameters();
TypeExpr calTypesArray[] = cf.getType();
boolean[] strictness = cf.getParameterStrictness();
for(int i = 0; i < parameterNames.length; ++i){
final QualifiedName name = QualifiedName.make(moduleName, parameterNames[i]);
if (alreadySeenTypes.contains(name)){
continue;
}
else{
alreadySeenTypes.add(name);
}
List<Object> nameToType = new ArrayList<Object>(3);
// Name
nameToType.add(name);
// Type
{
List<Object> calType = new ArrayList<Object>(calTypesArray.length);
calType.add(calTypesArray[i]);
nameToType.add(calType);
}
// Strictness
{
List<Object> calStrictness = new ArrayList<Object>(strictness.length);
calStrictness.add(Boolean.valueOf(strictness[i]));
nameToType.add(calStrictness);
}
nameToTypeList.add(nameToType);
}
}
/**
* Get the number of data constructors defined in the type of the given data constructor.
* @param dc The data constructor to get the number for.
* @return The number of data constructors defined in the type of the given data constructor.
*/
public static int dataConstructor_getNumberOfDataTypes(DataConstructor dc){
if (dc.getNArgumentNames() > 0){
return dc.getTypeConstructor().getNDataConstructors();
}
return dc.getTypeConstructor().getNDataConstructors();
}
/**
* True iff the given FunctionalAgent is Prelude.True.
* @param functionalAgent - Check whether or not this value is Prelude.True.
* @return True iff the given EntEntity is Prelude.True.
*/
public static boolean dataCons_isTrue(FunctionalAgent functionalAgent){
return functionalAgent.getName().equals(CAL_Prelude.DataConstructors.True);
}
/**
* True iff the given FunctionalAgent is Prelude.False.
* @param functionalAgent - Check whether or not this value is Prelude.False.
* @return True iff the given EntEntity is Prelude.False.
*/
public static boolean dataCons_isFalse(FunctionalAgent functionalAgent){
return functionalAgent.getName().equals(CAL_Prelude.DataConstructors.False);
}
}