Package org.openquark.cal.compiler

Source Code of org.openquark.cal.compiler.ClassInstance$InstanceStyle

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


/*
* ClassInstance.java
* Created: April 5, 2001
* By: Bo Ilic
*/
package org.openquark.cal.compiler;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.List;
import java.util.ArrayList;

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;


/**
* Models a class instance definition.
* <p>
* There are 2 kinds of class instances:
* <p>
* <ol>
<li> type constructor instances -the instance type has a type constructor root
*  e.g.
<ul>
*     <li> instance Num Int
*     <li> instance Eq a => Eq (List a)
*     <li> instance (Ord a, Ord b) => Ord (Tuple2 a b)
*     <li> instance Enum Ordering
</ul>
* <p>
* <li> universal record instances - the instance type is a record-polymorphic record.
*  It is "universal" because the instance definition applies to *all* records whose fields satisfy the specified
*  constraints i.e. it does not make any restrictions on the allowable field names. For example,
*  instance Outputable a => Outputable {a}
* </ol>
* <p>
* @author Bo Ilic
*/
public final class ClassInstance {

    private static final int serializationSchema = 0;
   
    /** the module in which this class instance is defined. */
    private final ModuleName moduleName;

    /**
     * The type of the instance e.g. if Int is an instance of Num, then this is Int. This is
     * a type (rather than just a string such as "Int") because of constrained instances.
     * For example, "instance Eq a => [a]" and "instance (Ord a, Ord b) => Ord (a, b)" to
     * define Eq on lists, and Ord for pairs.
     */
    private final TypeExpr instanceType;

    /** the TypeClass object that this instance implements */
    private final TypeClass typeClass;
       
    /** the style of the instance - indicates how it was created*/
    private final InstanceStyle instanceStyle;
   
    private transient ClassInstanceIdentifier identifier;   
    
    /**
     * the (QualifiedName) list of names of the concrete methods that implement the class methods.
     * Note, these must follow the same ordering as TypeClass.classMethodsList.
     * For example, in the case of Int as an instance of Num, this would be
     * ["addInt", "subtractInt", "multiplyInt", "divideInt"]
     * Note that an entry in this array will be null if no explicit instance method was supplied in the instance declaration
     * and we default to the default class method.
     */
    private final QualifiedName[] instanceMethods;
   
    /** The CALDoc comment for this instance, or null if there is none. */
    private CALDocComment calDocComment;
   
    /** The CALDoc comments for the instance methods. Each element can be null if the method has no corresponding CALDoc. */
    private final CALDocComment[] methodCALDocComments;
   
    /**
     * The prefix used for defining dictionary functions such as $dictEq#Int.   
     */
    static final String DICTIONARY_FUNCTION_PREFIX = "$dict"
   
    /**
     * This is an Enumeration that defines the different styles of instances
     * @author Magnus Byne
     */
    final public static class InstanceStyle {
        private final String name;
        private final int key;
       
        private InstanceStyle(String name, int key) { this.name = name; this.key = key; }
       
        @Override
        public String toString() { return name; }
       
        private static final int explicitKey = 1;
        private static final int derivingKey = 2;
        private static final int internalKey = 3;
                       
       
        /** instances that are defined explicitly in full in source. This does
         * not include instances that are created via a deriving clause*/
        public static final InstanceStyle EXPLICIT = new InstanceStyle("Explicit", explicitKey);

        /** instances that are created via a deriving clause*/
        public static final InstanceStyle DERIVING = new InstanceStyle("Deriving", derivingKey);
   
        /** instances that are created by the compiler. This includes most typeable instances,
         * which are typically created automatically be the compiler.*/
        public static final InstanceStyle INTERNAL = new InstanceStyle("Internal", internalKey);
       
        /**
         * @return this is true if the instance has been defined implicitly,
         * e.g. through a deriving clause, or by the compiler.
         */
        public final boolean isImplicit() {
            return this != EXPLICIT;
        }
               
        /** serialize the style*/
        void write(RecordOutputStream s) throws IOException {
            s.writeIntCompressed(key);
        }
       
