/* * 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; } }