Package org.openquark.cal.compiler

Source Code of org.openquark.cal.compiler.CoreFunction

/*
* 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.
*/


/*
* CoreFunction.java
* Created: March 7, 2001
* By: Luke Evans
*/
package org.openquark.cal.compiler;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.openquark.cal.internal.serialization.ModuleSerializationTags;
import org.openquark.cal.internal.serialization.RecordInputStream;
import org.openquark.cal.internal.serialization.RecordOutputStream;
import org.openquark.cal.internal.serialization.RecordInputStream.RecordHeaderInfo;


/**
* 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>
* CoreFunction holds a desugared representation of CAL functions (and other
* functional agents such as data constructors and class methods) suitable for use by run-times
* or low level optimizers such as ExpressionAnalyzer.
* <p>
* CoreFunction is intended to remain immutable to clients (so that there are no public mutators). The idea
* here is that the core function is that part of desugared CAL that is determined by the compiler.
*
* @author LWE
*/
public final class CoreFunction {
     
    private static final int serializationSchema = 1;

    // Constants used to indicate the type of the literal
    // value when serializing.
    private static final byte LITERAL_TYPE_CHARACTER = 0;
    private static final byte LITERAL_TYPE_BOOLEAN = 1;
    private static final byte LITERAL_TYPE_INTEGER = 2;
    private static final byte LITERAL_TYPE_DOUBLE = 3;
    private static final byte LITERAL_TYPE_BYTE = 4;
    private static final byte LITERAL_TYPE_SHORT = 5;
    private static final byte LITERAL_TYPE_FLOAT = 6;
    private static final byte LITERAL_TYPE_LONG = 7;
    private static final byte LITERAL_TYPE_STRING = 8;
    private static final byte LITERAL_TYPE_BIG_INTEGER = 9;       
   
    // Constants used to indicate the type of the function.
    private static final byte PRIMITIVE_FUNCTION_TYPE = 0;
    private static final byte FOREIGN_FUNCTION_TYPE = 1;
    private static final byte CAL_FUNCTION_TYPE = 2;
    private static final byte CAL_DATA_CONSTRUCTOR_TYPE = 3;
   
    /**
     * The name of the core function. For functions corresponding to top level CAL language functions, this will
     * be the top-level CAL language function name.
     */
    private final QualifiedName name;   

    /**
     * Holds the unqualified formal parameters names. They belong to the same module as the sc
     * and so a qualification is unnecessary. Note: the formal parameters are the formal parameters
     * that appear explicitly in the textual definition of this function, as well as the parameters
     * added because of overload resolution. So for example,
     * f x y z = [x, y, z] // 3 formal parameters x, y, z
     * g x = f x // 1 formal parameter x (even though g takes 3 arguments)
     * f xs = sum xs // 2 formal parameters. 1 for the hidden dictionary argument to resolve the overloading for sum. 1 for xs.
     */
    private final String[] formalParameters;
   
    private static final String[] NO_ARGS_FORMAL_PARAMETERS = new String[0];
   
    /**
     * ith element is true if the ith argument is strict. Same length as formalParameters.
     */
    private boolean[] parameterStrictness;
   
    private static final boolean[] NO_ARGS_PARAMETER_STRICTNESS = new boolean[0];
   
    /**
     * Same length as formalParameters.
     * the ith element is the type of the ith formal parameter.
     * if the type is not determinable, the value of that element of the array is null, For example, this is mostly the
     *    case with arguments corresponding to overload resolution variables.
     */
    private final TypeExpr[] parameterTypes;
   
    private static final TypeExpr[] NO_ARGS_PARAMETER_TYPES = new TypeExpr[0];

    /**
     * The result type of the expression.
     */
   
    private final TypeExpr resultType;
   
    private Expression expression;         
   
    private long timeStamp;

    /** true if this core function contains a fully saturated call to itself. */
    private boolean isTailRecursive = false;
   
    /** True if this CoreFunction represents a function in an adjunct. */
    private boolean isForAdjunct = false;

