예제 #1
0
        public static void Init(IokeObject obj)
        {
            obj.Kind = "Base";

            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects two or more arguments, the first arguments unevaluated, the last evaluated. assigns the result of evaluating the last argument in the context of the caller, and assigns this result to the name/s provided by the first arguments. the first arguments remains unevaluated. the result of the assignment is the value assigned to the name. if the last argument is a method-like object and it's name is not set, that name will be set to the name of the cell.",
                                                           new NativeMethod("=", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositionalUnevaluated("place")
                                                                            .WithRestUnevaluated("morePlacesForDestructuring")
                                                                            .WithRequiredPositional("value")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                var args = message.Arguments;
                if (args.Count == 2)
                {
                    IokeObject m1 = IokeObject.As(Message.GetArguments(message)[0], context);
                    string name   = m1.Name;
                    if (m1.Arguments.Count == 0)
                    {
                        object value = Interpreter.GetEvaluatedArgument(message, 1, context);
                        IokeObject.Assign(on, name, value, context, message);

                        if (value is IokeObject)
                        {
                            if ((IokeObject.dataOf(value) is Named) && ((Named)IokeObject.dataOf(value)).Name == null)
                            {
                                ((Named)IokeObject.dataOf(value)).Name = name;
                            }
                            else if (name.Length > 0 && char.IsUpper(name[0]) && !(IokeObject.As(value, context).HasKind))
                            {
                                if (on == context.runtime.Ground || on == context.runtime.IokeGround)
                                {
                                    IokeObject.As(value, context).Kind = name;
                                }
                                else
                                {
                                    IokeObject.As(value, context).Kind = IokeObject.As(on, context).GetKind(message, context) + " " + name;
                                }
                            }
                        }

                        return(value);
                    }
                    else
                    {
                        string newName  = name + "=";
                        IList arguments = new SaneArrayList(m1.Arguments);
                        arguments.Add(Message.GetArguments(message)[1]);
                        IokeObject msg = context.runtime.NewMessageFrom(message, newName, arguments);
                        return(Interpreter.Send(msg, context, on));
                    }
                }
                else
                {
                    int lastIndex = args.Count - 1;
                    int numPlaces = lastIndex;

                    return(RecursiveDestructuring(args, numPlaces, message, context, on, Interpreter.GetEvaluatedArgument(args[lastIndex], context)));
                }
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("will return a new derivation of the receiving object. Might throw exceptions if the object is an oddball object.",
                                                           new NativeMethod.WithNoArguments("mimic", (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                return(IokeObject.As(on, context).Mimic(message, context));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects one evaluated text or symbol argument that names the cell to set, sets this cell to the result of evaluating the second argument, and returns the value set.",
                                                           new NativeMethod("cell=",
                                                                            DefaultArgumentsDefinition
                                                                            .builder()
                                                                            .WithRequiredPositional("cellName")
                                                                            .WithRequiredPositional("value")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                return(AssignCell(context, message, on, args[0], args[1]));
            })));
            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects one evaluated text or symbol argument and returns the cell that matches that name, without activating even if it's activatable.",
                                                           new NativeMethod("cell", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("cellName")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                string name = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                return(IokeObject.GetCell(on, message, context, name));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a hash for the object",
                                                           new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                return(context.runtime.NewNumber(System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(IokeObject.As(on, context).body)));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns true if the left hand side is equal to the right hand side. exactly what this means depend on the object. the default behavior of Ioke objects is to only be equal if they are the same instance.",
                                                           new NativeMethod("==", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("other")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                IList args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                return((IokeObject.As(on, context).body == IokeObject.As(args[0], context).body) ? context.runtime.True : context.runtime.False);
            })));
            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects one evaluated text or symbol argument and returns a boolean indicating whether such a cell is reachable from this point.",
                                                           new NativeMethod("cell?", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("cellName")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                IList args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());

                string name = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                return(IokeObject.FindCell((IokeObject)on, name) != context.runtime.nul ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the documentation text of the object called on. anything can have a documentation text - this text will initially be nil.",
                                                           new NativeMethod.WithNoArguments("documentation",
                                                                                            (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary <string, object>());
                return(Documentation(context, message, on));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a boolean indicating of this object should be activated or not.",
                                                           new NativeMethod.WithNoArguments("activatable",
                                                                                            (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary <string, object>());
                return(IokeObject.As(on, context).IsActivatable ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("sets the activatable flag for a specific object. this will not impact objects that mimic this object..",
                                                           new TypeCheckingNativeMethod("activatable=", TypeCheckingArgumentsDefinition.builder()
                                                                                        .WithRequiredPositional("activatableFlag")
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                IokeObject.As(on, context).SetActivatable(IokeObject.IsObjectTrue(args[0]));
                return(args[0]);
            }
                                                                                        )));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns this object",
                                                           new NativeMethod.WithNoArguments("identity",
                                                                                            (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary <string, object>());
                return(on);
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("sets the documentation string for a specific object.",
                                                           new TypeCheckingNativeMethod("documentation=", TypeCheckingArgumentsDefinition.builder()
                                                                                        .WithRequiredPositional("text").WhichMustMimic(obj.runtime.Text).OrBeNil()
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                return(SetDocumentation(context, message, on, args[0]));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects one evaluated text or symbol argument and returns a boolean indicating whether this cell is owned by the receiver or not. the assumption is that the cell should exist. if it doesn't exist, a NoSuchCell condition will be signalled.",
                                                           new NativeMethod("cellOwner?", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("cellName")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                string name = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                return((IokeObject.FindPlace(on, message, context, name) == on) ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects one evaluated text or symbol argument and returns the closest object that defines such a cell. if it doesn't exist, a NoSuchCell condition will be signalled.",
                                                           new NativeMethod("cellOwner", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("cellName")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                string name   = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                object result = IokeObject.FindPlace(on, message, context, name);
                if (result == context.runtime.nul)
                {
                    return(context.runtime.nil);
                }
                return(result);
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects one evaluated text or symbol argument and removes that cell from the current receiver. if the current receiver has no such object, signals a condition. note that if another cell with that name is available in the mimic chain, it will still be accessible after calling this method. the method returns the receiver.",
                                                           new NativeMethod("removeCell!", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("cellName")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                string name = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                IokeObject.RemoveCell(on, message, context, name);
                return(on);
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("expects one evaluated text or symbol argument and makes that cell undefined in the current receiver. what that means is that from now on it will look like this cell doesn't exist in the receiver or any of its mimics. the cell will not show up if you call cellNames on the receiver or any of the receivers mimics. the undefined status can be removed by doing removeCell! on the correct cell name. a cell name that doesn't exist can still be undefined. the method returns the receiver.",
                                                           new NativeMethod("undefineCell!", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("cellName")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                string name = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                IokeObject.UndefineCell(on, message, context, name);
                return(on);
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("takes one optional evaluated boolean argument, which defaults to false. if false, this method returns a list of the cell names of the receiver. if true, it returns the cell names of this object and all it's mimics recursively.",
                                                           new NativeMethod("cellNames", DefaultArgumentsDefinition.builder()
                                                                            .WithOptionalPositional("includeMimics", "false")
                                                                            .WithOptionalPositional("cutoff", "nil")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                return(CellNames(context, message, on, args.Count > 0 && IokeObject.IsObjectTrue(args[0]), (args.Count > 1) ? args[1] : null));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("takes one optional evaluated boolean argument, which defaults to false. if false, this method returns a dict of the cell names and values of the receiver. if true, it returns the cell names and values of this object and all it's mimics recursively.",
                                                           new NativeMethod("cells", DefaultArgumentsDefinition.builder()
                                                                            .WithOptionalPositional("includeMimics", "false")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                var args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                return(Cells(context, message, on, args.Count > 0 && IokeObject.IsObjectTrue(args[0])));
            })));
        }
예제 #2
0
        public static void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;

            obj.Kind = "DefaultBehavior FlowControl";

            obj.RegisterMethod(runtime.NewNativeMethod("evaluates the first arguments, and then evaluates the second argument if the result was true, otherwise the last argument. returns the result of the call, or the result if it's not true.",
                                                       new NativeMethod("if", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositional("condition")
                                                                        .WithOptionalPositionalUnevaluated("then")
                                                                        .WithOptionalPositionalUnevaluated("else")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                object test = Interpreter.GetEvaluatedArgument(message, 0, context);


                IokeObject itContext = context.runtime.NewLexicalContext(context.RealContext, "Lexical activation context", context);
                itContext.SetCell("it", test);

                if (IokeObject.IsObjectTrue(test))
                {
                    if (message.Arguments.Count > 1)
                    {
                        return(Interpreter.GetEvaluatedArgument(message, 1, itContext));
                    }
                    else
                    {
                        return(test);
                    }
                }
                else
                {
                    if (message.Arguments.Count > 2)
                    {
                        return(Interpreter.GetEvaluatedArgument(message, 2, itContext));
                    }
                    else
                    {
                        return(test);
                    }
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("evaluates the first arguments, and then evaluates the second argument if the result was false, otherwise the last argument. returns the result of the call, or the result if it's true.",
                                                       new NativeMethod("unless", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositional("condition")
                                                                        .WithOptionalPositionalUnevaluated("then")
                                                                        .WithOptionalPositionalUnevaluated("else")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                object test = Interpreter.GetEvaluatedArgument(message, 0, context);

                IokeObject itContext = context.runtime.NewLexicalContext(context.RealContext, "Lexical activation context", context);
                itContext.SetCell("it", test);

                if (IokeObject.IsObjectTrue(test))
                {
                    if (message.Arguments.Count > 2)
                    {
                        return(Interpreter.GetEvaluatedArgument(message, 2, itContext));
                    }
                    else
                    {
                        return(test);
                    }
                }
                else
                {
                    if (message.Arguments.Count > 1)
                    {
                        return(Interpreter.GetEvaluatedArgument(message, 1, itContext));
                    }
                    else
                    {
                        return(test);
                    }
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes zero or more place and value pairs and one code argument, establishes a new lexical scope and binds the places to the values given. if the place is a simple name, it will just be created as a new binding in the lexical scope. if it is a place specification, that place will be temporarily changed - but guaranteed to be changed back after the lexical scope is finished. the let-form returns the final result of the code argument.",
                                                       new NativeMethod("let", DefaultArgumentsDefinition.builder()
                                                                        .WithRestUnevaluated("placesAndValues")
                                                                        .WithRequiredPositionalUnevaluated("code")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                var args           = message.Arguments;
                IokeObject lc      = context.runtime.NewLexicalContext(context.RealContext, "Let lexical activation context", context);
                int ix             = 0;
                int end            = args.Count - 1;
                var valuesToUnbind = new LinkedList <object[]>();
                try {
                    while (ix < end)
                    {
                        IokeObject place = IokeObject.As(args[ix++], context);

                        if (Message.GetNext(place) == null && place.Arguments.Count == 0)
                        {
                            object value = Interpreter.GetEvaluatedArgument(message, ix++, context);
                            lc.SetCell(Message.GetName(place), value);
                        }
                        else
                        {
                            place = Message.DeepCopy(place);
                            IokeObject realPlace = place;
                            while (Message.GetNext(realPlace) != null)
                            {
                                if (Message.GetNext(Message.GetNext(realPlace)) == null)
                                {
                                    IokeObject temp = Message.GetNext(realPlace);
                                    Message.SetNext(realPlace, null);
                                    realPlace = temp;
                                }
                                else
                                {
                                    realPlace = Message.GetNext(realPlace);
                                }
                            }

                            object wherePlace = context.RealContext;
                            if (place != realPlace)
                            {
                                wherePlace = Interpreter.GetEvaluatedArgument(place, context);
                            }

                            object originalValue = runtime.WithReturningRescue(context, null, () => { return(Interpreter.Send(realPlace, context, wherePlace)); });
                            if (realPlace.Arguments.Count != 0)
                            {
                                string newName = realPlace.Name + "=";
                                var arguments  = new SaneArrayList(realPlace.Arguments);
                                arguments.Add(args[ix++]);
                                IokeObject msg = context.runtime.NewMessageFrom(realPlace, newName, arguments);
                                Interpreter.Send(msg, context, wherePlace);
                                valuesToUnbind.AddFirst(new object[] { wherePlace, originalValue, realPlace });
                            }
                            else
                            {
                                object value = Interpreter.GetEvaluatedArgument(message, ix++, context);
                                IokeObject.Assign(wherePlace, realPlace.Name, value, context, message);
                                valuesToUnbind.AddFirst(new object[] { wherePlace, originalValue, realPlace });
                            }
                        }
                    }

                    return(Interpreter.GetEvaluatedArgument(message, end, lc));
                } finally {
                    while (valuesToUnbind.Count > 0)
                    {
                        try {
                            object[] vals = valuesToUnbind.First.Value;
                            valuesToUnbind.RemoveFirst();
                            IokeObject wherePlace = IokeObject.As(vals[0], context);
                            object value          = vals[1];
                            IokeObject realPlace  = IokeObject.As(vals[2], context);

                            if (realPlace.Arguments.Count != 0)
                            {
                                string newName = realPlace.Name + "=";
                                var arguments  = new SaneArrayList(realPlace.Arguments);

                                if (value == null)
                                {
                                    if (newName.Equals("cell="))
                                    {
                                        Interpreter.Send(context.runtime.removeCellMessage, context, wherePlace, new SaneArrayList(realPlace.Arguments));
                                    }
                                    else
                                    {
                                        arguments.Add(context.runtime.CreateMessage(Message.Wrap(context.runtime.nil)));
                                        IokeObject msg = context.runtime.NewMessageFrom(realPlace, newName, arguments);
                                        Interpreter.Send(msg, context, wherePlace);
                                    }
                                }
                                else
                                {
                                    arguments.Add(context.runtime.CreateMessage(Message.Wrap(IokeObject.As(value, context))));
                                    IokeObject msg = context.runtime.NewMessageFrom(realPlace, newName, arguments);
                                    Interpreter.Send(msg, context, wherePlace);
                                }
                            }
                            else
                            {
                                if (value == null)
                                {
                                    IokeObject.RemoveCell(wherePlace, context, message, realPlace.Name);
                                }
                                else
                                {
                                    IokeObject.Assign(wherePlace, realPlace.Name, value, context, message);
                                }
                            }
                        } catch (System.Exception) {}
                    }
                }
            })));



            obj.RegisterMethod(runtime.NewNativeMethod("breaks out of the enclosing context. if an argument is supplied, this will be returned as the result of the object breaking out of",
                                                       new NativeMethod("break", DefaultArgumentsDefinition.builder()
                                                                        .WithOptionalPositional("value", "nil")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                IList args = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());

                object value = runtime.nil;
                if (message.Arguments.Count > 0)
                {
                    value = Interpreter.GetEvaluatedArgument(message, 0, context);
                }
                throw new ControlFlow.Break(value);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns from the enclosing method/macro. if an argument is supplied, this will be returned as the result of the method/macro breaking out of.",
                                                       new NativeMethod("return", DefaultArgumentsDefinition.builder()
                                                                        .WithOptionalPositional("value", "nil")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                object value = runtime.nil;
                IList args   = new SaneArrayList();
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary <string, object>());
                if (args.Count > 0)
                {
                    value = args[0];
                }
                IokeObject ctx = context;
                while (ctx.data is LexicalContext)
                {
                    ctx = ((LexicalContext)ctx.data).surroundingContext;
                }

                throw new ControlFlow.Return(value, ctx);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("breaks out of the enclosing context and continues from that point again.",
                                                       new NativeMethod.WithNoArguments("continue",
                                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary <string, object>());
                throw new ControlFlow.Continue();
            })));


            obj.RegisterMethod(runtime.NewNativeMethod("until the first argument evaluates to something true, loops and evaluates the next argument",
                                                       new NativeMethod("until", DefaultArgumentsDefinition.builder()
                                                                        .WithOptionalPositionalUnevaluated("condition")
                                                                        .WithRestUnevaluated("body")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                if (message.Arguments.Count == 0)
                {
                    return(runtime.nil);
                }

                bool body    = message.Arguments.Count > 1;
                object ret   = runtime.nil;
                bool doAgain = false;
                do
                {
                    doAgain = false;
                    try {
                        while (!IokeObject.IsObjectTrue(Interpreter.GetEvaluatedArgument(message, 0, context)))
                        {
                            if (body)
                            {
                                ret = Interpreter.GetEvaluatedArgument(message, 1, context);
                            }
                        }
                    } catch (ControlFlow.Break e) {
                        ret = e.Value;
                    } catch (ControlFlow.Continue) {
                        doAgain = true;
                    }
                } while(doAgain);

                return(ret);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("while the first argument evaluates to something true, loops and evaluates the next argument",
                                                       new NativeMethod("while", DefaultArgumentsDefinition.builder()
                                                                        .WithOptionalPositionalUnevaluated("condition")
                                                                        .WithRestUnevaluated("body")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                if (message.Arguments.Count == 0)
                {
                    return(runtime.nil);
                }

                bool body    = message.Arguments.Count > 1;
                object ret   = runtime.nil;
                bool doAgain = false;
                do
                {
                    doAgain = false;
                    try {
                        while (IokeObject.IsObjectTrue(Interpreter.GetEvaluatedArgument(message, 0, context)))
                        {
                            if (body)
                            {
                                ret = Interpreter.GetEvaluatedArgument(message, 1, context);
                            }
                        }
                    } catch (ControlFlow.Break e) {
                        ret = e.Value;
                    } catch (ControlFlow.Continue) {
                        doAgain = true;
                    }
                } while(doAgain);

                return(ret);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("loops forever - executing it's argument over and over until interrupted in some way.",
                                                       new NativeMethod("loop", DefaultArgumentsDefinition.builder()
                                                                        .WithRestUnevaluated("body")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                if (message.Arguments.Count > 0)
                {
                    while (true)
                    {
                        try {
                            while (true)
                            {
                                Interpreter.GetEvaluatedArgument(message, 0, context);
                            }
                        } catch (ControlFlow.Break e) {
                            return(e.Value);
                        } catch (ControlFlow.Continue) {
                        }
                    }
                }
                else
                {
                    while (true)
                    {
                    }
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("will execute and return the value of the first argument. after the code has run, all the remaining blocks of code are guaranteed to run in order even if a non-local flow control happens inside the main code. if any code in the ensure blocks generate a new non-local flow control, the rest of the ensure blocks in that specific ensure invocation are not guaranteed to run.",
                                                       new NativeMethod("ensure", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositionalUnevaluated("code")
                                                                        .WithRestUnevaluated("ensureBlocks")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                var args     = message.Arguments;
                int argCount = args.Count;

                object result = runtime.nil;

                try {
                    IokeObject msg = IokeObject.As(args[0], context);
                    result         = context.runtime.interpreter.Evaluate(msg, context, context.RealContext, context);
                } finally {
                    foreach (object o in ArrayList.Adapter(args).GetRange(1, argCount - 1))
                    {
                        IokeObject msg = IokeObject.As(o, context);
                        context.runtime.interpreter.Evaluate(msg, context, context.RealContext, context);
                    }
                }

                return(result);
            })));
        }
예제 #3
0
        private static object RecursiveDestructuring(IList places, int numPlaces, IokeObject message, IokeObject context, object on, object toTuple)
        {
            object tupledValue = Interpreter.Send(context.runtime.asTuple, context, toTuple);

            object[] values    = Tuple.GetElements(tupledValue);
            int      numValues = values.Length;

            int min = System.Math.Min(numValues, numPlaces);

            bool hadEndingUnderscore = false;

            for (int i = 0; i < min; i++)
            {
                IokeObject m1   = IokeObject.As(places[i], context);
                string     name = m1.Name;
                if (name.Equals("_"))
                {
                    if (i == numPlaces - 1)
                    {
                        hadEndingUnderscore = true;
                    }
                }
                else
                {
                    if (m1.Arguments.Count == 0)
                    {
                        object value = values[i];

                        IokeObject.Assign(on, name, value, context, message);

                        if (value is IokeObject)
                        {
                            if ((IokeObject.dataOf(value) is Named) && ((Named)IokeObject.dataOf(value)).Name == null)
                            {
                                ((Named)IokeObject.dataOf(value)).Name = name;
                            }
                            else if (name.Length > 0 && char.IsUpper(name[0]) && !(IokeObject.As(value, context).HasKind))
                            {
                                if (on == context.runtime.Ground || on == context.runtime.IokeGround)
                                {
                                    IokeObject.As(value, context).Kind = name;
                                }
                                else
                                {
                                    IokeObject.As(value, context).Kind = IokeObject.As(on, context).GetKind(message, context) + " " + name;
                                }
                            }
                        }
                    }
                    else if (name.Equals(""))
                    {
                        var newArgs = m1.Arguments;
                        RecursiveDestructuring(newArgs, newArgs.Count, message, context, on, values[i]);
                    }
                    else
                    {
                        string newName   = name + "=";
                        IList  arguments = new SaneArrayList(m1.Arguments);
                        arguments.Add(context.runtime.CreateMessage(Message.Wrap(IokeObject.As(values[i], context))));
                        IokeObject msg = context.runtime.NewMessageFrom(message, newName, arguments);
                        Interpreter.Send(msg, context, on);
                    }
                }
            }

            if (numPlaces > min || (numValues > min && !hadEndingUnderscore))
            {
                IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition,
                                                                             message,
                                                                             context,
                                                                             "Error",
                                                                             "DestructuringMismatch"), context).Mimic(message, context);
                condition.SetCell("message", message);
                condition.SetCell("context", context);
                condition.SetCell("receiver", on);

                context.runtime.ErrorCondition(condition);
            }

            return(tupledValue);
        }