Exemplo n.º 1
0
 public override string GetSymbol()
 {
     return(impl.GetSymbol());
 }
Exemplo n.º 2
0
        // Can read any kind of array, except for jagged arrays that are multidimensional at the beginning, like [][,]
        // (jagged at start like [,][] or [,...][][] is OK, but only if we know the type, not for an Array slot). Recall
        // that mixed array types are read backwards, so [][,] is a 2-deep array of element type [] (i.e., it is multidimensional
        // at the start, not the end). One more limitation: For an Array argument slot, if the incoming array is 3-deep or deeper,
        // it must be rectangular, not jagged.
        // We know the incoming expression has head List.
        internal static Array readArbitraryArray(IMathLink ml, Type t)
        {
            int len;

            if (t == typeof(Array))
            {
                ExpressionType leafExprType;
                Type           leafType;
                // For the Array type, we have no clue about how the leaf elements will be read. Thus we need to peek into
                // the incoming data to decide what type it is.
                int           depth = determineIncomingArrayDepth(ml);
                ILinkMark     mark  = ml.CreateMark();
                ILoopbackLink loop  = null;
                try {
                    if (depth == 1)
                    {
                        len = ml.CheckFunction("List");
                        if (len == 0)
                        {
                            throw new MathLinkException(MathLinkException.MLE_EMPTY_ARRAY);
                        }
                        leafExprType = ml.GetNextExpressionType();
                        ml.SeekMark(mark);
                        leafType = netTypeFromExpressionType(leafExprType, ml);
                        // Fail if data could only be read as Expr. This means that we cannot pass a list of arbitrary expressions
                        // to an arg slot typed as Array. It would have to be typed as Expr[]. We make this choice to provide
                        // more meaningful error reporting for the cases where the array has bogus data in it. We assume that
                        // this convenience outweighs the very rare cases where a programmer would want to pass an array of exprs
                        // for an Array slot (they could always create the array separately and pass it as an object reference).
                        if (leafType == typeof(Expr))
                        {
                            if (leafExprType == ExpressionType.Complex)
                            {
                                throw new MathLinkException(MathLinkException.MLE_NO_COMPLEX);
                            }
                            else
                            {
                                throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY);
                            }
                        }
                        return((Array)ml.GetArray(leafType, 1));
                    }
                    else if (depth == 2)
                    {
                        // The loopback link is just a utility for quickly reading expressions off the link (via TransferExpression).
                        // Nothing is ever read back off the loopback link.
                        loop = MathLinkFactory.CreateLoopbackLink();
                        // Determine if the array is rectangular or jagged.
                        len = ml.CheckFunction("List");
                        bool isJagged      = false;
                        bool foundLeafType = false;
                        // This next assignment is strictly for the compiler. The value will never be used
                        // unless it is set to an actual value below. We have an existing function that will get
                        // the leafExprType of the incoming array (getLeafExprType()), but we also need to check if the array
                        // is jagged here, so we will do both tasks at once and save a little time.
                        leafExprType = ExpressionType.Integer;
                        int lenAtLevel2 = ml.CheckFunction("List");
                        if (lenAtLevel2 > 0)
                        {
                            leafExprType  = ml.GetNextExpressionType();
                            foundLeafType = true;
                        }
                        // peel off all the elements in the first sublist.
                        for (int j = 0; j < lenAtLevel2; j++)
                        {
                            loop.TransferExpression(ml);
                        }
                        // For each remaining sublist, check its length and peel off its members. At this point, though, we
                        // cannot be guaranteed that all elements are lists (or, at least, guaranteed that it is an error
                        // if they are not). They could be Null if the array is jagged: {{1, 2}, Null}.
                        for (int i = 1; i < len; i++)
                        {
                            ExpressionType nextExprType = ml.GetNextExpressionType();
                            if (nextExprType == ExpressionType.Object)
                            {
                                isJagged = true;
                                // OK to have null as an element in a jagged array.
                                if (ml.GetObject() != null)
                                {
                                    throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_SHAPE);
                                }
                            }
                            else if (nextExprType == ExpressionType.Function)
                            {
                                int thisLength = ml.CheckFunction("List");
                                if (!foundLeafType && thisLength > 0)
                                {
                                    leafExprType  = ml.GetNextExpressionType();
                                    foundLeafType = true;
                                }
                                if (thisLength != lenAtLevel2)
                                {
                                    isJagged = true;
                                    break;
                                }
                                else
                                {
                                    for (int j = 0; j < thisLength; j++)
                                    {
                                        loop.TransferExpression(ml);
                                    }
                                }
                            }
                            else
                            {
                                throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_DEPTH);
                            }
                        }
                        // If the array is empty we cannot create a .NET array for it, as there is no type info for the array we are creating.
                        if (!foundLeafType)
                        {
                            throw new MathLinkException(MathLinkException.MLE_EMPTY_ARRAY);
                        }
                        leafType = netTypeFromExpressionType(leafExprType, ml);
                        ml.SeekMark(mark);
                        if (isJagged)
                        {
                            ml.CheckFunction("List");
                            Array result = Array.CreateInstance(Array.CreateInstance(leafType, 0).GetType(), len);
                            for (int i = 0; i < len; i++)
                            {
                                // Have to check if elements are lists or Null.
                                ExpressionType nextExprType = ml.GetNextExpressionType();
                                if (nextExprType == ExpressionType.Function)
                                {
                                    result.SetValue(ml.GetArray(leafType, 1), i);
                                }
                                else
                                {
                                    string sym = ml.GetSymbol();
                                    if (sym != "Null")
                                    {
                                        throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_SHAPE);
                                    }
                                    result.SetValue(null, i);
                                }
                            }
                            return(result);
                        }
                        else
                        {
                            return(ml.GetArray(leafType, 2));
                        }
                    }
                    else
                    {
                        // For an Array argument slot, we only support passing >2-deep rectangular arrays, not jagged.
                        for (int i = 0; i < depth; i++)
                        {
                            ml.CheckFunction("List");
                        }
                        leafExprType = ml.GetNextExpressionType();
                        leafType     = netTypeFromExpressionType(leafExprType, ml);
                        ml.SeekMark(mark);
                        return(ml.GetArray(leafType, depth));
                    }
                } finally {
                    if (loop != null)
                    {
                        loop.Close();
                    }
                    ml.DestroyMark(mark);
                }
            }
            else
            {
                // We have the actual array shape encoded in the type. Either [], [,..], or array-of-arrays: [][]....
                int  arrayRank   = t.GetArrayRank();
                Type elementType = t.GetElementType();
                if (elementType.IsArray)
                {
                    if (arrayRank > 1)
                    {
                        // Don't support multidimensional array at start of jagged array: [][,]. Recall that mixed array types
                        // are read backwards, so [][,] is a 2-deep array of element type [].
                        throw new MathLinkException(MathLinkException.MLE_MULTIDIM_ARRAY_OF_ARRAY);
                    }
                    len = ml.CheckFunction("List");
                    Array result = Array.CreateInstance(elementType, len);
                    for (int i = 0; i < len; i++)
                    {
                        ExpressionType nextExprType = ml.GetNextExpressionType();
                        if (nextExprType == ExpressionType.Function)
                        {
                            result.SetValue(readArbitraryArray(ml, elementType), i);
                        }
                        else
                        {
                            string sym = ml.GetSymbol();
                            if (sym != "Null")
                            {
                                throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_SHAPE);
                            }
                            result.SetValue(null, i);
                        }
                    }
                    return(result);
                }
                else if (elementType == typeof(Array))
                {
                    // Don't support Array[].
                    throw new MathLinkException(MathLinkException.MLE_ARRAY_OF_ARRAYCLASS);
                }
                else
                {
                    return(ml.GetArray(elementType, arrayRank));
                }
            }
        }