Package org.openquark.cal.valuenode

Source Code of org.openquark.cal.valuenode.NTupleValueNode$NTupleValueNodeProvider

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


/*
* NTupleValueNode.java
* Created: June 15, 2001
* By: Michael Cheng
*/
package org.openquark.cal.valuenode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.openquark.cal.compiler.DataConstructor;
import org.openquark.cal.compiler.FieldName;
import org.openquark.cal.compiler.RecordType;
import org.openquark.cal.compiler.SourceModel;
import org.openquark.cal.compiler.TypeExpr;
import org.openquark.cal.compiler.io.InputPolicy;
import org.openquark.cal.compiler.io.OutputPolicy;
import org.openquark.util.UnsafeCast;


/**
* A specialized ValueNode used to handle tuple record values.
* Creation date: (15/06/01 11:44:36 AM)
* @author Michael Cheng
*/
public class NTupleValueNode extends AbstractRecordValueNode {

    /**
     * A custom ValueNodeProvider for the NTupleValueNode.
     * @author Frank Worsley
     */
    public static class NTupleValueNodeProvider extends ValueNodeProvider<NTupleValueNode> {
       
        public NTupleValueNodeProvider(ValueNodeBuilderHelper builderHelper) {
            super(builderHelper);
        }
       
        /**
         * @see org.openquark.cal.valuenode.ValueNodeProvider#getValueNodeClass()
         */
        @Override
        public Class<NTupleValueNode> getValueNodeClass() {
            return NTupleValueNode.class;
        }
       
        /**
         * {@inheritDoc}
         */
        @Override
        public NTupleValueNode getNodeInstance(Object value, DataConstructor dataConstructor, TypeExpr typeExpr) {
           
            // Check for handleability.
            if (!typeExpr.isTupleType()) {
                return null;
            }
           
            if (value == null) {

                List<ValueNode> tupleValue = new ArrayList<ValueNode>();
                RecordType recordType = typeExpr.rootRecordType();
                  
                Map<FieldName, TypeExpr> hasFieldsMap = recordType.getHasFieldsMap();
                for (final TypeExpr fieldType : hasFieldsMap.values()) {
               
                    ValueNode newVN = getValueNodeBuilderHelper().getValueNodeForTypeExpr(fieldType);
                   
                    // Return null if a child value node couldn't be built.
                    if (newVN == null) {
                        return null;
                    }
                   
                    tupleValue.add(newVN);
                }
               
                value = tupleValue;
            }
           
            // value is a List of ValueNode
            List<ValueNode> listValue = UnsafeCast.asTypeOf(value, Collections.<ValueNode>emptyList());

            return new NTupleValueNode(listValue, typeExpr, getValueNodeBuilderHelper());
        }
    }
   
    /** The list that holds on to the value nodes for the tuple pieces. */
    private List<ValueNode> tupleValue;
   
    /** The number of tuple pieces, ie: the size of the tuple. */
    private final int numPieces;
   
    /**
     * List that holds onto the Java marshalled values in the tuple. The 0th element of the list is the 1st component of the tuple,
     * the 1st element of the list holds onto the second component of the tuple, and so on.
     */
    private List<?> outputTupleValue;
   
    private final ValueNode[] tupleElementValueNodes;
   
    /**
     * NTupleValueNode constructor.
     * @param tupleValue the list of value nodes for the tuple parameters. Size of list must match size of tuple.
     * @param typeExprParam the type expression for the value node
     * @param builderHelper
     */
    private NTupleValueNode(List<ValueNode> tupleValue, TypeExpr typeExprParam, ValueNodeBuilderHelper builderHelper) {

        super(typeExprParam);
       
        if (!typeExprParam.isTupleType()) {
            throw new IllegalArgumentException("given type expression is not a tuple type: " + typeExprParam);
        }

        if (tupleValue == null) {
            throw new NullPointerException();
        }
       
        RecordType recordType = typeExprParam.rootRecordType();
        Map<FieldName, TypeExpr> hasFieldsMap = recordType.getHasFieldsMap();
       
        // Set the number of pieces in this tuple so that we know when we're completed
        this.numPieces = hasFieldsMap.size();
       
        if (tupleValue.size() != numPieces) {
            throw new IllegalArgumentException("invalid number of values in list: " + tupleValue.size() + " -- tuple size: " + numPieces);
        }
           
        this.tupleValue = new ArrayList<ValueNode>(tupleValue);
       
        tupleElementValueNodes = new ValueNode[numPieces];
        int i = 0;
        for (final TypeExpr fieldTypeExpr : hasFieldsMap.values()) {
            tupleElementValueNodes[i] = builderHelper.getValueNodeForTypeExpr(fieldTypeExpr);
            ++i;
        }
    }