        /** un-serialize the style*/
        static InstanceStyle load(RecordInputStream s, CompilerMessageLogger msgLogger) throws IOException {
            int key = s.readIntCompressed();
       
            switch (key) {
            case explicitKey:
                return EXPLICIT;
            case derivingKey:
                return DERIVING;
            case internalKey:
                return INTERNAL;
            default:
                throw new IOException("Unknown " + InstanceStyle.class.getName() + " key encountered: " + key);                
            }
        }
       
    }
   
    /**
     * ClassInstance constructor.
     * Creation date: (4/5/01 12:25:25 PM)
     * @param moduleName the module in which this class instance is defined
     * @param instanceType the type of the instance e.g. Int
     * @param typeClass the class that this is an instance of e.g. Ord
     * @param instanceMethods instance methods, in order of the type class methods. Can be null if they will be set later,
     *    or if they should be automatically determined for instanceStyle instances.
     * @param instanceStyle whether the class instance is internally defined e.g. most Typeable instances and derived
     *    instances (versus defined in source via an explicit instance declaration).
     */
    ClassInstance(ModuleName moduleName, TypeExpr instanceType, TypeClass typeClass, QualifiedName[] instanceMethods, InstanceStyle instanceStyle) {
       
        if (moduleName == null || instanceType == null || typeClass == null) {
            throw new NullPointerException();
        }
               
        final int nClassMethods = typeClass.getNClassMethods();       

        if (instanceType instanceof TypeConsApp) {
             //do a quick check to verify that all the arguments of the type constructor
             //are uninstantiated type variables.
             TypeConsApp instanceTypeConsApp = (TypeConsApp)instanceType;
             for (int i = 0, nVars = instanceTypeConsApp.getNArgs(); i < nVars; ++i) {
                 TypeVar typeVar = (TypeVar)instanceTypeConsApp.getArg(i);
                 if (typeVar.getInstance() != null) {
                     throw new IllegalStateException();
                 }
             }
            
             if ( (instanceStyle.isImplicit()) && instanceMethods == null) {
                
                 //the names of the instance methods of implicitly defined instance are determined from the
                 //class method name and instance type constructor (provided they haven't been pre-supplied via
                 //a non-null instanceMethods argument.
                
                 instanceMethods = new QualifiedName[nClassMethods];
                
                
                 //if this is a built-in Typeable instance, then there is a single class method whose name is derived from the TypeConsApp name
                 //For example, for Either, it will be $typeOfEither.
                
                 QualifiedName typeConsName = instanceTypeConsApp.getName();
              
                 for (int i = 0; i < nClassMethods; ++i) {
                     ClassMethod classMethod = typeClass.getNthClassMethod(i);
                     instanceMethods[i] = ClassInstance.makeInternalInstanceMethodName(classMethod.getName().getUnqualifiedName(), typeConsName);                                                        
                 }                                     
             }
            
        } else if (instanceType instanceof RecordType) {
            if ((instanceStyle.isImplicit())) {
                throw new IllegalArgumentException("there are no implicitly defined record instances.");
            }           
            //this is OK as well.          
        } else {           
            throw new IllegalArgumentException("instances must be based on type constructors or records.");
        }       

        this.moduleName = moduleName;
        this.instanceType = instanceType;
        this.typeClass = typeClass;
        this.instanceStyle = instanceStyle;
       
        if (instanceMethods == null) {
            //initialize, but do not populate. instanceMethods will be populated by addInstanceMethod calls below.
            this.instanceMethods = new QualifiedName[nClassMethods];
        } else {
            this.instanceMethods = instanceMethods;
        }
        this.identifier = ClassInstanceIdentifier.make(this);
       
        this.calDocComment = null;
        this.methodCALDocComments = new CALDocComment[this.instanceMethods.length];
    }
   
