private static bool Parse(object[] args, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k) { ArgumentCountException.CheckAtLeast(nameof(Parse), 2, args); var call = ArgumentTypeException.Cast <object[]>(nameof(Parse), env.Resolve(args[0]), args); var text = ArgumentTypeException.Cast <string[]>(nameof(Parse), env.Resolve(args[1]), args); if (!(call[0] is Task task)) { throw new InvalidOperationException( "Task argument to Parse must be a compound task, i.e. a user-defined task with methods."); } var taskArgs = new object[call.Length - 1]; var i = 0; for (var callIndex = 1; callIndex < call.Length; callIndex++) { taskArgs[i++] = call[callIndex]; } var parseBuffer = TextBuffer.MakeReadModeTextBuffer(text); return(task.Call(taskArgs, parseBuffer, env, predecessor, (buffer, u, s, p) => buffer.ReadCompleted && k(output, u, s, p))); }
/// <inheritdoc /> protected override IEnumerable <BindingList <LogicVariable> > Iterator(object[] args, BindingEnvironment env) { ArgumentCountException.Check(Name, 3, args); var input1 = ArgumentTypeException.Cast <TIn1>(Name, env.Resolve(args[0]), args); var input2 = ArgumentTypeException.Cast <TIn2>(Name, env.Resolve(args[1]), args); var result = implementation(input1, input2); if (env.Unify(args[2], result, out var bindings)) { return new[] { bindings } } ; return(EmptyBindingListArray); } }
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)); }
/// <inheritdoc /> protected override IEnumerable <BindingList <LogicVariable> > Iterator(object[] args, BindingEnvironment e) { ArgumentCountException.Check(Name, 1, args); var arg = e.Resolve(args[0]); switch (arg) { case LogicVariable v: { foreach (var result in outMode()) { yield return(BindingList <LogicVariable> .Bind(e.Unifications, v, result)); } break; } case T1 value: if (inMode(value)) { yield return(e.Unifications); } break; default: throw new ArgumentTypeException(Name, typeof(T1), arg, args); } }
/// <summary> /// Attempt to run this task /// </summary> /// <param name="output">Output to which to write text</param> /// <param name="env">Variable binding information</param> /// <param name="k">Continuation to call at the end of this step's step-chain</param> /// <param name="predecessor">Predecessor frame</param> /// <returns>True if this steps, the rest of its step-chain, and the continuation all succeed.</returns> public override bool Try(TextBuffer output, BindingEnvironment env, Continuation k, MethodCallFrame predecessor) { MethodCallFrame.CurrentFrame = env.Frame; var target = env.Resolve(Task); var arglist = env.ResolveList(Arglist); return(CallTask(output, env, k, target, arglist, target, predecessor)); }
public override bool Try(TextBuffer output, BindingEnvironment e, Continuation k, MethodCallFrame predecessor) { if (!e.TryCopyGround(e.Resolve(element), out var elt)) { throw new ArgumentInstantiationException("add", e, new[] { "add", collectionVariable, elt }); } var collectionValue = e.Resolve(collectionVariable); switch (collectionValue) { case Cons list: return(Continue(output, new BindingEnvironment(e, e.Unifications, e.State.Bind(collectionVariable, new Cons(elt, list))), k, predecessor)); case IImmutableSet <object> set: return(Continue(output, new BindingEnvironment(e, e.Unifications, e.State.Bind(collectionVariable, set.Add(elt))), k, predecessor)); case ImmutableStack <object> stack: return(Continue(output, new BindingEnvironment(e, e.Unifications, e.State.Bind(collectionVariable, stack.Push(elt))), k, predecessor)); case ImmutableQueue <object> queue: return(Continue(output, new BindingEnvironment(e, e.Unifications, e.State.Bind(collectionVariable, queue.Enqueue(elt))), k, predecessor)); default: throw new ArgumentTypeException("add", typeof(Cons), collectionValue, new[] { "add", elt, collectionValue }); } }
public override object Eval(BindingEnvironment e) { var value = e.Resolve(Variable); if (value is LogicVariable) { throw new ArgumentInstantiationException("variable reference", e, new[] { value }); } return(value); }
public override bool Try(TextBuffer output, BindingEnvironment e, Continuation k, MethodCallFrame predecessor) { var collectionValue = e.Resolve(collectionVariable); switch (collectionValue) { case Cons list: { return(list != Cons.Empty && e.Unify(element, list.First, out var bindings) && Continue(output, new BindingEnvironment(e, bindings, e.State.Bind(collectionVariable, list.Rest)), k, predecessor)); } case ImmutableStack <object> stack: { return(!stack.IsEmpty && e.Unify(element, stack.Peek(), out var bindings) && Continue(output, new BindingEnvironment(e, bindings, e.State.Bind(collectionVariable, stack.Pop())), k, predecessor)); } case ImmutableQueue <object> queue: { return(!queue.IsEmpty && e.Unify(element, queue.Peek(), out var bindings) && Continue(output, new BindingEnvironment(e, bindings, e.State.Bind(collectionVariable, queue.Dequeue())), k, predecessor)); } default: throw new ArgumentTypeException("removeNext", typeof(Cons), collectionValue, new[] { "removeNext", collectionValue }); } }
private static bool SaveText(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k) { ArgumentCountException.Check("SaveText", 2, args); var textVar = e.Resolve(args[1]); if (textVar == null) { throw new ArgumentInstantiationException("SaveText", e, args); } var invocation = args[0] as object[]; if (invocation == null || invocation.Length == 0) { throw new ArgumentTypeException("SaveText", typeof(Call), args[0], args); } var arglist = new object[invocation.Length - 1]; Array.Copy(invocation, 1, arglist, 0, arglist.Length); var call = new Call(invocation[0], arglist, null); var initialLength = o.Length; string[] chunk = null; var frame = predecessor; if (call.Try(o, e, (output, b, d, p) => { frame = p; chunk = new string[output.Length - initialLength]; Array.Copy(o.Buffer, initialLength, chunk, 0, output.Length - initialLength); return(true); }, predecessor) && e.Unify(textVar, chunk, e.Unifications, out var newUnifications)) { return(k(o, newUnifications, e.State, frame)); } return(false); }
private static bool CompoundTask(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k) { ArgumentCountException.Check("CompoundTask", 1, args); var arg = e.Resolve(args[0]); var l = arg as LogicVariable; if (l == null) { // Argument is instantiated; test if it's a compound task return((arg is CompoundTask) && k(o, e.Unifications, e.State, predecessor)); } foreach (var t in e.Module.DefinedTasks) { if (k(o, BindingList <LogicVariable> .Bind(e.Unifications, l, t), e.State, predecessor)) { return(true); } } return(false); }
private static bool FindUnique(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k) { ArgumentCountException.Check("FindUnique", 3, args); var solution = args[0]; var call = args[1] as object[]; if (call == null || call.Length == 0) { throw new ArgumentException("Invalid goal expression"); } var task = ArgumentTypeException.Cast <Task>("FindUnique", call[0], args); var taskArgs = call.Skip(1).ToArray(); var result = args[2]; var resultSet = new HashSet <object>(); task.Call(taskArgs, o, e, predecessor, (newO, u, s, p) => { resultSet.Add(e.Resolve(solution, u)); return(false); }); return(e.Unify(result, resultSet.ToArray(), out var final) && k(o, final, e.State, predecessor)); }
/// <summary> /// Core implementation of both Max and Min /// </summary> private static bool MaxMinDriver(string taskName, object[] args, int multiplier, TextBuffer o, BindingEnvironment e, Step.Continuation k, MethodCallFrame predecessor) { var scoreVar = args[0] as LogicVariable; if (scoreVar == null) { throw new ArgumentInstantiationException(taskName, e, args); } var bestScore = multiplier * float.NegativeInfinity; var bestFrame = predecessor; CapturedState bestResult = new CapturedState(); var gotOne = false; GenerateSolutionsFromBody(taskName, args.Skip(1).ToArray(), o, e, (output, u, d, p) => { gotOne = true; var env = new BindingEnvironment(e, u, d); var maybeScore = env.Resolve(scoreVar); float score; switch (maybeScore) { case int i: score = i; break; case float f: score = f; break; case double df: score = (float)df; break; case LogicVariable _: throw new ArgumentInstantiationException(taskName, new BindingEnvironment(e, u, d), args); default: throw new ArgumentTypeException(taskName, typeof(float), maybeScore, args); } if (multiplier * score > multiplier * bestScore) { bestScore = score; bestResult = new CapturedState(o, output, u, d); bestFrame = p; } // Always ask for another solution return(false); }, predecessor); // When we get here, we've iterated through all solutions and kept the best one. // So pass it on to our continuation return(gotOne && k(o.Append(bestResult.Output), bestResult.Bindings, bestResult.State, bestFrame)); }
/// <inheritdoc /> public override bool Call(object[] args, TextBuffer buffer, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k) { ArgumentCountException.Check(Name, 1, args); var arg = env.Resolve(args[0]); var text = arg as string[]; if (buffer.WriteMode) { if (text == null) { text = renderer(arg); } return(k(buffer.Append(text), env.Unifications, env.State, predecessor)); } // Read mode if (arg is LogicVariable l) { var token = buffer.NextToken(out var newBuffer); if (token == null) { return(false); } object value = token; switch (token) { case "null": value = null; break; case "true": value = true; break; case "false": value = false; break; default: if (int.TryParse(token, out var iValue)) { value = iValue; } else if (float.TryParse(token, out var fValue)) { value = fValue; } break; } return(k(newBuffer, BindingList <LogicVariable> .Bind(env.Unifications, l, value), env.State, predecessor)); } if (text == null) { text = renderer(arg); } return(buffer.Unify(text, out var result) && k(result, env.Unifications, env.State, predecessor)); }