Ejemplo n.º 1
0
    /*
     * Find an array type, for a given element type. If the array type
     * is not found, it is automatically created.
     */
    internal static XType LookupArray(XType elementType, bool embed)
    {
        string name = string.Format("({0} {1})",
                                    elementType.Name,
                                    embed ? "std::array&" : "std::array");
        XType xt;

        if (!ALL.TryGetValue(name, out xt))
        {
            if (embed && !elementType.IsEmbeddable)
            {
                throw new Exception(string.Format("type {0} is not embeddable", elementType.Name));
            }
            xt = new XType(name);
            xt.arrayElementType     = elementType;
            xt.arrayElementEmbedded = embed;
            xt.CloseArray();
            ALL[name] = xt;

            XType[] tArray            = new XType[] { xt };
            XType[] tIntArray         = new XType[] { INT, xt };
            XType[] tIntIntArray      = new XType[] { INT, INT, xt };
            XType[] tIntIntArrayArray = new XType[] {
                INT, INT, xt, xt
            };
            XType[] tEltIntArray = new XType[] {
                elementType, INT, xt
            };
            XType[] tArrayArray = new XType[] { xt, xt };

            Function.Register("std::sub", tIntIntArrayArray,
                              new NativeArrayAccessorSub(xt));
            Function.Register("std::subself", tIntIntArray,
                              new NativeArrayAccessorSubSelf(xt));
            Function.Register("std::init?", tArray,
                              new NativeArrayAccessorIsInit(xt));
            Function.Register("std::length", tArray,
                              new NativeArrayAccessorLength(xt));
            if (embed)
            {
                Function.Register("std::make", tIntArray,
                                  new NativeArrayAccessorMakeEmbed(xt));
                Function.Register("std::@&", tIntArray,
                                  new NativeArrayAccessorRef(xt));
            }
            else
            {
                Function.Register("std::make", tIntArray,
                                  new NativeArrayAccessorMakeRef(xt));
                Function.Register("std::@", tIntArray,
                                  new NativeArrayAccessorGet(xt));
                Function.Register("std::->@", tEltIntArray,
                                  new NativeArrayAccessorPut(xt));
                Function.Register("std::Z->@", tIntArray,
                                  new NativeArrayAccessorPut(xt));
                Function.Register("std::@?", tIntArray,
                                  new NativeArrayAccessorIsEltInit(xt));

                /*
                 * Arrays of references implement '=' by
                 * running that function on all elements.
                 * This is implemented with an interpreted
                 * function since it may call interpreted
                 * functions.
                 *
                 * : = (...)
                 *     ->{ a1 a2 }
                 *     a1 length ->{ len }
                 *     len a2 length = ifnot false ret then
                 *     0 ->{ i }
                 *     begin i len < while
                 *         i a1 @ i a2 @ = ifnot false ret then
                 *         i ++ ->i
                 *     repeat
                 *     true ;
                 */
                FunctionBuilder fb = new FunctionBuilder(
                    "std::=");
                /* { a1 a2 len i } */
                fb.DefLocalField("a1", null);
                fb.DefLocalField("a2", null);
                fb.DefLocalField("len", null);
                fb.DefLocalField("i", null);
                /* ->{ a1 a2 } */
                fb.DoLocal("->a2");
                fb.DoLocal("->a1");
                /* a1 length ->len */
                fb.DoLocal("a1");
                fb.Call("std::length");
                fb.DoLocal("->len");
                /* len a2 length = ifnot false ret then */
                fb.DoLocal("len");
                fb.DoLocal("a2");
                fb.Call("std::length");
                fb.Call("std::=");
                fb.AheadIf();
                fb.Literal(false);
                fb.Ret();
                fb.Then();
                /* 0 ->{ i } */
                fb.Literal(XValue.MakeInt(0));
                fb.DoLocal("->i");
                /* begin i len < while */
                fb.Begin();
                fb.DoLocal("i");
                fb.DoLocal("len");
                fb.Call("std::<");
                fb.AheadIfNot();
                fb.CSRoll(1);
                /*     i a1 @ i a2 @ = ifnot false ret then */
                fb.DoLocal("i");
                fb.DoLocal("a1");
                fb.Call("std::@");
                fb.DoLocal("i");
                fb.DoLocal("a2");
                fb.Call("std::@");
                fb.Call("std::=");
                fb.AheadIf();
                fb.Literal(false);
                fb.Ret();
                fb.Then();
                /*     i ++ ->i */
                fb.DoLocal("i");
                fb.Call("std::++");
                fb.DoLocal("->i");
                /* repeat */
                fb.Again();
                fb.Then();
                /* true ; */
                fb.Literal(true);
                fb.Ret();

                Function f = fb.Build();
                Function.Register("std::=", tArrayArray, f);

                /*
                 * The std::<> function is implemented by
                 * calling std::=, then negating.
                 */
                fb = new FunctionBuilder(
                    "std::<>");
                fb.Call("std::=");
                fb.Call("std::not");
                fb.Ret();
                f = fb.Build();
                Function.Register("std::<>", tArrayArray, f);
            }
        }
        else if (xt.arrayElementType != elementType)
        {
            throw new Exception(string.Format("type {0} already exists and is not an array of {1}", name, elementType.Name));
        }
        else if (xt.arrayElementEmbedded != embed)
        {
            throw new Exception(string.Format("elements of type {0} are {1}embedded", name, embed ? "not " : ""));
        }
        return(xt);
    }