IEnumerable <CutState> CallPrimitive(Symbol functor, PrologPrimitives.PrimitiveImplementation handler, object[] args, PrologContext context) { if (Trace) { context.TraceOutput("Goal: {0}", new Structure(functor, args)); } foreach (var state in handler(args, context)) { if (Trace) { context.TraceOutput((state == CutState.Continue) ? "Succeed: {0}" : "Cut: {0}", new Structure(functor, args)); } yield return(state); if (Trace) { context.TraceOutput("Retry: {0}", new Structure(functor, args)); } } if (Trace) { context.TraceOutput("Fail: {0}", new Structure(functor, args)); } context.PopGoalStack(); }
private ushort StartCallInstruction(PrologContext context, int framePointer, ref ushort pc, out ushort succeedPC, out IEnumerator <CutState> iterator) { int iteratorRegister = code[pc++]; ushort failPC = GetUShort(ref pc); succeedPC = GetUShort(ref pc); iterator = null; // Make the iterator. How we do this depends on the opcode, so re-fetch it. switch ((Opcode)code[pc - CallTargetOffset]) { case Opcode.CallWokenGoals: { if (context.GoalsHaveWoken) { iterator = context.ProveAllWokenGoals().GetEnumerator(); } } break; case Opcode.Call: { // It's a user-defined predicate call PredicateInfo calledPredicate = GetPredicate(ref pc); PushCallArgs(context, framePointer, predicate.Arity, ref pc); iterator = calledPredicate.StackCall(context).GetEnumerator(); } break; case Opcode.CallPrimitive: { // It's a primitive call PrologPrimitives.PrimitiveImplementation implementation = GetPrimitive(ref pc); int arity = code[pc++]; PushCallArgs(context, framePointer, arity, ref pc); iterator = PrologPrimitives.StackCall(implementation, arity, context).GetEnumerator(); } break; default: Debug.Assert(false, "Bad call opcode"); break; } context.SetStack(framePointer, iteratorRegister, iterator); return(failPC); }
/// <summary> /// Prints the byte code for the rule to System.Console. /// </summary> public void Disassemble() { ushort pc = 0; while (pc < code.Length) { var opcode = (Opcode)code[pc++]; Console.Write("L{0}: {1} ", pc - 1, opcode.ToString()); switch (opcode) { case Opcode.MatchStructure: { Symbol functor = GetSymbol(ref pc); int arity = code[pc++]; int endofMatch = GetUShort(ref pc); Console.Write("{0}/{1}, L{2}, ", functor.Name, arity, endofMatch); DisassembleOperand(ref pc); } break; case Opcode.MatchVar: case Opcode.MatchVarFirst: { if (opcode == Opcode.MatchVarFirst) { Console.Write("{0}, ", GetSymbol(ref pc)); } byte register = code[pc++]; Console.Write("{0}, ", FormatRegister(register)); DisassembleOperand(ref pc); } break; case Opcode.MatchLiteral: { Console.Write(GetLiteral(ref pc)); Console.Write(", "); DisassembleOperand(ref pc); } break; case Opcode.BuildStructure: { Console.Write(GetSymbol(ref pc)); Console.Write("/{0}, ", code[pc++]); DisassembleOperand(ref pc); } break; case Opcode.BuildVar: { Console.Write(GetSymbol(ref pc)); Console.Write(", "); DisassembleOperand(ref pc); } break; case Opcode.BuildReg: { byte reg = code[pc++]; Console.Write("{0}, ", FormatRegister(reg)); DisassembleOperand(ref pc); } break; case Opcode.BuildLiteral: { Console.Write(GetLiteral(ref pc)); DisassembleOperand(ref pc); } break; case Opcode.Call: case Opcode.CallPrimitive: case Opcode.CallWokenGoals: { Console.Write("{0}", FormatRegister(code[pc++])); Console.Write(", {0}", FormatLabel(GetUShort(ref pc))); Console.Write(", {0}", FormatLabel(GetUShort(ref pc))); if (opcode != Opcode.CallWokenGoals) { int arity; if (opcode == Opcode.Call) { PredicateInfo p = GetPredicate(ref pc); Console.Write(", {0}/{1}", p.Name, p.Arity); arity = p.Arity; } else { PrologPrimitives.PrimitiveImplementation impl = GetPrimitive(ref pc); arity = code[pc++]; Console.Write(", {0}/{1}", PrologPrimitives.PrimitiveName(impl), arity); } while (arity-- > 0) { Console.Write(", "); int arg = code[pc++]; if (arg < 0x80) { Console.Write("{0}", FormatRegister(arg)); // It's a register } else { // It's a literal arg = ((arg & 0x7f) << 8) + code[pc++]; Console.Write(GlobalLiteralTable[arg]); } } } } break; default: throw new Exception("Unknown opcode " + opcode); } Console.WriteLine(); } }