    /**
     * The name of the instance method for an internally defined class instance.  
     *  
     * @param classMethodName for example "equals" or "typeOf"
     * @param typeConsName for example, "Prelude.Either" or "LegacyTuple.Tuple2"
     * @return for example, "Prelude.$equals$Either" or "LegacyTuple.$typeOf$Tuple2"
     */
    static QualifiedName makeInternalInstanceMethodName(String classMethodName, QualifiedName typeConsName) {       
        String instanceMethodName =            
            new StringBuilder("$")
            .append(classMethodName)
            .append('$')
            .append(typeConsName.getUnqualifiedName()).toString();
        return QualifiedName.make(typeConsName.getModuleName(), instanceMethodName);         
    }
   
    /**    
     * @return true if the instance type is a record-polymorphic record type, such as e.g. "instance Eq r => {r}".
     */
    public final boolean isUniversalRecordInstance () {
                       
        return instanceType instanceof RecordType;
    }
        
    /**
     * @return the style of this instance, e.g. internal, deriving, explicit
     */
    public final InstanceStyle getInstanceStyle () {
        return instanceStyle;
    }
   
    /**    
     * @return true if the instance type has a type constructor root, such as e.g. "instance Ord Int", "instance Eq a => Eq (List a)"
     */
    public final boolean isTypeConstructorInstance () {
        return instanceType instanceof TypeConsApp; 
    }   
   
    /**
     * @return TypeClass the type class that this instance is an instance of. e.g. if Ord Int, then it is the Ord type class.
     */
    public final TypeClass getTypeClass() {
        return typeClass;
    }
   
    /**
     * Add the name of an implementing method to the instance.
     *
     * @param classMethod the class method that this instance method will implement
     * @param instanceMethodName
     */
    void addInstanceMethod(ClassMethod classMethod, QualifiedName instanceMethodName) {
       
        final int ordinal = classMethod.getOrdinal();
        if (instanceMethods[ordinal] != null) {
            throw new IllegalStateException("attempt to re-initialize an instance method.");
        }
       
        instanceMethods[ordinal] = instanceMethodName;
    }
           
    /**    
     * For example, if this is the Eq-Int instance, and the class method name is equals,
     * this returns equalsInt.
     * @param classMethodName
     * @return QualifiedName instance method name corresponding to classMethodName, or null if none such exists. 
     */
    QualifiedName getInstanceMethod(QualifiedName classMethodName) {

        if (!classMethodName.getModuleName().equals(typeClass.getName().getModuleName())) {       
            return null;
        }

        int methodN = typeClass.getClassMethodIndex(classMethodName.getUnqualifiedName());
        if (methodN == -1) {
            return null;
        }

        return getInstanceMethod(methodN);
    }   
         
    /**
     * Get the name of the implementing instance method.
     *
     * @return QualifiedName
     * @param methodN the number of the method in the list of class methods for the type class.
     *      Will be null the instance does not define the method. That is, the intent is to use
     *      the default class method.    
     */
    public final QualifiedName getInstanceMethod(int methodN) {

        return instanceMethods[methodN];
    }
   
    /**
     * Returns the type of the specified instance method. For example, the add method in the instance Num Int
     * would have a type of Int -> Int -> Int.
     * @param methodN the index of the method in the list of class methods for the type class
     * @return type type of the specified instance method.
     */
    public final TypeExpr getInstanceMethodType(int methodN) {
        ClassMethod classMethod = typeClass.getNthClassMethod(methodN);                              
       
        TypeExpr classMethodType = CopyEnv.freshType(classMethod.getTypeExpr(), null);       
        TypeVar classTypeVar = classMethodType.getTypeClassTypeVar(typeClass.getTypeClassTypeVarName());
        classTypeVar.setInstance(this.getType());
        TypeExpr instanceMethodType = classMethodType;
       
        return instanceMethodType;
    }
   
    /**
     * Returns the type of the specified instance method. For example, the add method in the instance Num Int
     * would have a type of Int -> Int -> Int.
     * @param methodName the name of the instance method.
     * @return type type of the specified instance method.
     */
    public final TypeExpr getInstanceMethodType(String methodName) {
        int methodN = typeClass.getClassMethodIndex(methodName);
        if (methodN == -1) {
            throw new IllegalArgumentException("There is no method named " + methodName + " in this instance.");
        }

        return getInstanceMethodType(methodN);
    }
   
