PublicShow sourceswicli.pl -- SWI-Prolog 2-Way interface to .NET/Mono

Introduction

This is an overview of an interface which allows SWI-Prolog programs to dynamically create and manipulate .NET objects.

Here are some significant features of the interface and its implementation:

author
- Douglas Miles
cli_load_lib(+AppDomainName, +AssemblyPartialName, +FullClassName, +StaticMethodName)
Loads an assembly into AppDomainName

cli_load_lib/4 is what was used to bootstrap SWICLI (it defined the next stage where cli_load_assembly/1) became present

remember to: export LD_LIBRARY_PATH=/development/opensim4opencog/bin:$LD_LIBRARY_PATH

in swicli.pl we called:

:- cli_load_lib('SWIProlog','Swicli.Library','Swicli.Library.Embedded','install').
cli_lib_type(-LibTypeName)
LibTypeName is an atom that denotes the implementation class SWICLI uses
cli_load_assembly(+AssemblyPartialNameOrPath)
cli_load_assembly_uncaught(+AssemblyPartialNameOrPath)
the cli_<Predicates> came because we had:
?- cli_load_assembly('Swicli.Library').

The uncaught version allows exception to come from .NET

cli_load_assembly_methods(+AssemblyPartialNameOrPath, +OnlyPrologVisible, +StringPrefixOrNull)
Loads foriegn predicates from Assembly
?- cli_load_assembly_methods('Swicli.Library', @false, "cli_").
cli_add_foreign_methods(+Type, +OnlyPrologVisible, +StringPrefixOrNull)
Loads foriegn predicates from Type
cli_add_assembly_search_path(+Path)
cli_remove_assembly_search_path(+Path)
Add or remove directories to the search path
?- cli_add_assembly_search_path('c:/myproj/bin').

?- cli_remove_assembly_search_path('c:/myproj/bin').

This now makes the System assembly resolver see Assemblies in that directory

Simular to Windows: adding to %PATH% Linux: adding to $MONO_PATH

cli_non_obj(+Obj)
is null or void or var
cli_non_null(+Obj)
is not null or void
cli_is_null(+Obj)
equiv to Obj == @(null)
cli_null(+Obj)
construct a null
cli_is_true(+Obj)
equiv to Obj == @(true)
cli_true(+Obj)
construct a @(true)
cli_is_false(+Obj)
equiv to Obj == @(false)
cli_false(+Obj)
construct a @(false)
cli_is_void(+Obj)
equiv to Obj == @(void)
cli_void(+Obj)
construct a @(void)
cli_is_type(+Obj)
equiv to cli_is_type(Obj,'System.Type')
cli_is_object(+Obj)
is Object a CLR object and not null or void (includes struct,enum,object,event)
cli_is_tagged_object(+Obj)
is Object a ref object (maybe null or void) (excludes struct,enum,object/N,event refernces)
cli_is_ref(+Obj)
is Object a ref object and not null or void (excludes struct,enum,object/N,event refernces)
cli_member_doc(+Memb, +Doc, +Xml)
cli_members(+ClazzOrInstance, -Members)
cli_memb(O, X)
cli_memb(O, F, X)
cli_memb(O,X):-cli_members(O,Y),member(X,Y).
cli_memb(O,F,X):-cli_memb(O,X),member(F,[f,p, c,m ,e]),functor(X,F,_).

