예제 #1
0
 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));
 }
예제 #2
0
        private static bool Call(object[] args, TextBuffer output, BindingEnvironment env,
                                 MethodCallFrame predecessor, Step.Continuation k)
        {
            ArgumentCountException.CheckAtLeast(nameof(Call), 1, args);
            var call = ArgumentTypeException.Cast <object[]>(nameof(Call), args[0], args);

            if (!(call[0] is Task task))
            {
                throw new InvalidOperationException(
                          "Task argument to Call must be a task");
            }

            var taskArgs = new object[call.Length - 1 + args.Length - 1];

            var i = 0;

            for (var callIndex = 1; callIndex < call.Length; callIndex++)
            {
                taskArgs[i++] = call[callIndex];
            }
            for (var argsIndex = 1; argsIndex < args.Length; argsIndex++)
            {
                taskArgs[i++] = args[argsIndex];
            }

            return(task.Call(taskArgs, output, env, predecessor, k));
        }
예제 #3
0
        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)));
        }
예제 #4
0
        public override bool Try(TextBuffer output, BindingEnvironment e, Continuation k,
                                 MethodCallFrame predecessor)
        {
            if (!e.TryCopyGround(Value.Eval(e), out var expValue))
            {
                // You can't set a variable to a non-ground value
                throw new ArgumentInstantiationException("set", e,
                                                         new[] { (object)GlobalVariable, Value });
            }

            if (LocalVariable == null)
            {
                return(Continue(output,
                                new BindingEnvironment(e,
                                                       e.Unifications,
                                                       e.State.Bind(GlobalVariable, expValue)),
                                k, predecessor));
            }

            if (e.Unify(LocalVariable, expValue, out var result))
            {
                return(Continue(output,
                                new BindingEnvironment(e, result, e.State),
                                k, predecessor));
            }

            return(false);
        }
예제 #5
0
        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));
        }
예제 #6
0
        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));
        }
예제 #7
0
파일: Call.cs 프로젝트: ianhorswill/Step
        /// <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));
        }
예제 #8
0
파일: Step.cs 프로젝트: ianhorswill/Step
 /// <summary>
 /// Run any remaining steps in the chain, otherwise run the continuation.
 /// </summary>
 /// <returns>True if all steps in the chain, and the continuation are all successful.  False means we're backtracking</returns>
 protected bool Continue(TextBuffer p, BindingEnvironment e, Continuation k, MethodCallFrame predecessor)
 {
     if (Next != null)
     {
         return(Next.Try(p, e, k, predecessor));
     }
     return(k == null || k(p, e.Unifications, e.State, predecessor));
 }
예제 #9
0
        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);
        }
예제 #10
0
 /// <inheritdoc />
 public override bool Call(object[] arglist, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k)
 {
     foreach (var bindings in Iterator(arglist, env))
     {
         if (k(output, bindings, env.State, predecessor))
         {
             return(true);
         }
     }
     return(false);
 }
예제 #11
0
        private static bool Eval(object[] call, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor,
                                 Step.Continuation k, string taskName)
        {
            if (!(call[0] is Task task))
            {
                throw new InvalidOperationException(
                          $"Task argument to {taskName} must be a task: {Writer.TermToString(call[0])}");
            }

            return(task.Call(call.Skip(1).ToArray(), output, env, predecessor, k));
        }
예제 #12
0
 /// <inheritdoc />
 public override bool Call(object[] arglist, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k)
 {
     ArgumentCountException.Check(Name, 0, arglist);
     foreach (var tokens in implementation())
     {
         if (k(output.Append(tokens), env.Unifications, env.State, predecessor))
         {
             return(true);
         }
     }
     return(false);
 }