    /**
     * @return int the number of instance methods. This is the same as the number of class methods of the correspoding type class.
     */
    public final int getNInstanceMethods() {

        return instanceMethods.length;
    }      
   
    /**
     * The type of the instance e.g. Int, Double, Eq a => [a].
     * Creation date: (4/5/01 1:00:23 PM)
     * @return TypeExpr
     */
    public final TypeExpr getType() {
        //make a copy so that clients don't accidentally mess up ClassInstance's own internal value.
        return CopyEnv.freshType(instanceType, null);
    }
   
    /**
     * @return the instance identifier, where the type class and type constructor entity name are
     *      fully qualified and separated by a space e.g. "Cal.Core.Prelude.Num Cal.Core.Prelude.Int"
     */
    public final ClassInstanceIdentifier getIdentifier() {       
        return identifier;             
    }
   
    /**    
     * The internal name of the hidden dictionary function corresponding to this class instance.
     * For example, for a C-T instance defined in module M this is M.$dictC#T.
     *
     * Note the behavior in the case of single method root classes is to return the instance method name
     * (or the default class method name if there is no instance method defined). This is because the single
     * method root class case is optimized and there are no dictionary functions generated for it. The instance
     * (or class) method returned serves an analogous role.
     *
     * @return the internal name of the dictionary function for this instance.
     */
    QualifiedName getDictionaryFunctionName() {
        //the dictionary function for an instance whose type class is a single class
        //method type classes with no parent classes can be defined as in the example:
        //$dictClass#Type = instanceFunction;
        //so we might as well inline the dictionary function, and just use instanceFunction.
        if (typeClass.internal_isSingleMethodRootClass()) {
           
            QualifiedName instanceMethodName = getInstanceMethod(0);           
            if (instanceMethodName == null) {
                //use the default class method
                ClassMethod classMethod = typeClass.getNthClassMethod(0);               
                return classMethod.getDefaultClassMethodName();               
            }
            return instanceMethodName;
        }
       
        return QualifiedName.make(moduleName, DICTIONARY_FUNCTION_PREFIX + getIdentifier().getInstanceIdentifier());
    }
     
    /**
     * A canonical form of the name of the class instance, including the context.
     * This is essentially what follows the "instance" keyword in the CAL source for the instance declaration if fully
     * qualified names are used.
     *
     * <p>Some examples:
     * <ol>
     *   <li> Cal.Core.Prelude.Ord Cal.Core.Prelude.Int
     *   <li> (Cal.Core.Prelude.Eq a, Cal.Core.Prelude.Eq b) => Cal.Core.Prelude.Eq (Cal.Core.Prelude.Either a b)
     *   <li> Cal.Core.Debug.Show a => Cal.Core.Debug.Show [a]
     * </ol>   
     *         
     * @return a canonical form of the name of the class instance, along with its context.
     */
    public final String getNameWithContext() {
        return getNameWithContext(ScopedEntityNamingPolicy.FULLY_QUALIFIED);
    }
   
    /**
     * The name of the class instance, including the context, using the specified naming policy.
     * This is essentially what follows the "instance" keyword in the CAL source for the instance declaration, modified
     * according to the naming policy.
     *
     * <p>Some examples with the unqualified naming policy:
     * <ol>
     *   <li> Ord Int
     *   <li> (Eq a, Eq b) => Eq (Either a b)
     *   <li> Show a => Show [a]
     * </ol>   
     *
     * @param namingPolicy used for formatting type class and type constructor names within the class instance name and context     
     * @return the name of the class instance, along with its context, using the specified naming policy.
     */   
    public final String getNameWithContext(ScopedEntityNamingPolicy namingPolicy) {       
        return getNameWithContext(typeClass, instanceType, namingPolicy);    
    }
   
    /**    
     * @return a canonical form of the name of the class instance.
     */
    public final String getName() {
        return getName(ScopedEntityNamingPolicy.FULLY_QUALIFIED);
    }
   
    /**    
     * @param namingPolicy
     * @return the name of the class instance (e.g. "Eq (Either a b)") not including the class context, using the specified naming policy.
     */
    public final String getName(ScopedEntityNamingPolicy namingPolicy) {
        return getNameHelper(typeClass, instanceType, namingPolicy, false);       
    }
           
