using System; using System.Collections.Generic; using SbsSW.SwiPlCs; using SbsSW.SwiPlCs.Callback; using SbsSW.SwiPlCs.Exceptions; using Swicli.Library; namespace SWICLITestDLL { // [StructLayout(LayoutKind.Sequential)] public struct NonDetTest { public int start; public int stop; public uint fid; //public NonDetDelegate Call; //public NonDetDelegate Cutted; } public partial class NonDetExample { readonly static Dictionary indexTest = new Dictionary() { { 1, "one" }, { 2, "two" }, }; public string this[int v] { get { return indexTest[v]; } set { indexTest[v] = value; } } public static void LoadNonDetExamples() { Fn015.Register(); const PlForeignSwitches Nondeterministic = PlForeignSwitches.Nondeterministic; PlEngine.RegisterForeign(null, "foo2", 2, new DelegateParameterBacktrack2(FooTwo), Nondeterministic); PlEngine.RegisterForeign(null, "foo3", 3, new DelegateParameterBacktrackVarArgs(FooThree), Nondeterministic | PlForeignSwitches.VarArgs); } private static int callNum = 0; static private PrologCLR.PinnedObject ndtp; // foo(X,Y),writeq(f(X,Y)),nl,X=5. public static int Foo(PlTerm t0, PlTerm term2, IntPtr control) { callNum++; if (callNum > 10) { callNum = 0; //return libpl.PL_fail; } var handle = control; FRG fc = (FRG)(libpl.PL_foreign_control(control)); switch (fc) { case FRG.PL_FIRST_CALL: unsafe { ndtp = new PrologCLR.PinnedObject(); ndtp.managedObject.start = 1; ndtp.managedObject.stop = 3; //ndtp.managedObject.fid = libpl.PL_open_foreign_frame(); ndtp.Recopy(); IntPtr ctxt = ndtp.Pointer; goto redo; int succeed = CountTo(t0, term2, ref ndtp.managedObject); if (ndtp.managedObject.start <= ndtp.managedObject.stop) { libpl.PL_retry_address(ctxt); } if (succeed == 0) return 0; return 3; } break; case FRG.PL_REDO: unsafe { goto redo; NonDetTest* o = (NonDetTest*)0; IntPtr ctxt = libpl.PL_foreign_context_address(control); if (!ctxt.ToString().Equals("0")) { o = (NonDetTest*)ctxt; } else { o = (NonDetTest*)ndtp.Pointer; } int succeed = CountTo(t0, term2, ref *o); NonDetTest managedObject = *o; if (managedObject.start <= managedObject.stop) { libpl.PL_retry_address(ctxt); if (succeed == 0) return 0; return 3; } if (managedObject.fid != 0) { libpl.PL_close_foreign_frame(managedObject.fid); managedObject.fid = 0; } if (succeed == 0) return 0; return 1; } break; case FRG.PL_CUTTED: unsafe { NonDetTest* o = (NonDetTest*)0; IntPtr ctxt = libpl.PL_foreign_context_address(control); if (!ctxt.ToString().Equals("0")) { o = (NonDetTest*)ctxt; } else { o = (NonDetTest*)ndtp.Pointer; } NonDetTest managedObject = *o; if (managedObject.fid != 0) { libpl.PL_close_foreign_frame(managedObject.fid); managedObject.fid = 0; } return libpl.PL_succeed; } break; default: { throw new PlException("no frg"); return libpl.PL_fail; } break; } redo: unsafe { NonDetTest* o = (NonDetTest*)0; IntPtr ctxt = libpl.PL_foreign_context_address(control); var fc0 = libpl.PL_foreign_context(control); if (!ctxt.ToString().Equals("0")) { o = (NonDetTest*)ctxt; } else { o = (NonDetTest*)ndtp.Pointer; } int succeed = CountTo(t0, term2, ref *o); NonDetTest managedObject = *o; if (managedObject.start <= managedObject.stop) { libpl.PL_retry_address(ctxt); if (succeed == 0) return 0; return 3; } if (managedObject.fid != 0) { libpl.PL_close_foreign_frame(managedObject.fid); managedObject.fid = 0; } if (succeed == 0) return 0; return 1; } } static public AbstractNondetMethod Fn015 = new ForNext(0, 15); // test with (foo2(X,Y)->writeln(p(X,Y));writeln(p(X,Y))),!. // test with (foo2(X,Y) *->writeln(p(X,Y));writeln(p(X,Y)),!). public static int FooTwo(PlTerm a0, PlTerm a1, IntPtr control) { var handle = control; FRG fc = (FRG)(libpl.PL_foreign_control(control)); switch (fc) { case FRG.PL_FIRST_CALL: { var v = NondetContextHandle.ObtainHandle(control, new ForNext(1, a0.intValue())); bool res = v.Setup(new PlTermV(a0, a1)); bool more = v.HasMore(); if (more) { libpl.PL_retry(v.Handle); return res ? 3 : 0; } return res ? 1 : 0; } break; case FRG.PL_REDO: { var v = NondetContextHandle.FindHandle(control); bool res = v.Call(new PlTermV(a0, a1)); bool more = v.HasMore(); if (more) { libpl.PL_retry(v.Handle); return res ? 3 : 0; } return res ? 1 : 0; } break; case FRG.PL_CUTTED: { var v = NondetContextHandle.FindHandle(control); bool res = v.Close(new PlTermV(a0, a1)); NondetContextHandle.ReleaseHandle(v); return res ? 1 : 0; } break; default: { throw new PlException("no frg"); return libpl.PL_fail; } break; } } public static int FooThree(PlTerm a0, int arity, IntPtr control) { var handle = control; FRG fc = (FRG)(libpl.PL_foreign_control(control)); switch (fc) { case FRG.PL_FIRST_CALL: { var v = NondetContextHandle.ObtainHandle(control); var tv = new PlTermV(a0, arity); bool res = v.Setup(tv); bool more = v.HasMore(); if (more) { libpl.PL_retry(v.Handle); return res ? 3 : 0; } return res ? 1 : 0; } break; case FRG.PL_REDO: { var v = NondetContextHandle.FindHandle(control); bool res = v.Call(new PlTermV(a0, arity)); bool more = v.HasMore(); if (more) { libpl.PL_retry(v.Handle); return res ? 3 : 0; } return res ? 1 : 0; } break; case FRG.PL_CUTTED: { var v = NondetContextHandle.FindHandle(control); bool res = v.Close(new PlTermV(a0, arity)); NondetContextHandle.ReleaseHandle(v); return res ? 1 : 0; } break; default: { throw new PlException("no frg"); return libpl.PL_fail; } break; } } private static int CountTo(PlTerm term, PlTerm term2, ref NonDetTest o) { try { var c = o.start; bool succed = term.Unify("callnum" + c); if (!succed) { succed = term2.Unify("callnum" + c); } if (succed) { succed = term2.Unify(term); } if (succed) { return libpl.PL_succeed; } return libpl.PL_fail; } finally { o.start++; } } } public class ForNext : AbstractNondetMethod { private int start = 0; private int end = 0; public ForNext(int i, int ii) { start = i; end = ii; } public override AbstractNondetMethod Clone() { return new ForNext(start, end); } #region Overrides of AbstractNondetMethod public override bool Setup(PlTermV a0) { return Call(a0); } public override bool Call(PlTermV a0) { bool success = false; try { for (int i = 0; i < a0.Size; i++) { if (a0[i].Unify(start)) { success = true; } } } finally { start++; } return success; } public override bool Close(PlTermV a0) { end = start + 1; return true; } public override bool HasMore() { return start <= end; } #endregion } }