#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 Class = java.lang.Class; #endif #region using System; using System.Reflection; using SbsSW.SwiPlCs; #endregion namespace Swicli.Library { public partial class PrologCLR { [PrologVisible] public static bool cliGetField(PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm valueOut) { if (!valueOut.IsVar) { var plvar = PlTerm.PlVar(); return cliGetField(clazzOrInstance, memberSpec, plvar) && SpecialUnify(valueOut, plvar); } object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; if (!CheckBound(memberSpec)) return false; bool found; foreach (var searchFlags in getInstance == null ? BindingFlags_SEARCHS : BindingFlags_SEARCHIS) { object cliGet01 = cliGet0(getInstance, memberSpec, c, out found, searchFlags | BindingFlags.GetField); if (found) { return valueOut.FromObject(cliGet01); } } return false; } [PrologVisible] public static bool cliSetField(PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm valueIn) { if (!valueIn.IsVar) { return Embedded.Error("Cant set property with a var {0}", valueIn); } object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; if (!CheckBound(memberSpec)) return false; bool found; foreach (var searchFlags in getInstance == null ? BindingFlags_SEARCHS : BindingFlags_SEARCHIS) { if (cliSet0(getInstance, memberSpec, valueIn, c, searchFlags | BindingFlags.SetField)) return true; } return false; } /// /// /// /// /// [] = 'Item' /// /// /// [PrologVisible] public static bool cliGetProperty(PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm indexValues, PlTerm valueOut) { if (!valueOut.IsVar) { var plvar = PlTerm.PlVar(); return cliGetProperty(clazzOrInstance, memberSpec, indexValues, plvar) && SpecialUnify(valueOut, plvar); } object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; Type[] paramz = null; BindingFlags searchFlags = BindingFlagsALL; if (!CheckBound(memberSpec, indexValues)) return false; var pi = findPropertyInfo(memberSpec, c, false, true, ref paramz, searchFlags); if (pi == null) { Embedded.Error("Cant find property {0} on {1}", memberSpec, c); return false; } Action postCallHook; var ps = PlListToCastedArray(indexValues, pi.GetIndexParameters(), out postCallHook); object cliGet01 = pi.GetValue(getInstance, ps); CommitPostCall(postCallHook); return valueOut.FromObject(cliGet01); } [PrologVisible] public static bool cliSetProperty(PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm indexValues, PlTerm valueIn) { if (!valueIn.IsVar) { return Embedded.Error("Cant set property with a var {0}", valueIn); } object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; Type[] paramz = null; if (!CheckBound(memberSpec, indexValues, valueIn)) return false; BindingFlags searchFlags = BindingFlagsALL; var pi = findPropertyInfo(memberSpec, c, false, true, ref paramz, searchFlags); if (pi == null) { Embedded.Error("Cant find property {0} on {1}", memberSpec, c); return false; } Action postCallHook; var ps = PlListToCastedArray(indexValues, pi.GetIndexParameters(), out postCallHook); pi.SetValue(getInstance, CastTerm(valueIn, pi.PropertyType), ps); CommitPostCall(postCallHook); return true; } [PrologVisible] public static bool cliGetRaw(PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm valueOut) { if (!valueOut.IsVar) { var plvar = PlTerm.PlVar(); return cliGetRaw(clazzOrInstance, memberSpec, plvar) && SpecialUnify(valueOut, plvar); } object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; if (!CheckBound(memberSpec)) return false; bool found; foreach (var searchFlags in getInstance == null ? BindingFlags_SEARCHS : BindingFlags_SEARCHIS) { object cliGet01 = cliGet0(getInstance, memberSpec, c, out found, searchFlags | BindingFlagsALL3); if (found) { return valueOut.FromObject(cliGet01); } } return false; } public static object cliGet0(object getInstance, PlTerm memberSpec, Type c, out bool found, BindingFlags icbf) { Type[] paramz = null; paramz = GetParamSpec(memberSpec) ?? ZERO_TYPES; if ((icbf & BindingFlags.GetProperty) != 0) { var pi = findPropertyInfo(memberSpec, c, false, true, ref paramz, icbf); if (pi != null && pi.CanRead) { var mi = pi.GetGetMethod(); if (mi != null) { found = true; return ((InvokeCaught(mi, mi.IsStatic ? null : getInstance, ZERO_OBJECTS) ?? VoidOrNull(mi))); } Embedded.Warn("Cant find getter for property " + memberSpec + " on " + c + " for " + pi); found = false; return null; } } if ((icbf & BindingFlags.GetField) != 0) { FieldInfo fi = findField(memberSpec, c, icbf); if (fi != null) { object fiGetValue = fi.GetValue(fi.IsStatic ? null : getInstance); found = true; return (fiGetValue); } } if ((icbf & BindingFlags.InvokeMethod) != 0) { if (memberSpec.IsVar) { Embedded.Warn("cliGet0 on IsVar={0} on {1} for {2}", memberSpec, c, getInstance); found = false; return getInstance; } string fn = memberSpec.Name; MethodInfo mi = findMethodInfo(memberSpec, -1, c, ref paramz, icbf) ?? GetMethod(c, fn, icbf) ?? GetMethod(c, "get_" + fn, icbf) ?? GetMethod(c, "Get" + fn, icbf) ?? GetMethod(c, "Is" + fn, icbf) ?? GetMethod(c, "To" + fn, icbf); if (mi == null) { Embedded.WarnMissing("Cant find getter " + memberSpec + " on " + c); found = false; return null; } Action postCallHook; object[] value = PlListToCastedArray(memberSpec, mi.GetParameters(), out postCallHook); object target = mi.IsStatic ? null : getInstance; object retval = InvokeCaught(mi, target, value, postCallHook) ?? VoidOrNull(mi); found = true; return retval; } else { found = false; return null; } } [PrologVisible] public static bool cliSetRaw(PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm paramIn) { object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; foreach (var searchFlags in getInstance == null ? BindingFlags_SEARCHS : BindingFlags_SEARCHIS) { if (cliSet0(getInstance, memberSpec, paramIn, c, searchFlags | BindingFlagsALL3)) return true; } return false; } public static bool cliSet0(object getInstance, PlTerm memberSpec, PlTerm paramIn, Type c, BindingFlags searchFlags) { Type[] paramz = null; if ((searchFlags & BindingFlags.SetProperty) != 0) { var pi = findPropertyInfo(memberSpec, c, false, true, ref paramz, searchFlags); if (pi != null) { var mi = pi.GetSetMethod(); if (mi != null) { object value = CastTerm(paramIn, pi.PropertyType); object target = mi.IsStatic ? null : getInstance; InvokeCaught(mi, target, new[] {value}); return true; } return Embedded.WarnMissing("Cant find setter for property " + memberSpec + " on " + c); } } if ((searchFlags & BindingFlags.SetField) != 0) { FieldInfo fi = findField(memberSpec, c, searchFlags); if (fi != null) { object value = CastTerm(paramIn, fi.FieldType); object target = fi.IsStatic ? null : getInstance; fi.SetValue(target, value); return true; } } if ((searchFlags & BindingFlags.InvokeMethod) != 0) { string fn = memberSpec.Name; MethodInfo mi = findMethodInfo(memberSpec, -1, c, ref paramz, searchFlags) ?? GetMethod(c, "set_" + fn, searchFlags) ?? GetMethod(c, "Set" + fn, searchFlags) ?? GetMethod(c, "from" + fn, searchFlags); if (mi == null) { Embedded.WarnMissing("Cant find setter " + memberSpec + " on " + c); return false; } Action postCallHook; object[] value = PlListToCastedArray(paramIn, mi.GetParameters(), out postCallHook); object target = mi.IsStatic ? null : getInstance; object retval = InvokeCaught(mi, target, value, postCallHook); return true; // valueOut.FromObject(retval); } Embedded.WarnMissing("Cant find setter " + memberSpec + " on " + c); return false; } private static MethodInfo GetMethod(Type type, string s, BindingFlags flags) { try { return type.GetMethod(s, flags); } catch (AmbiguousMatchException) { return null; } catch (MissingMethodException) { return null; } catch (Exception) { return null; } } private static MemberInfo findMember(PlTerm memberSpec, Type c) { return findMember(memberSpec, c, InstanceFields) ?? findMember(memberSpec, c, InstanceFields | BindingFlags.IgnoreCase); } private static MemberInfo findMember(PlTerm memberSpec, Type c, BindingFlags searchFlags) { if (IsTaggedObject(memberSpec)) { var r = GetInstance(memberSpec) as MemberInfo; if (r != null) return r; } Type[] paramz = GetParamSpec(memberSpec) ?? ZERO_TYPES; return findField(memberSpec, c, searchFlags) ?? findPropertyInfo(memberSpec, c, true, true, ref paramz, searchFlags) ?? findMethodInfo(memberSpec, -1, c, ref paramz, searchFlags) ?? (MemberInfo) findPropertyInfo(memberSpec, c, false, false, ref paramz, searchFlags); //findConstructor(memberSpec, c)); } private static FieldInfo findField(PlTerm memberSpec, Type c, BindingFlags searchFlags) { if (c == null) { Embedded.Error("findField no class for {0}", memberSpec); return null; } if (memberSpec.IsVar) { Embedded.Error("findField IsVar {0} on type {1}", memberSpec, c); return null; } if (memberSpec.IsInteger) { int ordinal = memberSpec.intValue(); var mis = c.GetFields(BindingFlagsALL); if (ordinal < 0 || ordinal >= mis.Length) return null; return mis[ordinal]; } if (IsTaggedObject(memberSpec)) { var r = tag_to_object(memberSpec[1].Name) as FieldInfo; if (r != null) return r; } if (memberSpec.IsCompound) { if (memberSpec.Name != "f") { return null; } return findField(memberSpec.Arg(0), c, searchFlags); } string fn = memberSpec.Name; if (fn == "[]") fn = "Get"; FieldInfo fi = c.GetField(fn, searchFlags); return fi; } private static PropertyInfo findPropertyInfo(PlTerm memberSpec, Type c, bool mustHaveP, bool assumeParamTypes, ref Type[] paramz, BindingFlags searchFlags) { if (c == null) { Embedded.Error("findProperty no class for {0}", memberSpec); return null; } if (memberSpec.IsVar) { Embedded.Error("findProperty IsVar {0} on type {1}", memberSpec, c); return null; } if (memberSpec.IsInteger) { int ordinal = memberSpec.intValue(); var mis = c.GetProperties(BindingFlagsALL); if (ordinal < 0 || ordinal >= mis.Length) return null; return mis[ordinal]; } if (IsTaggedObject(memberSpec)) { var r = tag_to_object(memberSpec[1].Name) as PropertyInfo; if (r != null) return r; } if (memberSpec.IsCompound) { if (memberSpec.Name == "p") { Type[] paramzN = null; return findPropertyInfo(memberSpec.Arg(0), c, false, assumeParamTypes, ref paramzN, searchFlags); } if (mustHaveP) return null; } if (paramz == null) { // Warn("using paramSpec {0}", ToString(memberSpec)); paramz = GetParamSpec(memberSpec) ?? ZERO_TYPES; } string fn = memberSpec.Name; if (fn == "[]") fn = "Item"; if (paramz == null || paramz.Length == 0) return c.GetProperty(fn, searchFlags) ?? c.GetProperty("Is" + fn, searchFlags); var ps = c.GetProperties(searchFlags); int len = paramz.Length; PropertyInfo nameMatched = null; bool ignoreCase0 = (BindingFlags.IgnoreCase & searchFlags) != 0; if (ignoreCase0) { fn = fn.ToLower(); } foreach (PropertyInfo info in ps) { if (info.Name == fn || (ignoreCase0 && info.Name.ToLower() == fn)) { nameMatched = nameMatched ?? info; ParameterInfo[] indexParameters = info.GetIndexParameters(); if (assumeParamTypes) { if (len == indexParameters.Length) { if (IsCompatTypes(paramz, GetObjectTypes(indexParameters))) { return info; } // incompat but ok nameMatched = info; } } } } return c.GetProperty(fn, searchFlags) ?? c.GetProperty("Is" + fn, searchFlags) ?? nameMatched; } } }