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