    /**
     * Flag indication that the expression used to have a call to unsafeCoerce
     */
    private boolean hadUnsafeCoerce = false;
       
    /**
     * If this function can be considered an alias of another function then aliasOf
     * will hold the name of another function. 
     *
     * One function is an alias of another if all references to the alias can be
     * safely replaced by references to the aliased function.  This is true when:
     *
     *   1. the body of the alias function consists solely of a call to the aliased
     *      function.
     *   2. All the arguments to the alias are passed to the aliased function in the
     *      same order as the alias's argument list
     *   3. the aliased function and the alias have the same arity
     *   4. the aliased function and the alias have compatible strictness (see below)
     *   5. the aliased function and the alias aren't defined in terms of each other
     *      (ie, there is no cycle between the two)
     *   6. the aliased function is not a 0-arity foreign function
     *
     * Ex, in the following:
     *  
     *   foo x y = bar x y;
     *  
     *   bar a b = baz a b;
     *  
     *   baz i j k = quux i j k;
     *  
     *   quux m n o = quux2 m n o;
     *  
     *   quux2 p q r = baz p q r + baz r q p;
     *  
     * foo is an alias of bar.
     * bar is _not_ an alias of baz, because bar and baz have different arities.
     * baz is _not_ an alias of quux, because quux is defined in terms of quux2,
     * which is defined in terms of baz. 
     *
     * The strictness of an alias is compatible with that of an aliased function
     * when the same arguments are plinged, up to the last plinged argument of the
     * alias.  In other words, it's okay for an aliased function to have extra
     * plinged arguments to the right of the last pling on the alias, but otherwise
     * they must match exactly.  Ex:
     *
     *   alpha x y z = delta x y z;
     *  
     *   beta x !y z = delta x y z;
     *  
     *   gamma !x y z = delta x y z;
     *  
     *   delta x !y !z = ...;
     *  
     *  
     *   epsilon x y !z = zeta x y z;
     *  
     *   zeta !x y !z = ...;
     *  
     * In the above code, alpha has compatible strictness with delta, because
     * alpha doesn't have any plinged arguments.
     *
     * beta has compatible strictness with delta, because the first and second
     * arguments have the same plings; the third argument doesn't need to have
     * the same strictness because the second argument is beta's last plinged
     * argument.
     *
     * gamma and delta do _not_ have compatible strictness, because gamma's
     * first argument is plinged and delta's is not.
     *
     * epsilon and zeta also don't have compatible strictness, because the
     * first argument's strictness does not match (which is important because
     * the third argument is epsilon's rightmost strict argument).
     *   
     */
    private QualifiedName aliasOf;

    /**
     * If this function is a literal value. (e.g. foo = 1.0;) this member will
     * hold the literal value, null otherwise.
     */
    private Object literalValue = null;
   
    /** Set of names (i.e. String) comprising the names of functions that are strongly connected to this function.*/
    private Set<String> connectedComponents = new HashSet<String>();
   
    /** Flag indicating the type of the function. This will be one of the constant values:
     * CAL_FUNCTION_TYPE, FOREIGN_FUNCTION_TYPE, or PRIMITIVE_FUNCTION_TYPE */
    private final byte functionType;
   
    /**
     * This flag indicates whether the function can be eagerly evaluated.
     * If true it means that we will evaluate the function in any situation where it
     * can be determined that each function argument is already in WHNF or is an
     * expression for which we can ignore laziness.
     */
    private final boolean functionCanBeEagerlyEvaluated;
   
    /**
     * Factory method for creating a CoreFunction instance for a DataConstructor
     * @param dc
     * @param timeStamp
     * @return the new CoreFunction
     */
    static final CoreFunction makeDataConstructorCoreFunction (DataConstructor dc, long timeStamp) {
        return new CoreFunction (dc, timeStamp);
    }
   