    /**
     * NTupleValueNode constructor.
     * @param tupleValue the list of value nodes for the tuple parameters. Size of list must match size of tuple.
     * @param outputTupleValue  List that holds onto the Java marshalled values in the tuple. The 0th element of the list is the 1st component of the tuple
     * @param typeExprParam the type expression for the value node
     * @param tupleElementValueNodes
     */
    private NTupleValueNode(List<ValueNode> tupleValue, List<?> outputTupleValue, TypeExpr typeExprParam, ValueNode[] tupleElementValueNodes) {

        super(typeExprParam);
       
        int tupleDimension = typeExprParam.getTupleDimension();
        if (tupleDimension == -1) {
            throw new IllegalArgumentException("given type expression is not a tuple type: " + typeExprParam);
        }

        if (tupleValue == null && outputTupleValue == null) {
            throw new NullPointerException();
        }
       
        // Set the number of pieces in this tuple so that we know when we're completed
        this.numPieces = tupleDimension;
       
        if ((tupleValue != null && tupleValue.size() != numPieces) && (outputTupleValue != null && outputTupleValue.size() != numPieces)) {
            throw new IllegalArgumentException("invalid number of values in list: " + tupleValue.size() + " -- tuple size: " + numPieces);
        }
       
        if (tupleValue != null) {
            this.tupleValue = new ArrayList<ValueNode>(tupleValue);
        }
        this.outputTupleValue = outputTupleValue;
       
        this.tupleElementValueNodes = tupleElementValueNodes;
    }
   
    /**
     * Makes a copy of this ValueNode, but with another TypeExpr instance (of the same type).
     * This is a deep copy, with respect to value nodes and the associated type expression.
     * Note: if the new TypeExpr is a different type from the present TypeExpr, an error is thrown.
     * Creation date: (06/07/01 8:49:28 AM)
     * @param newTypeExpr the new type of the copied node.
     * @return ValueNode
     */
    @Override
    public NTupleValueNode copyValueNode(TypeExpr newTypeExpr) {

        checkCopyType(newTypeExpr);
      
        List<ValueNode> tupleCopy = null;
       
        if (tupleValue != null) {
            Map<FieldName, TypeExpr> hasFieldsMap = newTypeExpr.rootRecordType().getHasFieldsMap();
            int tupleSize = getTupleSize();
            tupleCopy = new ArrayList<ValueNode>(tupleSize);
            int i = 0;
            for (final TypeExpr componentTypeExpr : hasFieldsMap.values()) {
                ValueNode elementVN = tupleValue.get(i);
                tupleCopy.add(elementVN.copyValueNode(componentTypeExpr));
                ++i;
            }
        }                     
       
        NTupleValueNode ntv = new NTupleValueNode(tupleCopy, outputTupleValue, newTypeExpr, tupleElementValueNodes);
        return ntv;
    }

    /**
     * Returns the source model representation of the expression represented by
     * this ValueNode.
     *
     * @return SourceModel.Expr
     */
    @Override
    public SourceModel.Expr getCALSourceModel() {

        int tupleDim = tupleValue.size();
        SourceModel.Expr[] components = new SourceModel.Expr[tupleDim];

        for (int i = 0; i < tupleDim; i++) {
            components[i] = tupleValue.get(i).getCALSourceModel();
        }

        return SourceModel.Expr.Tuple.make(components);
    }
   
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean containsParametricValue() {
        if (tupleValue != null) {
            for (int i = 0, tupleDim = tupleValue.size(); i < tupleDim; i++) {
   
                ValueNode elementVN = tupleValue.get(i);
                if (elementVN.containsParametricValue()) {
                    return true;
                }
            }
        }
       
        return false;
    }
   
