#region /* $Id$ * * Project: Swicli.Library - Two Way Interface for .NET and MONO to SWI-Prolog * Author: Douglas R. Miles * E-mail: logicmoo@gmail.com * WWW: http://www.logicmoo.com * Copyright (C): 2010-2012 LogicMOO Developement * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *********************************************************/ #endregion #if USE_MUSHDLR using MushDLR223.Utilities; #endif #if USE_IKVM //using jpl; using Type = System.Type; #else using System.Reflection; using JClass = System.Type; #endif using System; using System.Collections; using System.Collections.Generic; using System.Linq; using SbsSW.SwiPlCs; using PlTerm = SbsSW.SwiPlCs.PlTerm; namespace Swicli.Library { public partial class PrologCLR { /// /// ?- cliNewArray(long,10,Out),cliToString(Out,Str). /// /// /// 10 or [10] or [10,2] /// Tagged ref to the array /// [PrologVisible] public static bool cliNewArray(PlTerm clazzSpec, PlTerm indexes, PlTerm valueOut) { if (!valueOut.IsVar) { var plvar = PlTerm.PlVar(); return cliNewArray(clazzSpec, indexes, plvar) && SpecialUnify(valueOut, plvar); } Type c = getInstanceTypeFromClass(GetType(clazzSpec)); if (c == null) { Embedded.Warn("Cant find type {0}", clazzSpec); return false; } var dims = ToTermArray(indexes); var arrayType = c.MakeArrayType(dims.Length); var value = CreateArrayOfType(dims, c); return UnifyTagged(value, valueOut); } [PrologVisible] public static bool cliArrayFill(PlTerm arrayValue, PlTerm valueIn) { object getInstance; Type c; if (!GetInstanceAndType(arrayValue, out getInstance, out c)) return false; Array al = (Array) getInstance; var initValue = CastTerm(valueIn, c.GetElementType()); var idxIter = new ArrayIndexEnumerator(al); while (idxIter.MoveNext()) { al.SetValue(initValue, idxIter.Current); } return true; } [PrologVisible] public static bool cliArrayFillValues(PlTerm arrayValue, PlTerm valueIn) { object getInstance; Type c; if (!GetInstanceAndType(arrayValue, out getInstance, out c)) return false; Array al = (Array) getInstance; FillArray(ToTermArray(valueIn), c.GetElementType(), al); return true; } [PrologVisible] public static bool cliArrayToTerm(PlTerm arrayValue, PlTerm valueOut) { if (!valueOut.IsVar) { var plvar = PlTerm.PlVar(); return cliArrayToTerm(arrayValue, plvar) && SpecialUnify(valueOut, plvar); } object getInstance = GetInstance(arrayValue); if (getInstance == null) return valueOut.Unify(PLNULL); Array value = GetArrayValue(getInstance); if (value == null) { Embedded.Error("Cant find array from {0} as {1}", arrayValue, getInstance.GetType()); return false; } return unifyArrayToTerm(value, valueOut); } public static bool unifyArrayToTerm(Array value, PlTerm valueOut) { int len = value.Length; Type arrayType = value.GetType(); var termv = NewPlTermV(len); int rank = arrayType.GetArrayRank(); if (rank != 1) { var indexesv = new PlTermV(rank); for (int i = 0; i < rank; i++) { indexesv[i].Put(value.GetLength(i)); } var idxIter = new ArrayIndexEnumerator(value); int putAt = 0; while (idxIter.MoveNext()) { bool pf = termv[putAt++].FromObject((value.GetValue(idxIter.Current))); if (!pf) { return false; } } return /// array/3 valueOut.Unify(PlC("array", typeToSpec(arrayType), PlC("indexes", indexesv), PlC("values", termv))); } else { for (int i = 0; i < len; i++) { bool pf = termv[i].FromObject((value.GetValue(i))); if (!pf) { return false; } } return valueOut.Unify(PlC("array", typeToSpec(arrayType.GetElementType()), PlC("values", termv))); } } [PrologVisible] [PrologTest] public static bool cliTestArrayToTerm1(PlTerm valueOut) { return cliArrayToTerm(ToProlog(new[] {1, 2, 3, 4,}), valueOut); } [PrologVisible] [PrologTest] public static bool cliTestArrayToTerm2(PlTerm valueOut) { return cliArrayToTerm(ToProlog(new[,,] {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), valueOut); } [PrologVisible] public static bool cliArrayToTermlist(PlTerm arrayValue, PlTerm valueOut) { if (!valueOut.IsVar) { var plvar = PlTerm.PlVar(); return cliArrayToTermlist(arrayValue, plvar) && SpecialUnify(valueOut, plvar); } object getInstance = GetInstance(arrayValue); if (getInstance == null) return valueOut.Unify(PLNULL); Array value = GetArrayValue(getInstance); if (value == null) { Embedded.Error("Cant find array from {0} as {1}", arrayValue, getInstance.GetType()); return false; } Type arrayType = value.GetType(); if (arrayType.GetArrayRank() != 1) { Embedded.Error("Non rank==1 " + arrayType); } int len = value.Length; var termv = ATOM_NIL; for (int i = len - 1; i >= 0; i--) { termv = PlC(".", ToProlog((value.GetValue(i))), termv); } //Type et = value.GetType().GetElementType(); return valueOut.Unify(termv); } [PrologVisible] public static bool cliTermToArray(PlTerm arrayValue, PlTerm valueOut) { if (!valueOut.IsVar) { var plvar = PlTerm.PlVar(); return cliTermToArray(arrayValue, plvar) && SpecialUnify(valueOut, plvar); } if (arrayValue.Name == "array") { return valueOut.FromObject(GetInstance(arrayValue)); } Type elementType = ResolveType(arrayValue.Name); if (elementType == null) { Embedded.Error("Cant find vector from {0}", arrayValue); return false; } var value = CreateArrayOfTypeRankOneFilled(arrayValue, elementType.MakeArrayType()); return valueOut.FromObject((value)); } private static void ArraySet(Array array, object idx, object value) { if (idx is int) { array.SetValue(value, (int) idx); } else { array.SetValue(value, (int[]) idx); } } private static Array GetArrayValue(object getInstance) { if (getInstance == null) return null; lock (getInstance) { try { return GetArrayValue0(getInstance); } catch (Exception ex) { Embedded.WriteException(ex); throw; } } } private static Array GetArrayValue0(object getInstance) { if (getInstance is Array) { return (Array) getInstance; } Type t = getInstance.GetType(); Type et = typeof (object); if (t.IsGenericType) { Type[] typeArguments = t.GetGenericArguments(); if (typeArguments.Length == 1) { et = typeArguments[0]; } } if (getInstance is ArrayList) { return ((ArrayList) getInstance).ToArray(et); } if (getInstance is ICollection) { var collection = ((ICollection) getInstance); int count = collection.Count; var al = Array.CreateInstance(et, count); try { collection.CopyTo(al, 0); return al; } catch (Exception ex) { string warn = "CopyTo " + ex; Embedded.Warn(warn); int count2 = collection.Count; if (count2 != count) { Embedded.ConsoleWriteLine("Collection Modified while in CopyTo! " + count + "->" + count2 + " of " + collection); throw; } int index = 0; foreach (var e in collection) { al.SetValue(e, index++); } return al; } } if (getInstance is IEnumerable) { var collection = ((IEnumerable) getInstance).GetEnumerator(); var al = new ArrayList(); while (collection.MoveNext()) { al.Add(collection.Current); } return al.ToArray(et); } else if (getInstance is IEnumerator) { var collection = (IEnumerator) getInstance; var al = new ArrayList(); while (collection.MoveNext()) { al.Add(collection.Current); } return al.ToArray(et); } else { // this one is probly null return getInstance as Array; } } public static Object[] ToObjectArray(PlTerm[] a/*CONTEXT*/) { if (a == null) return null; Object[] ret = new Object[a.Length]; int i = 0; foreach (var term in a) { ret[i++] = GetInstance(term/*ctx*/); } return ret; } public static PlTerm[] ToTermArray(IEnumerable enumerable) { if (enumerable is PlTerm[]) return (PlTerm[]) enumerable; if (enumerable is PlTermV) { PlTermV tv = (PlTermV) enumerable; return tv.ToArray(); } if (enumerable is PlTerm) { // I guess IsList makes a copy PlTerm tlist = (PlTerm) enumerable; if (tlist.IsNil) return ZERO_PLTERMS; if (tlist.IsVar) return new PlTerm[] {tlist}; if (tlist.IsList) { enumerable = tlist.Copy(); } if (tlist.Name == "{}") { var t = tlist.Arg(0); var terms = new List(); while (t.Arity == 2) { terms.Add(t.Arg(0)); t = t.Arg(1); } // last Item terms.Add(t); return terms.ToArray(); } if (tlist.IsAtomic) { if (tlist.Name == "[]") return ZERO_PLTERMS; return new PlTerm[] {tlist}; } } return enumerable.ToArray(); } public static PlTerm[] ZERO_PLTERMS = new PlTerm[0]; /// /// Construct an array of some type /// /// /// The parent array type .. not the Element type /// private static Array CreateArrayOfType(PlTerm[] dims, Type arrayType) { if (!arrayType.IsArray) { Embedded.Error("Not Array Type! " + arrayType); } Type elementType = arrayType.GetElementType(); int rank = arrayType.GetArrayRank(); int[] lengths = new int[rank]; for (int i = 0; i < rank; i++) { lengths[i] = dims[i].intValue(); } Array al = Array.CreateInstance(elementType, lengths); return al; } private static Array CreateArrayOfTypeRankOneFilled(PlTerm arrayValue, Type arrayType) { if (!arrayType.IsArray) { Embedded.Error("Not Array Type! " + arrayType); } Type elementType = arrayType.GetElementType(); if (arrayType.GetArrayRank() != 1) { Embedded.Warn("Non rank==1 " + arrayType); } PlTerm[] terms = ToTermArray(arrayValue); Array al = Array.CreateInstance(elementType, terms.Length); FillArray(terms, elementType, al); return al; } private static Array CreateArrayNarrowest(object[] values) { if (values == null || values.Length == 0) return values; List elementType = null; Type lastType = null; foreach (var o in values) { if (o == null) continue; if (elementType == null) { lastType = o.GetType(); elementType = GetInheritsType(lastType); if (elementType.Count == 0) return values; continue; } if (lastType.IsInstanceOfType(o) || elementType[0].IsInstanceOfType(o)) continue; var ot = o.GetType(); elementType = new List(elementType.Intersect(GetInheritsType(ot))); if (elementType.Count == 0) return values; lastType = ot; } if (elementType == null) return values; Type elementType1 = elementType[0]; Array al = Array.CreateInstance(elementType1, values.Length); int at = 0; foreach (var o in values) { if (o != null) al.SetValue(o, at); } return al; } private static List exThese; private static List GetInheritsType(Type t1) { Type[] t1GetInterfaces = t1.GetInterfaces(); List l1 = new List(t1GetInterfaces.Length+2); while (t1 != null) { if (OkType(t1)) l1.Add(t1); t1 = t1.BaseType; } foreach(var it in t1GetInterfaces) { if (OkType(it)) l1.Add(it); } return l1; } static bool OkType(Type t) { if (t == null) return false; if (t == typeof(object)) return false; if (t == typeof(ValueType)) return false; if (t == typeof(IComparable)) return false; if (t == typeof(IFormattable)) return false; if (exThese == null) { exThese = new List(); //exThese = GetInheritsType(typeof (int)); // exThese.Remove(typeof (int)); } return !exThese.Contains(t); } private static void FillArray(PlTerm[] terms, Type elementType, Array al) { int termsLength = terms.Length; var idxIter = new ArrayIndexEnumerator(al); for (int i = 0; i < termsLength; i++) { idxIter.MoveNext(); PlTerm term = terms[i]; al.SetValue(CastTerm(term, elementType), idxIter.Current); } } } public class ArrayIndexEnumerator : IEnumerator { private readonly int[] idx; private readonly int len = 1; private readonly int[] lowers; private readonly int rank; private readonly int[] uppers; private int at = -1; public ArrayIndexEnumerator(Array value) { Type arrayType = value.GetType(); rank = arrayType.GetArrayRank(); uppers = new int[rank]; lowers = new int[rank]; idx = new int[rank]; len = 1; for (int i = 0; i < rank; i++) { int high = uppers[i] = value.GetUpperBound(i); int low = lowers[i] = value.GetLowerBound(i); if (low != 0) { Embedded.Error("LowerBound !=0 in " + arrayType); } int lenSize = (high - low + 1); len *= lenSize; } } #region Implementation of IDisposable /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// /// 2 public void Dispose() { } #endregion #region Implementation of IEnumerator /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// /// The collection was modified after the enumerator was created. /// 2 public bool MoveNext() { at++; if (at == 0) { return true; } if (at >= len) return false; for (int i = rank - 1; i >= 0; i--) { if (idx[i] < uppers[i]) { idx[i]++; return true; } idx[i] = lowers[i]; } return true; } /// /// Sets the enumerator to its initial position, which is before the first element in the collection. /// /// The collection was modified after the enumerator was created. /// 2 public void Reset() { for (int i = 0; i < rank; i++) { idx[i] = 0; } at = -1; } /// /// Gets the element in the collection at the current position of the enumerator. /// /// /// The element in the collection at the current position of the enumerator. /// public int[] Current { get { if (at < 0) throw new InvalidOperationException("forgot MoveNext"); return idx; } } /// /// Gets the current element in the collection. /// /// /// The current element in the collection. /// /// The enumerator is positioned before the first element of the collection or after the last element. /// 2 object IEnumerator.Current { get { return Current; } } #endregion } }