Object to the member infos of it

   3 ?- cli_new('System.Collections.Generic.List'(string),[int],[10],O),cli_members(O,M),!,member(E,M),writeq(E),nl,fail.
   f(0,'_items'(arrayOf('String')))
   f(1,'_size'('Int32'))
   f(2,'_version'('Int32'))
   f(3,'_syncRoot'('Object'))
   f(4,'_emptyArray'(arrayOf('String')))
   f(5,'_defaultCapacity'('Int32'))
   p(0,'Capacity'('Int32'))
   p(1,'Count'('Int32'))
   p(2,'System.Collections.IList.IsFixedSize'('Boolean'))
   p(3,'System.Collections.Generic.ICollection<T>.IsReadOnly'('Boolean'))
   p(4,'System.Collections.IList.IsReadOnly'('Boolean'))
   p(5,'System.Collections.ICollection.IsSynchronized'('Boolean'))
   p(6,'System.Collections.ICollection.SyncRoot'('Object'))
   p(7,'Item'('String'))
   p(8,'System.Collections.IList.Item'('Object'))
   m(0,'ConvertAll'('Converter'('String',<)))
   m(1,get_Capacity)
   m(2,set_Capacity('Int32'))
   m(3,get_Count)
   m(4,'System.Collections.IList.get_is_FixedSize')
   m(5,'System.Collections.Generic.ICollection<T>.get_is_ReadOnly')
   m(6,'System.Collections.IList.get_is_ReadOnly')
   m(7,'System.Collections.ICollection.get_is_Synchronized')
   m(8,'System.Collections.ICollection.get_SyncRoot')
   m(9,get_item('Int32'))
   m(10,set_item('Int32','String'))
   m(11,'IsCompatibleObject'('Object'))
   m(12,'VerifyValueType'('Object'))
   m(13,'System.Collections.IList.get_item'('Int32'))
   m(14,'System.Collections.IList.set_item'('Int32','Object'))
   m(15,'Add'('String'))
   m(16,'System.Collections.IList.Add'('Object'))
   m(17,'AddRange'('System.Collections.Generic.IEnumerable'('String')))
   m(18,'AsReadOnly')
   m(19,'BinarySearch'('Int32','Int32','String','System.Collections.Generic.IComparer'('String')))
   m(20,'BinarySearch'('String'))
   m(21,'BinarySearch'('String','System.Collections.Generic.IComparer'('String')))
   m(22,'Clear')
   m(23,'Contains'('String'))
   m(24,'System.Collections.IList.Contains'('Object'))
   m(25,'CopyTo'(arrayOf('String')))
   m(26,'System.Collections.ICollection.CopyTo'('Array','Int32'))
   m(27,'CopyTo'('Int32',arrayOf('String'),'Int32','Int32'))
   m(28,'CopyTo'(arrayOf('String'),'Int32'))
   m(29,'EnsureCapacity'('Int32'))
   m(30,'Exists'('System.Predicate'('String')))
   m(31,'Find'('System.Predicate'('String')))
   m(32,'FindAll'('System.Predicate'('String')))
   m(33,'FindIndex'('System.Predicate'('String')))
   m(34,'FindIndex'('Int32','System.Predicate'('String')))
   m(35,'FindIndex'('Int32','Int32','System.Predicate'('String')))
   m(36,'FindLast'('System.Predicate'('String')))
   m(37,'FindLastIndex'('System.Predicate'('String')))
   m(38,'FindLastIndex'('Int32','System.Predicate'('String')))
   m(39,'FindLastIndex'('Int32','Int32','System.Predicate'('String')))
   m(40,'ForEach'('System.Action'('String')))
   m(41,'GetEnumerator')
   m(42,'System.Collections.Generic.IEnumerable<T>.GetEnumerator')
   m(43,'System.Collections.IEnumerable.GetEnumerator')
   m(44,'GetRange'('Int32','Int32'))
   m(45,'IndexOf'('String'))
   m(46,'System.Collections.IList.IndexOf'('Object'))
   m(47,'IndexOf'('String','Int32'))
   m(48,'IndexOf'('String','Int32','Int32'))
   m(49,'Insert'('Int32','String'))
   m(50,'System.Collections.IList.Insert'('Int32','Object'))
   m(51,'InsertRange'('Int32','System.Collections.Generic.IEnumerable'('String')))
   m(52,'LastIndexOf'('String'))
   m(53,'LastIndexOf'('String','Int32'))
   m(54,'LastIndexOf'('String','Int32','Int32'))
   m(55,'Remove'('String'))
   m(56,'System.Collections.IList.Remove'('Object'))
   m(57,'RemoveAll'('System.Predicate'('String')))
   m(58,'RemoveAt'('Int32'))
   m(59,'RemoveRange'('Int32','Int32'))
   m(60,'Reverse')
   m(61,'Reverse'('Int32','Int32'))
   m(62,'Sort')
   m(63,'Sort'('System.Collections.Generic.IComparer'('String')))
   m(64,'Sort'('Int32','Int32','System.Collections.Generic.IComparer'('String')))
   m(65,'Sort'('System.Comparison'('String')))
   m(66,'ToArray')
   m(67,'TrimExcess')
   m(68,'TrueForAll'('System.Predicate'('String')))
   m(69,'ToString')
   m(70,'Equals'('Object'))
   m(71,'GetHashCode')
   m(72,'GetType')
   m(73,'Finalize')
   m(74,'MemberwiseClone')
   c(0,'List`1')
   c(1,'List`1'('Int32'))
   c(2,'List`1'('System.Collections.Generic.IEnumerable'('String')))
   c(3,'List`1')