    /**
     * Factory method for creating a CoreFunction for a primitive function
     * @param name
     * @param formalParameters
     * @param parameterStrictness
     * @param parameterTypes
     * @param resultType
     * @param timeStamp
     * @return the new CoreFunction
     */
    static final CoreFunction makePrimitiveCoreFunction(QualifiedName name,
                                                        String[] formalParameters,
                                                        boolean[] parameterStrictness,
                                                        TypeExpr[] parameterTypes,
                                                        TypeExpr resultType,
                                                        long timeStamp) {
        return new CoreFunction (name,
                                 formalParameters,
                                 parameterStrictness,
                                 parameterTypes,
                                 resultType,
                                 PRIMITIVE_FUNCTION_TYPE,
                                 EagerFunctionInfo.canFunctionBeEagerlyEvaluated(name),
                                 timeStamp);
    }

    /**
     * Factory method for creating a CoreFunction for a foreign function.
     * @param name
     * @param formalParameters
     * @param parameterStrictness
     * @param parameterTypes
     * @param resultType
     * @param timeStamp
     * @return the new CoreFunction
     */
    static final CoreFunction makeForeignCoreFunction(QualifiedName name,
                                                      String[] formalParameters,
                                                      boolean[] parameterStrictness,
                                                      TypeExpr[] parameterTypes,
                                                      TypeExpr resultType,
                                                      long timeStamp) {
        return new CoreFunction (name,
                                 formalParameters,
                                 parameterStrictness,
                                 parameterTypes,
                                 resultType,
                                 FOREIGN_FUNCTION_TYPE,
                                 EagerFunctionInfo.canFunctionBeEagerlyEvaluated(name),
                                 timeStamp);
    }

    /**
     * Factory method for creating a CoreFunction for a CAL function.
     * @param name
     * @param formalParameters
     * @param parameterStrictness
     * @param parameterTypes
     * @param resultType
     * @param timeStamp
     * @return the new CoreFunction
     */
    static final CoreFunction makeCALCoreFunction(QualifiedName name,
                                                  String[] formalParameters,
                                                  boolean[] parameterStrictness,
                                                  TypeExpr[] parameterTypes,
                                                  TypeExpr resultType,
                                                  long timeStamp) {
        return new CoreFunction (name,
                                 formalParameters,
                                 parameterStrictness,
                                 parameterTypes,
                                 resultType,
                                 CAL_FUNCTION_TYPE,
                                 EagerFunctionInfo.canFunctionBeEagerlyEvaluated(name),
                                 timeStamp);
    }
   
    /**
     * The SupercombinatorActivationRecord.
     * Creation date: (3/7/00 4:11:07 PM)
     * @param name
     * @param formalParameters
     * @param parameterStrictness
     * @param parameterTypes
     * @param resultType
     * @param functionType
     * @param functionCanBeEagerlyEvaluated
     * @param timeStamp
     */
    private CoreFunction(QualifiedName name,
            String[] formalParameters,
            boolean[] parameterStrictness,
            TypeExpr[] parameterTypes,
            TypeExpr resultType,
            byte functionType,
            boolean functionCanBeEagerlyEvaluated,
            long timeStamp) {
       
        if (name == null || resultType == null) {
            throw new IllegalArgumentException();
        }
       
        final int nArgs = formalParameters.length;
                       
        if (nArgs != parameterStrictness.length ||
            nArgs != parameterTypes.length) {           
            throw new IllegalArgumentException();
        }
       
        if (nArgs == 0) {
            this.formalParameters = NO_ARGS_FORMAL_PARAMETERS;
            this.parameterStrictness = NO_ARGS_PARAMETER_STRICTNESS;
            this.parameterTypes = NO_ARGS_PARAMETER_TYPES;
        } else {
            this.formalParameters = formalParameters;
            this.parameterStrictness = parameterStrictness;
            this.parameterTypes = parameterTypes;       
        }
                
        this.name = name;          
        this.resultType = resultType;
        this.functionType = functionType;
        this.functionCanBeEagerlyEvaluated = functionCanBeEagerlyEvaluated;
        this.timeStamp = timeStamp;   
    }     