    /**
     * Sometimes a class instance for typeClass-instanceType is required, but none is supplied. In that case
     * we want to give an error message describing what instance is required. This method provides the
     * declaration name for such an instance.
     * @param typeClass
     * @param instanceType
     * @param namingPolicy
     * @return String
     */
    static String getNameWithContext(TypeClass typeClass, TypeExpr instanceType, ScopedEntityNamingPolicy namingPolicy) {             
        return getNameHelper(typeClass, instanceType, namingPolicy, true);
    }
      
    static private String getNameHelper(
            final TypeClass typeClass,
            final TypeExpr instanceType,
            final ScopedEntityNamingPolicy namingPolicy,
            final boolean includeContext) {
       
        final String className = typeClass.getAdaptedName(namingPolicy);
        final String typeName = instanceType.toString(namingPolicy);
        final int nArgs;
        if (instanceType instanceof TypeConsApp) {
            nArgs = ((TypeConsApp)instanceType).getNArgs();
        } else {
            nArgs = 0;
        }
        //find if the type has a context
        final int index = typeName.indexOf(" => ");
        final String classInstanceName;
        if (index != -1) {           
            final String rawTypeString = typeName.substring(index + 4);
            if (includeContext) {
                final String contextString = typeName.substring(0, index);
                classInstanceName = contextString + " => " + className + " " + parenthesize(rawTypeString, nArgs);
            } else {
                classInstanceName = className + " " + parenthesize(rawTypeString, nArgs);
            }
        } else {
            classInstanceName = className + " " + parenthesize(typeName, nArgs);
        }

        return classInstanceName;
    }   
   
    private static String parenthesize (String typeName, int nArgs) {
        //don't print Eq ([a]) or Eq ((a, b)) but rather Eq [a] or Eq (a, b)
        //also don't parenthesize 0-arity constructors i.e. Eq Int not Eq (Int).
       
        if (Character.isLetter(typeName.charAt(0)) && nArgs > 0) {           
            return "(" + typeName + ")";
        }    
       
        return typeName;
    }   
   
    /**
     * @return the module in which this class instance is defined.
     */
    public final ModuleName getModuleName() {
        return moduleName;
    }
   
    /**
     * @return the CALDoc comment for this instance, or null if there is none.
     */
    public final CALDocComment getCALDocComment() {
        return calDocComment;
    }
   
    /**
     * Set the CALDoc comment associated with this instance.
     * @param comment the CALDoc comment for this instance, or null if there is none.
     */
    final void setCALDocComment(CALDocComment comment) {
        calDocComment = comment;
    }
   
    /**
     * @param methodName the name of the method.
     * @return the CALDoc comment for the named method, or null if there is none.
     */
    public final CALDocComment getMethodCALDocComment(String methodName) {
        int methodN = typeClass.getClassMethodIndex(methodName);
        if (methodN == -1) {
            throw new IllegalArgumentException("There is no method named " + methodName + " in this instance.");
        }

        return methodCALDocComments[methodN];
    }
   
    /**
     * Set the CALDoc comment associated with the named method.
     * @param methodName the name of the method.
     * @param comment the CALDoc comment for the named method, or null if there is none.
     */
    void setMethodCALDocComment(String methodName, CALDocComment comment) {
        int methodN = typeClass.getClassMethodIndex(methodName);
        if (methodN == -1) {
            throw new IllegalArgumentException("There is no method named " + methodName + " in this instance.");
        }

        methodCALDocComments[methodN] = comment;
    }
   
    /**
     * Textual description of the instance. This is very close to what Haskell source
     * for the instance declaration would be.
     * Creation date: (4/5/01 1:14:01 PM)
     * @return String
     */
    @Override
    public String toString() {

        StringBuilder result = new StringBuilder("instance ");
        result.append(getNameWithContext());
        result.append(" where\n");

        int nClassMethods = typeClass.getNClassMethods();
        int nInstanceMethods = getNInstanceMethods();

        for (int i = 0; i < nClassMethods; ++i) {

            result.append("    ").append(typeClass.getNthClassMethod(i).getName()).append(" = ");

            if (i < nInstanceMethods) {
                result.append(getInstanceMethod(i));
            } else {
                result.append("???");
            }

            result.append(";\n");

        }

        return result.toString();
    }
   
