コード例 #1
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);
        }
コード例 #2
0
ファイル: RemoveNextStep.cs プロジェクト: ianhorswill/Step
        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 });
            }
        }
コード例 #3
0
ファイル: SimpleFunction.cs プロジェクト: ianhorswill/Step
        /// <inheritdoc />
        protected override IEnumerable <BindingList <LogicVariable> > Iterator(object[] args, BindingEnvironment env)
        {
            ArgumentCountException.Check(Name, 2, args);
            var input  = ArgumentTypeException.Cast <TIn>(Name, env.Resolve(args[0]), args);
            var result = implementation(input);

            if (env.Unify(args[1], result, out var bindings))
            {
                return new[] { bindings }
            }
            ;
            return(EmptyBindingListArray);
        }
    }
コード例 #4
0
ファイル: SimpleFunction.cs プロジェクト: ianhorswill/Step
        /// <inheritdoc />
        protected override IEnumerable <BindingList <LogicVariable> > Iterator(object[] args, BindingEnvironment env)
        {
            ArgumentCountException.Check(Name, 4, args);
            var input1 = ArgumentTypeException.Cast <TIn1>(Name, args[0], args);
            var input2 = ArgumentTypeException.Cast <TIn2>(Name, args[1], args);
            var input3 = ArgumentTypeException.Cast <TIn3>(Name, args[2], args);
            var result = implementation(input1, input2, input3);

            if (env.Unify(args[3], result, out var bindings))
            {
                return new[] { bindings }
            }
            ;
            return(EmptyBindingListArray);
        }
    }
コード例 #5
0
ファイル: SimpleFunction.cs プロジェクト: ianhorswill/Step
        /// <inheritdoc />
        protected override IEnumerable <BindingList <LogicVariable> > Iterator(object[] args, BindingEnvironment env)
        {
            ArgumentCountException.CheckAtLeast(Name, 1, args);
            var fArgs = new object[args.Length - 1];

            Array.Copy(args, fArgs, args.Length - 1);
            var result = implementation(fArgs);

            if (env.Unify(args[args.Length - 1], result, out var bindings))
            {
                return new[] { bindings }
            }
            ;
            return(EmptyBindingListArray);
        }
    }
コード例 #6
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);
        }
コード例 #7
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);
        }
コード例 #8
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);
        }
コード例 #9
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));
        }
コード例 #10
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)}");
            }
        }