    /**
     * Create a CoreFunction instance for a data constructor.
     * @param dc
     * @param timeStamp
     */
    private CoreFunction (DataConstructor dc, long timeStamp) {
        if (dc == null) {
            throw new IllegalArgumentException();
        }

        this.name = dc.getName()
       
        final int nArgs = dc.getArity();

        if (nArgs == 0) {
            this.formalParameters = NO_ARGS_FORMAL_PARAMETERS;
            this.parameterStrictness = NO_ARGS_PARAMETER_STRICTNESS;
            this.parameterTypes = NO_ARGS_PARAMETER_TYPES;
        } else {
            this.formalParameters = new String [nArgs];
            for (int i = 0; i < nArgs; ++i) {
                this.formalParameters [i] = dc.getNthFieldName(i).toString();
            }
            this.parameterStrictness = dc.getArgStrictness();
            this.parameterTypes = new TypeExpr [nArgs];
        }
              
        TypeExpr dcType = dc.getTypeExpr();
        TypeExpr[] tft = dcType.getTypePieces(nArgs);
        System.arraycopy(tft, 0, this.parameterTypes, 0, this.parameterTypes.length);
        this.resultType = tft[tft.length-1];
                
        this.functionType = CAL_DATA_CONSTRUCTOR_TYPE;
        this.functionCanBeEagerlyEvaluated = false;
        this.timeStamp = timeStamp;   
       
    }
   
    /**
     * Return rich diagnostic information about the supercombinator.
     * @return a MessageKind object containing the information about this supercombinator
     */
    MessageKind dump() {
        if( getNFormalParameters() == 0) {
            return new MessageKind.Info.SupercombinatorInfoDumpCAF(toString(), formalParameters.toString());
        } else {
            return new MessageKind.Info.SupercombinatorInfoDumpNonCAF(toString(), formalParameters.toString());
        }       
    }
   
    public String[] getFormalParameters() {
        if (formalParameters.length == 0) {
            return NO_ARGS_FORMAL_PARAMETERS;
        }
       
        return formalParameters.clone();
    }
        
    /**
     * Get the number of formal arguments for this supercombinator.
     * Creation date: (3/9/00 3:30:22 PM)
     * @return int
     */
    public int getNFormalParameters() {
        return formalParameters.length;
    }
   
    public String getNthFormalParameter(int n) {
        return formalParameters[n];           
    }
   
    /**
     * Get the ordinal (0 based) for the named formal parameter.   
     * @return int the  ordinal or -1 if not found 
     * @param parameterName the name of the argument variable   
     */
    public int getFormalParameter(String parameterName) {
        for (int i = 0, n = getNFormalParameters(); i < n; ++i) {
            if (parameterName.equals(formalParameters[i])) {
                return i;
            }
        }
       
        return -1;                   
    }   
   
    public boolean isNthFormalParameterStrict(int paramN) {
        return parameterStrictness[paramN];
    }
   
    /**
     * @return - true if any of the arguments are strict.
     */
    public boolean hasStrictArguments() {
        for (int i = 0, n = getNFormalParameters(); i < n; ++i) {
            if (isNthFormalParameterStrict(i)) {
                return true;
            }
        }
       
        return false;      
    }

    public boolean[] getParameterStrictness(){
        if (parameterStrictness.length == 0) {
            return NO_ARGS_PARAMETER_STRICTNESS;
        }
       
        return parameterStrictness.clone();
    }
   
    public TypeExpr[] getParameterTypes() {
        if (parameterTypes.length == 0) {
            return NO_ARGS_PARAMETER_TYPES;
        }
        return TypeExpr.copyTypeExprs(parameterTypes);
    }
   
    public TypeExpr getResultType() {
        return resultType;
    }
   
    /**
     * Get the type signature for the function. This is arguments and return type.
     * @return The function type signature.
     */
    public TypeExpr[] getType(){
        TypeExpr[] argAndResultTypes = new TypeExpr[parameterTypes.length + 1];
        for(int i = 0; i < parameterTypes.length; ++i){
            argAndResultTypes[i] = parameterTypes[i];
        }
        argAndResultTypes[parameterTypes.length] = resultType;
       
        argAndResultTypes = TypeExpr.copyTypeExprs(argAndResultTypes);

        return argAndResultTypes;
    }
     
