/* $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
*
*********************************************************/
#if USE_MUSHDLR
using MushDLR223.Utilities;
#endif
using org.jpl7;
using SbsSW.SwiPlCs;
#if USE_IKVM
//using jpl;
//using JClass = java.lang.JavaClass;
using Type = System.Type;
#else
using JClass = System.Type;
using Type = System.Type;
#endif
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using SbsSW.SwiPlCs;
using PlTerm = SbsSW.SwiPlCs.PlTerm;
namespace Swicli.Library
{
public partial class PrologCLR
{
public static PlTerm ATOM_NIL { get { return PlTerm.PlAtom("[]"); } }
public static PlTerm PLNULL { get { return PlTerm.PlCompound("@", PlTerm.PlAtom("null")); } }
public static PlTerm PLVOID { get { return PlTerm.PlCompound("@", PlTerm.PlAtom("void")); } }
public static PlTerm PLTRUE { get { return PlTerm.PlCompound("@", PlTerm.PlAtom(PreserveObjectType ? object_to_tag(true) : "true")); } }
public static PlTerm PLFALSE { get { return PlTerm.PlCompound("@", PlTerm.PlAtom(PreserveObjectType ? object_to_tag(false) : "false")); } }
[PrologVisible]
public static bool cliMakeDefault(PlTerm typeSpec, PlTerm valueOut)
{
CheckMI();
MethodInfo rc = MakeDefaultViaReflectionInfo.MakeGenericMethod(GetType(typeSpec));
return UnifyTagged(rc.Invoke(null, ZERO_OBJECTS), valueOut);
}
public static object GetInstance(PlTerm classOrInstance)
{
if (classOrInstance.IsVar)
{
Embedded.Warn("GetInstance(PlVar) {0}", classOrInstance);
return null;
}
if (!classOrInstance.IsCompound)
{
if (classOrInstance.IsString)
{
String str = (string)classOrInstance;
return str;
}
if (classOrInstance.IsNil)
{
return CastCompoundTerm("[]", 0, classOrInstance, classOrInstance, null);
}
if (classOrInstance.IsAtom)
{
Type t = GetType(classOrInstance);
// we do this for static invokations like: cliGet('java.lang.Integer','MAX_VALUE',...)
// the arg1 denotes a type, then return null!
if (t != null) return null;
Embedded.Warn("GetInstance(atom) {0}", classOrInstance);
// possibly should always return null?!
}
return CastTerm(classOrInstance, null);
}
string name = classOrInstance.Name;
int arity = classOrInstance.Arity;
return CastCompoundTerm(name, arity, classOrInstance[1], classOrInstance, null);
}
///
/// Returns the Type when denoated by a 'namespace.type' (usefull for static instance specification)
/// if a @C#234234 the type of the object unless its a a class
/// c(a) => System.Char "sdfsdf" => System.String uint(5) => System.UInt32
///
/// instanceMaybe maybe Null.. it is passed in so the method code doesn't have to call GetInstance again
/// on classOrInstance
///
///
///
///
private static Type GetTypeFromInstance(object instanceMaybe, PlTerm classOrInstance)
{
if (!classOrInstance.IsNil)
{
if (classOrInstance.IsAtom)
{
return GetType(classOrInstance);
}
if (classOrInstance.IsString)
{
if (instanceMaybe != null) return instanceMaybe.GetType();
return typeof (string);
}
if (classOrInstance.IsCompound)
{
if (classOrInstance.Name == "static")
{
return GetType(classOrInstance[1]);
}
}
}
object val = instanceMaybe ?? GetInstance(classOrInstance);
//if (val is Type) return (Type)val;
if (val == null)
{
Embedded.Warn("GetTypeFromInstance: {0}", classOrInstance);
return null;
}
return val.GetType();
}
private static bool SpecialUnify(PlTerm valueOut, PlTerm plvar)
{
bool b = valueOut.Unify(plvar);
if (b) return true;
object obj1 = GetInstance(plvar);
if (ReferenceEquals(obj1, null))
{
return false;
}
Type t1 = obj1.GetType();
object obj2 = CastTerm(valueOut, t1);
if (ReferenceEquals(obj2, null))
{
return false;
}
Type t2 = obj2.GetType();
if (obj1.Equals(obj2))
{
return true;
}
if (t1 == t2)
{
return false;
}
return false;
}
public static int UnifyAtom(uint TermRef, string s)
{
uint temp = libpl.PL_new_term_ref();
libpl.PL_put_atom(temp, libpl.PL_new_atom_wchars(s.Length, s));
return libpl.PL_unify(temp, TermRef);
}
private static bool UnifySpecialObject(PlTerm plTerm, object ret1)
{
if (plTerm.IsVar)
{
return plTerm.FromObject(ret1);
}
else
{
var plvar = PlTerm.PlVar();
return plvar.FromObject(ret1) && SpecialUnify(plTerm, plvar);
}
}
public static int UnifyToProlog(object o, PlTerm term)
{
if (!term.IsVar)
{
Embedded.Warn("Not a free var {0}", term);
return libpl.PL_fail;
}
uint TermRef = term.TermRef;
if (TermRef == 0)
{
Embedded.Warn("Not a allocated term {0}", o);
return libpl.PL_fail;
}
#if USE_IKVM
org.jpl7.Term args = o as org.jpl7.Term;
if (args != null) return UnifyToProlog(ToPLCS(args), term);
#endif
if (PreserveObjectType)
{
return PlSucceedOrFail(UnifyTagged(o, term));
}
return UnifyToPrologImmediate(o, term);
}
public static object ToFromConvertLock = new object();
public static int UnifyToPrologImmediate(object o, PlTerm term)
{
uint TermRef = term.TermRef;
if (o is PlTerm)
{
return libpl.PL_unify(TermRef, ((PlTerm)o).TermRef);
}
if (o is string)
{
string s = (string)o;
switch (Embedded.VMStringsAsAtoms)
{
case libpl.CVT_STRING:
{
try
{
return libpl.PL_unify_string_chars(TermRef, (string)o);
}
catch (Exception)
{
return UnifyAtom(TermRef, s);
}
}
case libpl.CVT_ATOM:
try
{
return libpl.PL_unify_atom_chars(TermRef, (string)o);
}
catch (Exception)
{
return UnifyAtom(TermRef, s);
}
case libpl.CVT_LIST:
return libpl.PL_unify_list_chars(TermRef, (string)o);
default:
Embedded.Warn("UNKNOWN VMStringsAsAtoms {0}", Embedded.VMStringsAsAtoms);
return libpl.PL_fail;
}
}
if (o == null)
{
return AddTagged(TermRef, "null");
}
if (o is Type || o is Type)
{
if (true)
{
//lock (ToFromConvertLock)
{
var tag = object_to_tag(o);
AddTagged(TermRef, tag);
return libpl.PL_succeed;
}
}
return PlSucceedOrFail(term.Unify(typeToSpec((Type)o)));
}
Type t = o.GetType();
if (t == typeof(void))
{
return AddTagged(TermRef, "void");
}
if (o is ValueType)
{
if (o is bool)
{
bool tf = (bool)o;
return AddTagged(TermRef, tf ? "true" : "false");
}
if (o is char)
{
try
{
char ch = (char)o;
string cs = new string(ch, 1);
switch (Embedded.VMStringsAsAtoms)
{
case libpl.CVT_STRING:
return libpl.PL_unify_atom_chars(TermRef, cs);
case libpl.CVT_ATOM:
return libpl.PL_unify_atom_chars(TermRef, cs);
case libpl.CVT_LIST:
return libpl.PL_unify_integer(TermRef, (int)ch);
default:
Embedded.Warn("UNKNOWN VMStringsAsAtoms {0}", Embedded.VMStringsAsAtoms);
return libpl.PL_fail;
}
}
catch (Exception e)
{
Embedded.Warn("@TODO unmappable errors? {0} type {1}", o, t);
//
}
}
if (t.IsEnum)
{
int res = FromEnum(TermRef, o, t);
///term.ToString();
return res;
}
if (t.IsPrimitive)
{
try
{
int res = ToVMNumber(o, term);
if (res == libpl.PL_succeed) return res;
if (res == libpl.PL_fail) return res;
if (res != -1)
{
// Warn("@TODO Missing code for ToVmNumber? " + o + " type " + t);
return res;
}
if (t.IsPrimitive)
{
Embedded.Warn("@TODO Missing code for primitive? {0} type {1}", o, t);
}
}
catch (Exception e)
{
Embedded.Warn("@TODO unmappable errors? {0} type {1}", o, t);
}
}
}
lock (FunctorToLayout)
{
PrologTermLayout layout;
if (TypeToLayout.TryGetValue(t, out layout))
{
MemberInfo[] tGetFields = layout.FieldInfos;// GetStructFormat(t);
int len = tGetFields.Length;
PlTermV tv = NewPlTermV(len);
for (int i = 0; i < len; i++)
{
object v = GetMemberValue(tGetFields[i], o);
tv[i].FromObject((v));
}
return PlSucceedOrFail(term.Unify(PlC(layout.Name, tv)));
}
}
lock (FunctorToRecomposer)
{
PrologTermRecomposer layout = GetTypeMap(t, TypeToRecomposer);
if (layout != null)
{
lock (ToFromConvertLock)
{
var tag = object_to_tag(o);
uint newref = libpl.PL_new_term_refs(2);
AddTagged(newref, tag);
PlTerm into = new PlTerm(newref);
PlTerm outto = new PlTerm(newref + 1);
var ret = PlQuery.PlCall(layout.module, layout.obj2r, new PlTermV(@into, outto));
if (ret)
{
return term.Unify(outto) ? libpl.PL_succeed
: libpl.PL_fail;
}
}
}
}
if (o is IList)
{
}
if (IsStructRecomposable(t))
{
return ToFieldLayout("struct", typeToName(t), o, t, term, false, false);
}
if (o is EventArgs)
{
return ToFieldLayout("event", typeToName(t), o, t, term, false, false);
}
if (t.IsArray)
{
Array al = (Array) o;
if (false && al.Length > 0 && al.Length < 1024)
{
Type et = t.GetElementType();
object firstNonNull = null;
foreach (var ele in al)
{
if (ele!=null)
{
firstNonNull = ele;
}
}
var needMake = firstNonNull != null;
if (needMake)
{
PlTerm newVar = PlTerm.PlVar();
needMake = NeedsToMakeRef(firstNonNull, newVar);
}
if (!needMake)
{
return PlSucceedOrFail(unifyArrayToTerm(al, term));
}
}
}
return PlObject(TermRef, o);
}
private static bool NeedsToMakeRef(object al, PlTerm newVar)
{
var resoreMadeARef = MadeARef;
var restoreMakeNoRefs = MakeNoRefs;
try
{
MadeARef = false;
MakeNoRefs = true;
int doit = UnifyToPrologImmediate(al, newVar);
if (!MadeARef)
{
return false;
}
return true;
}
finally
{
MadeARef = resoreMadeARef;
MakeNoRefs = restoreMakeNoRefs;
}
}
public static PlTerm C(string collection)
{
return PlTerm.PlAtom(collection);
}
private static int FromEnum(uint TermRef, object o, Type t)
{
uint temp = libpl.PL_new_term_ref();
libpl.PL_cons_functor_v(temp,
ENUM_2,
new PlTermV(typeToSpec(t), PlTerm.PlAtom(o.ToString())).A0);
return libpl.PL_unify(TermRef, temp);
}
private static uint _enum2;
private static uint _obj1;
protected static uint ENUM_2
{
get
{
if (_enum2 == 0)
{
_enum2 = libpl.PL_new_functor(libpl.PL_new_atom("enum"), 2);
}
return _enum2;
}
}
static object ToBigInteger(string value)
{
Type t;
// Just Mono
t = Type.GetType("Mono.Math.BigInteger");
if (t != null)
{
var m = t.GetMethod("Parse", ONE_STRING);
if (m != null) return m.Invoke(null, new object[] { value });
}
// .net 4.0 and Mono
t = ResolveType("System.Numerics.BigInteger");
if (t != null)
{
var m = t.GetMethod("Parse", ONE_STRING);
if (m != null) return m.Invoke(null, new object[] { value });
}
// Just Mono Android
t = ResolveType("Java.Math.BigInteger");
if (t != null)
{
var m = t.GetMethod("Parse", ONE_STRING);
if (m != null) return m.Invoke(null, new object[] { value });
}
// IKVM
t = ResolveType("java.math.BigInteger");
if (t != null)
{
var m = t.GetConstructor(ONE_STRING);
if (m != null) return m.Invoke(new object[] { value });
}
#if USE_IKVM
return new java.math.BigInteger(value);
#else
if (!value.StartsWith("-")) return UInt64.Parse(value);
return Int64.Parse(value);
#endif
}
static object ToBigDecimal(string value)
{
Type t;
// Just Mono
t = Type.GetType("Mono.Math.BigDecimal");
if (t != null)
{
var m = t.GetMethod("Parse", ONE_STRING);
if (m != null) return m.Invoke(null, new object[] { value });
}
// .net 4.0 and Mono
t = ResolveType("System.Numerics.BigDecimal");
if (t != null)
{
var m = t.GetMethod("Parse", ONE_STRING);
if (m != null) return m.Invoke(null, new object[] { value });
}
// Just Mono Android
t = ResolveType("Java.Math.BigDecimal");
if (t != null)
{
var m = t.GetMethod("Parse", ONE_STRING);
if (m != null) return m.Invoke(null, new object[] { value });
}
// IKVM
t = ResolveType("java.math.BigDecimal");
if (t != null)
{
var m = t.GetConstructor(ONE_STRING);
if (m != null) return m.Invoke(new object[] { value });
}
#if USE_IKVM
return new java.math.BigDecimal(value);
#else
return Double.Parse(value);
#endif
}
}
}