    @Override
    public List<ValueNode> getValue() {
        return Collections.unmodifiableList(tupleValue);
    }     
   
    /**
     * Returns the display text representation of the expression
     * represented by this ValueNode.
     * Creation date: (03/07/01 11:03:28 AM)
     * @return String
     */
    @Override
    public String getTextValue() {
      
        if (outputTupleValue != null) {
            return outputTupleValue.toString();
        }
              
        StringBuilder sbTuple = new StringBuilder("(");     

        for (int i = 0, tupleDim = tupleValue.size(); i < tupleDim; i++) {

            if (i > 0) {
                sbTuple.append(", ");
            }

            ValueNode elementVN = tupleValue.get(i);
            sbTuple.append(elementVN.getTextValue());
        }

        sbTuple.append(")");

        return sbTuple.toString();
    }   
   
    /**
     * @return int the size of the tuple. eg. for a 4-tuple, returns 4.
     */
    public int getTupleSize() {
        return numPieces;
    }
   
    /**
     * @param index the index of the value within the tuple.
     * @return the value node for the ith item in the tuple.
     */
    @Override
    public ValueNode getValueAt(int index) {
        return tupleValue.get(index);
    }
   
    /**
     * @param i the index for the value within the tuple.
     * @param valueNode the new value node for the ith item in the tuple.
     */
    @Override
    public void setValueNodeAt(int i, ValueNode valueNode) {
        tupleValue.set(i, valueNode);
    }          
   
    /**
     * @see ValueNode#transmuteValueNode(ValueNodeBuilderHelper, ValueNodeTransformer, TypeExpr)
     */
    @Override
    public ValueNode transmuteValueNode(ValueNodeBuilderHelper valueNodeBuilderHelper, ValueNodeTransformer valueNodeTransformer, TypeExpr newTypeExpr) {
       
        Class<? extends ValueNode> handlerClass = valueNodeBuilderHelper.getValueNodeClass(newTypeExpr);

        // If we don't need to change type expressions... Then we just basically copy the value
        if (getClass().equals(handlerClass)) {
           
            int currentTupleSize = getTupleSize();
            RecordType newRecordType = newTypeExpr.rootRecordType();
            Map<FieldName, TypeExpr> newRecordHasFieldsMap = newRecordType.getHasFieldsMap();
           
            List<ValueNode> newComponentList = new ArrayList<ValueNode>();

            int i = 0;
            for (final TypeExpr componentTypeExpr : newRecordHasFieldsMap.values()) {
                // Copy as many current args as we have. Provide default value nodes for the others.
               
                if (i < currentTupleSize) {
                    ValueNode componentVN = getValueAt(i);
                    newComponentList.add(componentVN.transmuteValueNode(valueNodeBuilderHelper, valueNodeTransformer, componentTypeExpr));
               
                } else {
                    newComponentList.add(valueNodeBuilderHelper.getValueNodeForTypeExpr(componentTypeExpr));
                }
               
                ++i;
            }
           
            return valueNodeBuilderHelper.buildValueNode(newComponentList, null, newTypeExpr);

        } else {
            return valueNodeTransformer.transform(valueNodeBuilderHelper, this, newTypeExpr);
        }
    }

    /**
     * Return an array of objects which are the values needed by the marshaller
     * described by 'getInputPolicy()'.
     * @return - an array of Java objects corresponding to the value represented by a value node instance.
     */
    @Override
    public Object[] getInputJavaValues() {
       
        // We simply gather up all the arguments required for the components in order.
        // These are the arguments expected by the custom input policy build by getInputPolicy()
       
        List<Object> argumentValues = new ArrayList<Object>();
        for (final ValueNode vn : tupleValue) {
            Object[] vals = vn.getInputJavaValues();
            if (vals != null) {
                argumentValues.addAll(Arrays.asList(vals));
            }
        }
       
        return argumentValues.toArray();
    }
   