cli_is_type(+Impl, ?Type)
tests to see if the Impl Object is assignable to Type
cli_subclass(+Subclass, +Superclass)
tests to see if the Subclass is assignable to Superclass
cli_get_typespec(+Obj, ?TypeSpec)
gets or checks the TypeSpec
cli_get_typeref(+Obj, ?TypeRef)
gets or checks the TypeRef
cli_get_typename(+Obj, ?TypeName)
gets or checks the TypeName
cli_type_to_typespec(+ClazzSpec, -Value)
coerces a ClazzSpec to a Value representing a TypeSpec term
cli_add_tag(+RefObj, +TagString)
lowlevel access to create a tag name
?- cli_new(array(string),[int],[32],O),cli_add_tag(O,'string32').

?- cli_get_type(@(string32),T),cli_writeln(T).

cli_remove_tag(+TagString)
lowlevel access to remove a tag name
cli_to_ref(+Obj, +Ref)
return a @(Ref) version of the object (even if a enum)
15 ?- cli_to_ref(sbyte(127),O),cli_get_type(O,T),cli_writeln(O is T).
"127"is"System.SByte"
O = @'C#283319280',
T = @'C#283324332'.

16 ?- cli_to_ref(long(127),O),cli_get_type(O,T),cli_writeln(O is T).
"127"is"System.Int64"
O = @'C#283345876',
T = @'C#283345868'.

17 ?- cli_to_ref(ulong(127),O),cli_get_type(O,T),cli_writeln(O is T).
"127"is"System.UInt64"
O = @'C#283346772',
T = @'C#283346760'.

15 ?- cli_to_ref(sbyte(127),O),cli_get_type(O,T),cli_writeln(O is T).
"127"is"System.SByte"
O = @'C#283319280',
T = @'C#283324332'.

16 ?- cli_to_ref(long(127),O),cli_get_type(O,T),cli_writeln(O is T).
"127"is"System.Int64"
O = @'C#283345876',
T = @'C#283345868'.

18 ?- cli_to_ref(343434127,O),cli_get_type(O,T),cli_writeln(O is T).
"343434127"is"System.Int32"
O = @'C#281925284',
T = @'C#281925280'.

19 ?- cli_to_ref(3434341271,O),cli_get_type(O,T),cli_writeln(O is T).
"3434341271"is"System.UInt64"
O = @'C#281926616',
T = @'C#283346760'.

21 ?- cli_to_ref(343434127111,O),cli_get_type(O,T),cli_writeln(O is T).
"343434127111"is"System.UInt64"
O = @'C#281930092',
T = @'C#283346760'.

28 ?- cli_to_ref(34343412711111111111111111111111111111,O),cli_get_type(O,T),cli_writeln(O is T).
"34343412711111111111111111111111111111"is"java.math.BigInteger"
O = @'C#281813796',
T = @'C#281810860'.
cli_to_immediate(+Ref, -Immediate)
return an Immediate value of Ref to just REf if no immediate type exists
cli_cast(+Value, +ClazzSpec, -Ref)
cli_cast_immediate(+Value, +ClazzSpec, -Immediate)
Convert the type of Value to ClazzSpec returning eigther a Ref or Immediate value.
?- cli_cast(1,'double',X).
X = @'C#568261440'.

?- cli_cast(1,'System.DayOfWeek',X).
X = @'C#568269000'.

?- cli_cast_immediate(1,'System.DayOfWeek',X).
X = enum('DayOfWeek', 'Monday').

?- cli_cast_immediate(1.0,'System.DayOfWeek',X).
X = enum('DayOfWeek', 'Monday').