    /**
     * Return this supercombinator's name.
     * Creation date: (3/17/00 3:50:52 PM)
     * @return QualifiedName the name
     */
    public QualifiedName getName() {
        return name;
    }             
        
    /**
     * Return description of CoreFunction.
     * @return a string description of this CoreFunction
     */
    @Override
    public String toString() {
       
        StringBuilder result = new StringBuilder(name.getQualifiedName());
        result.append('\n');
        for (int i = 0, nArgs = getNFormalParameters(); i < nArgs; ++i) {
            result.append("arg#").append(i).append(" = ");
            if (isNthFormalParameterStrict(i)) {
                result.append('!');
            }
            result.append(getNthFormalParameter(i));
            result.append(" :: ");
            result.append(parameterTypes[i]);
            result.append('\n');           
        }
        result.append('\n');            
        return result.toString();
    }
   
    /**
     * Set the expression form for the associated supercombinator.
     * @param e
     */
    public void setExpression (Expression e) {
        expression = e;
        if (expression != null) {
            if (expression.asLiteral() != null && getNFormalParameters() == 0) {
                literalValue = expression.asLiteral().getLiteral();
                aliasOf = null;
            } else {
                literalValue = null;
            }
        }
    }
   
   
    /**
     * Reset the strictness of the arguments. This is only for use in the compiler. Current needed
     * by the CAL optimizer to updated the strictness as part of the optimization that moves Seq'ed
     * arguments to plinged arguments.
     *
     * @param parameterStrictness The new array of strictness values.
     */
    void setParameterStrictness(boolean[] parameterStrictness){
        if (formalParameters.length != parameterStrictness.length){
            throw new IllegalArgumentException();
        }

        this.parameterStrictness = parameterStrictness;
    }   
   
    /**
     * Get the expressoin form for the associated supercombinator.
     * @return Expression
     */
    public Expression getExpression () {
        return expression;
    }
   
    /**
     * Return the timestamp associated with this record.
     * @return long
     */
    public long getTimeStamp () {
        return timeStamp;
    }
    /**
     * @return Returns the isTailRecursive.
     */
    public boolean isTailRecursive() {
        return isTailRecursive;
    }
    /**
     * @param isTailRecursive The isTailRecursive to set.
     */
    public void setIsTailRecursive(boolean isTailRecursive) {
        this.isTailRecursive = isTailRecursive;
    }
    /**
     * @return Returns the aliasOf.
     */
    public QualifiedName getAliasOf() {
        return aliasOf;
    }
    /**
     * @param aliasOf The aliasOf to set.
     */
    public void setAliasOf(QualifiedName aliasOf) {
        this.aliasOf = aliasOf;
    }

    /**
     * @return (String set) the connectedComponents. Will be unmodifiable and not null.
     */
    public Set<String> getStronglyConnectedComponents() {
        return Collections.unmodifiableSet(connectedComponents);
    }
   
    /**
     * @param connectedComponents (String set) The connectedComponents to set. Cannot be null.
     */
    public void setStronglyConnectedComponents(Set<String> connectedComponents) {
        if (connectedComponents == null) {
            throw new NullPointerException();
        }
        this.connectedComponents = connectedComponents;
    }
   
    /**
     * @param function name of the function, assumed to be in the same module as this function
     * @return true if this is strongly connected to function.
     */
    public boolean isStronglyConnectedTo (String function) {
        if (connectedComponents.contains(function)) {
            return true;
        }
        return false;
    }   
   