    /**
     * Return an input policy which describes how to marshall a value represented
     * by a value node from Java to CAL.
     * @return - the input policy associated with ValueNode instance.
     */
    @Override
    public InputPolicy getInputPolicy() {
       
        // Instead of using Prelude.input as the input policy, we create a custom one that
        // simply applies the tuple constructor on the components, of the form:
        // (\arg_0 ... arg_N -> ( (<input policy for component 0> <args>) , ... , (<input policy for component k> <args>) ))
       
        int tupleDim = tupleValue.size();
        SourceModel.Expr[] components = new SourceModel.Expr[tupleDim];

        int argCount = 0;
        List<SourceModel.Parameter> paramsForMarshaler = new ArrayList<SourceModel.Parameter>();
       
        for (int i = 0; i < tupleDim; i++) {
           
            InputPolicy componentInputPolicy = tupleValue.get(i).getInputPolicy();
           
            int nComponentInputPolicyArgs = componentInputPolicy.getNArguments();           
            SourceModel.Expr[] componentInputPolicyArgs = new SourceModel.Expr[nComponentInputPolicyArgs + 1];
            componentInputPolicyArgs[0] = componentInputPolicy.getMarshaler();

            //this loop is from 1 as the first element is always the input policy itself
            for (int j = 1; j <= nComponentInputPolicyArgs; j++) {               
                String componentArg = "arg_" + (argCount++);
               
                paramsForMarshaler.add(SourceModel.Parameter.make(componentArg, false));
                componentInputPolicyArgs[j] = SourceModel.Expr.Var.makeUnqualified(componentArg);              
            }
           
            if (componentInputPolicyArgs.length >= 2) {
                components[i] = SourceModel.Expr.Application.make(componentInputPolicyArgs);
            } else {
                components[i] = componentInputPolicyArgs[0];
            }
        }

        SourceModel.Expr marshaler;
        if (paramsForMarshaler.isEmpty()) {
            marshaler = SourceModel.Expr.Tuple.make(components);
           
        } else {
            marshaler = SourceModel.Expr.Lambda.make(
                paramsForMarshaler.toArray(new SourceModel.Parameter[paramsForMarshaler.size()]),
                SourceModel.Expr.Tuple.make(components));
        }
       
        return InputPolicy.makeWithTypeAndMarshaler(getNonParametricType().toSourceModel().getTypeExprDefn(), marshaler, paramsForMarshaler.size());
    }
   
    /**
     * Return an output policy which describes how to marshall a value represented
     * by a value node from CAL to Java.
     * @return - the output policy associated with the ValueNode instance.
     */
    @Override
    public OutputPolicy getOutputPolicy() {
        return OutputPolicy.DEFAULT_OUTPUT_POLICY;
    }
    /**
     * Set a value which is the result of the marshaller described by
     * 'getOutputPolicy()'.
     * @param value - the java value
     */
    @Override
    public void setOutputJavaValue(Object value) {
        if (!(value instanceof List)) {
            throw new IllegalArgumentException("Error in NTupleValueNode.setOutputJavaValue: output must be an instance of Tuple, not an instance of: " + value.getClass().getName());
        }
        outputTupleValue = (List<?>)value;
        tupleValue = new ArrayList<ValueNode>();
        for (int i = 0; i < numPieces; ++i) {
            ValueNode vn = tupleElementValueNodes[i].copyValueNode();
            vn.setOutputJavaValue(outputTupleValue.get(i));
            tupleValue.add(vn);
        }
        outputTupleValue = null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FieldName getFieldName(int i) {
        return getFieldNames().get(i);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<FieldName> getFieldNames() {
        return ((RecordType)getTypeExpr()).getHasFieldNames();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TypeExpr getFieldTypeExpr(FieldName fieldName) {
        return ((RecordType)getTypeExpr()).getHasFieldsMap().get(fieldName);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getNFieldNames() {
        return numPieces;
    }
   
}
TOP

Related Classes of org.openquark.cal.valuenode.NTupleValueNode$NTupleValueNodeProvider

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.