private void AssignArgumentValues(IokeObject locals, IokeObject context, IokeObject message, object on, IList argumentsWithoutKeywords, IDictionary <string, object> givenKeywords, int argCount)
        {
            Runtime runtime = context.runtime;

            var intersection = new SaneHashSet <string>(givenKeywords.Keys);

            foreach (string k in keywords)
            {
                intersection.Remove(k);
            }

            int ix = 0;

            for (int i = 0, j = this.arguments.Count; i < j; i++)
            {
                Argument a = this.arguments[i];

                if (a is KeywordArgument)
                {
                    string nm     = a.Name + ":";
                    object result = null;
                    if (givenKeywords.ContainsKey(nm))
                    {
                        object given = givenKeywords[nm];
                        result = given;
                        locals.SetCell(a.Name, result);
                    }
                    else
                    {
                        object defVal = ((KeywordArgument)a).DefaultValue;
                        if (!(defVal is string))
                        {
                            IokeObject m1 = IokeObject.As(defVal, context);
                            result = runtime.interpreter.Evaluate(m1, locals, locals.RealContext, locals);
                            locals.SetCell(a.Name, result);
                        }
                    }
                }
                else if ((a is OptionalArgument) && ix >= argCount)
                {
                    object defVal = ((OptionalArgument)a).DefaultValue;
                    if (!(defVal is string))
                    {
                        IokeObject m2 = IokeObject.As(defVal, context);
                        locals.SetCell(a.Name, runtime.interpreter.Evaluate(m2, locals, locals.RealContext, locals));
                    }
                }
                else
                {
                    locals.SetCell(a.Name, argumentsWithoutKeywords[ix++]);
                }
            }

            if (krest != null)
            {
                var krests = new SaneHashtable();
                foreach (string s in intersection)
                {
                    object given  = givenKeywords[s];
                    object result = given;
                    krests[runtime.GetSymbol(s.Substring(0, s.Length - 1))] = result;
                }

                locals.SetCell(krest, runtime.NewDict(krests));
            }

            if (rest != null)
            {
                IList rests = new SaneArrayList();
                for (int j = argumentsWithoutKeywords.Count; ix < j; ix++)
                {
                    rests.Add(argumentsWithoutKeywords[ix]);
                }

                locals.SetCell(rest, runtime.NewList(rests));
            }
        }
        private void AssignArgumentValues(IokeObject locals, IokeObject context, IokeObject message, object on, IList argumentsWithoutKeywords, IDictionary<string, object> givenKeywords, int argCount)
        {
            Runtime runtime = context.runtime;

            var intersection = new SaneHashSet<string>(givenKeywords.Keys);
            foreach(string k in keywords) intersection.Remove(k);

            int ix = 0;
            for(int i=0, j=this.arguments.Count;i<j;i++) {
                Argument a = this.arguments[i];

                if(a is KeywordArgument) {
                    string nm = a.Name + ":";
                    object result = null;
                    if(givenKeywords.ContainsKey(nm)) {
                        object given = givenKeywords[nm];
                        result = given;
                        locals.SetCell(a.Name, result);
                    } else {
                        object defVal = ((KeywordArgument)a).DefaultValue;
                        if(!(defVal is string)) {
                            IokeObject m1 = IokeObject.As(defVal, context);
                            result = ((Message)IokeObject.dataOf(m1)).EvaluateCompleteWithoutExplicitReceiver(m1, locals, locals.RealContext);
                            locals.SetCell(a.Name, result);
                        }
                    }
                } else if((a is OptionalArgument) && ix>=argCount) {
                    object defVal = ((OptionalArgument)a).DefaultValue;
                    if(!(defVal is string)) {
                        IokeObject m2 = IokeObject.As(defVal, context);
                        locals.SetCell(a.Name, ((Message)IokeObject.dataOf(m2)).EvaluateCompleteWithoutExplicitReceiver(m2, locals, locals.RealContext));
                    }
                } else {
                    locals.SetCell(a.Name, argumentsWithoutKeywords[ix++]);
                }
            }

            if(krest != null) {
                var krests = new SaneHashtable();
                foreach(string s in intersection) {
                    object given = givenKeywords[s];
                    object result = given;
                    krests[runtime.GetSymbol(s.Substring(0, s.Length-1))] = result;
                }

                locals.SetCell(krest, runtime.NewDict(krests));
            }

            if(rest != null) {
                IList rests = new SaneArrayList();
                for(int j=argumentsWithoutKeywords.Count;ix<j;ix++) {
                    rests.Add(argumentsWithoutKeywords[ix]);
                }

                locals.SetCell(rest, runtime.NewList(rests));
            }
        }
        public int GetEvaluatedArguments(IokeObject context, IokeObject message, object on, IList argumentsWithoutKeywords, IDictionary <string, object> givenKeywords)
        {
            Runtime runtime   = context.runtime;
            IList   arguments = message.Arguments;
            int     argCount  = 0;

            foreach (object o in arguments)
            {
                if (Message.IsKeyword(o))
                {
                    givenKeywords[IokeObject.As(o, context).Name] = Interpreter.GetEvaluatedArgument(((Message)IokeObject.dataOf(o)).next, context);
                }
                else if (Message.HasName(o, "*") && IokeObject.As(o, context).Arguments.Count == 1)    // Splat
                {
                    object result = Interpreter.GetEvaluatedArgument(IokeObject.As(o, context).Arguments[0], context);
                    if (IokeObject.dataOf(result) is IokeList)
                    {
                        IList elements = IokeList.GetList(result);
                        foreach (object ox in elements)
                        {
                            argumentsWithoutKeywords.Add(ox);
                        }
                        argCount += elements.Count;
                    }
                    else if (IokeObject.dataOf(result) is Dict)
                    {
                        IDictionary keys = Dict.GetMap(result);
                        foreach (DictionaryEntry me in keys)
                        {
                            givenKeywords[Text.GetText(IokeObject.ConvertToText(me.Key, message, context, true)) + ":"] = me.Value;
                        }
                    }
                    else if (IokeObject.FindCell((IokeObject)result, "asTuple") != runtime.nul)
                    {
                        object   tupledValue = Interpreter.Send(runtime.asTuple, context, result);
                        object[] values      = Tuple.GetElements(tupledValue);
                        foreach (object val in values)
                        {
                            argumentsWithoutKeywords.Add(val);
                        }
                        argCount += values.Length;
                    }
                    else
                    {
                        IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                                     message,
                                                                                     context,
                                                                                     "Error",
                                                                                     "Invocation",
                                                                                     "NotSpreadable"), context).Mimic(message, context);
                        condition.SetCell("message", message);
                        condition.SetCell("context", context);
                        condition.SetCell("receiver", on);
                        condition.SetCell("given", result);

                        IList outp = IokeList.GetList(runtime.WithRestartReturningArguments(() => { runtime.ErrorCondition(condition); },
                                                                                            context,
                                                                                            new Restart.DefaultValuesGivingRestart("ignoreArgument", runtime.nil, 0),
                                                                                            new Restart.DefaultValuesGivingRestart("takeArgumentAsIs", IokeObject.As(result, context), 1)
                                                                                            ));

                        foreach (object ox in outp)
                        {
                            argumentsWithoutKeywords.Add(ox);
                        }
                        argCount += outp.Count;
                    }
                }
                else
                {
                    var xx = Interpreter.GetEvaluatedArgument(o, context);
                    argumentsWithoutKeywords.Add(xx);
                    argCount++;
                }
            }

            while (argCount < min || (max != -1 && argCount > max))
            {
                int finalArgCount = argCount;
                if (argCount < min)
                {
                    IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                                 message,
                                                                                 context,
                                                                                 "Error",
                                                                                 "Invocation",
                                                                                 "TooFewArguments"), context).Mimic(message, context);
                    condition.SetCell("message", message);
                    condition.SetCell("context", context);
                    condition.SetCell("receiver", on);
                    condition.SetCell("missing", runtime.NewNumber(min - argCount));

                    IList newArguments = IokeList.GetList(runtime.WithRestartReturningArguments(() => { runtime.ErrorCondition(condition); },
                                                                                                context,
                                                                                                new NewArgumentGivingRestart("provideExtraArguments"),
                                                                                                new Restart.DefaultValuesGivingRestart("substituteNilArguments", runtime.nil, min - argCount)));

                    foreach (object ox in newArguments)
                    {
                        argumentsWithoutKeywords.Add(ox);
                    }
                    argCount += newArguments.Count;
                }
                else
                {
                    IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                                 message,
                                                                                 context,
                                                                                 "Error",
                                                                                 "Invocation",
                                                                                 "TooManyArguments"), context).Mimic(message, context);
                    condition.SetCell("message", message);
                    condition.SetCell("context", context);
                    condition.SetCell("receiver", on);
                    condition.SetCell("extra", runtime.NewList(ArrayList.Adapter(argumentsWithoutKeywords).GetRange(max, finalArgCount - max)));

                    runtime.WithReturningRestart("ignoreExtraArguments", context, () => { runtime.ErrorCondition(condition); });
                    argCount = max;
                }
            }

            var intersection = new SaneHashSet <string>(givenKeywords.Keys);

            foreach (string k in keywords)
            {
                intersection.Remove(k);
            }

            if (krest == null && intersection.Count > 0)
            {
                IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                             message,
                                                                             context,
                                                                             "Error",
                                                                             "Invocation",
                                                                             "MismatchedKeywords"), context).Mimic(message, context);
                condition.SetCell("message", message);
                condition.SetCell("context", context);
                condition.SetCell("receiver", on);

                IList expected = new SaneArrayList();
                foreach (string s in keywords)
                {
                    expected.Add(runtime.NewText(s));
                }

                condition.SetCell("expected", runtime.NewList(expected));

                IList extra = new SaneArrayList();
                foreach (string s in intersection)
                {
                    extra.Add(runtime.NewText(s));
                }
                condition.SetCell("extra", runtime.NewList(extra));
                runtime.WithReturningRestart("ignoreExtraKeywords", context, () => { runtime.ErrorCondition(condition); });
            }

            return(argCount);
        }
        public int GetEvaluatedArguments(IokeObject context, IokeObject message, object on, IList argumentsWithoutKeywords, IDictionary<string, object> givenKeywords)
        {
            Runtime runtime = context.runtime;
            IList arguments = message.Arguments;
            int argCount = 0;

            foreach(object o in arguments) {
                if(Message.IsKeyword(o)) {
                    givenKeywords[IokeObject.As(o, context).Name] = Message.GetEvaluatedArgument(((Message)IokeObject.dataOf(o)).next, context);
                } else if(Message.HasName(o, "*") && IokeObject.As(o, context).Arguments.Count == 1) { // Splat
                    object result = Message.GetEvaluatedArgument(IokeObject.As(o, context).Arguments[0], context);
                    if(IokeObject.dataOf(result) is IokeList) {
                        IList elements = IokeList.GetList(result);
                        foreach(object ox in elements) argumentsWithoutKeywords.Add(ox);
                        argCount += elements.Count;
                    } else if(IokeObject.dataOf(result) is Dict) {
                        IDictionary keys = Dict.GetMap(result);
                        foreach(DictionaryEntry me in keys) {
                            givenKeywords[Text.GetText(IokeObject.ConvertToText(me.Key, message, context, true)) + ":"] = me.Value;
                        }
                    } else if(IokeObject.FindCell(result, message, context, "asTuple") != runtime.nul) {
                        object tupledValue = ((Message)IokeObject.dataOf(runtime.asTuple)).SendTo(runtime.asTuple, context, result);
                        object[] values = Tuple.GetElements(tupledValue);
                        foreach(object val in values) argumentsWithoutKeywords.Add(val);
                        argCount += values.Length;
                    } else {
                        IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                                     message,
                                                                                     context,
                                                                                     "Error",
                                                                                     "Invocation",
                                                                                     "NotSpreadable"), context).Mimic(message, context);
                        condition.SetCell("message", message);
                        condition.SetCell("context", context);
                        condition.SetCell("receiver", on);
                        condition.SetCell("given", result);

                        IList outp = IokeList.GetList(runtime.WithRestartReturningArguments(()=>{runtime.ErrorCondition(condition);},
                                                                                            context,
                                                                                            new Restart.DefaultValuesGivingRestart("ignoreArgument", runtime.nil, 0),
                                                                                            new Restart.DefaultValuesGivingRestart("takeArgumentAsIs", IokeObject.As(result, context), 1)
                                                                                            ));

                        foreach(object ox in outp) argumentsWithoutKeywords.Add(ox);
                        argCount += outp.Count;
                    }
                } else {
                    argumentsWithoutKeywords.Add(Message.GetEvaluatedArgument(o, context));
                    argCount++;
                }
            }

            while(argCount < min || (max != -1 && argCount > max)) {
                int finalArgCount = argCount;
                if(argCount < min) {
                    IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                                 message,
                                                                                 context,
                                                                                 "Error",
                                                                                 "Invocation",
                                                                                 "TooFewArguments"), context).Mimic(message, context);
                    condition.SetCell("message", message);
                    condition.SetCell("context", context);
                    condition.SetCell("receiver", on);
                    condition.SetCell("missing", runtime.NewNumber(min-argCount));

                    IList newArguments = IokeList.GetList(runtime.WithRestartReturningArguments(()=>{runtime.ErrorCondition(condition);},
                                                                                                context,
                                                                                                new NewArgumentGivingRestart("provideExtraArguments"),
                                                                                                new Restart.DefaultValuesGivingRestart("substituteNilArguments", runtime.nil, min-argCount)));

                    foreach(object ox in newArguments) argumentsWithoutKeywords.Add(ox);
                    argCount += newArguments.Count;
                } else {
                    IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                                 message,
                                                                                 context,
                                                                                 "Error",
                                                                                 "Invocation",
                                                                                 "TooManyArguments"), context).Mimic(message, context);
                    condition.SetCell("message", message);
                    condition.SetCell("context", context);
                    condition.SetCell("receiver", on);
                    condition.SetCell("extra", runtime.NewList(ArrayList.Adapter(argumentsWithoutKeywords).GetRange(max, finalArgCount-max)));

                    runtime.WithReturningRestart("ignoreExtraArguments", context, ()=>{runtime.ErrorCondition(condition);});
                    argCount = max;
                }
            }

            var intersection = new SaneHashSet<string>(givenKeywords.Keys);
            foreach(string k in keywords) intersection.Remove(k);

            if(krest == null && intersection.Count > 0) {
                IokeObject condition = IokeObject.As(IokeObject.GetCellChain(runtime.Condition,
                                                                             message,
                                                                             context,
                                                                             "Error",
                                                                             "Invocation",
                                                                             "MismatchedKeywords"), context).Mimic(message, context);
                condition.SetCell("message", message);
                condition.SetCell("context", context);
                condition.SetCell("receiver", on);

                IList expected = new SaneArrayList();
                foreach(string s in keywords) {
                    expected.Add(runtime.NewText(s));
                }

                condition.SetCell("expected", runtime.NewList(expected));

                IList extra = new SaneArrayList();
                foreach(string s in intersection) {
                    extra.Add(runtime.NewText(s));
                }
                condition.SetCell("extra", runtime.NewList(extra));
                runtime.WithReturningRestart("ignoreExtraKeywords", context, ()=>{runtime.ErrorCondition(condition);});
            }

            return argCount;
        }