예제 #1
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)));
        }
예제 #2
0
        /// <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);
        }
    }
예제 #3
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));
        }
예제 #4
0
        /// <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);
            }
        }
예제 #5
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));
        }
예제 #6
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 });
            }
        }
예제 #7
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);
        }
예제 #8
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 });
            }
        }
예제 #9
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);
        }
예제 #10
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);
        }
예제 #11
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));
        }
예제 #12
0
        /// <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));
        }
예제 #13
0
        /// <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));
        }