    /**
     * Gets the constraints on the polymorphic variables of a class instance in a way suitable for processing.
     * For example, for the instance (Eq a, Ord c, Ord d, Enum a, Outputable d) => Ord (Foo a b c d),
     * this would return [{Eq, Enum}, {}, {Eq, Ord}, {Eq, Ord, Outputable}].
     *    
     * For example, for the instance (Eq a) => Eq {a} this would return [{Eq}].
     *
     * The constraints include the implicit superclass constraints as well.       
     * @return List<Set<TypeClass>> the ith element of the list is the set of all (including implicit superclass) TypeClass constraints
     *         on the ith polymorphic var of the instance type. (T in C-T).
     */
    List<Set<TypeClass>> getSuperclassPolymorphicVarConstraints() {
       
        if (isUniversalRecordInstance()) {           
            List<Set<TypeClass>> varConstraints = new ArrayList<Set<TypeClass>>(1);
            Set<TypeClass> varConstraint = new HashSet<TypeClass>(((RecordType)instanceType).getPrunedRecordVar().getTypeClassConstraintSet());
            varConstraints.add(varConstraint);
            return varConstraints;
        }            
                                                  
        //call getType() in order to work with a copy of the type
        TypeConsApp typeConsApp = (TypeConsApp)getType();
        final int nVars = typeConsApp.getNArgs();
       
        List<Set<TypeClass>> varConstraints = new ArrayList<Set<TypeClass>>(nVars);
        for (int i = 0; i < nVars; ++i) {           
            TypeVar typeVar = (TypeVar)(typeConsApp.getArg(i));           
            varConstraints.add(typeVar.flattenTypeClassConstraintSet());
        }       
       
        return varConstraints;                                             
    }
   
    /**
     * Gets the constraints on the polymorphic variables of a class instance in a way suitable for processing.
     * For example, for the instance (Eq a, Ord c, Ord d, Enum a, Outputable d) => Ord (Foo a b c d),
     * this would return [{Enum, Eq}, {}, {Ord}, {Outputable, Ord}].
     * The ordering of the sets is alphabetical (by fully qualified type class name). 
     * The constraints do not include implicit superclass constraints.
     *
     * For example, for the universal record instance (Eq a) => Eq {a} this would return [{Eq}].
     *    
     * @return SortedSet[] the ith element of the array is the set of all TypeClass constraints on the ith constrained
     *      polymorphic var of the instance type. (T in C-T).
     */
    List<SortedSet<TypeClass>> getDeclaredPolymorphicVarConstraints() {

        if (isUniversalRecordInstance()) {
            List<SortedSet<TypeClass>> varConstraints = new ArrayList<SortedSet<TypeClass>>(1);
            varConstraints.add(((RecordType)instanceType).getPrunedRecordVar().getTypeClassConstraintSet());           
            return varConstraints;
        }             

        //call getType() in order to work with a copy of the type
        TypeConsApp typeConsApp = (TypeConsApp)getType();
        final int nVars = typeConsApp.getNArgs();
       
        List<SortedSet<TypeClass>> varConstraints = new ArrayList<SortedSet<TypeClass>>(nVars);
        for (int i = 0; i < nVars; ++i) {           
            TypeVar typeVar = (TypeVar)(typeConsApp.getArg(i));           
            varConstraints.add(typeVar.getTypeClassConstraintSet());
        }
       
        return varConstraints;     
    }  
   