コード例 #11
0
        private static bool UniqueCall(object[] args, TextBuffer output, BindingEnvironment env,
                                       MethodCallFrame predecessor, Step.Continuation k)
        {
            ArgumentCountException.CheckAtLeast(nameof(UniqueCall), 1, args);
            var call = ArgumentTypeException.Cast <object[]>(nameof(PreviousCall), args[0], args);

            if (!(call[0] is Task task))
            {
                throw new InvalidOperationException(
                          "Task argument to UniqueCall 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];
            }

            var fullCall = call;

            if (args.Length > 1)
            {
                fullCall    = new object[taskArgs.Length + 1];
                fullCall[0] = task;
                for (var j = 0; j < taskArgs.Length; j++)
                {
                    fullCall[j + 1] = taskArgs[j];
                }
            }

            if (task.Call(taskArgs, output, env, predecessor,
                          (o, u, s, newPredecessor) =>
            {
                foreach (var priorGoal in predecessor.GoalChain)
                {
                    if (priorGoal.Method.Task != task)
                    {
                        // Don't bother making the call expression and trying to unify.
                        continue;
                    }

                    if (env.Unify(fullCall, priorGoal.CallExpression, u, out BindingList <LogicVariable> _))
                    {
                        // We already did a call that matches this call
                        // So have the continuation return false, forcing the task.Call above to backtrack
                        // and try to generate a new solution
                        return(false);
                    }
                }

                return(k(o, u, s, newPredecessor));
            }))
            {
                return(true);
            }

            return(false);
        }
コード例 #12
0
 private static bool LastMethodCallFrame(object[] args, TextBuffer o, BindingEnvironment e, MethodCallFrame predecessor, Step.Continuation k)
 {
     ArgumentCountException.Check("LastMethodCallFrame", 1, args);
     return(e.Unify(args[0], predecessor, out var u) &&
            k(o, u, e.State, predecessor));
 }
コード例 #13
0
ファイル: CompoundTask.cs プロジェクト: ianhorswill/Step
        /// <summary>
        /// Call this task with the specified arguments
        /// </summary>
        /// <param name="arglist">Task arguments</param>
        /// <param name="output">Output accumulated so far</param>
        /// <param name="env">Binding environment</param>
        /// <param name="predecessor">Most recently succeeded MethodCallFrame</param>
        /// <param name="k">Continuation</param>
        /// <returns>True if task succeeded and continuation succeeded</returns>
        /// <exception cref="CallFailedException">If the task fails</exception>
        public override bool Call(object[] arglist, TextBuffer output, BindingEnvironment env, MethodCallFrame predecessor, Step.Continuation k)
        {
            string lastToken = null;

            if (Suffix)
            {
                (lastToken, output) = output.Unappend();
                arglist             = new object[] { lastToken };
            }

            ArgumentCountException.Check(this, this.ArgCount, arglist);
            var successCount = 0;

            if (ReadCache)
            {
                // Check for a hit in the cache.  If we find one, we're done.
                if (Cache.TryGetValue(env.State, arglist, out var result))
                {
                    if (result.Success)
                    {
                        if (Function)
                        {
                            // We got a hit, and since this is a function, it's the only allowable hit.
                            // So we succeed deterministically.
                            return(env.Unify(arglist[arglist.Length - 1], result.FunctionValue,
                                             out BindingList <LogicVariable> u) &&
                                   k(output.Append(result.Text), u, env.State, predecessor));
                        }
                        else
                        {
                            successCount++;
                            if (k(output.Append(result.Text), env.Unifications, env.State, predecessor))
                            {
                                return(true);
                            }
                        }
                    }
                    else
                    {
                        // We have a match on a cached fail result, so force a failure, skipping over the methods.
                        goto failed;
                    }
                }
                else if (arglist.Any(x => x is LogicVariable))
                {
                    foreach (var pair in Cache.Bindings(env.State))
                    {
                        if (pair.Value.Success &&
                            env.UnifyArrays((object[])pair.Key, arglist,
                                            out BindingList <LogicVariable> unifications))
                        {
                            successCount++;
                            if (k(output.Append(pair.Value.Text), unifications, env.State, predecessor))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            if (ContainsCoolStep)
            {
                var s = env.State;
                s   = CallCounts.SetItem(s, this, CallCount(s) + 1);
                env = new BindingEnvironment(env, env.Unifications, s);
            }

            var methods = this.EffectiveMethods;

            for (var index = 0; index < methods.Count && !(this.Deterministic && successCount > 0); index++)
            {
                var method = methods[index];
                if (method.Try(arglist, output, env, predecessor,
                               (o, u, s, newPredecessor) =>
                {
                    successCount++;
                    if (WriteCache)
                    {
                        var final = env.ResolveList(arglist, u);
                        if (Term.IsGround(final))
                        {
                            s = StoreResult(s, final, new CachedResult(true,
                                                                       Function?final[final.Length - 1]:null,
                                                                       TextBuffer.Difference(output, o)));
                        }
                    }
                    return(k(o, u, s, newPredecessor));
                }))
                {
                    return(true);
                }
                if (Suffix)
                {
                    // Undo any overwriting that the method might have done
                    output.Buffer[output.Length - 1] = lastToken;
                }
            }

failed:
            var currentFrame = MethodCallFrame.CurrentFrame = env.Frame;

            if (currentFrame != null)
            {
                currentFrame.BindingsAtCallTime = env.Unifications;
            }
            if (successCount == 0 && this.MustSucceed)
            {
                throw new CallFailedException(this, arglist);
            }

            if (currentFrame != null)
            {
                env.Module.TraceMethod(Module.MethodTraceEvent.CallFail, currentFrame.Method, currentFrame.Arglist, output,
                                       env);
                MethodCallFrame.CurrentFrame = currentFrame.Predecessor;
            }

            // Failure
            return(false);
        }