/* $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
*
*********************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;
using SbsSW.SwiPlCs;
using PlTerm = SbsSW.SwiPlCs.PlTerm;
using XElement = System.Xml.XmlNode;
using XDocument = System.Xml.XmlDocument;
namespace Swicli.Library
{
public partial class PrologCLR
{
///
/// Retreves the ClazzSpec Fields and Properties into a MemberSpecList
///
///
///
///
[PrologVisible]
static public bool cliPropsForType(PlTerm clazzSpec, PlTerm memberSpecList)
{
Type type = GetType(clazzSpec);
var props = GetPropsForTypes(type);
var value = props.Key.ToArray();
int len = value.Length;
var termv = ATOM_NIL;
for (int i = len - 1; i >= 0; i--)
{
termv = PlC(".", ToProlog((value[i].Name)), termv);
}
var value2 = props.Value.ToArray();
len = value2.Length;
for (int i = len - 1; i >= 0; i--)
{
termv = PlC(".", ToProlog((value2[i].Name)), termv);
}
return memberSpecList.Unify(termv);
}
static readonly Dictionary, List>> PropForTypes = new Dictionary, List>>();
private static KeyValuePair, List> GetPropsForTypes(Type t)
{
KeyValuePair, List> kv;
if (PropForTypes.TryGetValue(t, out kv)) return kv;
lock (PropForTypes)
{
if (!PropForTypes.TryGetValue(t, out kv))
{
kv = new KeyValuePair, List>(new List(),
new List());
var ta = t.GetCustomAttributes(typeof(XmlTypeAttribute), false);
bool specialXMLType = false;
if (ta != null && ta.Length > 0)
{
XmlTypeAttribute xta = (XmlTypeAttribute)ta[0];
specialXMLType = true;
}
HashSet lowerProps = new HashSet();
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; //BindingFlags.NonPublic
foreach (
PropertyInfo o in t.GetProperties(flags))
{
if (o.CanRead)
{
if (o.Name.StartsWith("_")) continue;
if (o.DeclaringType == typeof(Object)) continue;
if (!lowerProps.Add(o.Name.ToLower())) continue;
if (o.GetIndexParameters().Length > 0)
{
continue;
}
if (specialXMLType)
{
var use = o.GetCustomAttributes(typeof(XmlArrayItemAttribute), false);
if (use == null || use.Length < 1) continue;
}
kv.Key.Add(o);
}
}
foreach (FieldInfo o in t.GetFields(flags))
{
if (o.Name.StartsWith("_")) continue;
if (o.DeclaringType == typeof(Object)) continue;
if (!lowerProps.Add(o.Name.ToLower())) continue;
if (specialXMLType)
{
var use = o.GetCustomAttributes(typeof(XmlArrayItemAttribute), false);
if (use == null || use.Length < 1) continue;
}
kv.Value.Add(o);
}
}
return kv;
}
}
///
/// Retreves the clazzOrInstance Members into MemberSpec List
///
/// used by cli_memb/2
///
///
///
///
[PrologVisible]
static public bool cliMembers(PlTerm clazzOrInstance, PlTerm membersSpecListOut)
{
object getInstance;
Type c;
if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false;
MemberInfo[] members = c.GetMembers(BindingFlagsALL);
List list = new List();
string cname = c.Name;
List exclude = new List();
int ordinal = 0;
foreach (var info in c.GetFields(BindingFlagsALL))
{
AddMemberToList(info, list, cname, ordinal++);
exclude.Add(info);
}
ordinal = 0;
foreach (var info in c.GetProperties(BindingFlagsALL))
{
AddMemberToList(info, list, cname, ordinal++);
exclude.Add(info);
}
ordinal = 0;
foreach (var info in c.GetMethods(BindingFlagsALL))
{
AddMemberToList(info, list, cname, ordinal++);
exclude.Add(info);
}
ordinal = 0;
foreach (var info in c.GetConstructors(BindingFlagsALL))
{
AddMemberToList(info, list, cname, ordinal++);
exclude.Add(info);
}
ordinal = 0;
foreach (var info in c.GetEvents(BindingFlagsALL))
{
AddMemberToList(info, list, cname, ordinal++);
exclude.Add(info);
}
foreach (MemberInfo info in members)
{
break;
try
{
if (exclude.Contains(info)) continue;
}
catch (Exception e)
{
Embedded.Debug("Warn exclude.Contains {0}: {1}", info, e);
continue;
}
AddMemberToList(info, list, cname, ordinal++);
exclude.Add(info);
}
return membersSpecListOut.Unify(ToPlArray(list.ToArray()));
}
private static void AddMemberToList(MemberInfo info, List list, string cname, int ordinal)
{
PlTerm memb = MemberTerm(info, cname, ordinal);
if (memb.TermRef != 0) list.Add(memb);
}
private static PlTerm MemberTerm(MemberInfo info, string cname, int ordinal)
{
string mn = info.Name;
switch (info.MemberType)
{
case MemberTypes.Constructor:
{
var fi = (ConstructorInfo)info;
var mi = fi;
return PlC("c", new PlTerm(ordinal), PlTerm.PlAtom(mn),
ToPlListParams(fi.GetParameters()),
(mi.IsGenericMethodDefinition ? ToPlListTypes(mi.GetGenericArguments()) : ATOM_NIL),
PlC("decl",
AFlag(mi.IsStatic, "static"),
typeToSpec(fi.DeclaringType)),
PlC("access_pafv",
AFlag(mi.IsPublic),
AFlag(mi.IsAssembly),
AFlag(mi.IsFamily),
AFlag(mi.IsPrivate)),
ToProlog(info));
}
break;
case MemberTypes.Event:
{
var fi = (EventInfo)info;
MethodInfo mi = (fi.GetRaiseMethod() ??
(fi.EventHandlerType != null ? fi.EventHandlerType.GetMethod("Invoke") : null) ??
fi.GetAddMethod() ?? fi.GetRemoveMethod());
ParameterInfo[] parme = GetParmeters(fi);
return PlC("e", new PlTerm(ordinal), PlTerm.PlAtom(mn),
typeToSpec(fi.EventHandlerType),
ToPlListParams(parme),
(mi.IsGenericMethodDefinition ? ToPlListTypes(mi.GetGenericArguments()) : ATOM_NIL),
PlC("decl",
AFlag(mi.IsStatic, "static"),
typeToSpec(fi.DeclaringType)),
PlC("access_pafv",
AFlag(mi.IsPublic),
AFlag(mi.IsAssembly),
AFlag(mi.IsFamily),
AFlag(mi.IsPrivate)),
ToProlog(info));
}
break;
case MemberTypes.Field:
{
var fi = (FieldInfo)info;
var mi = fi;
return PlC("f", new PlTerm(ordinal), PlTerm.PlAtom(mn),
typeToSpec(fi.FieldType),
PlC("decl",
AFlag(mi.IsStatic, "static"),
typeToSpec(fi.DeclaringType)),
PlC("access_pafv",
AFlag(mi.IsPublic),
AFlag(mi.IsAssembly),
AFlag(mi.IsFamily),
AFlag(mi.IsPrivate)),
ToProlog(info));
}
break;
case MemberTypes.Method:
{
var fi = (MethodInfo)info;
var mi = fi;
return PlC("m", new PlTerm(ordinal), PlTerm.PlAtom(mn),
typeToSpec(fi.ReturnParameter.ParameterType),
ToPlListParams(fi.GetParameters()),
(mi.IsGenericMethodDefinition ? ToPlListTypes(mi.GetGenericArguments()) : ATOM_NIL),
PlC("decl",
AFlag(mi.IsStatic, "static"),
typeToSpec(fi.DeclaringType)),
PlC("access_pafv",
AFlag(mi.IsPublic),
AFlag(mi.IsAssembly),
AFlag(mi.IsFamily),
AFlag(mi.IsPrivate)),
ToProlog(info));
}
break;
case MemberTypes.Property:
{
var fi = (PropertyInfo)info;
MethodInfo mi = (fi.CanRead ? fi.GetGetMethod(true) : fi.GetSetMethod(true));
return PlC("p", new PlTerm(ordinal), PlTerm.PlAtom(mn),
typeToSpec(fi.PropertyType),
ToPlListParams(fi.GetIndexParameters()),
(mi.IsGenericMethodDefinition ? ToPlListTypes(mi.GetGenericArguments()) : ATOM_NIL),
AFlag(fi.CanRead, "CanRead"),
AFlag(fi.CanWrite, "CanWrite"),
PlC("decl",
AFlag(mi.IsStatic, "static"),
typeToSpec(fi.DeclaringType)),
PlC("access_pafv",
AFlag(mi.IsPublic),
AFlag(mi.IsAssembly),
AFlag(mi.IsFamily),
AFlag(mi.IsPrivate)),
ToProlog(info));
}
break;
case MemberTypes.TypeInfo:
break;
case MemberTypes.Custom:
break;
case MemberTypes.NestedType:
break;
case MemberTypes.All:
break;
default:
throw new ArgumentOutOfRangeException();
}
return default(PlTerm);
}
public static PlTerm PlC(string decl, params PlTerm[] plTerms)
{
return PlTerm.PlCompound(decl, plTerms);
}
public static PlTerm PlC(string decl, PlTermV termV)
{
return PlTerm.PlCompound(decl, termV);
}
private static PlTerm AFlag(bool tf, string name)
{
PlTerm plTermPlAtom = PlTerm.PlAtom(tf ? "true" : "false");
return PlC(name, plTermPlAtom);
}
private static PlTerm AFlag(bool tf)
{
PlTerm plTermPlAtom = PlTerm.PlAtom(tf ? "true" : "false");
return plTermPlAtom;
}
static public Dictionary AssmblyXDoics = new Dictionary();
public static XElement GetXmlDocMembers(Assembly typeAssembly)
{
XElement ele;
lock (AssmblyXDoics)
if (!AssmblyXDoics.TryGetValue(typeAssembly, out ele))
{
try
{
AssmblyXDoics[typeAssembly] = ele = GetXmlDocMembers0(typeAssembly);
}
catch (Exception e)
{
Embedded.Debug("Cannot doc {0} {1}", typeAssembly, e);
AssmblyXDoics[typeAssembly] = ele = null;
}
}
return ele;
}
public static XElement GetXmlDocMembers0(Assembly typeAssembly)
{
var file = GetXmlDocFile(typeAssembly);
if (file == null) return null;
XDocument f = new XDocument();
f.Load(file.FullName);
if (f.FirstChild == null) return null;
foreach (XElement mn in f.ChildNodes)
{
if (mn.Name.ToLower() == "members") return mn;
foreach (XElement mn0 in mn.ChildNodes)
{
if (mn0.Name.ToLower() == "members") return mn0;
}
}
return null;
}
public static XElement GetXmlDocMembers(Type type)
{
return GetXmlDocMembers(type.Assembly);
}
private static FileInfo GetXmlDocFile(Assembly assembly)
{
string assemblyDirPath = Path.GetDirectoryName(assembly.Location);
string fileName = String.Format("{0}.xml", Path.GetFileNameWithoutExtension(assembly.Location).ToLower());
foreach (string file in Directory.GetFiles(assemblyDirPath))
{
if (Path.GetFileName(file).ToLower().Equals(fileName))
{
return new FileInfo(file);
}
}
return null;
}
static string GetMemberId(MemberInfo member)
{
char memberKindPrefix = GetMemberPrefix(member);
string memberName = GetMemberFullName(member);
return memberKindPrefix + ":" + memberName;
}
static char GetMemberPrefix(MemberInfo member)
{
return member.GetType().Name
.Replace("Runtime", "")[0];
}
static string GetMemberFullName(MemberInfo member)
{
string memberScope = "";
if (member.DeclaringType != null)
memberScope = GetMemberFullName(member.DeclaringType);
else if (member is Type)
memberScope = ((Type)member).Namespace;
memberScope = memberScope + "." + member.Name;
if (member is MethodBase)
{
memberScope += "(";
var mi = member as MethodBase;
var ps = mi.GetParameters();
bool needsComma = false;
foreach (ParameterInfo info in ps)
{
if (needsComma)
{
memberScope += ",";
}
else
{
needsComma = true;
}
memberScope += "" + info.ParameterType;
}
memberScope += ")";
}
return memberScope;
}
///
/// =Attempt to find assembly doc of member
///
///
///
///
///
[PrologVisible]
static public bool cliMemberDoc(PlTerm membIn, PlTerm docOut, PlTerm xmlOut)
{
var mi = GetInstance(membIn) as MemberInfo;
if (mi != null)
{
XElement xmls = GetDocString(mi);
return xmlOut.Unify(ToProlog(xmls)) && docOut.Unify(PlTerm.PlString(xmls == null ? "" : xmls.InnerXml));
}
return true;
}
static public XElement GetDocString(MemberInfo memberInfo)
{
var docMembers = GetXmlDocMembers(memberInfo.DeclaringType.Assembly);
return GetDocString(docMembers, memberInfo);
}
public static XElement GetDocString(XElement docMembers, MemberInfo info)
{
if (docMembers == null) return null;
string memberId = GetMemberId(info).ToLower();
foreach (XElement e in docMembers.ChildNodes)
{
var anme = e.Attributes["name"];
if (anme != null)
{
string matchWith = anme.Value.ToLower();
if (matchWith.StartsWith(memberId))
{
return e;
}
}
}
return null;
}
}
public class CycTypeInfo
{
readonly public PlTerm cycFort;
readonly Type CType;
public static Dictionary typeFort = new Dictionary();
public bool IsEnum
{
get { return CType.IsEnum; }
}
public bool IsBitFlags
{
get; set;
}
public CycTypeInfo(PlTerm fort, Type type)
{
cycFort = fort;
CType = type;
typeFort[type] = this;
if (type.IsEnum)
{
SetupEnum();
}
else if (type.IsInterface)
{
SetupType("Interface");
}
else if (type.IsClass)
{
SetupType("Class");
}
}
private void SetupEnum()
{
/* SimCyclifier simCyclifier = SimCyclifier.Master;
var docMembers = SimCyclifier.GetXmlDocMembers(CType);
simCyclifier.assertIsa(cycFort, C("Collection"));
simCyclifier.assertIsa(cycFort, C("SimEnumCollection"));
String ele = SimCyclifier.GetDocString(docMembers, CType);
simCyclifier.assertVocabGaf(CycAccess.comment, cycFort, "The sim enum for " + CType);
if (!String.IsNullOrEmpty(ele))
{
simCyclifier.assertVocabGaf(CycAccess.comment, cycFort, ele);
}*/
if (CType.IsEnum)
{
IsBitFlags = IsFlagType(CType);
if (IsBitFlags)
{
// simCyclifier.assertIsa(cycFort, C("SimEnumBitFlagsCollection"));
}
foreach (FieldInfo fort in CType.GetFields(BindingFlags.Public | BindingFlags.Static))
{
// Enum ev = (Enum) fort.GetValue(null);
// var tc= ev.GetTypeCode();
string v = string.Format("{0}-{1}", CType.Name, fort.Name);
PlTerm cv = C(v);
/* simCyclifier.assertIsa(cv, C("Collection"));
simCyclifier.assertVocabGafNow(C("genls"), cv, cycFort);
simCyclifier.assertVocabGaf(CycAccess.comment, cv, "The sim enum value for: " + fort);
MemberInfo mi = fort;
simCyclifier.DocQueue.Enqueue(() =>
{
ele = SimCyclifier.GetDocString(docMembers, mi);
if (!String.IsNullOrEmpty(ele))
{
simCyclifier.assertVocabGaf(CycAccess.comment, cv, ele);
}
});*/
}
}
}
public static bool IsFlagType(Type type)
{
object[] attributes = type.GetCustomAttributes(typeof (FlagsAttribute), true);
if (attributes != null && attributes.Length > 0)
{
return true;
}
/* if (type == typeof(OpenMetaverse.PrimFlags))
{
return true;
}*/
return false;
}
private void SetupType(String s)
{
// SimCyclifier simCyclifier = SimCyclifier.Master;
//var docMembers = SimCyclifier.GetXmlDocMembers(CType);
//simCyclifier.assertIsa(cycFort, C("Collection"));
//simCyclifier.assertIsa(cycFort, C("Sim" + s + "Collection"));
//String ele = SimCyclifier.GetDocString(docMembers, CType);
//simCyclifier.assertVocabGaf(CycAccess.comment, cycFort, "The sim " + s + " for " + CType);
//if (!String.IsNullOrEmpty(ele))
//{
// simCyclifier.assertVocabGaf(CycAccess.comment, cycFort, ele);
//}
}
private PlTerm C(string collection)
{
return PrologCLR.C(collection);
}
}
}