internal static IEnumerable <bool> UnifyArraysFast(object[] a1, object[] a2, PrologContext context) { int mark = context.MarkTrail(); if (UnifyArrays(a1, a2, context)) { yield return(false); } context.RestoreVariables(mark); }
public static IEnumerable <CutState> SucceedAndRestoreTrail(PrologContext context, int trailMark) { try { yield return(CutState.Continue); } finally { context.RestoreVariables(trailMark); } }
private IEnumerable <CutState> EnumerateArg1Driver(LogicVariable arg1, T2 arg2, PrologContext context) { int tracePointer = context.MarkTrace(); foreach (var newValue in arg1Enumerator(arg2)) { arg1.UnifyWithAtomicConstant(newValue, context); yield return(CutState.Continue); context.RestoreVariables(tracePointer); } }
private IEnumerable <CutState> EnumerateBothDriver(LogicVariable arg1, LogicVariable arg2, PrologContext context) { int tracePointer = context.MarkTrace(); foreach (var pair in doubleEnumerator()) { arg1.UnifyWithAtomicConstant(pair.Arg1, context); arg2.UnifyWithAtomicConstant(pair.Arg2, context); yield return(CutState.Continue); context.RestoreVariables(tracePointer); } }
/// <summary> /// Tests clauses in a randomized order (but still exhaustively). /// Uses Shuffler to generate a random permutation. /// </summary> IEnumerable <CutState> TestShuffledClauses(object[] args, PrologContext context, ushort myFrame) { entriesListUsed = true; var mark = context.MarkTrace(); var shuffler = new Shuffler((ushort)Entries.Count); var argIndexers = PredicateArgumentIndexer.ArglistIndexers(args); while (!shuffler.Done) { var entry = Entries[shuffler.Next()]; if (entry.Prematch(argIndexers)) { // This shouldn't be here... //context.PushGoalStack(Name, args, myFrame); context.SetCurrentRule(entry); foreach (var cutState in entry.Prove(args, context, myFrame)) { if (cutState == CutState.ForceFail) { if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Cut: {0}", new Structure(Name, args)); } goto fail; } if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Succeed: {0}", new Structure(Name, args)); } yield return(CutState.Continue); if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Retry: {0}", new Structure(Name, args)); } } } } fail: context.RestoreVariables(mark); if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Fail: {0}", new Structure(Name, args)); } //context.UnwindStack(Name, args); context.UnwindStack(myFrame); }
/// <summary> /// Tests clauses in the order they appear in the database. /// </summary> IEnumerable <CutState> TestClausesInOrder(object[] args, PrologContext context, ushort myFrame) { var mark = context.MarkTrace(); var argIndexers = PredicateArgumentIndexer.ArglistIndexers(args); entriesListUsed = true; foreach (var entry in Entries) { if (entry.Prematch(argIndexers)) { context.SetCurrentRule(entry); foreach (var cutState in entry.Prove(args, context, myFrame)) { if (cutState == CutState.ForceFail) { if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Cut: {0}", new Structure(Name, args)); } goto fail; } if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Succeed: {0}", new Structure(Name, args)); } yield return(CutState.Continue); if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Retry: {0}", new Structure(Name, args)); } } } } fail: context.RestoreVariables(mark); if (KnowledgeBase.Trace || Trace) { context.TraceOutput("Fail: {0}", new Structure(Name, args)); } //context.UnwindStack(Name, args); context.UnwindStack(myFrame); }
private const byte NoRegister = 0xff; // Target register meaning not to write to register // So here's append([], X, X). : // MatchLiteral([], 0) // MatchVarFirst(1) % This is actually a no-op // MatchVar(1, 2) // Return // // And here's append([H|T], X, [H|T1]) :- append(T, X, T1). // MatchStructure(dot, 2, L1, 0) // MatchVarFirst(0>0>3) % H is at 3 // MatchVarFirst(0>1>4) % T is at 4 // L1 MatchVarFirst(1) % Actually a no-op // MatchStructure(dot, 2, L2, 2) // MatchVar(3, 2>0) // MatchVarFirst(5, 2>1) % T1 is at 5 // L2 Call(6, Fail, Succeed, append/3, register(4), register(2), register(5)) #endregion #region Interpreter internal IEnumerable <CutState> StackCall(PrologContext context) { int traceMark = context.MarkTrail(); // On entry, the stack pointer points at the base of our arguments. int framePointer = context.MakeFrame(frameSize); ushort pc = 0; ushort writeModeEndAddress = 0; // We're in write mode if pc < writeModeEndAddress. // ReSharper disable TooWideLocalVariableScope // Resharper is confused - can't move this inside the while loop, or its lifetime changes. ushort endOfBuilds; // PC of last call instruction whose arguments have been built. // ReSharper restore TooWideLocalVariableScope while (true) { switch ((Opcode)code[pc++]) { #region Head opcodes case Opcode.MatchLiteral: { object literal = GetLiteral(ref pc); if (pc < writeModeEndAddress) { // Write mode SetOperand(context, framePointer, ref pc, literal); } else { // Read mode if (!Term.Unify(DecodeOperand(context, framePointer, ref pc), literal, context)) { goto fail; } } } break; case Opcode.MatchVarFirst: { if (pc < writeModeEndAddress) { // Write mode Symbol name = GetSymbol(ref pc); int register = code[pc++]; var l = new LogicVariable(name); SetOperand(context, framePointer, ref pc, l); if (register != NoRegister) { context.SetStack(framePointer, register, l); } } else { pc += 2; // Skip over variable name. int register = code[pc++]; // Read mode object operand = DecodeOperand(context, framePointer, ref pc); if (register != NoRegister) { context.SetStack(framePointer, register, operand); } } } break; case Opcode.MatchVar: { object register = Register(context, framePointer, pc++); if (pc < writeModeEndAddress) { // Write mode SetOperand(context, framePointer, ref pc, register); } else { // Read mode if (!Term.Unify(DecodeOperand(context, framePointer, ref pc), register, context)) { goto fail; } } } break; case Opcode.MatchStructure: { Symbol functor = GetSymbol(ref pc); int arity = code[pc++]; ushort endAddress = GetUShort(ref pc); if (pc < writeModeEndAddress) { // Write mode SetOperand(context, framePointer, ref pc, new Structure(functor, new object[arity])); } else { // Read mode object arg = DecodeOperand(context, framePointer, ref pc); var s = arg as Structure; if (s == null || !s.IsFunctor(functor, arity)) { var l = arg as LogicVariable; if (l == null) { goto fail; } l.UnifyWithStructure(new Structure(functor, new object[arity])); writeModeEndAddress = endAddress; } } } break; #endregion #region Body opcodes: structure building case Opcode.BuildStructure: { Symbol functor = GetSymbol(ref pc); int arity = code[pc++]; SetOperand(context, framePointer, ref pc, new Structure(functor, new object[arity])); } break; case Opcode.BuildLiteral: SetOperand(context, framePointer, ref pc, GetLiteral(ref pc)); break; case Opcode.BuildVar: { Symbol name = GetSymbol(ref pc); SetOperand(context, framePointer, ref pc, new LogicVariable(name)); } break; case Opcode.BuildReg: object registerValue = Register(context, framePointer, pc++); SetOperand(context, framePointer, ref pc, registerValue); break; #endregion #region Body: control flow case Opcode.CallWokenGoals: case Opcode.Call: case Opcode.CallPrimitive: endOfBuilds = pc; // ReSharper disable once InconsistentNaming ushort succeedPC; IEnumerator <CutState> iterator; var failPC = StartCallInstruction(context, framePointer, ref pc, out succeedPC, out iterator); while (true) { if (iterator == null || iterator.MoveNext()) { // Call succeeds if (succeedPC == SuccessContinuationPC) { yield return(CutState.Continue); // If we get here, then our caller is requesting a redo // Fall through and continue this iterator. if (iterator == null) { goto fail; // Kluge: special case to handle CallWokenGoals instruction where there are no woken goals. } } else { if (succeedPC > endOfBuilds) { // Haven't run the build instructions for next goal, so break out and run them. break; } pc = (ushort)(succeedPC + 1); // StartCallInstruction assumes we've skipped over the opcode. // succeedPC is address of call/callprimitive instruction; next byte is iterator register failPC = this.StartCallInstruction(context, framePointer, ref pc, out succeedPC, out iterator); // Continue while loop } } else { // Call fails switch (failPC) { case FailContinuationPC: goto fail; case CutContinuationPC: goto cut; default: // failPC is address of call/callprimitive instruction; next byte is iterator register pc = (ushort)(failPC + 1); // +1 because we're skipping over the opcode iterator = (IEnumerator <CutState>)context.GetStack(framePointer, code[pc++]); if (iterator == null) // Kluge: special case to handle CallWokenGoals instruction where there are no woken goals. { goto fail; } failPC = GetUShort(ref pc); succeedPC = GetUShort(ref pc); break; } } } break; #endregion default: Debug.Assert(false, "Bad opcode in byte compiled Prolog rule, pc=" + (pc - 1) + ", opcode=" + ((Opcode)code[pc - 1])); break; } } // The while loop above never terminates normally; it only yeilds or branches to one of the following labels cut: context.PopFrame(framePointer); context.RestoreVariables(traceMark); yield return(CutState.ForceFail); fail: context.PopFrame(framePointer); context.RestoreVariables(traceMark); }
internal static IEnumerable<bool> UnifyArraysFast(object[] a1, object[] a2, PrologContext context) { int mark = context.MarkTrace(); if (UnifyArrays(a1, a2, context)) yield return false; context.RestoreVariables(mark); }
/// <summary> /// Tests clauses in a randomized order (but still exhaustively). /// Uses Shuffler to generate a random permutation. /// </summary> IEnumerable<CutState> TestShuffledClauses(object[] args, PrologContext context, ushort myFrame) { entriesListUsed = true; var mark = context.MarkTrace(); var shuffler = new Shuffler((ushort)Entries.Count); var argIndexers = PredicateArgumentIndexer.ArglistIndexers(args); while (!shuffler.Done) { var entry = Entries[shuffler.Next()]; if (entry.Prematch(argIndexers)) { // This shouldn't be here... //context.PushGoalStack(Name, args, myFrame); context.SetCurrentRule(entry); foreach (var cutState in entry.Prove(args, context, myFrame)) { if (cutState == CutState.ForceFail) { if (KnowledgeBase.Trace || Trace) context.TraceOutput("Cut: {0}", new Structure(Name, args)); goto fail; } if (KnowledgeBase.Trace || Trace) context.TraceOutput("Succeed: {0}", new Structure(Name, args)); yield return CutState.Continue; if (KnowledgeBase.Trace || Trace) context.TraceOutput("Retry: {0}", new Structure(Name, args)); } } } fail: context.RestoreVariables(mark); if (KnowledgeBase.Trace || Trace) context.TraceOutput("Fail: {0}", new Structure(Name, args)); //context.UnwindStack(Name, args); context.UnwindStack(myFrame); }
/// <summary> /// Tests clauses in the order they appear in the database. /// </summary> IEnumerable<CutState> TestClausesInOrder(object[] args, PrologContext context, ushort myFrame) { var mark = context.MarkTrace(); var argIndexers = PredicateArgumentIndexer.ArglistIndexers(args); entriesListUsed = true; foreach (var entry in Entries) { if (entry.Prematch(argIndexers)) { context.SetCurrentRule(entry); foreach (var cutState in entry.Prove(args, context, myFrame)) { if (cutState == CutState.ForceFail) { if (KnowledgeBase.Trace || Trace) context.TraceOutput("Cut: {0}", new Structure(Name, args)); goto fail; } if (KnowledgeBase.Trace || Trace) context.TraceOutput("Succeed: {0}", new Structure(Name, args)); yield return CutState.Continue; if (KnowledgeBase.Trace || Trace) context.TraceOutput("Retry: {0}", new Structure(Name, args)); } } } fail: context.RestoreVariables(mark); if (KnowledgeBase.Trace || Trace) context.TraceOutput("Fail: {0}", new Structure(Name, args)); //context.UnwindStack(Name, args); context.UnwindStack(myFrame); }