    /**
     * Write this ClassInstance to the RecordOutputStream.
     * @param s
     * @throws IOException
     */
    final void write (RecordOutputStream s) throws IOException {
        s.startRecord(ModuleSerializationTags.CLASS_INSTANCE, serializationSchema);
       
        s.writeModuleName(moduleName);
      
        instanceStyle.write(s);
               
        instanceType.write(s);
        s.writeQualifiedName(typeClass.getName());
        s.writeShortCompressed(instanceMethods.length);
        for (int i = 0; i < instanceMethods.length; ++i) {
            s.writeQualifiedName(instanceMethods[i]);
        }

        // CALDoc comment
        boolean hasCALDocComment = (calDocComment != null);
        s.writeBoolean(hasCALDocComment);
        if (hasCALDocComment) {
            calDocComment.write(s);
        }
       
        // CALDoc comments for instance methods
        // 1) write out a bit vector describing which of the instance methods have associated CALDoc comments
        boolean[] hasMethodCALDocComment = new boolean[methodCALDocComments.length];
        for (int i = 0; i < methodCALDocComments.length; i++) {
            hasMethodCALDocComment[i] = (methodCALDocComments[i] != null);
        }
       
        byte[] caldocFlags = RecordOutputStream.booleanArrayToBitArray(hasMethodCALDocComment);
        s.write(caldocFlags);
       
        // 2) write out the actual comments
        for (final CALDocComment methodCALDocComment : methodCALDocComments) {
            if (methodCALDocComment != null) {
                methodCALDocComment.write(s);
            }           
        }
       
        s.endRecord();
    }
   
    /**
     * Load an instance of ClassInstance from the RecordInputStream.
     * The read position will be before the record header.
     * @param s
     * @param mti
     * @param msgLogger the logger to which to log deserialization messages.
     * @return an instance of ClassInstance.
     * @throws IOException
     */
    static final ClassInstance load (RecordInputStream s, ModuleTypeInfo mti, CompilerMessageLogger msgLogger) throws IOException {
        // Look for Record header.
        RecordHeaderInfo rhi = s.findRecord(ModuleSerializationTags.CLASS_INSTANCE);
        if (rhi == null) {
           throw new IOException("Unable to find ClassInstance record header.");
        }
        DeserializationHelper.checkSerializationSchema(rhi.getSchema(), serializationSchema, mti.getModuleName(), "ClassInstance", msgLogger);

        ModuleName moduleName = s.readModuleName();

        InstanceStyle instanceStyle = InstanceStyle.load(s, msgLogger);
       
        TypeExpr instanceType = TypeExpr.load(s, mti, msgLogger);
       
        QualifiedName typeClassName = s.readQualifiedName();
        TypeClass typeClass = mti.getReachableTypeClass(typeClassName);
        if (typeClass == null) {
            throw new IOException("Unable to resolve TypeClass " + typeClassName + " while loading ClassInstance.");
        }
       
        int nInstanceMethods = s.readShortCompressed();
        QualifiedName instanceMethods[] = new QualifiedName[nInstanceMethods];
        for (int i = 0; i < nInstanceMethods; ++i) {
            QualifiedName qn = s.readQualifiedName();
            instanceMethods[i] = qn;
        }
       
        ClassInstance ci = new ClassInstance(moduleName, instanceType, typeClass, instanceMethods, instanceStyle);
       
       
        // CALDoc comment
        boolean hasCALDocComment = s.readBoolean();
        if (hasCALDocComment) {
            ci.calDocComment = CALDocComment.load(s, mti.getModuleName(), msgLogger);
        }
       
        // CALDoc comments for instance methods
        // 1) read the bit vector describing which of the instance methods have associated CALDoc comments
        int nBytesForCALDocFlags = (nInstanceMethods + 7) / 8;
        byte[] caldocFlags = new byte[nBytesForCALDocFlags];
        for (int i = 0; i < nBytesForCALDocFlags; i++) {
            caldocFlags[i] = s.readByte();
        }
       
        // 2) read the actual comments
        for (int i = 0; i < nInstanceMethods; i++) {
            boolean hasMethodCALDocComment = RecordInputStream.booleanFromBitArray(caldocFlags, i);
            if (hasMethodCALDocComment) {
                ci.methodCALDocComments[i] = CALDocComment.load(s, mti.getModuleName(), msgLogger);
            }           
        }       
       
        s.skipRestOfRecord();
       
        return ci;
    }
}
TOP

Related Classes of org.openquark.cal.compiler.ClassInstance$InstanceStyle

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.