예제 #13
0
        public override bool Try(TextBuffer output, BindingEnvironment e, Continuation k, MethodCallFrame predecessor)
        {
            var s         = e.State;
            var callCount = e.Frame.Task.CallCount(s);
            var readyTime = ReadyTime(s);

            if (callCount > readyTime)
            {
                var newState = ReadyTimes.SetItem(s, this, Duration == int.MaxValue ? int.MaxValue : (callCount + Duration));
                if (Continue(output, new BindingEnvironment(e, e.Unifications, newState), k, predecessor))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #14
0
        private static bool TaskSubtask(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k)
        {
            ArgumentCountException.Check("TaskSubtask", 2, args);
            var task = ArgumentTypeException.Cast <CompoundTask>("TaskSubtask", args[0], args);

            foreach (var callExpression in e.Module.Subtasks(task))
            {
                if (e.Unify(args[1], callExpression, out var unifications))
                {
                    if (k(o, unifications, e.State, predecessor))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
예제 #15
0
파일: AddStep.cs 프로젝트: ianhorswill/Step
        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 });
            }
        }
예제 #16
0
        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 });
            }
        }
예제 #17
0
        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));
        }
예제 #18
0
        /// <inheritdoc />
        public override bool Call(object[] arglist, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k)
        {
            ArgumentCountException.Check(this, Arity, arglist);

            // Check types and find the shortest list of candidate tuples that match
            var candidateTuples = tuples;

            for (var i = 0; i < Arity; i++)
            {
                var arg = arglist[i];
                if (arg is LogicVariable)
                {
                    continue;
                }
                ArgumentTypeException.Check(this, Signature[i], arg, arglist);
                var index = indices[i];
                if (index != null)
                {
                    if (!index.TryGetValue(arg, out var indexedTuples))
                    {
                        // There are literally no tuples with the specified argument value
                        return(false);
                    }
                    if (indexedTuples.Count < candidateTuples.Count)
                    {
                        candidateTuples = indexedTuples;
                    }
                }
            }

            // Attempt to unify each candidate tuple with the argument list
            foreach (var t in Shuffler(candidateTuples))
            {
                if (env.UnifyArrays(arglist, t, out BindingList <LogicVariable> unifications))
                {
                    if (k(output, unifications, env.State, predecessor))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
예제 #19
0
        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);
        }
예제 #20
0
        private static bool PreviousCall(object[] args, TextBuffer output, BindingEnvironment env,
                                         MethodCallFrame predecessor, Step.Continuation k)
        {
            ArgumentCountException.Check(nameof(PreviousCall), 1, args);
            if (args[0] is LogicVariable)
            {
                // [PreviousCall ?var]
                foreach (var priorGoal in predecessor.GoalChain)
                {
                    var e = priorGoal.CallExpression;
                    if (env.Unify(args[0], e, out BindingList <LogicVariable> unifications) &&
                        k(output, unifications, env.State, predecessor))
                    {
                        return(true);
                    }
                }

                return(false);
            }

            // [PreviousCall [Task ?args]]
            var call = ArgumentTypeException.Cast <object[]>(nameof(PreviousCall), args[0], args);

            foreach (var priorGoal in predecessor.GoalChain)
            {
                if (priorGoal.Method.Task != call[0])
                {
                    // Don't bother making the call expression and trying to unify.
                    continue;
                }

                var e = priorGoal.CallExpression;
                if (call.Length == e.Length &&
                    env.UnifyArrays(call, e, out BindingList <LogicVariable> unifications) &&
                    k(output, unifications, env.State, predecessor))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #21
0
        /// <summary>
        /// Find all solutions to the specified sequence of calls.  Return a list of the text outputs of each solution.
        /// </summary>
        internal static List <string[]> AllSolutionTextFromBody(string callingTaskName, object[] body, TextBuffer o,
                                                                BindingEnvironment e, MethodCallFrame predecessor)
        {
            var results       = new List <string[]>();
            var initialLength = o.Length;

            GenerateSolutionsFromBody(callingTaskName, body, o, e,
                                      (output, b, d, p) =>
            {
                var chunk = new string[output.Length - initialLength];
                for (var i = initialLength; i < output.Length; i++)
                {
                    chunk[i - initialLength] = o.Buffer[i];
                }
                results.Add(chunk);
                return(false);
            },
                                      predecessor);
            return(results);
        }
예제 #22
0
        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);
        }
예제 #23
0
        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));
        }
