/* $Id$
*
* Project: Swicli.Library - Two Way Interface for .NET and MONO to SWI-Prolog
* Author: Douglas R. Miles
* Uwe Lesta (SbsSW.SwiPlCs classes)
* E-mail: logicmoo@gmail.com
* WWW: http://www.logicmoo.com
* Copyright (C): 2008, Uwe Lesta SBS-Softwaresysteme GmbH,
* 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.Windows.Forms;
#if USE_IKVM
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.Collections.ObjectModel;
using System.Text;
using SbsSW.DesignByContract;
using SbsSW.SwiPlCs.Exceptions;
using SbsSW.SwiPlCs.Streams;
using Swicli.Library;
/********************************
* TYPES Comment *
********************************/
#region used type from SWI-Prolog.h
/*
*/
#endregion
// The namespace summary is above class NamespaceDoc
namespace SbsSW.SwiPlCs.Callback
{
#region namspace documentation
///
/// The namespace SbsSW.SwiPlCs.Callback provides the delegates to register .NET methods to be
/// called from SWI-Prolog
///
///
///
/// It is only possible to call methods
///
///
[System.Runtime.CompilerServices.CompilerGenerated()]
class NamespaceDoc
{
}
#endregion namspace documentation
#region enum PlForeignSwitches
///
/// Flags that are responsible for the foreign predicate parameters
///
[Flags]
public enum PlForeignSwitches:uint
{
/// 0 - PL_FA_NOTHING: no flags.
None = 0,
/// 1 - PL_FA_NOTRACE: Predicate cannot be seen in the tracer.
NoTrace = 1,
/// 2 - PL_FA_TRANSPARENT: Predicate is module transparent.
Transparent = 2,
/// 4 - PL_FA_NONDETERMINISTIC: Predicate is non-deterministic. See also PL_retry().
/// PL_retry()
Nondeterministic = 4,
/// 8 - PL_FA_VARARGS: (Default) Use alternative calling convention. call using t0, ac, ctx
VarArgs = 8,
/// 16 - PL_FA_CREF: /* call using t0, ac, ctx */.
CRef = 16,
///
/// /* Internal: ISO core predicate */
///
ISO = 32,
}
#endregion enum PlForeignSwitches
#region delagates for C# callbacks
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate Int32 PL_agc_hook_t(uint t_atom);
///
/// PL_EXPORT(void) PL_on_halt(void (*)(int, void *), void *);
///
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public unsafe delegate void SwiOnHalt(int i, void* closureObj);
///
/// typedef void (*PL_abort_hook_t)(void);
///
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public unsafe delegate void PL_abort_hook_t();
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate bool DelegateParameter0();
///
///
/// See also the example in .
///
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate bool DelegateParameter1(PlTerm term);
///
/// Provide a predefined Delegate to register a C# method to be called from SWI-Prolog
///
///
/// This example is for and shows how o call a C# method with two parameter.
/// For other samples see the source file CallbackForeigenPredicate.cs in the TestSwiPl VS2008 test project.
///
///
///
///
/// true for succeeding otherwise false for fail
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate bool DelegateParameter2(PlTerm term1, PlTerm term2);
///
///
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate bool DelegateParameter3(PlTerm term1, PlTerm term2, PlTerm term3);
///
///
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate bool DelegateParameter4(PlTerm term1, PlTerm term2, PlTerm term3, PlTerm term4);
///
///
///
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate bool DelegateParameter5(PlTerm term1, PlTerm term2, PlTerm term3, PlTerm term4, PlTerm term5);
///
/// With this delegate you can build a call-back predicate with a variable amount of parameters.
///
///
///
///
/// The termVector representing the arguments which can be accessed by the
/// indexer of PlTermV see . The amount of parameters is in
///
/// True for succeeding otherwise false for fail
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate bool DelegateParameterVarArgs(PlTermV termVector);
///
/// NOT IMPLEMENTED YET
/// For details to implement see 9.6.17 Registering Foreign Predicates
/// see also PL_foreign_control
///
/// TODO
/// TODO
/// TODO
/// TODO
/// TODO
/// See "t_backtrack" in TestSwiPl.CallbackForeigenPredicate.cs
///
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate int DelegateParameterBacktrack1(PlTerm term1, IntPtr control);
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate int DelegateParameterBacktrack2(PlTerm term1, PlTerm term2, IntPtr control);
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate int DelegateParameterBacktrackVarArgs(PlTerm term1, int arity, IntPtr control);
#endregion delagates for C# callbacks
} // namespace SbsSW.SwiPlCs.Callback
namespace SbsSW.SwiPlCs.Streams
{
#region namspace documentation
///
/// The namespace SbsSW.SwiPlCs.Streams provides the delegates to redirect the read
/// and write functions of the SWI-Prolog IO Streams.
/// When is called the *Sinput->functions.read is
/// replaced by the .NET method 'Sread_function' and *Sinput->functions.write by 'Swrite_funktion'.
/// For further examples see the methods and
///
///
/// The reason for this is debugging.
///
///
///
///
///
[System.Runtime.CompilerServices.CompilerGenerated()]
class NamespaceDoc
{
}
#endregion namspace documentation
///
/// The standard SWI-Prolog streams ( input output error )
///
public enum PlStreamType
{
/// 0 - The standard input stream.
Input = 0,
/// 1 - The standard input stream.
Output = 1,
/// 1 - The standard error stream.
Error = 2
}
///
/// See
///
/// A C stream handle. simple ignore it.
/// A pointer to a string buffer
/// The size of the string buffer
/// A
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate long DelegateStreamReadFunction(IntPtr handle, System.IntPtr buffer, long bufferSize);
///
/// See
///
/// A C stream handle. simple ignore it.
/// A pointer to a string buffer
/// The size of the string buffer
/// A
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate long DelegateStreamWriteFunction(IntPtr handle, string buffer, long bufferSize);
/*
*/
}
// The namespace summary is above class NamespaceDoc
namespace SbsSW.SwiPlCs
{
#region namspace documentation
///
/// The online documentation home is here.
/// This namespace SbsSW.SwiPlCs provides an .NET interface to SWI-Prolog
///
///
/// Overview
/// Prolog variables are dynamically typed and all information is passed around using the
/// C-interface type term_t witch is an int. In C#, term_t is embedded in the lightweight struct .
/// Constructors and operator definitions provide flexible operations and integration with important C#-types (string, int and double).
///
///
/// The list below summarises the important classes / struct defined in the C# interface.
///
/// class / structShort description
/// - A static class represents the prolog engine.
/// - A struct representing prolog data.
/// - A vector of .
/// - A class to query Prolog.
///
///
///
///
/// Before going into a detailed description of the CSharp classes let me present a few examples
/// illustrating the `feel' of the interface. The Assert class in the sample is from the test framework
/// and has nothing to do with the interface. It shows only which return values are expected.
///
/// Creating terms
/// This very simple example shows the basic creation of a Prolog term and how a Prolog term is converted to C#-data:
///
/// PlTerm t1 = new PlTerm("x(A)");
/// PlTerm t2 = new PlTerm("x(1)");
/// Assert.IsTrue(t1.Unify(t2));
/// Assert.AreEqual("x(1)", t1.ToString());
///
///
/// Calling Prolog
/// This example shows how to make a simple call to prolog.
///
/// PlTerm l1 = new PlTerm("[a,b,c,d]");
/// Assert.IsTrue(PlQuery.PlCall("is_list", l1));
///
///
/// Getting the solutions of a query
/// This example shows how to obtain all solutions of a prolog query.
/// takes the name of a predicate and the goal-argument vector as arguments.
/// From this information it deduces the arity and locates the predicate. the member-function
/// NextSolution() yields true if there was a solution and false otherwise.
/// If the goal yielded a Prolog exception it is mapped into a C# exception.
///
/// PlQuery q = new PlQuery("member", new PlTermV(new PlTerm("A"), new PlTerm("[a,b,c]")));
/// while (q.NextSolution())
/// PrologCLR.ConsoleTrace(s[0].ToString());
///
/// There is an other constructor of which simplify the sample above.
///
/// PlQuery q = new PlQuery("member(A, [a,b,c])");
/// foreach (PlTermV s in q.Solutions)
/// PrologCLR.ConsoleTrace(s[0].ToString());
///
/// An other way to get the results is to use to iterate over .
///
/// PlQuery q = new PlQuery("member(A, [a,b,c])");
/// foreach (PlQueryVariables vars in q.SolutionVariables)
/// PrologCLR.ConsoleTrace(vars["A"].ToString());
///
/// It is also possible to get all solutions in a list by .
/// This could be used to work with LinQ to objects which is really nice. and for further samples.
///
/// var results = from n in new PlQuery("member(A, [a,b,c])").ToList() select new {A = n["A"].ToString()};
/// foreach (var s in results)
/// PrologCLR.ConsoleTrace(s.A);
///
///
[System.Runtime.CompilerServices.CompilerGenerated()]
class NamespaceDoc
{
}
#endregion namspace documentation
///
/// Obtain the type of a term, which should be a term returned by one of the other
/// interface predicates or passed as an argument. The function returns the type of
/// the Prolog term. The type identifiers are listed below.
///
/// see PL_term_type(term_t) in the SWI-Prolog Manual.
///
///
/// In this sample a Prolog variable is created in PlTerm t and the
/// is checked by his integer representation and his name.
///
/// PlTerm t = PlTerm.PlVar();
/// Assert.AreEqual(1, (int)t.PlType);
/// Assert.AreEqual(PlType.PlVariable, t.PlType);
///
///
public enum PlType
{
/// 0 - PL_UNKNOWN: Undefined
PlUnknown = 0,
/// 1 - PL_VARIABLE: An unbound variable. The value of term as such is a unique identifier for the variable.
PlVariable = 1,
/// 2 - PL_ATOM: A Prolog atom.
PlAtom = 2,
/// 3 - PL_INTEGER: A Prolog integer.
PlInteger = 3,
/// 4 - PL_FLOAT: A Prolog floating point number.
PlFloat = 4,
/// 5 - PL_STRING: A Prolog string.
PlString = 5,
/// 6 - PL_TERM: A compound term. Note that a list is a compound term ./2.
PlTerm = 6,
PlNil = (7), /* The constant [] */
PlBlob = (8), /* non-atom blob */
PlListPair = (9), /* [_|_] term */
PL_VARIABLE =(1), /* nothing */
PL_ATOM =(2), /* const char * */
PL_INTEGER =(3), /* int */
PL_FLOAT =(4), /* double */
PL_STRING =(5), /* const char * */
PL_TERM =(6),
PL_NIL =(7), /* The constant [] */
PL_BLOB =(8), /* non-atom blob */
PL_LIST_PAIR =(9), /* [_|_] term */
/* PL_unify_term(), */
PL_FUNCTOR =(10), /* functor_t, arg ... */
PL_LIST =(11), /* length, arg ... */
PL_CHARS =(12), /* const char * */
PL_POINTER =(13), /* void * */
/* PlArg::PlArg=(text, type), */
PL_CODE_LIST =(14), /* [ascii...] */
PL_CHAR_LIST =(15), /* [h,e,l,l,o] */
PL_BOOL =(16), /* PL_set_prolog_flag=(), */
PL_FUNCTOR_CHARS =(17), /* PL_unify_term=(), */
_PL_PREDICATE_INDICATOR =(18), /* predicate_t =(Procedure), */
PL_SHORT =(19), /* short */
PL_INT =(20), /* int */
PL_LONG =(21), /* long */
PL_DOUBLE =(22), /* double */
PL_NCHARS =(23), /* size_t, const char * */
PL_UTF8_CHARS =(24), /* const char * */
PL_UTF8_STRING =(25), /* const char * */
PL_INT64 =(26), /* int64_t */
PL_NUTF8_CHARS =(27), /* size_t, const char * */
PL_NUTF8_CODES =(29), /* size_t, const char * */
PL_NUTF8_STRING =(30), /* size_t, const char * */
PL_NWCHARS =(31), /* size_t, const wchar_t * */
PL_NWCODES =(32), /* size_t, const wchar_t * */
PL_NWSTRING =(33), /* size_t, const wchar_t * */
PL_MBCHARS =(34), /* const char * */
PL_MBCODES =(35), /* const char * */
PL_MBSTRING =(36), /* const char * */
PL_INTPTR =(37), /* intptr_t */
PL_CHAR =(38), /* int */
PL_CODE =(39), /* int */
PL_BYTE =(40), /* int */
/* PL_skip_list=(), */
PL_PARTIAL_LIST =(41), /* a partial list */
PL_CYCLIC_TERM =(42), /* a cyclic list/term */
PL_NOT_A_LIST =(43), /* Object is not a list */
/* dicts */
PL_DICT =(44),
}
/*
///
/// Extends PlTerm
///
public static class PlTermList
{
///
/// extension "doit"
///
/// how ?
public static void DoIt(this PlTerm plTerm)
{
PrologCLR.ConsoleTrace(plTerm.ToString());
}
}
*/
public class PlArrayEnumerator: IEnumerator
{
PlTerm orig;
int index = 0;
public PlArrayEnumerator(PlTerm compound, int startElement)
{
orig = compound;
index = startElement - 1;
}
#region IEnumerator Members
PlTerm IEnumerator.Current
{
get { return orig[index]; }
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
//orig = null;
}
#endregion
#region IEnumerator Members
object IEnumerator.Current
{
get { return orig[index]; }
}
bool IEnumerator.MoveNext()
{
return (index++ < orig.Arity);
}
void IEnumerator.Reset()
{
index = 0;
}
#endregion
}
public class PlTermVEnumerator : IEnumerator
{
PlTermV orig;
int index = -1;
public PlTermVEnumerator(PlTermV compound, int startElement)
{
orig = compound;
index = startElement - 1;
}
#region IEnumerator Members
PlTerm IEnumerator.Current
{
get
{
try
{
return orig[index];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
//orig = null;
}
#endregion
#region IEnumerator Members
object IEnumerator.Current
{
get
{
try
{
return orig[index];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
bool IEnumerator.MoveNext()
{
return (++index < orig.Size);
}
void IEnumerator.Reset()
{
index = -1;
}
#endregion
}
public interface IndexableWithLength
{
T this[int index] { get; }
int Length { get; }
}
/********************************
* GENERIC PROLOG TERM *
********************************/
#region public struct PlTerm
///
/// The PlTerm plays a central role in conversion and operating on Prolog data.
/// PlTerm implements to support ordering in queries if PlTerm is a List.
/// Creating a PlTerm can be done by the Constructors or by the following static methods:
/// PlVar(), PlTail(), PlCompound, PlString(), PlCodeList(), PlCharList() (see remarks)
///
///
///
/// static methodDescription
/// - Creates a new initialised term (holding a Prolog variable).
/// - PlTail is for analysing and constructing lists.
/// - PlCompound(string)Create compound terms. E.g. by parsing (as read/1) the given text.
/// - Create a SWI-Prolog string.
/// - Create a Prolog list of ASCII codes from a 0-terminated C-string.
/// - Create a Prolog list of one-character atoms from a 0-terminated C-string.
///
///
public struct PlTerm : IComparable, IEnumerable, IndexableWithLength// TODO, IList // LISTS
{
///
///
///
///
//public static explicit operator uint(PlTerm t)
// {
// return t.TermRef;
// }
private uint _termRef; // term_t
// Properties
internal uint TermRef
{
get
{
//if (0 == _termRef) {
// _termRef = libpl.PL_new_term_ref();
//}
Check.Require(_termRef != 0, "use of an uninitialised plTerm. If you need a variable use PlTerm.PlVar() instead");
return _termRef;
}
//set { _termRef = (uint)value; }
}
///
/// This one should be for checks only e.g.
/// Check.Require(arg1.TermRefIntern != 0);
///
internal uint TermRefIntern
{
get { return _termRef; }
}
#region implementing IComparable CompareTo
///
public int CompareTo(object obj)
{
if (obj is PlTerm)
{
return libpl.PL_compare(this.TermRef, ((PlTerm)obj).TermRef);
}
else
{
throw new ArgumentException("object is not a PlTerm");
}
}
#endregion
///
/// If PlTerm is compound and index is between 0 and Arity (including), the nth PlTerm is returned.
/// If pos is 0 the functor of the term is returned (For a list '.').
/// See: PL_get_arg/3
///
/// To Get the nth PlTerm
/// a PlTerm
///
///
///
/// Is thrown if PlTerm is not of Type PlCompound see
/// Is thrown if (pos < 0 || pos >= Arity)
/// Is thrown if PL_get_arg returns 0.
public PlTerm this[int pos]
{
get
{
if(!this.IsCompound)
throw new NotSupportedException("Work only for compound terms!");
if (pos < 0 || pos > this.Arity)
throw new ArgumentOutOfRangeException("pos", "Must be greater than 0 and lesser then the arity of the term " + "this=" + this + " pos=" + pos);
if (0 == pos)
{
if (this.IsList)
return PlTerm.PlAtom(PlTerm.LIST_FUNCTOR_NAME);
else
return PlTerm.PlAtom(this.Name);
}
else
{
uint a = libpl.PL_new_term_ref();
if (0 != libpl.PL_get_arg(pos, this.TermRef, a))
return new PlTerm(a);
else
throw new InvalidOperationException("PlTerm indexer: PL_get_arg return 0");
}
}
//set
//{
// myData[pos] = value;
//}
}
#region constructors
// Creates a new initialised term (holding a Prolog variable).
//public PlTerm()
//{
// _termRef = libpl.PL_new_term_ref();
//}
// NOTE : Be Careful you *can* delete this constructor or make it private
// it compiles but the tests will fail
///
/// Create a PlTerm but *no* new term_ref it only copies the term_ref into the new object
/// Used Intern by
/// - PlException constructor
/// - PlQueryQ.GetSolutions()
/// - PlTermV this[int index] indexer
///
///
internal PlTerm(uint termRef)// PlTerm(term_t termRef)
{
_termRef = termRef;
}
///
///
/// A new PlTerm can be also created by the static methods:
///
/// static methodDescription
/// - Creates a new initialised term (holding a Prolog variable).
/// - PlTail is for analysing and constructing lists.
/// - PlCompound(string)Create compound terms. E.g. by parsing (as read/1) the given text.
/// - Create a SWI-Prolog string.
/// - Create a Prolog list of ASCII codes from a 0-terminated C-string.
/// - Create a Prolog list of one-character atoms from a 0-terminated C-string.
///
///
///
///
/// Creates a term-references holding a Prolog term representing text.
///
/// the text
public PlTerm(string text)
{
// old
//_termRef = libpl.PL_new_term_ref();
//if (0 == libpl.PL_chars_to_term(text, this.TermRef))
// throw new PlException("Term creation failed : " + text);
// term_t
uint t = libpl.PL_new_term_ref();
if (0 == libpl.PL_chars_to_term(text, t))
throw new PlException("PlTerm creation failed : " + text);
this._termRef = libpl.PL_new_term_ref();
libpl.PL_put_term(this.TermRef, t);
}
///
/// Creates a term-references holding a Prolog integer representing value.
///
/// a integer value
public PlTerm(int value)
{
_termRef = libpl.PL_new_term_ref();
libpl.PL_put_integer(this.TermRef, value);
}
public PlTerm(long value)
{
_termRef = libpl.PL_new_term_ref();
libpl.PL_put_integer(this.TermRef, value);
}
///
/// Creates a term-references holding a Prolog float representing value.
///
/// a double value
public PlTerm(double value)
{
_termRef = libpl.PL_new_term_ref();
libpl.PL_put_float(this.TermRef, value);
}
#endregion
/***************************************
* SPECIALISED TERM CREATION *
* as static methods *
***************************************/
#region PlVar Creation
///
/// Creates a new initialised term (holding a Prolog variable).
///
/// a PlTerm
static public PlTerm PlVar()
{
PlTerm term = new PlTerm();
term._termRef = libpl.PL_new_term_ref();
return term;
}
#endregion
#region PlList Creation
///
///
/// PlTail is for analysing and constructing lists.
/// It is called PlTail as enumeration-steps make the term-reference follow the `tail' of the list.
///
///
/// A PlTail is created by making a new term-reference pointing to the same object.
/// As PlTail is used to enumerate or build a Prolog list, the initial list
/// term-reference keeps pointing to the head of the list.
///
///
///
/// The initial PlTerm
/// A PlTerm for which is_list/1 succeed.
///
///
///
///
///
static public PlTerm PlTail(PlTerm list)
{
Check.Require((object)list != null);
Check.Require(list.IsList || list.IsVar);
PlTerm term = new PlTerm();
if (0 != libpl.PL_is_variable(list.TermRef) || 0 != libpl.PL_is_list(list.TermRef))
term._termRef = libpl.PL_copy_term_ref(list.TermRef);
else
throw new PlTypeException("list", list);
return term;
}
#endregion
#region PlCompound Creation
///
///
/// These static methods creates a new compound .
/// For an example
///
///
///
/// Create a term by parsing (as read/1) the text.
///
/// If the text is not valid Prolog syntax, a syntax error exception is raised.
/// Otherwise a new term-reference holding the parsed text is created.
///
/// The string representing the compound term parsed by read/1.
/// a new
static internal PlTerm PlCompound(string text)
{
// term_t
uint t = libpl.PL_new_term_ref();
if (0 == libpl.PL_chars_to_term(text, t))
throw new PlException("PlCompound creation failed : " + text);
PlTerm term = PlVar();
libpl.PL_put_term(term.TermRef, t);
return term;
}
///
/// Create a compound term with the given name from the given vector of arguments. See for details.
///
///
/// The example below creates the Prolog term hello(world).
///
/// PlTerm t = PlTerm.PlCompound("hello", new PlTermv("world"));
///
///
/// The functor (name) of the compound term
/// the arguments as a
/// a new
static public PlTerm PlCompound(string functor, PlTermV args)
{
Check.Require((object)args != null);
//if (args == null)
// throw new ArgumentNullException("args");
int arity = args.Size;
if (arity == 2 && (functor == "." || functor == "[|]"))
{
return PlList(args);
}
else
{
PlTerm term = new PlTerm();
term._termRef = libpl.PL_new_term_ref();
functor = checkForNewList(functor, arity);
libpl.PL_cons_functor_v(term.TermRef, libpl.PL_new_functor(libpl.PL_new_atom(functor), args.Size), args.A0);
return term;
}
}
public static PlTerm PlList(PlTermV args)
{
PlTerm term = new PlTerm();
term._termRef = libpl.PL_new_term_ref();
libpl.PL_cons_functor_v(term.TermRef, libpl.PL_new_functor(libpl.PL_new_atom(LIST_FUNCTOR_NAME), args.Size), args.A0);
//libpl.PL_put_list(term._termRef, args.A0, args.A0 + 1);
return term;
}
public static PlTerm PlList(PlTerm h, PlTerm t)
{
return PlTerm.PlList(new PlTermV(h, t));
}
public static String OLD_LIST_FUNCTOR_NAME = ".";
public static String NEW_LIST_FUNCTOR_NAME = "[|]";
static bool _wasTraditional;
public static String LIST_FUNCTOR_NAME = IsTraditional ? OLD_LIST_FUNCTOR_NAME : NEW_LIST_FUNCTOR_NAME;
public static bool IsTraditional {
get
{
return _wasTraditional;
}
set
{
if (_wasTraditional == value) return;
_wasTraditional = value;
LIST_FUNCTOR_NAME = _wasTraditional ? OLD_LIST_FUNCTOR_NAME : NEW_LIST_FUNCTOR_NAME;
}
}
private static string checkForNewList(string functor, int arity)
{
if (arity == 2 && ((functor == ".") || functor == "[|]")) return LIST_FUNCTOR_NAME;
return functor;
}
///
/// Create a compound term with the given name ant the arguments
///
/// The functor (name) of the compound term
/// The first Argument as a
/// a new
static public PlTerm PlCompound(string functor, params PlTerm[] arg1)
{
PlTermV args = new PlTermV(arg1);
return PlTerm.PlCompound(functor, args);
}
public static PlTerm PlNewAtom(string name)
{
uint termRef = libpl.PL_new_term_refs(1);
PlTerm term = new PlTerm();
term._termRef = termRef;
libpl.PL_put_atom(termRef, libpl.PL_new_atom(name));
return term;
}
public static PlTerm PlAtom(string name)
{
uint termRef = libpl.PL_new_term_refs(1);
PlTerm term = new PlTerm();
term._termRef = termRef;
libpl.PL_put_atom_chars(termRef, name);
return term;
}
#pragma warning disable 1573
///
/// The second Argument as a
static public PlTerm PlCompound(string functor, PlTerm arg1, PlTerm arg2)
{
PlTermV args = new PlTermV(arg1, arg2);
return PlTerm.PlCompound(functor, args);
}
///
/// The third Argument as a
static public PlTerm PlCompound(string functor, PlTerm arg1, PlTerm arg2, PlTerm arg3)
{
PlTermV args = new PlTermV(arg1, arg2, arg3);
return PlTerm.PlCompound(functor, args);
}
static public PlTerm PlCompound(string functor, PlTerm arg1, PlTerm arg2, PlTerm arg3, PlTerm arg4)
{
PlTermV args = new PlTermV(arg1, arg2, arg3, arg4);
return PlTerm.PlCompound(functor, args);
}
#pragma warning restore 1573
#endregion PlCompound Creation
#region PlString Creation
///
///
/// A SWI-Prolog string represents a byte-string on the global stack.
/// It's lifetime is the same as for compound terms and other data living on the global stack.
/// Strings are not only a compound representation of text that is garbage-collected,
/// but as they can contain 0-bytes, they can be used to contain arbitrary C-data structures.
///
///
/// the string
/// a new PlTerm
static public PlTerm PlString(string text)
{
PlTerm t = new PlTerm();
t._termRef = libpl.PL_new_term_ref();
libpl.PL_put_string_chars(t.TermRef, text);
return t;
}
#pragma warning disable 1573
///
/// the length of the string
static public PlTerm PlString(string text, int len)
{
PlTerm t = new PlTerm();
t._termRef = libpl.PL_new_term_ref();
libpl.PL_put_string_nchars(t.TermRef, len, text);
return t;
}
#pragma warning restore 1573
#endregion PlString Creation
#region PlCodeList Creation
///
/// Create a Prolog list of ASCII codes from a 0-terminated C-string.
///
/// The text
/// a new
static public PlTerm PlCodeList(string text)
{
PlTerm term = new PlTerm();
term._termRef = libpl.PL_new_term_ref();
libpl.PL_put_list_codes(term.TermRef, text);
return term;
}
#endregion
#region PlCharList Creation
///
///
/// These static methods creates a new PlCharList TODO TODO .
///
///
/// Create a Prolog list of one-character atoms from a C#-string.
/// Character lists are compliant to Prolog's atom_chars/2 predicate.
/// a string
/// A new PlTerm containing a prolog list of character
static public PlTerm PlCharList(string text)
{
PlTerm term = new PlTerm();
term._termRef = libpl.PL_new_term_ref();
libpl.PL_put_list_chars(term.TermRef, text);
return term;
}
#endregion
/***************************************
* *
***************************************/
#region Testing the type of a term ( IsVar, IsList, .... )
/// Get the of a .
public PlType PlType
{
get { return (PlType)libpl.PL_term_type(this.TermRef); }
}
// all return non zero if condition succeed
/// Return true if is a variable
///
public bool IsVar { get { return 0 != libpl.PL_is_variable(this.TermRef); } }
/// Return true if is a ground term. See also ground/1. This function is cycle-safe.
///
public bool IsGround { get { return 0 != libpl.PL_is_ground(this.TermRef); } }
/// Return true if is an atom.
///
public bool IsAtom
{
get
{
return 0 != libpl.PL_is_atom(this.TermRef);
}
}
/// Return true if is an atom.
///
public bool IsBlob
{
get
{
UIntPtr type = new UIntPtr();
return 0 != libpl.PL_is_blob(this.TermRef, ref type);
}
} /// Return true if is an atom.
///
public bool IsAttVar
{
get
{
return 0 != libpl.PL_is_attvar(this.TermRef);
}
}
/// Return true if is an atom.
///
public bool IsAtomOrNil
{
get
{
bool wasAtom = 0 != libpl.PL_is_atom(this.TermRef);
if (!wasAtom) return IsNil;
return wasAtom;
}
}
/// Return true if is an atom.
///
public bool IsAtomOrString
{
get
{
bool wasAtom = 0 != libpl.PL_is_atom(this.TermRef);
if (!wasAtom) return IsString;
return wasAtom;
}
}
/// Return true if is a string.
///
public bool IsString { get { return 0 != libpl.PL_is_string(this.TermRef); } }
/// Return true if is an integer.
///
public bool IsInteger { get { return 0 != libpl.PL_is_integer(this.TermRef); } }
/// Return true if is a float.
///
public bool IsFloat { get { return 0 != libpl.PL_is_float(this.TermRef); } }
/// Return true if is a compound term. Note that a list is a compound term ./2
///
public bool IsCompound { get { return 0 != libpl.PL_is_compound(this.TermRef); } }
/// Return true if is a compound term with functor ./2 or the atom [].
///
public bool IsList { get { return 0 != libpl.PL_is_list(this.TermRef) || IsNewList; } }
/// Return true if is a compound term with functor ./2 or the atom [].
///
public bool IsNewList { get
{
return (PlType == PlType.PlListPair) || (IsCompound && Arity == 2 && Name == LIST_FUNCTOR_NAME);
} }
/// Return true if is atomic (not variable or compound).
///
public bool IsAtomic { get { return 0 != libpl.PL_is_atomic(this.TermRef); } }
/// Return true if is an integer or float.
///
public bool IsNumber { get { return 0 != libpl.PL_is_number(this.TermRef); } }
/// Return true if is an empty list or nil.
///
public bool IsNil { get { return 0 != libpl.PL_get_nil(this.TermRef); } }
#endregion
/***************************************
* LIST ( PlTerm ) implementation *
***************************************/
#region list ( PlTail ) Methods
// building
///
/// Appends element to the list and make the PlTail reference point to the new variable tail.
/// If A is a variable, and this method is called on it using the argument "gnat",
/// a list of the form [gnat|B] is created and the PlTail object now points to the new variable B.
///
/// This method returns TRUE if the unification succeeded and FALSE otherwise. No exceptions are generated.
///
///
///
///
/// The PlTerm to append on the list.
/// true if successful otherwise false
public bool Append(PlTerm term)
{
Check.Require(this.IsList || this.IsVar, "" + this + " must be a list or var for Append " + term);
Check.Require((object)term != null);
uint tmp = libpl.PL_new_term_ref();
if (0 != libpl.PL_unify_list(TermRef, tmp, TermRef) && 0 != libpl.PL_unify(tmp, term.TermRef))
return true;
return false;
}
///
/// Appends an element to a list by creating a new one and copy all elements
/// Note This is a slow version
/// see my mail from Jan from 2007.11.06 14:44
///
/// a closed list
/// True if Succeed
public bool Add(PlTerm term)
{
Check.Require(this.IsList, "" + this + " must be a list for Add");
Check.Require((object)term != null);
uint list, head, tail;
BuildOpenList(out list, out head, out tail);
if (0 == libpl.PL_unify_list(tail, head, tail)) // extend the list with a variable
return false;
if (0 == libpl.PL_unify(term.TermRef, head)) // Unify this variable with the new list
return false;
libpl.PL_unify_nil(tail);
this._termRef = list;
return true;
}
///
/// Appends a list ( PlTail ) to a list by creating a new one and copy all elements
///
///
///
///
/// a closed list
/// True if Succeed
public bool AddList(PlTerm listToAppend)
{
Check.Require(this.IsList, "" + this + " must be a list for AddList " + listToAppend);
Check.Require((object)listToAppend != null);
Check.Require(listToAppend.IsList);
uint list, head, tail;
BuildOpenList(out list, out head, out tail);
uint list2 = libpl.PL_copy_term_ref(listToAppend.TermRef);
uint elem = libpl.PL_new_term_ref(); // 'elem' for iterating the old list
while (0 != libpl.PL_get_list(list2, elem, list2))
{
libpl.PL_unify_list(tail, head, tail); // extend the list with a variable
libpl.PL_unify(elem, head); // Unify this variable with the new list
}
libpl.PL_unify_nil(tail);
this._termRef = list;
return true;
}
///
/// Unifies the term with [] and returns the result of the unification.
///
///
public int Close()
{
Check.Require(this.IsList || this.IsVar, "" + this + " must be a list or var for Close ");
return libpl.PL_unify_nil(TermRef);
}
///
/// return a PlTerm bound to the next element of the list PlTail and advance PlTail.
/// Returns the element on success or a free PlTerm (Variable) if PlTail represents the empty list.
/// If PlTail is neither a list nor the empty list, a PlTypeException (type_error) is thrown.
///
///
/// The Next element in the list as a PlTerm which is a variable for the last element or an empty list
public PlTerm NextValue()
{
Check.Require(this.IsList, "" + this + " must be a list for NextValue");
// PlTerm term = new PlTerm();
PlTerm term = PlTerm.PlVar();
if (0 != libpl.PL_get_list(this.TermRef, term.TermRef, this.TermRef))
{
return term;
}
if (0 != libpl.PL_get_nil(this.TermRef))
{
return term;
}
throw new PlTypeException("list", this);
}
///
/// Converts to a strongly typed ReadOnlyCollection of PlTerm objects that can be accessed by index
///
/// A strongly typed ReadOnlyCollection of PlTerm objects
public ReadOnlyCollection ToList()
{
Check.Require(this.IsList, "" + this + " must be a list for ToList");
List l = new List();
foreach (PlTerm t in this)
{
l.Add(t);
}
return new ReadOnlyCollection(l);
}
///
/// Converts to a strongly typed Collection of strings that can be accessed by index
///
/// A strongly typed string Collection
public Collection ToListString()
{
Check.Require(this.IsList, " must be a list for ToListString");
List l = new List();
foreach (PlTerm t in this.Copy())
{
l.Add(t.ToString());
}
return new Collection(l);
}
#region IEnumerable Members
///
/// Returns an enumerator that iterates through the collection.
///
/// A System.Collections.Generic.IEnumerator<T that can be used to iterate through the collection.
public IEnumerator GetEnumerator()
{
if (IsList)
{
// list is destrctive!?!
return Copy().GetEnumeratorL();
}
return new PlArrayEnumerator(this, 1);
}
private IEnumerator GetEnumeratorL()
{
Check.Require(this.IsList, " must be a list for GetEnumeratorL");
PlTerm t = default(PlTerm);// new PlTerm(); //null;
while (this.Next(ref t))
{
yield return (PlTerm)t;
}
}
#endregion IEnumerable Members
// private list helper methods
// enumerating
// see: http://www.mycsharp.de/wbb2/thread.php?threadid=53241
#region IEnumerable Members
///
/// Returns an enumerator that iterates through a collection.
///
/// An System.Collections.IEnumerator object that can be used to iterate through the collection.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator(); // Looks recursive but it is *not*.
}
#endregion
///
/// Bind termRef to the next element of the list PlTail and advance PlTail.
/// Returns TRUE on success and FALSE if PlTail represents the empty list.
/// If PlTail is neither a list nor the empty list, a type_error is thrown.
///
///
///
private bool Next(ref PlTerm termRef)
{
Check.Require(this.IsList, "must be a list of Next ");
// termRef = new PlTerm();
termRef = PlTerm.PlVar();
if (0 != libpl.PL_get_list(this.TermRef, termRef._termRef, this.TermRef))
{
return true;
}
if (0 != libpl.PL_get_nil(this.TermRef))
{
return false;
}
throw new PlTypeException("list", this);
}
private void BuildOpenList(out uint list, out uint head, out uint tail)
{
list = libpl.PL_new_term_ref(); // our list (starts unbound)
tail = libpl.PL_copy_term_ref(list); // the tail of it (starts as the whole)
head = libpl.PL_new_term_ref(); // placeholder for the element
uint elem = libpl.PL_new_term_ref(); // for iterating the old list
while (0 != libpl.PL_get_list(this.TermRef, elem, this.TermRef))
{
libpl.PL_unify_list(tail, head, tail); // extend the list with a variable
libpl.PL_unify(elem, head); // Unify this variable with the new list
}
}
#endregion list ( PlTail ) Methods
#region ToString and helpers
private string ToStringAsListFormat()
{
StringBuilder sb = new StringBuilder(""); ;
PlTerm list = PlTerm.PlTail(this);
//list.GetEnumerator();
foreach (PlTerm t in list)
{
if (0 < sb.Length)
sb.Append(',');
sb.Append(t.ToString());
}
sb.Insert(0, '[');
sb.Append(']');
return sb.ToString();
}
///
///
/// If PlTerm is a list the string is build by calling ToString() for each element in the list
/// separated by ',' and put the brackets around '[' ']'.
///
///
///
/// A string representing the PlTerm.
override public string ToString()
{
string s = "";
if (this.IsList) //switch (this.PlType)
s = ToStringAsListFormat();
else
s = (string)this;
return s;
}
static string string_buffer;
static long SwriteStringCanonical(IntPtr handle, string buffer, long buffersize)
{
string s = buffer.Substring(0, (int)buffersize);
string_buffer = s;
return buffersize;
}
///
/// Convert a PlTerm to a string by write_canonical/1
/// This Method use and is slow.
///
/// return the string of a PlTerm
public string ToStringCanonical()
{
// redirect write stream
DelegateStreamWriteFunction old_write_function = PlEngine._function_write;
DelegateStreamWriteFunction wf = new DelegateStreamWriteFunction(SwriteStringCanonical);
PlEngine.SetStreamFunctionWrite(PlStreamType.Output, wf);
PlQuery.PlCall("write_canonical", new PlTermV(this));
PlQuery.PlCall("flush_output");
// restore stream function
PlEngine.SetStreamFunctionWrite(PlStreamType.Output, old_write_function);
return string_buffer;
}
#endregion
#region unification
///
/// This methods performs Prolog unification and returns true if successful and false otherwise.
/// It is equal to the prolog =/2 operator.
/// See for an example.
///
/// This methods are introduced for clear separation between the destructive assignment in C# using =
/// and prolog unification.
///
///
/// Put a PlTerm with a PlTerm
///
///
///
/// the second term for unification
/// true or false
public void Put(PlTerm term)
{
libpl.PL_put_term(this.TermRef, term.TermRef);
}
///
/// A string to Put with
public void Put(string atom)
{
libpl.PL_put_atom_chars(this.TermRef, atom);
}
public void Put(long integer)
{
libpl.PL_put_integer(this.TermRef, integer);
}
public void Put(ulong integer)
{
if (integer > long.MaxValue)
{
// slow but works
Put(new PlTerm("" + integer));
return;
}
libpl.PL_put_integer(this.TermRef, (long)integer);
}
public void Put(double atom)
{
libpl.PL_put_float(this.TermRef, atom);
}
/*
*/
#endregion unification
#region unification
///
/// This methods performs Prolog unification and returns true if successful and false otherwise.
/// It is equal to the prolog =/2 operator.
/// See for an example.
///
/// This methods are introduced for clear separation between the destructive assignment in C# using =
/// and prolog unification.
///
///
/// Unify a PlTerm with a PlTerm
///
///
///
/// the second term for unification
/// true or false
public bool Unify(PlTerm term)
{
return 0 != libpl.PL_unify(this.TermRef, term.TermRef);
}
public bool CanUnify(PlTerm term)
{
return 0 != libpl.PL_unify(this.TermRef, term.TermRef);
}
///
/// A string to unify with
public bool Unify(string atom)
{
return 0 != libpl.PL_unify_atom_chars(this.TermRef, atom);
}
public bool UnifyAtom(string atom)
{
return 0 != libpl.PL_unify_atom_chars(this.TermRef, atom);
}
public bool Unify(long atom)
{
return 0 != libpl.PL_unify_integer(this.TermRef, atom);
}
public bool Unify(ulong atom)
{
if (atom > long.MaxValue)
{
// slow but works
return Unify(new PlTerm("" + atom));
}
return 0 != libpl.PL_unify_integer(this.TermRef, (long)atom);
}
public bool Unify(double atom)
{
return 0 != libpl.PL_unify_float(this.TermRef, atom);
}
///
/// Useful e.g. for lists list.Copy().ToList(); list.ToString();
///
/// Return a unifies PlTerm.PlVar of this term
internal PlTerm Copy()
{
PlTerm tc = PlTerm.PlVar();
if (!this.Unify(tc))
throw new PlLibException("Copy term fails (Unification return false)");
return tc;
}
/*
*/
#endregion unification
#region Arity and Name
/// Get the arity of the functor if is a compound term.
/// and are for compound terms only
/// Is thrown if the term isn't compound
public int Arity
{
get
{
uint name = 0; // atom_t
int arity = 0;
if (0 != libpl.PL_get_name_arity(this.TermRef, ref name, ref arity))
return arity;
if (IsString) return 0;
Embedded.Error(" arity called on a " + this.PlType);
throw new NotSupportedException("Only possible for compound or atoms");
//throw new PlTypeException("compound", this); // FxCop Don't like this type of exception
}
}
///
/// Get a holding the name of the functor if is a compound term.
///
///
public string Name
{
get
{
uint name = 0; // atom_t
int arity = 0;
var pltype = this.PlType;
if (pltype == PlType.PlNil) return "[]";
if (pltype == PlType.PlListPair) return LIST_FUNCTOR_NAME;
if (0 != libpl.PL_get_name_arity(this.TermRef, ref name, ref arity))
{
return libpl.PL_atom_chars(name);
}
if (IsString) return ToString();
Embedded.Debug("pltype = "+pltype);
throw new NotSupportedException("Only possible for compound or atoms or string");
//throw new PlTypeException("compound", this); // FyCop Don't like this type of exception
}
}
#endregion Arity and Name
public long longValue()
{
return (long)this;
}
public int intValue()
{
return (int)this;
}
public double doubleValue()
{
return (double)this;
}
#region cast oprators
///
/// Converts the Prolog argument into a string which implies Prolog atoms and strings
/// are converted to the represented text or throw a PlTypeException.
///
///
/// Converts the Prolog argument using PL_get_chars() using the
/// flags CVT_ALL|CVT_WRITE|BUF_RING, which implies Prolog atoms and strings
/// are converted to the represented text or throw a PlTypeException.
///
/// If the above call return 0 PL_get_chars is called a second time with the flags CVT_ALL|CVT_WRITE|BUF_RING|REP_UTF8.
/// All other data is handed to write/1.
///
/// A PlTerm that can be converted to a string
/// A C# string
/// Throws a PlTypeException exception
/// Is thrown if the operator is used on an uninitialized PlTerm
public static explicit operator string(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
return CastToString(term.TermRef);
}
public static string CastToString(uint TermRef)
{
return CastToString0(TermRef);
return PrologCLR.InvokeFromC(() => CastToString0(TermRef), true);
}
public static string CastToString0(uint TermRef)
{
String s = "";
if (0 != libpl.PL_get_chars(TermRef, ref s, libpl.CVT_ALL | libpl.CVT_WRITE | libpl.BUF_RING))
return s;
else if (0 != libpl.PL_get_chars(TermRef, ref s, libpl.CVT_ALL | libpl.CVT_WRITE | libpl.BUF_RING | libpl.REP_UTF8)) // libpl.REP_MB -> convertiert nach BestFitMapping
{
return s;
}
if (0 != libpl.PL_get_chars(TermRef, ref s, libpl.CVT_ALL | libpl.CVT_WRITE | libpl.REP_UTF8 | libpl.BUF_RING | libpl.CVT_VARIABLE))
return s;
throw new PlTypeException("text", new PlTerm(TermRef));
}
///
/// Yields a int if the PlTerm is a Prolog integer or float that can be converted
/// without loss to a int. Throws a PlTypeException exception otherwise
///
/// A PlTerm is a Prolog integer or float that can be converted without loss to a int.
/// A C# int
/// Throws a PlTypeException exception if
/// is not a or a .
/// Is thrown if the operator is used on an uninitialized PlTerm
public static explicit operator int(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
int v = 0;
if (0 != libpl.PL_get_integer(term.TermRef, ref v))
return v;
throw new PlTypeException("int", term);
}
///
/// Yields a long if the PlTerm is a Prolog integer or float that can be converted
/// without loss to a long. Throws a PlTypeException exception otherwise
///
/// A PlTerm is a Prolog integer or float that can be converted without loss to a long.
/// A C# long
/// Throws a PlTypeException exception if
/// is not a or a .
/// Is thrown if the operator is used on an uninitialized PlTerm
public static explicit operator long(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
long v = 0;
if (0 != libpl.PL_get_long(term.TermRef, ref v))
return v;
string s = (string) term;
long longValue;
if (long.TryParse(s, out longValue))
{
return longValue;
}
throw new PlTypeException("long", term);
}
public static explicit operator IntPtr(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
IntPtr v = IntPtr.Zero;
if (0 != libpl.PL_get_intptr(term.TermRef, ref v))
return v;
throw new PlTypeException("intptr", term);
}
public static explicit operator ulong(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
string s = (string) term;
ulong ulongValue;
if (ulong.TryParse(s, out ulongValue))
{
return ulongValue;
}
throw new PlTypeException("ulong", term);
}
#if USE_IKVM
public static explicit operator java.math.BigInteger(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
string s = (string)term;
return new java.math.BigInteger(s);
}
public static explicit operator java.math.BigDecimal(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
string s = (string)term;
return new java.math.BigDecimal(s);
}
#endif
///
/// Yields the value as a C# double if PlTerm represents a Prolog integer or float.
/// Throws a PlTypeException exception otherwise.
///
/// A PlTerm represents a Prolog integer or float
/// A C# double
/// Throws a PlTypeException exception if
/// is not a or a .
/// Is thrown if the operator is used on an uninitialized PlTerm
public static explicit operator double(PlTerm term)
{
Check.Require(term.TermRefIntern != 0);
double v = 0;
if (0 != libpl.PL_get_float(term.TermRef, ref v))
return v;
throw new PlTypeException("float", term);
}
#endregion cast oprators
#region compare operators
// Comparison standard order terms
///
public override int GetHashCode()
{
return this.TermRef.GetHashCode();
}
///
public override bool Equals(Object obj)
{
if (obj is PlTerm)
return this == ((PlTerm)obj);
else if (obj is int)
return this == ((int)obj);
else
return false;
}
/// Compare the instance term1 with term2 and return the result according to the Prolog defined standard order of terms.
///
/// Yields TRUE if the PlTerm is an atom or string representing the same text as the argument,
/// FALSE if the conversion was successful, but the strings are not equal and an
/// type_error exception if the conversion failed.
///
/// a PlTerm
/// a PlTerm
/// true or false
public static bool operator ==(PlTerm term1, PlTerm term2)
{
Check.Require(term1.TermRefIntern != 0);
Check.Require(term2.TermRefIntern != 0);
return libpl.PL_compare(term1.TermRef, term2.TermRef) == 0;
}
///
public static bool operator !=(PlTerm term1, PlTerm term2)
{
return libpl.PL_compare(term1.TermRef, term2.TermRef) != 0;
}
///
public static bool operator <(PlTerm term1, PlTerm term2)
{
return libpl.PL_compare(term1.TermRef, term2.TermRef) < 0;
}
///
public static bool operator >(PlTerm term1, PlTerm term2)
{
return libpl.PL_compare(term1.TermRef, term2.TermRef) > 0;
}
///
public static bool operator <=(PlTerm term1, PlTerm term2)
{
return libpl.PL_compare(term1.TermRef, term2.TermRef) <= 0;
}
///
public static bool operator >=(PlTerm term1, PlTerm term2)
{
return libpl.PL_compare(term1.TermRef, term2.TermRef) >= 0;
}
/*
int operator <=(const PlTerm &t2)
{
return PL_compare(_termRef, t2.TermRef) <= 0;
}
int operator >=(const PlTerm &t2)
{
return PL_compare(_termRef, t2._termRef) >= 0;
}
*/
// comparison (long)
#endregion
#region Equality Method
/// test overload
///
/// a PlTerm
/// a int
/// A bool
public static bool operator ==(PlTerm term, int lng)
{
int v0 = 0;
if (0 != libpl.PL_get_integer(term.TermRef, ref v0))
return v0 == lng;
else
return false; // throw new PlTypeException("integer", term);
}
///
public static bool operator ==(int lng, PlTerm term)
{
return term == lng;
}
// comparison (string)
///
public static bool operator ==(PlTerm term, string value)
{
string s0 = "";
if (0 != libpl.PL_get_chars(term.TermRef, ref s0, libpl.CVT_ALL | libpl.CVT_WRITE | libpl.BUF_RING))
return s0.Equals(value);
else
return false; // throw new PlTypeException("text", term);
}
///
public static bool operator ==(string value, PlTerm term)
{
return term == value;
}
#endregion
#region Inequality Method
///
///
/// Inequality Method overload
///
/// a
///
///
///
///
///
/// summary
///
///
///
///
public static bool operator !=(PlTerm term, int lng)
{
int v0 = 0;
if (0 != libpl.PL_get_integer(term.TermRef, ref v0))
return v0 != lng;
else
return true; // throw new PlTypeException("integer", term);
}
///
public static bool operator !=(int lng, PlTerm term)
{
return term != lng;
}
///
/// test
///
///
///
///
public static bool operator !=(PlTerm term, string value)
{
return !(term == value);
}
///
public static bool operator !=(string value, PlTerm term)
{
return term != value;
}
#endregion compare operators
#region IndexableWithLength Members
PlTerm IndexableWithLength.this[int index]
{
get
{
return this[index];
}
}
int IndexableWithLength.Length
{
get { return Arity; }
}
internal PlTerm[] Args
{
get
{
if (!IsCompound)
{
if(IsAtom) return new PlTerm[0];
if (IsNil) return null;
return null;
}
throw new NotImplementedException("PLTerm.Args");
}
// set { throw new NotImplementedException(); }
}
#endregion
public bool FromObject(object o)
{
if (!IsVar)
{
Embedded.Warn("Not a free object! {0}", this);
}
var v = PrologCLR.UnifyToProlog(o, this);
if (IsVar || v == 0)
{
if (PrologCLR.MakeArrayImmediate && PrologCLR.MakeNoRefs && PrologCLR.MadeARef && IsVar)
{
return true;
}
Embedded.Warn("Unify failed! {0}", this);
return false;
}
return v != 0;
}
///
/// Zero Based
///
///
///
internal PlTerm Arg(int p0)
{
return this[p0 + 1];
}
///
/// Zero Based
///
///
///
public PlTerm ArgItem(int p0)
{
if (IsList)
{
PlTerm li = Copy();
int itnum = p0;
while (itnum-- > 0)
{
li = li.Arg(1);
}
return li.Arg(0);
}
return this[p0 + 1];
}
public PlTerm Shift(int i)
{
return new PlTerm((uint) (_termRef + i));
}
} // class PlTerm
#endregion
/********************************
* PlTermV *
********************************/
#region public class PlTermV
///
/// The struct PlTermv represents an array of term-references.
/// This type is used to pass the arguments to a foreign defined predicate (see ),
/// construct compound terms (see
/// and to create queries (see ).
///
/// The only useful member function is the overloading of [], providing (0-based) access to the elements.
/// Range checking is performed and raises a ArgumentOutOfRangeException exception.
///
public struct PlTermV : IEquatable, IEnumerable, IndexableWithLength
{
private uint _a0; // term_t
private int _size;
#region IndexableWithLength Members
PlTerm IndexableWithLength.this[int index]
{
get
{
return this[index];
}
}
int IndexableWithLength.Length
{
get { return Size; }
}
#endregion
public override string ToString()
{
try
{
string ts = "";
}
catch (Exception)
{
return base.ToString();
}
}
#region constructors
/// Create a PlTermV vector from the given PlTerm parameters
///
/// Create a new vector with PlTerm as elements
/// It can be created with elements
/// or
/// automatically for 1, 2 or 3 plTerms
///
///
///
///
/// Create a vector of PlTerms with elements
///
/// The amount of PlTerms in the vector
public PlTermV(int size)
{
_a0 = libpl.PL_new_term_refs(size);
_size = size;
}
/*
/// Create a PlTermV from the given s.
/// The first in the vector.
public PlTermV(PlTerm term0)
{
Check.Require(term0.TermRefIntern != 0);
_size = 1;
_a0 = term0.TermRef;
}*/
// warning CS1573: Parameter 'term0' has no matching param tag in the XML comment for 'SbsSW.SwiPlCs.PlTermV.PlTermV(SbsSW.SwiPlCs.PlTerm, SbsSW.SwiPlCs.PlTerm)' (but other parameters do)
#pragma warning disable 1573
///
/// The second in the vector.
/*public PlTermV(PlTerm term0, PlTerm term1)
{
Check.Require(term0.TermRefIntern != 0);
Check.Require(term1.TermRefIntern != 0);
_size = 2;
_a0 = libpl.PL_new_term_refs(2);
libpl.PL_put_term(_a0 + 0, term0.TermRef);
libpl.PL_put_term(_a0 + 1, term1.TermRef);
}
*/
public PlTermV(params PlTerm[] terms)
{
_size = terms.Length;
_a0 = libpl.PL_new_term_refs(_size);
for (int i = 0; i < _size; i++)
{
//if (terms[i].TermRefIntern != 0)
libpl.PL_put_term((uint)(_a0 + i), terms[i].TermRef);
}
}
public PlTermV(PlTerm terms, int arity)
{
_size = arity;
Check.Require(terms.TermRefIntern != 0);
_a0 = terms.TermRefIntern;
}
public void Resize(int newSize)
{
int addTo = newSize - _size;
_size = newSize;
}
/*
///
/// The third in the vector.
public PlTermV(PlTerm term0, PlTerm term1, PlTerm term2)
{
Check.Require(term0.TermRefIntern != 0);
Check.Require(term1.TermRefIntern != 0);
Check.Require(term2.TermRefIntern != 0);
_size = 3;
_a0 = libpl.PL_new_term_refs(3);
libpl.PL_put_term(_a0 + 0, term0.TermRef);
libpl.PL_put_term(_a0 + 1, term1.TermRef);
libpl.PL_put_term(_a0 + 2, term2.TermRef);
}*/
#pragma warning restore 1573
#endregion
// internal PlTermV(PlTermV toCopy)
// : this(toCopy._size)
// {
// for (uint i = 0; i < toCopy._size; i++)
// {
//// libpl.PL_put_term(_a0 + i, new PlTerm(toCopy[(int)i].TermRef).TermRef);
// this[i].TermRef = libpl.PL_copy_term_ref(toCopy[i].TermRef);
// }
// }
// Properties
///
/// the first term_t reference of the array
///
internal uint A0
{
get { return _a0; }
}
/// Get the size of a PlTermV
public int Size
{
get { return _size; }
}
///
/// A zero based list
///
///
/// The PlTerm for the given index
/// Is thrown if (index < 0 || index >= Size)
/// Is thrown if the operator is used on an uninitialized PlTerm
public PlTerm this[int index]
{
get
{
if (index < 0 || index >= Size)
throw new ArgumentOutOfRangeException("index");
else
return new PlTerm(A0 + (uint)index); // If this line is deleted -> update comment in PlTern(term_ref)
}
set
{
if (index < 0 || index >= Size)
throw new ArgumentOutOfRangeException("index");
else
{
Check.Require(value.TermRefIntern != 0, "use of an uninitialized plTerm. If you need a variable use PlTerm.PlVar() instead");
libpl.PL_put_term(_a0 + (uint)index, ((PlTerm)value).TermRef);
}
}
}
#region IEquatable Members
// see http://msdn.microsoft.com/de-de/ms182276.aspx
///
public override int GetHashCode()
{
return (int)A0;
}
///
public override bool Equals(object obj)
{
if (!(obj is PlTermV))
return false;
return Equals((PlTermV)obj);
}
///
///// TODO compare each PlTerm in PlTermV not only the refereces in A0
public bool Equals(PlTermV other)
{
if (this._size != other._size)
return false;
if (this.A0 != other.A0)
return false;
return true;
}
///
///
///
///
///
///
public static bool operator ==(PlTermV tv1, PlTermV tv2)
{
return tv1.Equals(tv2);
}
///
///
///
///
///
///
public static bool operator !=(PlTermV tv1, PlTermV tv2)
{
return !tv1.Equals(tv2);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return new PlTermVEnumerator(this, 0);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return new PlTermVEnumerator(this, 0);
}
#endregion
} // class PlTermV
#endregion
/****************************************************
* PlFrame *
* PlQuery is in the file SWI-cs-PlQuery.cs *
****************************************************/
#region public class PlFrame
///
/// The class PlFrame provides an interface to discard unused term-references as well as rewinding unifications (data-backtracking).
/// Reclaiming unused term-references is automatically performed after a call to a C#-defined predicate has finished and
/// returns control to Prolog. In this scenario PlFrame is rarely of any use.
/// This class comes into play if the top level program is defined in C# and calls Prolog multiple times.
/// Setting up arguments to a query requires term-references and using PlFrame is the only way to reclaim them.
///
/// see
///
/// A typical use for PlFrame is the definition of C# methods that call Prolog and may be called repeatedly from C#.
/// Consider the definition of assertWord(), adding a fact to word/1:
///
/// alternatively you can use
///
/// NOTE: in any case you have to destroy any query object used inside a PlFrame
///
public class PlFrame : IDisposable
{
#region IDisposable
// see : "Implementing a Dispose Method [C#]" in ms-help://MS.VSCC/MS.MSDNVS/cpguide/html/cpconimplementingdisposemethod.htm
// and IDisposable in class PlQuery
/// Implement IDisposable.
///
/// Do not make this method virtual.
/// A derived class should not be able to override this method.
///
public void Dispose()
{
Dispose(true);
// Take yourself off of the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
Free();
}
#endregion
private uint m_fid; // fid_t
public uint FID
{
get { return m_fid; }
}
///
/// Creating an instance of this class marks all term-references created afterwards to be valid only in the scope of this instance.
///
public PlFrame()
{
m_fid = libpl.PL_open_foreign_frame();
}
///
/// Reclaims all term-references created after constructing the instance.
///
~PlFrame()
{
Dispose(false);
}
///
/// Discards all term-references and global-stack data created as well as undoing all unifications after the instance was created.
///
public void Rewind()
{
libpl.PL_rewind_foreign_frame(m_fid);
}
/// called by Dispose
private void Free()
{
if (m_fid > 0 && PlEngine.IsInitialized)
{
libpl.PL_close_foreign_frame(m_fid);
}
m_fid = 0;
}
} // PlFrame
#endregion
/********************************
* ENGINE *
********************************/
#region public class PlEngine
///
/// This static class represents the prolog engine.
///
///
/// A sample
///
/// if (!PlEngine.IsInitialized)
/// {
/// String[] empty_param = { "" };
/// PlEngine.Initialize(empty_param);
/// // do some funny things ...
/// PlEngine.PlCleanup();
/// }
/// // program ends here
///
/// The following sample show how a file is consult via comand-line options.
///
///
public static class PlEngine
{
#region RegisterForeign
///
/// Dictionary to pin foriegn method delegates so that are not GC'd
///
public static readonly Dictionary SavedRegisterForeign = new Dictionary();
public static readonly List MoreSavedDelegates = new List();
public static bool SaveRegisterForeign(string module, string name, int arity, Delegate method)
{
Delegate prev;
string key = (module ?? "user") + ":" + (name ?? "_NONAME_") + "/" + arity;
PrologCLR.RegisterInfo(name, arity, method.Method);
lock (SavedRegisterForeign)
{
if (!SavedRegisterForeign.TryGetValue(key, out prev))
{
SavedRegisterForeign[key] = method;
return true;
}
}
if (prev == method)
{
return true;
}
if (true)
{
MoreSavedDelegates.Add(method);
if (false)
Embedded.Debug("PinDelegate: " + key + " <- " + method.Method + " from " + prev.Method +
" as " + method.GetType().Name);
return true;
}
Embedded.ConsoleWriteLine("PinDelegate: " + key + " <- " + method.Method + " from " + prev.Method +
" as " + method.GetType().Name);
return false;
}
///
///
/// Register a C-function to implement a Prolog predicate.
/// After this call returns successfully a predicate with name (a string) and arity arity (a C# int) is created in module module.
/// If module is NULL, the predicate is created in the module of the calling context or if no context is present in the module user.
///
///
/// Add a additional namespace by using SbsSW.SwiPlCs.Callback;
///
/// For an example see and .
///
///
///
///
/// Register a C# callback method
///
/// For an example see and .
/// a delegate to a c# method
/// true if registration succeed otherwise false
public static bool RegisterForeign(Delegate method)
{
return RegisterForeign(null, method);
}
// warning CS1573: Parameter 'term0' has no matching param tag in the XML comment for 'SbsSW.SwiPlCs.PlTermV.PlTermV(SbsSW.SwiPlCs.PlTerm, SbsSW.SwiPlCs.PlTerm)' (but other parameters do)
#pragma warning disable 1573
///
/// the name of a prolog module Using Modules
public static bool RegisterForeign(string module, Delegate method)
{
Callback.PlForeignSwitches flags = Callback.PlForeignSwitches.None;
if (method is Callback.DelegateParameterBacktrack2 || method is Callback.DelegateParameterBacktrack1)
flags |= Callback.PlForeignSwitches.Nondeterministic;
if (method is Callback.DelegateParameterVarArgs || method is Callback.DelegateParameterBacktrackVarArgs)
flags |= Callback.PlForeignSwitches.VarArgs;
return RegisterForeign(module, method, flags);
}
///
/// The amount of parameters
public static bool RegisterForeign(string name, int arity, Delegate method)
{
return RegisterForeign(null, name, arity, method);
}
///
/// The name of the method
public static bool RegisterForeign(string module, string name, int arity, Delegate method)
{
return RegisterForeign(module, name, arity, method, Callback.PlForeignSwitches.VarArgs);
}
#pragma warning restore 1573
// make public to activate the foreign predicated in named modules
#region privates
internal static bool RegisterForeign(string module, Delegate method, Callback.PlForeignSwitches plForeign)
{
string name = method.Method.Name;
int arity = method.Method.GetParameters().Length;
return RegisterForeign(module, name, arity, method, plForeign);
}
///
///
///
///
public static bool RegisterForeign(string module, string name, int arity, Delegate method, Callback.PlForeignSwitches plForeign)
{
if (!SaveRegisterForeign(module, name, arity, method)) return false;
return Convert.ToBoolean(libpl.PL_register_foreign_in_module(module, name, arity, method, (int)plForeign));
}
#endregion privates
#endregion RegisterForeign
/// To test if the prolog engine is up.
public static bool IsInitialized
{
get
{
int i = libpl.PL_is_initialised(IntPtr.Zero, IntPtr.Zero);
if (0 == i)
return false;
else
return true;
}
}
///
/// Initialise SWI-Prolog
/// The write method of the output stream is redirected to
/// before Initialize. The read method of the input stream just after Initialize.
///
///
/// A known bug: Initialize work *not* as expected if there are e.g. German umlauts in the parameters
/// See marshalling in the sorce NativeMethods.cs
///
///
/// For a complete parameter description see the SWI-Prolog reference manual section 2.4 Command-line options.
/// sample parameter: String[] param = { "-q", "-f", @"some\filename" };
/// At the first position a parameter "" is added in this method. PL_initialise
///
///
/// For an example see
public static void Initialize(String[] argv)
{
if (argv == null)
throw new ArgumentNullException("argv", "Minimum is one empty string");
if (IsInitialized)
{
throw new PlLibException("PlEngine is already initialised");
}
else
{
libpl.LoadLibPl();
// redirect input and output stream to receive messages from prolog
DelegateStreamWriteFunction wf = new DelegateStreamWriteFunction(Swrite_function);
if (!IsStreamFunctionWriteModified)
{
if (Embedded.RedirectStreams) PlEngine.SetStreamFunctionWrite(PlStreamType.Output, wf);
IsStreamFunctionWriteModified = false;
}
String[] local_argv = new String[argv.Length+1];
int idx = 0;
local_argv[idx++] = "";
foreach (string s in argv)
local_argv[idx++] = s;
if (Embedded.IsEmbeddedFromProlog && 0 == libpl.PL_initialise(local_argv.Length, local_argv))
throw new PlLibException("failed to initialize");
else
{
Embedded.ConsoleWriteLine("PL_initialised");
SetStreamReader(Sread_function);
}
}
}
public static void SetStreamReader(DelegateStreamReadFunction rf)
{
if (Embedded.RedirectStreams)
{
// if (!IsStreamFunctionReadModified)
{
PlEngine.SetStreamFunctionRead(PlStreamType.Input, new DelegateStreamReadFunction(rf));
IsStreamFunctionReadModified = true;
}
}
}
///
/// Try a clean up but it is buggy
/// search the web for "possible regression from pl-5.4.7 to pl-5.6.27" to see reasons
///
/// Use this method only at the last call before run program ends
static public void PlCleanup()
{
unsafe
{
try
{
libpl.PL_cleanup(0);
}
catch (Exception e)
{
PrologCLR.ConsoleTrace(e);
if (e is Exception) throw (Exception)e;
throw new Exception("SPECIAL: " + e);
}
}
}
/// Stops the PlEngine and the program
/// SWI-Prolog calls internally pl_cleanup and than exit(0)
static public void PlHalt()
{
libpl.PL_halt(0);
}
// *****************************
// STATICs for STREAMS
// *****************************
#region stream IO
#region default_io_doc
static internal long Swrite_function(IntPtr handle, string buf, long bufsize)
{
long ssize = bufsize;
if (bufsize > buf.Length)
{
ssize = buf.Length;
}
string s = buf.Substring(0, (int)ssize);
Console.Write(s);
System.Diagnostics.Trace.WriteLine(s);
return bufsize;
}
static internal long Sread_function(IntPtr handle, System.IntPtr buf, long bufsize)
{
throw new PlLibException("SwiPlCs: Prolog try to read from stdin");
}
#endregion default_io_doc
public static bool IsStreamFunctionWriteModified; // default = false;
public static bool IsStreamFunctionReadModified; // default = false;
/// To Avoid callbackOnCollectedDelegate MDA
internal static Streams.DelegateStreamWriteFunction _function_write;
/// To Avoid callbackOnCollectedDelegate MDA
internal static Streams.DelegateStreamReadFunction _function_read;
///
/// This is a primitive approach to enter the output from a stream.
///
///
///
///
/// Determine which stream to use
/// A
static public void SetStreamFunctionWrite(Streams.PlStreamType streamType, Streams.DelegateStreamWriteFunction function)
{
libpl.LoadLibPl();
libpl.SetStreamFunction(streamType, libpl.StreamsFunction.Write, function);
IsStreamFunctionWriteModified = true;
_function_write = function;
}
///
/// TODO
///
///
///
///
/// Determine which stream to use
/// A
static public void SetStreamFunctionRead(Streams.PlStreamType streamType, Streams.DelegateStreamReadFunction function)
{
libpl.LoadLibPl();
libpl.SetStreamFunction(streamType, libpl.StreamsFunction.Read, function);
IsStreamFunctionReadModified = true;
_function_read = function;
}
#endregion stream IO
// *****************************
// STATICs for MULTI THreading
// *****************************
#region STATICs for MULTI THreading
///
/// return : reference count of the engine
/// If an error occurs, -1 is returned.
/// If this Prolog is not compiled for multi-threading, -2 is returned.
///
/// A reference count of the engine
public static int PlThreadAttachEngine()
{
return libpl.PL_thread_attach_engine(IntPtr.Zero);
}
///
/// Returns the integer Prolog identifier of the engine or
/// -1 if the calling thread has no Prolog engine.
/// This method is also provided in the single-threaded version of SWI-Prolog, where it returns -2.
///
///
public static int PlThreadSelf()
{
return libpl.PL_thread_self();
}
///
/// Returns TRUE on success and FALSE if the calling thread has no
/// engine or this Prolog does not support threads.
///
///
public static bool PlThreadDestroyEngine()
{
return 0 != libpl.PL_thread_destroy_engine();
}
#endregion
} // class PlEngine
#endregion
/****************************************************************************
* PrologServer ( PL_initialise, pl_halt, pl_cleanup ) *
****************************************************************************/
#region public class PrologServer
///
/// Experimental
///
public class PrologServer
{
///
///
///
///
///
///
static public bool IsInitialized(int argc, String[] argv)
{
int i = libpl.PL_is_initialised(ref argc, ref argv);
if (0 == i)
return false;
else
return true;
}
///
///
///
///
///
public PrologServer(int argc, String[] argv)
{
if (0 != libpl.PL_is_initialised(ref argc, ref argv))
{
throw new PlLibException("PlEngine is already initialized");
}
else
{
if (0 == libpl.PL_initialise(argc, argv))
throw new PlLibException("failed to initialize");
}
}
//static public void PlCleanup()
//{
// libpl.PL_cleanup(0);
//}
/// Stops the PlEngine and the program
/// SWI-Prolog calls internally exit(0)
static public void PLHalt()
{
//libpl.PL_cleanup(0);
libpl.PL_halt(0);
}
} // PrologServer
#endregion public class PrologServer
#region public class PlMtEngine
///
/// This class is experimental
///
public class PlMtEngine : IDisposable
{
private IntPtr _iEngineNumber = IntPtr.Zero;
private IntPtr _iEngineNumberStore = IntPtr.Zero;
public IntPtr EngineNumber
{
get { return _iEngineNumber; }
}
#region IDisposable
// see : "Implementing a Dispose Method [C#]" in ms-help://MS.VSCC/MS.MSDNVS/cpguide/html/cpconimplementingdisposemethod.htm
// and IDisposable in class PlQuery
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
///
///
///
public void Dispose()
{
Dispose(true);
// Take yourself off of the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
///
///
///
///
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
Free();
}
#endregion
///
///
///
public void Free()
{
if (IntPtr.Zero != _iEngineNumber && PlEngine.IsInitialized)
{
if (0 == libpl.PL_destroy_engine(_iEngineNumber))
throw (new PlException("failed to destroy engine"));
_iEngineNumber = IntPtr.Zero;
}
}
///
///
///
~PlMtEngine()
{
Dispose(false);
}
///
///
///
public PlMtEngine()
{
try
{
if (0 != libpl.PL_is_initialised(IntPtr.Zero, IntPtr.Zero))
{
try
{
_iEngineNumber = libpl.PL_create_engine(IntPtr.Zero);
}
catch (Exception ex)
{
throw (new PlException("PL_create_engine : " + ex.Message));
}
}
else
{
throw new PlLibException("There is no PlEngine initialized");
}
} catch(Exception e)
{
throw new PlLibException("new PlEngine: " + e.Message + " " + e.StackTrace);
}
}
public PlMtEngine(IntPtr engineNumber)
{
_iEngineNumber = engineNumber;
}
// override object.Equals
public override bool Equals(object obj)
{
//
// See the full list of guidelines at
// http://go.microsoft.com/fwlink/?LinkID=85237
// and also the guidance for operator== at
// http://go.microsoft.com/fwlink/?LinkId=85238
//
if (obj == null || GetType() != obj.GetType())
{
return false;
}
PlMtEngine other = (PlMtEngine)obj;
return other._iEngineNumber == _iEngineNumber;
}
// override object.GetHashCode
public override int GetHashCode()
{
return _iEngineNumber.GetHashCode();
}
///
///
///
public void PlSetEngine()
{
IntPtr pNullPointer = IntPtr.Zero;
int iRet = libpl.PL_set_engine(_iEngineNumber, ref pNullPointer);
switch (iRet)
{
case libpl.PL_ENGINE_SET: break; // all is fine
case libpl.PL_ENGINE_INVAL: throw (new PlLibException("PlSetEngine returns Invalid")); //break;
case libpl.PL_ENGINE_INUSE: throw (new PlLibException("PlSetEngine returns it is used by an other thread")); //break;
default: throw (new PlLibException("Unknown return from PlSetEngine"));
}
}
///
///
///
public void PlDetachEngine()
{
int iRet = libpl.PL_set_engine(_iEngineNumber, ref _iEngineNumberStore);
switch (iRet)
{
case libpl.PL_ENGINE_SET: break; // all is fine
case libpl.PL_ENGINE_INVAL: throw (new PlLibException("PlSetEngine(detach) returns Invalid")); //break;
case libpl.PL_ENGINE_INUSE: throw (new PlLibException("PlSetEngine(detach) returns it is used by an other thread")); //break;
default: throw (new PlLibException("Unknown return from PlSetEngine(detach)"));
}
}
///
///
///
///
override public string ToString()
{
return _iEngineNumber.ToString();
}
} // class PlMtEngine
#endregion
} // namespace SbsSW.SwiPlCs