?- cli_cast_immediate(1.01,'System.DayOfWeek',X).
ERROR: Having time of it convcerting 1.01 to System.DayOfWeek why System.ArgumentException: Requested value '1.01' was not found.
cli_tracker_begin(-Tracker)
Return a Tracker ref and all objects created from this point can be released via cli_tracker_free/1
cli_tracker_free(+Tracker)
See also
- cli_tracker_begin/1
cli_free(+RefObject)
remove a RefObject from the heap
cli_heap(+RefObject)
Pin a RefObject onto the heap
cli_with_gc(+Call)
as ref objects are created they are tracked .. when the call is complete any new object tags are released uses Forienly defined cli_tracker_begin/1 and cli_tracker_free/1
cli_with_lock(+Lock, +Call)
Lock the first arg while calling Call
cli_lock_enter(+LockObj)
Does a Monitor.Enter on LockObj
cli_lock_exit(+LockObj)
Does a Monitor.Exit on LockObj
cli_write(+Obj)
writes an object out
cli_writeln(+Obj)
writes an object out with a new line
cli_fmt(+String, +Args)
cli_fmt(+Obj, +String, +Args)
use .NET system string.Format(String,Args) Obj is WriteLineDelegate
to_string(+Obj, -String)
cli_to_str(+Obj, -String)
Resolves inner @(Obj)s to strings
cli_to_str_raw(+Obj, -String)
cli_java_to_string(+Obj, -Value)
Resolves @(Obj) to string
cli_halt
cli_halt(+Obj)
cli_throw(+Ex)
throw an exception to .NET
cli_break(+Ex)
cli_debug(+Obj)
cli_debug(+Fmt, Args)
writes to user_error
cli_col(+Col, -Elem)
cli_enumerator_element(+Enumer, -Elem)
cli_iterator_element(+Iter, -Elem)
Iterates out Elem for Col/Iter/Enumer
   ?- cli_new('System.Collections.Generic.List'('System.String'),[int],[10],Obj).
   Obj = @'C#516939544'.


   ?- cli_get($Obj,'Count',Out).
   Out = 0.


   ?- cli_call($Obj,'Add'("foo"),Out).
   Out = @void.


   ?- cli_call($Obj,'Add'("bar"),Out).
   Out = @void.


   ?- cli_get($Out,'Count',Out).
   Out = 2.


   ?- cli_col($Obj,E).
   E = "foo" ;
   E = "bar" ;
   false.
cli_col_add(+Col, +Item)
add an Item to Col
cli_col_contains(+Col, +Item)
Test an Item in Col
cli_col_remove(+Col, +Item)
Remove an Item in Col
cli_col_removeall(+Col)
Clears a Col
cli_col_size(+Col, ?Count)
Returns the Count
cli_set_element(+Obj, +IndexParams, +Item)
cli_add_element(+Obj, +Item)
todo
cli_make_list(+Obj, +Arg2, +Arg3)
See also
- cli_new_list_1/2
cli_new_list_1(+Obj, +Arg2, +Arg3)
See also
- cli_make_list/2
cli_sublist(+Mask, +List)
Test to see if Mask appears in List
cli_new_array(+ClazzSpec, +Rank, -Value)
cli_array_fill(+Obj, Arg2)
cli_array_fill_values(+Obj, Arg2)
cli_array_to_length(+Obj, Arg2)
cli_array_to_list(+Obj, +Arg2)
cli_array_to_term(+ArrayValue, -Value)
cli_array_to_termlist(+ArrayValue, -Value)
cli_term_to_array(+ArrayValue, -Value)
cli_array_to_term_args(+Array, -Term)
todo
cli_map(Map, ?Key, ?Value)
cli_map_add(+Map, +Key, +Value)
cli_map_set(+Map, +Key, +Value)
cli_map_remove(+Map, +Key)
cli_map_remove(+Map, ?Key, ?Value)
cli_map_removeall(+Map)
cli_map_size(+Map, -Count)
Map calls
cli_preserve(TF, :Call)
make Call with PreserveObjectType set to TF
member_elipse(Ele, Elipse)
?- member_elipse(E,{a,b,c}).
E = a ;
E = b ;
E = c.
cli_to_data(+Ref, -Term)
cli_to_data(+ValueCol, +Ref, -Term)
cli_getterm(+ValueCol, +Ref, -Term)
converts a Ref to prolog Term ValCol is a .NET List used to break cyclic loops
?- cli_cast("Yellow",'System.Drawing.Color',C),cli_to_data(C,D),writeq(D).
["R"=255,"G"=255,"B"=0,"A"=255,"IsKnownColor"= @true,"IsEmpty"= @false,"IsNamedColor"= @true,"IsSystemColor"= @false,"Name"="Yellow"]
C = @'C#802963000',
D = ["R"=255, "G"=255, "B"=0, "A"=255, "IsKnownColor"= @true, "IsEmpty"= @false, "IsNamedColor"= @true, "IsSystemColor"= @ ..., ... = ...].
cli_unify(OE, PE)
cli_make_default(+ClazzSpec, -Result)
cli_new(+ClassNameWithParams, -Result)
cli_new(+ClazzSpec, +Params, -Result)
cli_new(+ClazzSpec, +MemberSpec, +Params, -Result)
?- cli_load_assembly('IKVM.OpenJDK.Core')
?- cli_new('java.lang.Long'(long),[44],Out),cli_to_str(Out,Str).