예제 #24
0
        public override bool Try(TextBuffer output, BindingEnvironment e, Continuation k, MethodCallFrame predecessor)
        {
            foreach (var branch in EffectiveBranches)
            {
                if (branch == null)  // Empty branch, e.g. [case ?x] Something : Something [else] [end]
                {
                    if (Continue(output, e, k, predecessor))
                    {
                        return(true);
                    }
                }
                else if (branch.Try(output, e,
                                    (o, u, d, newP) =>
                                    Continue(o, new BindingEnvironment(e, u, d), k, newP)
                                    , predecessor))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #25
0
        private static bool Once(object[] args, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k)
        {
            TextBuffer finalOutput = output;
            BindingList <LogicVariable> finalBindings = null;
            State           finalState = State.Empty;
            MethodCallFrame finalFrame = predecessor;
            bool            success    = false;

            GenerateSolutionsFromBody("Once", args, output, env,
                                      (o, u, d, p) =>
            {
                success       = true;
                finalOutput   = o;
                finalBindings = u;
                finalState    = d;
                finalFrame    = p;
                return(true);
            },
                                      predecessor);

            return(success && k(finalOutput, finalBindings, finalState, finalFrame));
        }
예제 #26
0
파일: Method.cs 프로젝트: ianhorswill/Step
        /// <summary>
        /// Attempt to run this method
        /// </summary>
        /// <param name="args">Arguments from the call to the method's task</param>
        /// <param name="output">Output buffer to write to</param>
        /// <param name="env">Variable binding information</param>
        /// <param name="k">Continuation to call if method succeeds</param>
        /// <param name="pre">Predecessor frame</param>
        /// <returns>True if the method and its continuation succeeded</returns>
        public bool Try(object[] args, TextBuffer output, BindingEnvironment env, MethodCallFrame pre, Step.Continuation k)
        {
            // Make stack frame for locals
            var locals = new LogicVariable[LocalVariableNames.Length];

            for (var i = 0; i < LocalVariableNames.Length; i++)
            {
                locals[i] = new LogicVariable(LocalVariableNames[i]);
            }
            var newFrame = new MethodCallFrame(this, env.Unifications, locals, env.Frame, pre);

            MethodCallFrame.CurrentFrame = newFrame;
            var newEnv = new BindingEnvironment(env, newFrame);

            if (newEnv.UnifyArrays(args, ArgumentPattern, out BindingEnvironment finalEnv))
            {
                env.Module.TraceMethod(Module.MethodTraceEvent.Enter, this, args, output, finalEnv);
                newFrame.BindingsAtCallTime = finalEnv.Unifications;
                var traceK = env.Module.Trace == null
                    ? k
                    : (newO, newU, newState, predecessor) =>
                {
                    MethodCallFrame.CurrentFrame = newFrame;
                    env.Module.TraceMethod(Module.MethodTraceEvent.Succeed, this, args, newO,
                                           new BindingEnvironment(finalEnv, newU, newState));
                    MethodCallFrame.CurrentFrame = newFrame.Caller;
                    return(k(newO, newU, newState, predecessor));
                };
                if (StepChain?.Try(output, finalEnv, traceK, newFrame) ?? traceK(output, finalEnv.Unifications, finalEnv.State, newFrame))
                {
                    return(true);
                }
            }

            MethodCallFrame.CurrentFrame = newFrame;
            env.Module.TraceMethod(Module.MethodTraceEvent.MethodFail, this, args, output, finalEnv);
            return(false);
        }
예제 #27
0
        public override bool Try(TextBuffer output, BindingEnvironment e, Continuation k, MethodCallFrame predecessor)
        {
            var tps = e.State.LookupOrDefault(Tps, true);

            if (!(tps is bool b))
            {
                throw new ArgumentException($"The Plural variable's value is {tps}, but must be a Boolean");
            }

            if (!b)
            {
                // We're not generating TPS.
                return(Continue(output, e, k, predecessor));
            }

            // We're generating third person singular, so add an s.
            var lastIndex = output.Length - 1;
            var lastWord  = output.Buffer[lastIndex];

            if (Suffix == "es" && lastWord.EndsWith("y"))
            {
                output.Buffer[lastIndex] = lastWord.Substring(0, lastWord.Length - 1) + "ies";
            }
            else
            {
                output.Buffer[lastIndex] = lastWord + Suffix;
            }
            if (Continue(output, e, k, predecessor))
            {
                return(true);
            }
            // Undo change to word
            // Probably not necessary, but you never know.
            output.Buffer[lastIndex] = lastWord;
            return(false);
        }
예제 #28
0
        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));
        }
