Пример #1
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);
        }
Пример #2
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);
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        /// <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);
        }