same as..

?- cli_new('java.lang.Long',[long],[44],Out),cli_to_str(Out,Str).

arity 4 exists to specify generic types

?- cli_new('System.Int64',[int],[44],Out),cli_to_str(Out,Str).
?- cli_new('System.Text.StringBuilder',[string],["hi there"],Out),cli_to_str(Out,Str).
?- cli_new('System.Int32'(int),[44],Out),cli_to_str(Out,Str).

ClazzSpec can be:

if ClazzSpec is an object (non-array) type or descriptor and Params is a list of values or references, then Result is the result of an invocation of that type's most specifically-typed constructor to whose respective formal parameters the actual Params are assignable (and assigned)

if ClazzSpec is an array type or descriptor and Params is a list of values or references, each of which is (independently) assignable to the array element type, then Result is a new array of as many elements as Params has members, initialised with the respective members of Params;

if ClazzSpec is an array type or descriptor and Params is a non-negative integer N, then Result is a new array of that type, with N elements, each initialised to CLR's appropriate default value for the type;

If Result is {Term} then we attempt to convert a new PlTerm instance to a corresponding term; this is of little obvious use here, but is consistent with cli_call/4 and cli_get/3

Make a "new string[32]" and get it's length.

 ?- cli_new(array(string),[int],[32],O),cli_get(O,'Length',L).
cli_call(+ClazzOrInstance, +CallTerm, -Result)
cli_call(+ClazzOrInstance, +MethodSpec, +Params, -Result)
cli_call_raw(+ClazzOrInstance, +MethodSpec, +Params, -Result)
cli_raise_event_handler(+ClazzOrInstance, +MemberSpec, +Params, -Result)
ClazzOrInstance should be:

MethodSpec should be:

Params should be:

CallTerm should be:

finally, an attempt will be made to unify Result with the returned result

cli_lib_call(+CallTerm, -Result)
CallTerm should be:

finally, an attempt will be made to unify Result with the returned result

cli_set(+Obj, +NameValueParis:list)
cli_get(+Obj, +NameValueParis:list)
gets or set multiple values
cli_get(+ClazzOrInstance, +MemberSpec, -Value)
cli_set(+ClazzOrInstance, +MemberSpec, +Value)
cli_get_raw(+ClazzOrInstance, +MemberSpec, -Value)
cli_set_raw(+ClazzOrInstance, +MemberSpec, +Value)
cli_get_field(+ClazzOrInstance, +MemberSpec, -Value)
cli_set_field(+ClazzOrInstance, +MemberSpec, +Value)
cli_set_property(+ClazzOrInstance, +MemberSpec, +IndexValues, +Value)
cli_get_property(+ClazzOrInstance, +MemberSpec, +IndexValues, -Value)
_get/_set (the first two) Attempts to find the "best" member

_raw is the foreing impls of the first two (Actually the above search impl is done from this _raw) _field will only try to set fields _property will only try to set fields

ClazzOrInstance can be:

MemberSpec can be:

IndexValues can be:

Value:

