private static bool ExactlyOnce(object[] args, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k) { ArgumentCountException.Check("ExactlyOnce", 1, args); TextBuffer finalOutput = output; BindingList <LogicVariable> finalBindings = null; State finalState = State.Empty; MethodCallFrame finalFrame = predecessor; bool failure = true; var chain = Step.ChainFromBody("ExactlyOnce", args); chain.Try(output, env, (o, u, d, p) => { failure = false; finalOutput = o; finalBindings = u; finalState = d; finalFrame = p; return(true); }, predecessor); if (failure) { var failedCall = (Call)chain; throw new CallFailedException(env.Resolve(failedCall.Task), env.ResolveList(failedCall.Arglist)); } return(k(finalOutput, finalBindings, finalState, finalFrame)); }
private static bool Not(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k) { foreach (var arg in args) { if (!Term.IsGround(arg)) { throw new ArgumentInstantiationException("Not", e, args, "Use NotAny if you intend goals that aren't ground."); } } // Whether the call to args below succeeded var success = false; // This always fails, since its continuation fails too Step.ChainFromBody("Not", args) .Try(o, e, (newOut, newE, newK, newP) => { // Remember that we succeeded, then fail success = true; return(false); }, predecessor); // If the call to args succeeded, fail; otherwise call continuation return(!success && k(o, e.Unifications, e.State, predecessor)); }
private static bool IgnoreOutput(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k) { return(Step.ChainFromBody("IgnoreOutput", args).Try( o, e, (_, u, s, p) => k(o, u, s, p), predecessor)); }
private static bool NotAny(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k) { // Whether the call to args below succeeded var success = false; // This always fails, since its continuation fails too Step.ChainFromBody("NotAny", args) .Try(o, e, (newOut, newE, newK, newP) => { // Remember that we succeeded, then fail success = true; return(false); }, predecessor); // If the call to args succeeded, fail; otherwise call continuation return(!success && k(o, e.Unifications, e.State, predecessor)); }
private static bool Implies(object[] args, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k) { if (args.Length < 2) { throw new ArgumentCountException(nameof(Implies), 2, args); } var producer = args[0]; var producerChain = Step.ChainFromBody(nameof(Implies), producer); var consumer = args.Skip(1).ToArray(); var consumerChain = Step.ChainFromBody(nameof(Implies), consumer); var dynamicState = env.State; var resultOutput = output; var allTrue = true; producerChain.Try(resultOutput, env, (o, u, d, p) => { // We've got a solution to the producer in u. // So run the consumer once with u but not d or o. allTrue &= consumerChain.Try(resultOutput, new BindingEnvironment(env, u, dynamicState), (o2, u2, d2, newP) => { // Save modifications to dynamic state, output; throw away binding state dynamicState = d2; resultOutput = o2; // Accept this one solution to consumer; don't backtrack it. return(true); }, p); // Backtrack to generate the next solution for producer return(false); }, predecessor); // Use original unifications but accumulated output and state. return(allTrue && k(resultOutput, env.Unifications, dynamicState, predecessor)); }
/// <summary> /// Calls all the tasks in the body and allows the user to provide their own continuation. /// The only (?) use case for this is when you want to forcibly generate multiple solutions /// </summary> internal static void GenerateSolutionsFromBody(string callingTaskName, object[] body, TextBuffer o, BindingEnvironment e, Step.Continuation k, MethodCallFrame predecessor) { Step.ChainFromBody(callingTaskName, body).Try(o, e, k, predecessor); }
private static bool And(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k) => Step.ChainFromBody("And", args).Try(o, e, k, predecessor);