    /**
     * Write this instance of CoreFunction to the RecordOutputStream.
     * @param s
     * @throws IOException
     */
    public final void write (RecordOutputStream s) throws IOException {
        s.startRecord (ModuleSerializationTags.CORE_FUNCTION, serializationSchema);

        // name
        s.writeQualifiedName(name);
       
        // flags for existence of 'aliasOf', tail recursion, and safety.
        byte[] flags = RecordOutputStream.booleanArrayToBitArray(new boolean[]{aliasOf != null, isTailRecursive, canFunctionBeEagerlyEvaluated()});
        if (flags.length != 1) {
            throw new IOException("Unexpected number of bytes for flags in CoreFunction: " + flags.length);
        }
        s.writeByte(flags[0]);
       
        // formalParameters
        s.writeShortCompressed(formalParameters.length);
        for (int i = 0; i < formalParameters.length; ++i) {           
            s.writeUTF (formalParameters [i]);
        }

        // parameterStrictnss
        int nBytesForArgFlags = ((formalParameters.length) + 7) / 8;
        byte[] bytesForArgFlags = RecordOutputStream.booleanArrayToBitArray(parameterStrictness);
        if (bytesForArgFlags.length != nBytesForArgFlags) {
            throw new IOException("Unexpected number of bytes for strictness flags in CoreFunction.");
        }
        s.write(bytesForArgFlags);
       
        // parameterTypes
        boolean[] typeExistence = new boolean[formalParameters.length];
        for (int i = 0; i < formalParameters.length; ++i) {
            typeExistence[i] = parameterTypes[i] != null;
        }
        bytesForArgFlags = RecordOutputStream.booleanArrayToBitArray(typeExistence);
        if (bytesForArgFlags.length != nBytesForArgFlags) {
            throw new IOException("Unexpected number of bytes for strictness flags in CoreFunction.");
        }
        s.write(bytesForArgFlags);

        // Write the function type
        {
            ArrayList<TypeExpr> types = new ArrayList<TypeExpr>(formalParameters.length+1);
            for (int i = 0; i < formalParameters.length; ++i) {           
                if (parameterTypes[i] != null) {
                    types.add(parameterTypes[i]);
                }
            }
            types.add(resultType);
            TypeExpr.write(s, types);
        }

        // aliasOf
        if (aliasOf != null) {
            s.writeQualifiedName(aliasOf);
        }
       
        // timestamp
        s.writeLong (timeStamp);
       
        s.writeShortCompressed(connectedComponents.size());
        for (final String componentName : connectedComponents) {
            s.writeUTF (componentName);
        }

        // Write out the function type (i.e. primitive, foreign, cal
        s.writeByte(functionType);
       
       
        s.writeBoolean(literalValue != null);
        if (literalValue != null) {
            Class<? extends Object> valueClass = literalValue.getClass();
            if (valueClass == java.lang.Character.class) {
                s.writeByte(LITERAL_TYPE_CHARACTER);
                s.writeChar(((Character)literalValue).charValue());
            } else if (valueClass == java.lang.Boolean.class) {
                s.writeByte(LITERAL_TYPE_BOOLEAN);
                s.writeBoolean(((Boolean)literalValue).booleanValue());
            } else if (valueClass == java.lang.Integer.class) {
                s.writeByte(LITERAL_TYPE_INTEGER);
                s.writeInt(((Integer)literalValue).intValue());
            } else if (valueClass == java.lang.Double.class) {
                s.writeByte(LITERAL_TYPE_DOUBLE);
                s.writeDouble(((Double)literalValue).doubleValue());
            } else if (valueClass == java.lang.Byte.class) {
                s.writeByte(LITERAL_TYPE_BYTE);
                s.writeByte(((Byte)literalValue).byteValue());
            } else if (valueClass == java.lang.Short.class) {
                s.writeByte(LITERAL_TYPE_SHORT);
                s.writeShort(((Short)literalValue).shortValue());
            } else if (valueClass == java.lang.Float.class) {
                s.writeByte(LITERAL_TYPE_FLOAT);
                s.writeFloat(((Float)literalValue).floatValue());
            } else if (valueClass == java.lang.Long.class) {
                s.writeByte(LITERAL_TYPE_LONG);
                s.writeLong(((Long)literalValue).longValue());
            } else if (valueClass == String.class) {
                s.writeByte(LITERAL_TYPE_STRING);
                s.writeUTF((String)literalValue);
            } else if (valueClass == BigInteger.class) {
                s.writeByte(LITERAL_TYPE_BIG_INTEGER);
                String ds = ((BigInteger)literalValue).toString();
                s.writeUTF(ds);
            else {
                throw new IOException ("Attemp to write unhandled literal value of type: " + literalValue.getClass().getName());
            }
        }
       
        s.writeBoolean(isForAdjunct);
        s.writeBoolean(hadUnsafeCoerce);
       
        expression.write(s);
       
        s.endRecord ();
    }
   
    /**
     * Load an instance of CoreFunction from the RecordInputStream.
     * The read position of the RecordInputStream will be before the record header.
     * @param s
     * @param mti
     * @param msgLogger the logger to which to log deserialization messages.
     * @return an instance of CoreFunction.
     * @throws IOException
     */
    public static final CoreFunction load (RecordInputStream s, ModuleTypeInfo mti, CompilerMessageLogger msgLogger) throws IOException {
        RecordHeaderInfo rhi = s.findRecord(ModuleSerializationTags.CORE_FUNCTION);
        if (rhi == null) {
            throw new IOException("Unable to find CoreFunction record header.");
        }
        DeserializationHelper.checkSerializationSchema(rhi.getSchema(), serializationSchema, mti.getModuleName(), "CoreFunction", msgLogger);
       
        QualifiedName name = s.readQualifiedName();
        try {
            byte flags = s.readByte();
            boolean aliasOfExists = (flags & 0x01) > 0;
            boolean isTailRecursive = (flags & 0x02) > 0;
            boolean functionCanBeEagerlyEvaluated = (flags &0x04) > 0;
           
            int nArgs = s.readShortCompressed();
            String[] argNames = new String[nArgs];
            for (int i = 0; i < nArgs; ++i) {
                argNames[i] = s.readUTF();
            }
           
            int nBytesForArgFlags = (nArgs + 7) / 8;
            byte[] argFlags = new byte[nBytesForArgFlags];
            for (int i = 0; i < argFlags.length; ++i) {
                argFlags[i] = s.readByte();
            }
           
            boolean[] argStrictness = RecordInputStream.bitArrayToBooleans(argFlags, nArgs);
           
            TypeExpr[] argTypes = new TypeExpr[nArgs];
            for (int i = 0; i < argFlags.length; ++i) {
                argFlags[i] = s.readByte();
            }
            boolean[] typeExistence = RecordInputStream.bitArrayToBooleans(argFlags, nArgs);
            int nArgsPresent = 0;
            for (int i = 0; i < nArgs; ++i) {
                if (typeExistence[i]) {
                    nArgsPresent++;
                }
            }
           
            TypeExpr[] types = TypeExpr.load(s, mti, nArgsPresent+1, msgLogger);
            int iSource = 0;
            // length of type existence is the number of args
            for(int iDest = 0; iDest < nArgs; ++iDest){
                if (typeExistence[iDest]){
                    argTypes[iDest] = types[iSource++];
                }
            }
           
            TypeExpr resultType = types[nArgsPresent];
           
            QualifiedName aliasOf = null;
            if (aliasOfExists) {
                aliasOf = s.readQualifiedName();
            }
           
            long timeStamp = s.readLong();
           
            int nConnectedComponents = s.readShortCompressed();
            Set<String> connectedComponents = new HashSet<String>();
            for (int i = 0; i < nConnectedComponents; ++i) {
                String componentName = s.readUTF();
                connectedComponents.add(componentName);
            }
           
            byte type = s.readByte();
           
            CoreFunction cf = new CoreFunction (name,
                                                argNames,
                                                argStrictness,
                                                argTypes,
                                                resultType,
                                                type,
                                                functionCanBeEagerlyEvaluated,
                                                timeStamp);
           
            cf.setIsTailRecursive(isTailRecursive);
            cf.setAliasOf(aliasOf);
            cf.setStronglyConnectedComponents(connectedComponents);
           
            if (!s.atEndOfRecord()) {
                boolean b = s.readBoolean();
                if (b) {
                    byte typeByte = s.readByte();
                    if (typeByte == LITERAL_TYPE_CHARACTER) {
                        cf.literalValue = Character.valueOf(s.readChar());
                    } else if (typeByte == LITERAL_TYPE_BOOLEAN) {
                        cf.literalValue = Boolean.valueOf(s.readBoolean());
                    } else if (typeByte == LITERAL_TYPE_INTEGER) {
                        cf.literalValue = Integer.valueOf(s.readInt());
                    } else if (typeByte == LITERAL_TYPE_DOUBLE) {
                        cf.literalValue = Double.valueOf(s.readDouble());
                    } else if (typeByte == LITERAL_TYPE_BYTE) {
                        cf.literalValue = Byte.valueOf(s.readByte());
                    } else if (typeByte == LITERAL_TYPE_SHORT) {
                        cf.literalValue = Short.valueOf(s.readShort());
                    } else if (typeByte == LITERAL_TYPE_FLOAT) {
                        cf.literalValue = Float.valueOf(s.readFloat());
                    } else if (typeByte == LITERAL_TYPE_LONG) {
                        cf.literalValue = Long.valueOf(s.readLong());
                    } else if (typeByte == LITERAL_TYPE_STRING) {
                        cf.literalValue = s.readUTF();
                    } else if (typeByte == LITERAL_TYPE_BIG_INTEGER) {
                        String ds = s.readUTF();
                        cf.literalValue = new BigInteger(ds);
                    else {
                        throw new IOException ("Attemp to read unhandled literal value.");
                    }
                   
                }
            }
           
            boolean isForAdjunct = s.readBoolean();
            cf.setForAdjunct(isForAdjunct);
           
            if (rhi.getSchema() >= serializationSchema){
                boolean hadUnsafeCoerce = s.readBoolean();
                if (hadUnsafeCoerce){
                    cf.setHadUnsafeCoerce();
                }
            }
           
            if (mti.getModule().mustLoadExpressions()) {
                Expression expr = Expression.load (s, mti, msgLogger);
                cf.setExpression (expr);
            }
           
            return cf;
       
        } catch (IOException e) {
            throw new IOException ("Error loading CoreFunction " + name.getQualifiedName() + ": " + e.getLocalizedMessage());
        } finally {
            s.skipRestOfRecord();
        }
    }

    /**
     * @return literal value if this supercombinator is defined as a literal value, null otherwise
     */
    public Object getLiteralValue() {
        return literalValue;
    }
   
    /**
     * @return true if this is a primitive function, false otherwise.
     */
    public boolean isPrimitiveFunction() {
        return functionType == PRIMITIVE_FUNCTION_TYPE;
    }
   
    /**
     * @return true if this is a foreign function, false otherwise.
     */
    public boolean isForeignFunction () {
        return functionType == FOREIGN_FUNCTION_TYPE;
    }
   
    /**
     * @return true if this is a CAL function (i.e. not primitive and not foreign), false otherwise.
     */
    public boolean isCALFunction () {
        return functionType == CAL_FUNCTION_TYPE;
    }
   
    /**
     * @return true if this is a CAL Data Constructor.
     */
    public boolean isDataConstructor () {
        return functionType == CAL_DATA_CONSTRUCTOR_TYPE;
    }
   
    /**
     * @return true if this CAL function is marked as being valid for
     * eager evaluation.
     */
    public boolean canFunctionBeEagerlyEvaluated () {
        return functionCanBeEagerlyEvaluated;
    }

    public boolean isForAdjunct() {
        return isForAdjunct;
    }

    public void setForAdjunct(boolean isForAdjunct) {
        this.isForAdjunct = isForAdjunct;
    }
   
    /**
     * @return True if the function contained a call to unsafeCoerce.
     */
    public boolean getHadUnsafeCoerce(){
        return hadUnsafeCoerce;
    }

    /**
     * Mark the expression as having contained an unsafeCoerce call.
     */
    public void setHadUnsafeCoerce(){
        hadUnsafeCoerce = true;
    }
}
TOP

Related Classes of org.openquark.cal.compiler.CoreFunction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.