cli_new_event_waiter(+ClazzOrInstance, +MemberSpec, -WaitOn)
Creates a new ManualResetEvent (WaitOn) that when an Event is called WaitOn in pulsed so that cli_block_until_event/3 will unblock
cli_add_event_waiter(+WaitOn, +ClazzOrInstance, +MemberSpec, -NewWaitOn)
Adds a new Event to the ManualResetEvent (WaitOn) created by cli_new_event_waiter/3
cli_block_until_event(+WaitOn, +Time, +Lambda)
Calls (foriegnly defined) cli_block_until_event/4 and then cleansup the .NET objects.
cli_block_until_event(+WaitOn, +MaxTime, +TestVarsCode, -ExitCode)
foriegnly defined tododocs
cli_new_delegate(+DelegateClass, +PrologPred, -Value)
cli_new_delegate_term(+TypeFi, +PrologPred, +BooleanSaveKey, -Delegate)
todo
cli_add_event_handler(+Term1, +Arity, +IntPtrControl, Pred)
See also
- cli_add_event_handler/4
cli_add_event_handler(+ClazzOrInstance, +MemberSpec, +PrologPred)
Create a .NET Delegate that calls PrologPred when MemberSpec is called
cli_remove_event_handler(+ClazzOrInstance, +MemberSpec, +PrologPred)
cli_new_prolog_collection(+PredImpl, +ElementType, -PBD)
Prolog Backed Collection
cli_new_prolog_dictionary(+PredImpl, +KeyType, +ValueType, -PBD)
Prolog Backed Dictionaries
module_functor(+Obj, Arg2, Arg3, Arg4)
cli_hide(+Pred)
hide Pred from tracing
cli_notrace(+Call) is nondet
use call/1 with trace turned off
cli_class_from_type(+Value, -Value)
cli_find_class(+ClazzName, -ClazzObject)
cli_find_type(+ClazzSpec, +ClassRef)
cli_get_class(+Value, -Value)
cli_get_classname(+Value, -Value)
cli_get_type(+Value, -Value)
cli_type_to_fullname(+Value, -Value)
cli_type_from_class(+Value, -Value)
todo
cli_is_layout(+MemberSpec)
cli_add_layout(+ClazzSpec, +MemberSpec)
cli_add_layout(+ClazzSpec, +MemberSpec, +ToSpec)
cli_add_recomposer(+ClazzSpec, +MemberSpec, +Obj2r, +R2obj)
need doc!
cli_find_constructor(+ClazzSpec, +MemberSpec, -Method)
cli_find_method(+ClazzOrInstance, +MemberSpec, -Method)
cli_add_shorttype(+Short, +Long)
cli_props_for_type(+ClazzSpec, +MemberSpecs)
need doc
cli_special_unify(+Obj, Arg2)
cli_expand(+Obj, Arg2)
cli_expanded(+Obj, Arg2)
cli_eval(+Obj, Arg2, Arg3)
cli_eval_hook(+Obj, Arg2, Arg3)
cli_set_hook(+Obj, Arg2, Arg3)
cli_get_hook(+Obj, Arg2, Arg3)
cli_subproperty(+Obj, Arg2)
cli_link_swiplcs(+Obj)
cli_demo(+Obj, Arg2)
cli_is_defined(+Obj, Arg2)
cli_interned(+Obj, Arg2, Arg3)
cli_intern(+Obj, Arg2, Arg3)
cli_get_symbol(+Obj, Arg2, Arg3)
need docs!
cli_test_array_to_term1(-Value)
cli_test_array_to_term2(-Value)
cli_test_opt(+Incoming, ?REFInt32Outbound)
cli_test_opt(+Incoming, +StringOptionalstr, ?REFInt32Outbound)
cli_test_out(+Incoming, ?REFInt32Outbound)
cli_test_pbc(+Pred, +Counted)
cli_test_pbct(+Pred, +Counted)
cli_test_pbd(+Pred, +Counted)
cli_test_pbdt(+Pred, +Counted)
cli_test_ref(+Incoming, ?REFInt32Outbound)
cli_test_ref(+Incoming, ?REFStringOptionalstr, ?REFInt32Outbound)
cli_test_var_arg(?REFInt32Outbound, +ArrayOfInt32Incoming)
Assembly definition test preds for Examples