예제 #29
0
파일: Call.cs 프로젝트: ianhorswill/Step
        private bool CallTask(TextBuffer output, BindingEnvironment env, Continuation k, object target, object[] arglist,
                              object originalTarget, MethodCallFrame predecessor)
        {
            switch (target)
            {
            case Task p:
                return(p.Call(arglist, output, env, predecessor,
                              (newOutput, u, s, newPredecessor) => Continue(newOutput, new BindingEnvironment(env, u, s), k, newPredecessor)));

            case string[] text:
                return(Continue(output.Append(text), env, k, predecessor));

            case IDictionary d:
                ArgumentCountException.Check(d, 2, arglist);
                var arg0 = arglist[0];
                var v0   = arg0 as LogicVariable;
                var arg1 = arglist[1];
                if (v0 == null)
                {
                    return(d.Contains(arg0) &&
                           env.Unify(arg1, d[arg0], out var u) &&
                           Continue(output,
                                    new BindingEnvironment(env, u, env.State), k, predecessor));
                }
                else
                {
                    // Arg 0 is out
                    foreach (DictionaryEntry e in d)
                    {
                        if (env.Unify(arg0, e.Key, out var unif1) &&
                            env.Unify(arg1, e.Value, unif1, out var unif2) &&
                            Continue(output, new BindingEnvironment(env, unif2, env.State), k, predecessor))
                        {
                            return(true);
                        }
                    }
                }
                return(false);

            case IList l:
                // If it's a list in the operator position, pretend it's a call to member
                if (arglist.Length != 1)
                {
                    throw new ArgumentCountException("<list member>", 1, arglist);
                }

                if (arglist[0] is LogicVariable l0)
                {
                    foreach (var e in l)
                    {
                        if (Continue(output,
                                     new BindingEnvironment(env, BindingList <LogicVariable> .Bind(env.Unifications, l0, e),
                                                            env.State),
                                     k,
                                     predecessor))
                        {
                            return(true);
                        }
                    }
                }
                else
                {
                    if (l.Contains(arglist[0]) && Continue(output, env, k, predecessor))
                    {
                        return(true);
                    }
                }
                return(false);

            case LogicVariable v:
                throw new ArgumentException($"Attempt to call an unbound variable {v}");

            case null:
                throw new ArgumentException($"Null is not a valid task in call {CallSourceText(originalTarget, arglist)}");

            case bool b:
                if (arglist.Length != 0)
                {
                    throw new ArgumentCountException(b, 0, arglist);
                }
                return(b && Continue(output, env, k, predecessor));

            default:
                if (arglist.Length == 0)
                {
                    var hook = env.Module.FindTask(MentionHook, 1, false);
                    if (hook != null)
                    {
                        return(MakeCall(hook, target, Next).Try(output, env, k, predecessor));
                    }

                    return(Continue(output.Append(target.ToString()), env, k, predecessor));
                }

                throw new ArgumentException($"Unknown task {target} in call {CallSourceText(originalTarget, arglist)}");
            }
        }
예제 #30
0
 /// <summary>
 /// Make a binding environment identical to e but with v bound to newValue
 /// </summary>
 public BindingEnvironment(BindingEnvironment e, StateElement v, object newValue)
     : this(e.Module, e.Frame, e.Unifications, e.State.Bind(v, newValue))
 {
 }