Пример #1
0
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;

            obj.Kind = "List";
            obj.Mimics(IokeObject.As(IokeObject.FindCell(runtime.Mixins, "Sequenced"), null), runtime.nul, runtime.nul);

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a hash for the list",
                                                           new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => {
                                                                   outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                                                                   return context.runtime.NewNumber(((IokeList)IokeObject.dataOf(on)).list.GetHashCode());
                                                               })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if the left hand side list is equal to the right hand side list.",
                                                       new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(runtime.List)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        IokeList d = (IokeList)IokeObject.dataOf(on);
                                                                                        object other = args[0];
                                                                                        return ((other is IokeObject) &&
                                                                                                (IokeObject.dataOf(other) is IokeList) &&
                                                                                                d.list.Equals(((IokeList)IokeObject.dataOf(other)).list)) ? context.runtime.True : context.runtime.False;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a new sequence to iterate over this list",
                                                       new TypeCheckingNativeMethod.WithNoArguments("seq", runtime.List,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        IokeObject ob = method.runtime.IteratorSequence.AllocateCopy(null, null);
                                                                                                        ob.MimicsWithoutCheck(method.runtime.IteratorSequence);
                                                                                                        ob.Data = new Sequence.IteratorSequence(IokeList.GetList(on).GetEnumerator());
                                                                                                        return ob;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes either one or two or three arguments. if one argument is given, it should be a message chain that will be sent to each object in the list. the result will be thrown away. if two arguments are given, the first is an unevaluated name that will be set to each of the values in the list in succession, and then the second argument will be evaluated in a scope with that argument in it. if three arguments is given, the first one is an unevaluated name that will be set to the index of each element, and the other two arguments are the name of the argument for the value, and the actual code. the code will evaluate in a lexical context, and if the argument name is available outside the context, it will be shadowed. the method will return the list.",
                                                       new NativeMethod("each", DefaultArgumentsDefinition.builder()
                                                                        .WithOptionalPositionalUnevaluated("indexOrArgOrCode")
                                                                        .WithOptionalPositionalUnevaluated("argOrCode")
                                                                        .WithOptionalPositionalUnevaluated("code")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                                                                            outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                                                                            object onAsList = context.runtime.List.ConvertToThis(on, message, context);
                                                                            var ls = ((IokeList)IokeObject.dataOf(onAsList)).list;
                                                                            switch(message.Arguments.Count) {
                                                                            case 0: {
                                                                                return Interpreter.Send(runtime.seqMessage, context, on);
                                                                            }
                                                                            case 1: {
                                                                                IokeObject code = IokeObject.As(message.Arguments[0], context);

                                                                                foreach(object o in ls) {
                                                                                    context.runtime.interpreter.Evaluate(code, context, context.RealContext, o);
                                                                                }
                                                                                break;
                                                                            }
                                                                            case 2: {
                                                                                IokeObject c = context.runtime.NewLexicalContext(context, "Lexical activation context for List#each", context);
                                                                                string name = IokeObject.As(message.Arguments[0], context).Name;
                                                                                IokeObject code = IokeObject.As(message.Arguments[1], context);

                                                                                foreach(object o in ls) {
                                                                                    c.SetCell(name, o);
                                                                                    context.runtime.interpreter.Evaluate(code, c, c.RealContext, c);
                                                                                }
                                                                                break;
                                                                            }
                                                                            case 3: {
                                                                                IokeObject c = context.runtime.NewLexicalContext(context, "Lexical activation context for List#each", context);
                                                                                string iname = IokeObject.As(message.Arguments[0], context).Name;
                                                                                string name = IokeObject.As(message.Arguments[1], context).Name;
                                                                                IokeObject code = IokeObject.As(message.Arguments[2], context);

                                                                                int index = 0;
                                                                                foreach(object o in ls) {
                                                                                    c.SetCell(name, o);
                                                                                    c.SetCell(iname, runtime.NewNumber(index++));
                                                                                    context.runtime.interpreter.Evaluate(code, c, c.RealContext, c);
                                                                                }
                                                                                break;
                                                                            }
                                                                            }
                                                                            return onAsList;
                                                                        })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument, the index of the element to be returned. can be negative, and will in that case return indexed from the back of the list. if the index is outside the bounds of the list, will return nil. the argument can also be a range, and will in that case interpret the first index as where to start, and the second the end. the end can be negative and will in that case be from the end. if the first argument is negative, or after the second, an empty list will be returned. if the end point is larger than the list, the size of the list will be used as the end point.",
                                                       new TypeCheckingNativeMethod("at", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(runtime.List)
                                                                                    .WithRequiredPositional("index")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        object arg = args[0];

                                                                                        if(IokeObject.dataOf(arg) is Range) {
                                                                                            int first = Number.ExtractInt(Range.GetFrom(arg), message, context);

                                                                                            if(first < 0) {
                                                                                                return context.runtime.NewList(new SaneArrayList());
                                                                                            }

                                                                                            int last = Number.ExtractInt(Range.GetTo(arg), message, context);
                                                                                            bool inclusive = Range.IsInclusive(arg);

                                                                                            var o = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                            int size = o.Count;

                                                                                            if(last < 0) {
                                                                                                last = size + last;
                                                                                            }

                                                                                            if(last < 0) {
                                                                                                return context.runtime.NewList(new SaneArrayList());
                                                                                            }

                                                                                            if(last >= size) {

                                                                                                last = inclusive ? size-1 : size;
                                                                                            }

                                                                                            if(first > last || (!inclusive && first == last)) {
                                                                                                return context.runtime.NewList(new SaneArrayList());
                                                                                            }

                                                                                            if(!inclusive) {
                                                                                                last--;
                                                                                            }

                                                                                            var l = new SaneArrayList();
                                                                                            for(int i = first; i<last+1; i++) {
                                                                                                l.Add(o[i]);
                                                                                            }

                                                                                            return context.runtime.NewList(l);
                                                                                        }

                                                                                        if(!(IokeObject.dataOf(arg) is Number)) {
                                                                                            arg = IokeObject.ConvertToNumber(arg, message, context);
                                                                                        }
                                                                                        int index = ((Number)IokeObject.dataOf(arg)).AsNativeInteger();
                                                                                        var o2 = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                        if(index < 0) {
                                                                                            index = o2.Count + index;
                                                                                        }

                                                                                        if(index >= 0 && index < o2.Count) {
                                                                                            return o2[index];
                                                                                        } else {
                                                                                            return context.runtime.nil;
                                                                                        }
                                                                                    })));
            obj.AliasMethod("at", "[]", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("returns the size of this list",
                                                       new TypeCheckingNativeMethod.WithNoArguments("size", runtime.List,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return context.runtime.NewNumber(((IokeList)IokeObject.dataOf(on)).List.Count);
                                                                                                    })));
            obj.AliasMethod("size", "length", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("inspect", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return method.runtime.NewText(IokeList.GetInspect(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a brief text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("notice", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return method.runtime.NewText(IokeList.GetNotice(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Compares this object against the argument. The comparison is only based on the elements inside the lists, which are in turn compared using <=>.",
                                                       new TypeCheckingNativeMethod("<=>", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        var one = IokeList.GetList(on);
                                                                                        object arg = args[0];
                                                                                        if(!(IokeObject.dataOf(arg) is IokeList)) {
                                                                                            return context.runtime.nil;
                                                                                        }
                                                                                        var two = IokeList.GetList(arg);

                                                                                        int len = Math.Min(one.Count, two.Count);
                                                                                        SpaceshipComparator sc = new SpaceshipComparator(context, message);

                                                                                        for(int i = 0; i < len; i++) {
                                                                                            int v = sc.Compare(one[i], two[i]);
                                                                                            if(v != 0) {
                                                                                                return context.runtime.NewNumber(v);
                                                                                            }
                                                                                        }

                                                                                        len = one.Count - two.Count;

                                                                                        if(len == 0) return context.runtime.NewNumber(0);
                                                                                        if(len > 0) return context.runtime.NewNumber(1);
                                                                                        return context.runtime.NewNumber(-1);
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument and adds it at the end of the list, and then returns the list",
                                                       new TypeCheckingNativeMethod("<<", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("value")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        IokeList.Add(on, args[0]);
                                                                                        return on;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument and adds it at the end of the list, and then returns the list",
                                                       new TypeCheckingNativeMethod("append!", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("value")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        object value = args[0];
                                                                                        IokeList.Add(on, value);
                                                                                        return on;
                                                                                    })));

            obj.AliasMethod("append!", "push!", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument and adds it at the beginning of the list, and then returns the list",
                                                       new TypeCheckingNativeMethod("prepend!", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("value")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        object value = args[0];
                                                                                        IokeList.Add(on, 0, value);
                                                                                        return on;
                                                                                    })));

            obj.AliasMethod("prepend!", "unshift!", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("removes the last element from the list and returns it. returns nil if the list is empty.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("pop!", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var l = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                                        if(l.Count == 0) {
                                                                                                            return context.runtime.nil;
                                                                                                        }
                                                                                                        object result = l[l.Count-1];
                                                                                                        l.RemoveAt(l.Count-1);
                                                                                                        return result;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("removes the first element from the list and returns it. returns nil if the list is empty.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("shift!", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var l = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                                        if(l.Count == 0) {
                                                                                                            return context.runtime.nil;
                                                                                                        }
                                                                                                        object result = l[0];
                                                                                                        l.RemoveAt(0);
                                                                                                        return result;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("will remove all the entries from the list, and then returns the list",
                                                       new TypeCheckingNativeMethod.WithNoArguments("clear!", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        ((IokeList)IokeObject.dataOf(on)).List.Clear();
                                                                                                        return on;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if this list is empty, false otherwise",
                                                       new TypeCheckingNativeMethod.WithNoArguments("empty?", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return ((IokeList)IokeObject.dataOf(on)).List.Count == 0 ? context.runtime.True : context.runtime.False;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if the receiver includes the evaluated argument, otherwise false",
                                                       new TypeCheckingNativeMethod("include?", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("object")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        return ((IokeList)IokeObject.dataOf(on)).List.Contains(args[0]) ? context.runtime.True : context.runtime.False;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("adds the elements in the argument list to the current list, and then returns that list",
                                                       new TypeCheckingNativeMethod("concat!", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("otherList").WhichMustMimic(obj)
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        var l = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                        var l2 = ((IokeList)IokeObject.dataOf(args[0])).List;
                                                                                        foreach(object x in l2) l.Add(x);
                                                                                        return on;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a new list that contains the receivers elements and the elements of the list sent in as the argument.",
                                                       new TypeCheckingNativeMethod("+", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("otherList").WhichMustMimic(obj)
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        var newList = new SaneArrayList();
                                                                                        newList.AddRange(((IokeList)IokeObject.dataOf(on)).List);
                                                                                        newList.AddRange(((IokeList)IokeObject.dataOf(args[0])).List);
                                                                                        return context.runtime.NewList(newList, IokeObject.As(on, context));
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a new list that contains all the elements from the receivers list, except for those that are in the argument list",
                                                       new TypeCheckingNativeMethod("-", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("otherList").WhichMustMimic(obj)
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        var newList = new SaneArrayList();
                                                                                        var l = ((IokeList)IokeObject.dataOf(args[0])).List;
                                                                                        foreach(object x in ((IokeList)IokeObject.dataOf(on)).List) {
                                                                                            if(!l.Contains(x)) {
                                                                                                newList.Add(x);
                                                                                            }
                                                                                        }
                                                                                        return context.runtime.NewList(newList, IokeObject.As(on, context));
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a new sorted version of this list",
                                                       new TypeCheckingNativeMethod.WithNoArguments("sort", obj,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        object newList = IokeObject.Mimic(on, message, context);
                                                                                                        var ll = ((IokeList)IokeObject.dataOf(newList)).List;
                                                                                                        if(ll is ArrayList) {
                                                                                                            ((ArrayList)ll).Sort(new SpaceshipComparator(context, message));
                                                                                                        } else {
                                                                                                            ArrayList second = new SaneArrayList(ll);
                                                                                                            ((ArrayList)second).Sort(new SpaceshipComparator(context, message));
                                                                                                            ((IokeList)IokeObject.dataOf(newList)).List = second;
                                                                                                        }
                                                                                                        return newList;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("sorts this list in place and then returns it",
                                                       new TypeCheckingNativeMethod.WithNoArguments("sort!", obj,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var ll = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                                        if(ll is ArrayList) {
                                                                                                            ((ArrayList)ll).Sort(new SpaceshipComparator(context, message));
                                                                                                        } else {
                                                                                                            ArrayList second = new SaneArrayList(ll);
                                                                                                            ((ArrayList)second).Sort(new SpaceshipComparator(context, message));
                                                                                                            ((IokeList)IokeObject.dataOf(on)).List = second;
                                                                                                        }
                                                                                                        return on;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes an index and zero or more objects to insert at that point. the index can be negative to index from the end of the list. if the index is positive and larger than the size of the list, the list will be filled with nils inbetween.",
                                                       new TypeCheckingNativeMethod("insert!", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("index").WhichMustMimic(runtime.Number)
                                                                                    .WithRest("objects")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        int index = ((Number)IokeObject.dataOf(args[0])).AsNativeInteger();
                                                                                        var l = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                        int size = l.Count;
                                                                                        if(index < 0) {
                                                                                            index = size + index + 1;
                                                                                        }

                                                                                        if(args.Count>1) {
                                                                                            while(index < 0) {
                                                                                                IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition,
                                                                                                                                                             message,
                                                                                                                                                             context,
                                                                                                                                                             "Error",
                                                                                                                                                             "Index"), context).Mimic(message, context);
                                                                                                condition.SetCell("message", message);
                                                                                                condition.SetCell("context", context);
                                                                                                condition.SetCell("receiver", on);
                                                                                                condition.SetCell("index", context.runtime.NewNumber(index));

                                                                                                object[] newCell = new object[]{context.runtime.NewNumber(index)};

                                                                                                context.runtime.WithRestartReturningArguments(()=>{context.runtime.ErrorCondition(condition);},
                                                                                                                                              context,
                                                                                                                                              new IokeObject.UseValue("index", newCell));

                                                                                                index = Number.ExtractInt(newCell[0], message, context);
                                                                                                if(index < 0) {
                                                                                                    index = size + index;
                                                                                                }
                                                                                            }

                                                                                            for(int x = (index-size); x>0; x--) {
                                                                                                l.Add(context.runtime.nil);
                                                                                            }

                                                                                            for(int i=1, j=args.Count; i<j; i++) l.Insert(index + i - 1, args[i]);
                                                                                        }

                                                                                        return on;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes two arguments, the index of the element to set, and the value to set. the index can be negative and will in that case set indexed from the end of the list. if the index is larger than the current size, the list will be expanded with nils. an exception will be raised if a abs(negative index) is larger than the size.",
                                                       new TypeCheckingNativeMethod("at=", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("index")
                                                                                    .WithRequiredPositional("value")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        object arg = args[0];
                                                                                        object value = args[1];
                                                                                        if(!(IokeObject.dataOf(arg) is Number)) {
                                                                                            arg = IokeObject.ConvertToNumber(arg, message, context);
                                                                                        }
                                                                                        int index = ((Number)IokeObject.dataOf(arg)).AsNativeInteger();
                                                                                        var o = ((IokeList)IokeObject.dataOf(on)).List;
                                                                                        if(index < 0) {
                                                                                            index = o.Count + index;
                                                                                        }

                                                                                        while(index < 0) {
                                                                                            IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition,
                                                                                                                                                         message,
                                                                                                                                                         context,
                                                                                                                                                         "Error",
                                                                                                                                                         "Index"), context).Mimic(message, context);
                                                                                            condition.SetCell("message", message);
                                                                                            condition.SetCell("context", context);
                                                                                            condition.SetCell("receiver", on);
                                                                                            condition.SetCell("index", context.runtime.NewNumber(index));

                                                                                            object[] newCell = new object[]{context.runtime.NewNumber(index)};

                                                                                            context.runtime.WithRestartReturningArguments(()=>{context.runtime.ErrorCondition(condition);},
                                                                                                                                          context,
                                                                                                                                          new IokeObject.UseValue("index", newCell));

                                                                                            index = Number.ExtractInt(newCell[0], message, context);
                                                                                            if(index < 0) {
                                                                                                index = o.Count + index;
                                                                                            }
                                                                                        }

                                                                                        if(index >= o.Count) {
                                                                                            int toAdd = (index-o.Count) + 1;
                                                                                            for(int i=0;i<toAdd;i++) {
                                                                                                o.Add(context.runtime.nil);
                                                                                            }
                                                                                        }

                                                                                        o[(int)index] = value;

                                                                                        return value;
                                                                                    })));

            obj.AliasMethod("at=", "[]=", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod(
                                                     "takes as argument the index of the element to be removed and returns it. can be " +
                                                     "negative and will in that case index from the back of the list. if the index is " +
                                                     "outside the bounds of the list, will return nil. the argument can also be a range, " +
                                                     "and will in that case remove the sublist beginning at the first index and extending " +
                                                     "to the position in the list specified by the second index (inclusive or exclusive " +
                                                     "depending on the range). the end of the range can be negative and will in that case " +
                                                     "index from the back of the list. if the start of the range is negative, or greater " +
                                                     "than the end, an empty list will be returned. if the end index exceeds the bounds " +
                                                     "of the list, its size will be used instead.",
                                                     new TypeCheckingNativeMethod("removeAt!", TypeCheckingArgumentsDefinition.builder()
                                                                                  .ReceiverMustMimic(obj)
                                                                                  .WithRequiredPositional("indexOrRange")
                                                                                  .Arguments,
                                                                                  (method, on, args, keywords, context, message) => {
                                                                                      object arg = args[0];

                                                                                      if(IokeObject.dataOf(arg) is Range) {
                                                                                          int first = Number.ExtractInt(Range.GetFrom(arg), message, context);
                                                                                          if(first < 0) {
                                                                                              return EmptyList(context);
                                                                                          }

                                                                                          int last = Number.ExtractInt(Range.GetTo(arg), message, context);
                                                                                          var receiver = GetList(on);
                                                                                          int size = receiver.Count;

                                                                                          if(last < 0) {
                                                                                              last = size + last;
                                                                                          }

                                                                                          if(last < 0) {
                                                                                              return EmptyList(context);
                                                                                          }

                                                                                          bool inclusive = Range.IsInclusive(arg);

                                                                                          if(last >= size) {
                                                                                              last = inclusive ? size-1 : size;
                                                                                          }

                                                                                          if(first > last || (!inclusive && first == last)) {
                                                                                              return EmptyList(context);
                                                                                          }

                                                                                          if(!inclusive) {
                                                                                              last--;
                                                                                          }

                                                                                          var result = new SaneArrayList();
                                                                                          for(int i = 0; i <= last - first; i++) {
                                                                                              result.Add(receiver[first]);
                                                                                              receiver.RemoveAt(first);
                                                                                          }

                                                                                          return CopyList(context, result);
                                                                                      }

                                                                                      if(!(IokeObject.dataOf(arg) is Number)) {
                                                                                          arg = IokeObject.ConvertToNumber(arg, message, context);
                                                                                      }

                                                                                      int index = ((Number)IokeObject.dataOf(arg)).AsNativeInteger();
                                                                                      var receiver2 = GetList(on);
                                                                                      int size2 = receiver2.Count;

                                                                                      if(index < 0) {
                                                                                          index = size2 + index;
                                                                                      }

                                                                                      if(index >= 0 && index < size2) {
                                                                                          object result = receiver2[(int)index];
                                                                                          receiver2.RemoveAt((int)index);
                                                                                          return result;
                                                                                      } else {
                                                                                          return context.runtime.nil;
                                                                                      }
                                                                                  })));

            obj.RegisterMethod(runtime.NewNativeMethod(
                                                     "takes one or more arguments. removes all occurrences of the provided arguments from " +
                                                     "the list and returns the updated list. if an argument is not contained, the list " +
                                                     "remains unchanged. sending this method to an empty list has no effect.",
                                                     new TypeCheckingNativeMethod("remove!", TypeCheckingArgumentsDefinition.builder()
                                                                                  .ReceiverMustMimic(obj)
                                                                                  .WithRequiredPositional("element")
                                                                                  .WithRest("elements")
                                                                                  .Arguments,
                                                                                  (method, on, args, keywords, context, message) => {
                                                                                      var receiver = GetList(on);
                                                                                      if(receiver.Count == 0) {
                                                                                          return on;
                                                                                      }
                                                                                      foreach(object o in args) {
                                                                                          for(int i = 0, j=receiver.Count; i<j; i++) {
                                                                                              if(o.Equals(receiver[i])) {
                                                                                                  receiver.RemoveAt(i);
                                                                                                  i--;
                                                                                                  j--;
                                                                                              }
                                                                                          }
                                                                                      }
                                                                                      return on;
                                                                                  })));

            obj.RegisterMethod(runtime.NewNativeMethod(
                                                     "takes one or more arguments. removes the first occurrence of the provided arguments " +
                                                     "from the list and returns the updated list. if an argument is not contained, the list " +
                                                     "remains unchanged. arguments that are provided multiple times are treated as distinct " +
                                                     "elements. sending this message to an empty list has no effect.",
                                                     new TypeCheckingNativeMethod("removeFirst!", TypeCheckingArgumentsDefinition.builder()
                                                                                  .ReceiverMustMimic(obj)
                                                                                  .WithRequiredPositional("element")
                                                                                  .WithRest("elements")
                                                                                  .Arguments,
                                                                                  (method, on, args, keywords, context, message) => {
                                                                                      var receiver = GetList(on);
                                                                                      if(receiver.Count == 0) {
                                                                                          return on;
                                                                                      }
                                                                                      foreach(object o in args) {
                                                                                          receiver.Remove(o);
                                                                                      }
                                                                                      return on;
                                                                                  })));

            obj.RegisterMethod(runtime.NewNativeMethod("removes all nils in this list, and then returns the list",
                                                       new TypeCheckingNativeMethod.WithNoArguments("compact!", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var list = GetList(on);
                                                                                                        var newList = new SaneArrayList();
                                                                                                        object nil = context.runtime.nil;
                                                                                                        foreach(object o in list) {
                                                                                                            if(o != nil) {
                                                                                                                newList.Add(o);
                                                                                                            }
                                                                                                        }
                                                                                                        SetList(on, newList);
                                                                                                        return on;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("reverses the elements in this list, then returns it",
                                                       new TypeCheckingNativeMethod.WithNoArguments("reverse!", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var list = GetList(on);
                                                                                                        if(list is ArrayList) {
                                                                                                            ((ArrayList)list).Reverse();
                                                                                                        } else {
                                                                                                            ArrayList list2 = new SaneArrayList(list);
                                                                                                            list2.Reverse();
                                                                                                            SetList(on, list2);
                                                                                                        }
                                                                                                        return on;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("flattens all lists in this list recursively, then returns it",
                                                       new TypeCheckingNativeMethod.WithNoArguments("flatten!", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        SetList(on, Flatten(GetList(on)));
                                                                                                        return on;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a text composed of the asText representation of all elements in the list, separated by the separator. the separator defaults to an empty text.",
                                                       new TypeCheckingNativeMethod("join", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithOptionalPositional("separator", "")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        var list = GetList(on);
                                                                                        string result;
                                                                                        if(list.Count == 0) {
                                                                                            result = "";
                                                                                        } else {
                                                                                            string sep = args.Count > 0 ? Text.GetText(args[0]) : "";
                                                                                            StringBuilder sb = new StringBuilder();
                                                                                            Join(list, sb, sep, context.runtime.asText, context);
                                                                                            result = sb.ToString();
                                                                                        }
                                                                                        return context.runtime.NewText(result);
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes one or two arguments, and will then use these arguments as code to transform each element in this list. the transform happens in place. finally the method will return the receiver.",
                                                       new NativeMethod("map!", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositionalUnevaluated("argOrCode")
                                                                        .WithOptionalPositionalUnevaluated("code")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                                                                            outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                                                                            object onAsList = context.runtime.List.ConvertToThis(on, message, context);

                                                                            var ls = ((IokeList)IokeObject.dataOf(onAsList)).list;
                                                                            int size = ls.Count;

                                                                            switch(message.Arguments.Count) {
                                                                            case 1: {
                                                                                IokeObject code = IokeObject.As(message.Arguments[0], context);

                                                                                for(int i = 0; i<size; i++) {
                                                                                    ls[i] = context.runtime.interpreter.Evaluate(code, context, context.RealContext, ls[i]);
                                                                                }
                                                                                break;
                                                                            }
                                                                            case 2: {
                                                                                IokeObject c = context.runtime.NewLexicalContext(context, "Lexical activation context for List#map!", context);
                                                                                string name = IokeObject.As(message.Arguments[0], context).Name;
                                                                                IokeObject code = IokeObject.As(message.Arguments[1], context);

                                                                                for(int i = 0; i<size; i++) {
                                                                                    c.SetCell(name, ls[i]);
                                                                                    ls[i] = context.runtime.interpreter.Evaluate(code, c, c.RealContext, c);
                                                                                }
                                                                                break;
                                                                            }
                                                                            }
                                                                            return on;
                                                                        })));

            obj.AliasMethod("map!", "collect!", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("takes one or two arguments, and will then use these arguments as code to decide what elements should be removed from the list. the method will return the receiver.",
                                                       new NativeMethod("removeIf!", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositionalUnevaluated("argOrCode")
                                                                        .WithOptionalPositionalUnevaluated("code")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                                                                            outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                                                                            object onAsList = context.runtime.List.ConvertToThis(on, message, context);

                                                                            var ls = ((IokeList)IokeObject.dataOf(onAsList)).list;

                                                                            switch(message.Arguments.Count) {
                                                                            case 1: {
                                                                                IokeObject code = IokeObject.As(message.Arguments[0], context);

                                                                                int count = ls.Count;
                                                                                for(int i = 0; i<count; i++) {
                                                                                    object o1 = ls[i];
                                                                                    if(IokeObject.IsObjectTrue(context.runtime.interpreter.Evaluate(code, context, context.RealContext, o1))) {
                                                                                        ls.RemoveAt(i);
                                                                                        i--;
                                                                                        count--;
                                                                                    }
                                                                                }
                                                                                break;
                                                                            }
                                                                            case 2: {
                                                                                IokeObject c = context.runtime.NewLexicalContext(context, "Lexical activation context for List#removeIf!", context);
                                                                                string name = IokeObject.As(message.Arguments[0], context).Name;
                                                                                IokeObject code = IokeObject.As(message.Arguments[1], context);

                                                                                int count = ls.Count;
                                                                                for(int i = 0; i<count; i++) {
                                                                                    object o2 = ls[i];
                                                                                    c.SetCell(name, o2);
                                                                                    if(IokeObject.IsObjectTrue(context.runtime.interpreter.Evaluate(code, c, c.RealContext, c))) {
                                                                                        ls.RemoveAt(i);
                                                                                        i--;
                                                                                        count--;
                                                                                    }
                                                                                }
                                                                                break;
                                                                            }
                                                                            }
                                                                            return on;
                                                                        })));
        }
Пример #2
0
        public override void Init(IokeObject obj)
        {
            obj.Kind = "Message";
            obj.Mimics(IokeObject.As(IokeObject.FindCell(obj.runtime.Mixins, "Enumerable"), null), obj.runtime.nul, obj.runtime.nul);

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Takes one or more evaluated arguments and sends this message chain to where the first argument is ground, and if there are more arguments, the second is the receiver, and the rest will be the arguments",
                                                               new NativeMethod("evaluateOn", DefaultArgumentsDefinition.builder()
                                                                                .WithRequiredPositional("ground")
                                                                                .WithOptionalPositional("receiver", "ground")
                                                                                .WithRest("arguments")
                                                                                .Arguments,
                                                                                (method, on, args, keywords, context, message) => {
                                                                                    IokeObject messageGround = IokeObject.As(args[0], context);
                                                                                    IokeObject receiver = messageGround;
                                                                                    int size = args.Count;
                                                                                    if(size > 1) {
                                                                                        receiver = IokeObject.As(args[1], context);
                                                                                        if(size > 2) {
                                                                                            IokeObject m = IokeObject.As(on, context).AllocateCopy(IokeObject.As(on, context), context);
                                                                                            m.Arguments.Clear();
                                                                                            for(int ix=2;ix<size;ix++) {
                                                                                                m.Arguments.Add(args[ix]);
                                                                                            }
                                                                                            on = m;
                                                                                        }
                                                                                    }

                                                                                    IokeObject msg = IokeObject.As(on, context);
                                                                                    return context.runtime.interpreter.Evaluate(msg, messageGround, messageGround, receiver);
                                                                                })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a deep clone of this message chain, starting at the current point.",
                                                           new TypeCheckingNativeMethod.WithNoArguments("deepCopy", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return Message.DeepCopy(on);
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Returns a code representation of the object",
                                                           new TypeCheckingNativeMethod.WithNoArguments("code", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return method.runtime.NewText(((Message)IokeObject.dataOf(on)).Code());
                                                           })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Returns the unevaluated arguments for this message",
                                                           new TypeCheckingNativeMethod.WithNoArguments("arguments", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return context.runtime.NewList(((Message)IokeObject.dataOf(on)).arguments);
                                                           })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Returns a formatted code representation of the object",
                                                           new TypeCheckingNativeMethod.WithNoArguments("formattedCode", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return method.runtime.NewText(Message.FormattedCode(IokeObject.As(on, context), 0, context));
                                                           })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the name of this message",
                                                           new TypeCheckingNativeMethod.WithNoArguments("name", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return method.runtime.GetSymbol(((Message)IokeObject.dataOf(on)).name);
                                                           })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("sets the name of the message and then returns that name",
                                                           new TypeCheckingNativeMethod("name=", TypeCheckingArgumentsDefinition.builder()
                                                                                        .ReceiverMustMimic(obj)
                                                                                        .WithRequiredPositional("newName")
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                                                                                            object o = args[0];
                                                                                            string name = null;
                                                                                            if(IokeObject.dataOf(o) is Symbol) {
                                                                                                name = Symbol.GetText(o);
                                                                                            } else if(IokeObject.dataOf(o) is Text) {
                                                                                                name = Text.GetText(o);
                                                                                            } else {
                                                                                                name = Text.GetText(IokeObject.ConvertToText(o, message, context, true));
                                                                                            }

                                                                                            Message.SetName(IokeObject.As(on, context), name);
                                                                                            return o;
                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("sets the next pointer of the message and then returns that pointer",
                                                           new TypeCheckingNativeMethod("next=", TypeCheckingArgumentsDefinition.builder()
                                                                                        .ReceiverMustMimic(obj)
                                                                                        .WithRequiredPositional("newNext")
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                                                                                            object o = args[0];
                                                                                            if(o == context.runtime.nil) {
                                                                                                Message.SetNext(IokeObject.As(on, context), null);
                                                                                            } else {
                                                                                                o = context.runtime.Message.ConvertToThis(o, message, context);
                                                                                                Message.SetNext(IokeObject.As(on, context), IokeObject.As(o, context));
                                                                                            }
                                                                                            return o;
                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("sets the prev pointer of the message and then returns that pointer",
                                                           new TypeCheckingNativeMethod("prev=", TypeCheckingArgumentsDefinition.builder()
                                                                                        .ReceiverMustMimic(obj)
                                                                                        .WithRequiredPositional("newPrev")
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                                                                                            object o = args[0];
                                                                                            if(o == context.runtime.nil) {
                                                                                                Message.SetPrev(IokeObject.As(on, context), null);
                                                                                            } else {
                                                                                                o = context.runtime.Message.ConvertToThis(o, message, context);
                                                                                                Message.SetPrev(IokeObject.As(on, context), IokeObject.As(o, context));
                                                                                            }
                                                                                            return o;
                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the file name where this message is written",
                                                           new TypeCheckingNativeMethod.WithNoArguments("filename", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return method.runtime.NewText(((Message)IokeObject.dataOf(on)).file);
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the line where this message is written",
                                                           new TypeCheckingNativeMethod.WithNoArguments("line", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return method.runtime.NewNumber(((Message)IokeObject.dataOf(on)).line);
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the position on the line where this message is written",
                                                           new TypeCheckingNativeMethod.WithNoArguments("position", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return method.runtime.NewNumber(((Message)IokeObject.dataOf(on)).pos);
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the next message in the chain, or nil",
                                                           new TypeCheckingNativeMethod.WithNoArguments("next", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            IokeObject next = ((Message)IokeObject.dataOf(on)).next;
                                                                                                            if(next == null) {
                                                                                                                return context.runtime.nil;
                                                                                                            } else {
                                                                                                                return next;
                                                                                                            }
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the last message in the chain",
                                                           new TypeCheckingNativeMethod.WithNoArguments("last", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            IokeObject current = IokeObject.As(on, context);
                                                                                                            while(GetNext(current) != null) {
                                                                                                                current = GetNext(current);
                                                                                                            }
                                                                                                            return current;
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns the previous message in the chain, or nil",
                                                           new TypeCheckingNativeMethod.WithNoArguments("prev", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            IokeObject prev = ((Message)IokeObject.dataOf(on)).prev;
                                                                                                            if(prev == null) {
                                                                                                                return context.runtime.nil;
                                                                                                            } else {
                                                                                                                return prev;
                                                                                                            }
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns true when this message is a terminator, otherwise false",
                                                           new TypeCheckingNativeMethod.WithNoArguments("terminator?", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return Message.IsTerminator(on) ? context.runtime.True : context.runtime.False;
                                                                                                        })));
            obj.RegisterMethod(obj.runtime.NewNativeMethod("takes one index, and a context and returns the evaluated argument at that index.",
                                                           new NativeMethod("evalArgAt", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("argumentIndex")
                                                                            .WithRequiredPositional("context")
                                                                            .Arguments,
                                                                            (method, on, args, keywords, context, message) => {
                                                                                int index = Number.ExtractInt(args[0], message, context);
                                                                                IokeObject newContext = IokeObject.As(args[1], context);
                                                                                IokeObject _m =  IokeObject.As(on, context);
                                                                                int argCount = _m.Arguments.Count;
                                                                                while(index < 0 || index >= argCount) {
                                                                                    IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition,
                                                                                                                                                 message,
                                                                                                                                                 context,
                                                                                                                                                 "Error",
                                                                                                                                                 "Index"), context).Mimic(message, context);
                                                                                    condition.SetCell("message", message);
                                                                                    condition.SetCell("context", context);
                                                                                    condition.SetCell("receiver", on);
                                                                                    condition.SetCell("index", context.runtime.NewNumber(index));

                                                                                    object[] newCell = new object[]{context.runtime.NewNumber(index)};

                                                                                    context.runtime.WithRestartReturningArguments(()=>{context.runtime.ErrorCondition(condition);},
                                                                                                                                  context,
                                                                                                                                  new IokeObject.UseValue("index", newCell));

                                                                                    index = Number.ExtractInt(newCell[0], message, context);
                                                                                }

                                                                                return Interpreter.GetEvaluatedArgument(_m, index, newContext);
                                                                            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Takes one evaluated argument and returns a message that wraps the value of that argument.",
                                                           new NativeMethod("wrap", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("value")
                                                                            .Arguments,
                                                                            (method, on, args, keywords, context, message) => {
                                                                                return context.runtime.CreateMessage(Message.Wrap(IokeObject.As(args[0], context)));
                                                                            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("evaluates the argument and makes it the new next pointer of the receiver. it also modifies the argument so its prev pointer points back to this message. if the argument is nil, the next pointer will be erased. it then returns the receiving message.",
                                                           new TypeCheckingNativeMethod("->", TypeCheckingArgumentsDefinition.builder()
                                                                                        .ReceiverMustMimic(obj)
                                                                                        .WithRequiredPositional("nextMessage")
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                                                                                            object arg = args[0];
                                                                                            if(arg == context.runtime.nil) {
                                                                                                Message.SetNext(IokeObject.As(on, context), null);
                                                                                            } else {
                                                                                                arg = context.runtime.Message.ConvertToThis(arg, message, context);
                                                                                                Message.SetNext(IokeObject.As(on, context), IokeObject.As(arg, context));
                                                                                                Message.SetPrev(IokeObject.As(arg, context), IokeObject.As(on, context));
                                                                                            }
                                                                                            return arg;
                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("evaluates the argument and adds it to the beginning of the argument list of this message. it then returns the receiving message.",
                                                           new NativeMethod(">>", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("newArgument")
                                                                            .Arguments,
                                                                            (method, on, args, keywords, context, message) => {
                                                                                IokeObject.As(on, context).Arguments.Insert(0, args[0]);
                                                                                return on;
                                                                            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("evaluates the argument and adds it to the argument list of this message. it then returns the receiving message.",
                                                           new NativeMethod("appendArgument", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("newArgument")
                                                                            .Arguments,
                                                                            (method, on, args, keywords, context, message) => {
                                                                                IokeObject.As(on, context).Arguments.Add(args[0]);
                                                                                return on;
                                                                            })));
            obj.AliasMethod("appendArgument", "<<", null, null);

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a string that describes this message as a stack trace elemtn",
                                                           new TypeCheckingNativeMethod.WithNoArguments("asStackTraceText", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return context.runtime.NewText(Message.GetStackTraceText(on));
                                                                                                        })));
            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns true if this message is a keyword parameter or not",
                                                           new TypeCheckingNativeMethod.WithNoArguments("keyword?", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return ((Message)IokeObject.dataOf(on)).IsKeyword() ? context.runtime.True : context.runtime.False;
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns true if this message is a symbol message or not",
                                                           new TypeCheckingNativeMethod.WithNoArguments("symbol?", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                                                                                                            return ((Message)IokeObject.dataOf(on)).IsSymbolMessage ? context.runtime.True : context.runtime.False;
                                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("takes either one or two arguments. if one argument is given, it should be a message chain that will be sent to each message in the chain, recursively. the result will be thrown away. if two arguments are given, the first is an unevaluated name that will be set to each of the messages in the chain in succession, and then the second argument will be evaluated in a scope with that argument in it. the code will evaluate in a lexical context, and if the argument name is available outside the context, it will be shadowed. the method will return the original message.",
                                                           new NativeMethod("walk", DefaultArgumentsDefinition.builder()
                                                                            .WithOptionalPositionalUnevaluated("argOrCode")
                                                                            .WithOptionalPositionalUnevaluated("code")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                                                                                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                                                                                object onAsMessage = context.runtime.Message.ConvertToThis(on, message, context);

                                                                                switch(message.Arguments.Count) {
                                                                                case 1: {
                                                                                    IokeObject code = IokeObject.As(message.Arguments[0], context);
                                                                                    WalkWithReceiver(context, onAsMessage, code);
                                                                                    break;
                                                                                }
                                                                                case 2: {
                                                                                    IokeObject c = context.runtime.NewLexicalContext(context, "Lexical activation context for Message#walk", context);
                                                                                    string name = IokeObject.As(message.Arguments[0], context).Name;
                                                                                    IokeObject code = IokeObject.As(message.Arguments[1], context);

                                                                                    WalkWithoutExplicitReceiver(onAsMessage, c, name, code);
                                                                                    break;
                                                                                }
                                                                                }
                                                                                return onAsMessage;

                                                                            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("takes either one or two or three arguments. if one argument is given, it should be a message chain that will be sent to each message in the chain. the result will be thrown away. if two arguments are given, the first is an unevaluated name that will be set to each of the messages in the chain in succession, and then the second argument will be evaluated in a scope with that argument in it. if three arguments is given, the first one is an unevaluated name that will be set to the index of each message, and the other two arguments are the name of the argument for the value, and the actual code. the code will evaluate in a lexical context, and if the argument name is available outside the context, it will be shadowed. the method will return the original message.",
                                                           new NativeMethod("each",  DefaultArgumentsDefinition.builder()
                                                                            .WithOptionalPositionalUnevaluated("indexOrArgOrCode")
                                                                            .WithOptionalPositionalUnevaluated("argOrCode")
                                                                            .WithOptionalPositionalUnevaluated("code")
                                                                            .Arguments,
                                                                            (method, context, message, on, outer) => {
                                                                                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);

                                                                                object onAsMessage = context.runtime.Message.ConvertToThis(on, message, context);

                                                                                Runtime runtime = context.runtime;
                                                                                switch(message.Arguments.Count) {
                                                                                case 0: {
                                                                                    return Interpreter.Send(runtime.seqMessage, context, on);
                                                                                }
                                                                                case 1: {
                                                                                    IokeObject code = IokeObject.As(message.Arguments[0], context);
                                                                                    object o = onAsMessage;
                                                                                    while(o != null) {
                                                                                        runtime.interpreter.Evaluate(code, context, context.RealContext, o);
                                                                                        o = GetNext(o);
                                                                                    }

                                                                                    break;
                                                                                }
                                                                                case 2: {
                                                                                    IokeObject c = runtime.NewLexicalContext(context, "Lexical activation context for Message#each", context);
                                                                                    string name = IokeObject.As(message.Arguments[0], context).Name;
                                                                                    IokeObject code = IokeObject.As(message.Arguments[1], context);

                                                                                    object o = onAsMessage;
                                                                                    while(o != null) {
                                                                                        c.SetCell(name, o);
                                                                                        runtime.interpreter.Evaluate(code, c, c.RealContext, c);
                                                                                        o = GetNext(o);
                                                                                    }
                                                                                    break;
                                                                                }
                                                                                case 3: {
                                                                                    IokeObject c = runtime.NewLexicalContext(context, "Lexical activation context for Message#each", context);
                                                                                    string iname = IokeObject.As(message.Arguments[0], context).Name;
                                                                                    string name = IokeObject.As(message.Arguments[1], context).Name;
                                                                                    IokeObject code = IokeObject.As(message.Arguments[2], context);

                                                                                    int index = 0;
                                                                                    object o = onAsMessage;
                                                                                    while(o != null) {
                                                                                        c.SetCell(name, o);
                                                                                        c.SetCell(iname, runtime.NewNumber(index++));
                                                                                        runtime.interpreter.Evaluate(code, c, c.RealContext, c);
                                                                                        o = GetNext(o);
                                                                                    }
                                                                                    break;
                                                                                }
                                                                                }
                                                                                return onAsMessage;
                                                                            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Takes one evaluated argument and sends this message to that argument",
                                                           new NativeMethod("sendTo", DefaultArgumentsDefinition.builder()
                                                                            .WithRequiredPositional("newReceiver")
                                                                            .WithOptionalPositional("context", "nil")
                                                                            .Arguments,
                                                                            (method, on, args, keywords, context, message) => {
                                                                                IokeObject realReceiver = IokeObject.As(args[0], context);
                                                                                IokeObject realContext = realReceiver;
                                                                                if(args.Count > 1) {
                                                                                    realContext = IokeObject.As(args[1], context);
                                                                                }

                                                                                IokeObject msg = IokeObject.As(on, context);
                                                                                return Interpreter.Send(msg, realContext, realReceiver);
                                                                            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("sets the arguments for this message. if given nil the arguments list will be creared, otherwise the list given as arguments will be used. it then returns the receiving message.",
                                                           new TypeCheckingNativeMethod("arguments=", TypeCheckingArgumentsDefinition.builder()
                                                                                        .ReceiverMustMimic(obj)
                                                                                        .WithRequiredPositional("newArguments")
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                                                                                            object arg = args[0];
                                                                                            SetArguments(on, new SaneArrayList());
                                                                                            if(arg == context.runtime.nil) {
                                                                                                // no arguments for this message
                                                                                            } else if (IokeObject.dataOf(arg) is IokeList) {
                                                                                                var elements = IokeList.GetList(arg);
                                                                                                var arg1 = IokeObject.As(on, method).Arguments;
                                                                                                foreach(object o in elements) arg1.Add(o);
                                                                                            } else {
                                                                                                IokeObject.As(on, method).Arguments.Insert(0, arg);
                                                                                            }
                                                                                            return on;
                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Takes one evaluated argument and returns the message resulting from parsing and operator shuffling the resulting message.",
                                                           new TypeCheckingNativeMethod("fromText", TypeCheckingArgumentsDefinition.builder()
                                                                                        .WithRequiredPositional("code").WhichMustMimic(obj.runtime.Text)
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                                                                                            string code = Text.GetText(args[0]);
                                                                                            return Message.NewFromStream(context.runtime, new StringReader(code), message, context);
                                                                                        })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Takes one evaluated argument and executes the contents of that text in the current context and returns the result of that.",
                                                           new TypeCheckingNativeMethod("doText", TypeCheckingArgumentsDefinition.builder()
                                                                                        .WithRequiredPositional("code").WhichMustMimic(obj.runtime.Text)
                                                                                        .Arguments,
                                                                                        (method, on, args, keywords, context, message) => {
                                                                                            string code = Text.GetText(args[0]);
                                                                                            return context.runtime.EvaluateString(code, message, context);
                                                                                        })));
        }
Пример #3
0
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;
            obj.Kind = "Regexp";

            IokeObject regexpMatch  = new IokeObject(runtime, "contains behavior related to assignment", new RegexpMatch(obj, null, null));
            regexpMatch.MimicsWithoutCheck(runtime.Origin);
            regexpMatch.Init();
            obj.RegisterCell("Match", regexpMatch);

            obj.RegisterMethod(runtime.NewNativeMethod("returns a hash for the regexp",
                                                           new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => {
                                                                   outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                                                                   Regexp r = (Regexp)IokeObject.dataOf(on);
                                                                   return context.runtime.NewNumber(r.pattern.GetHashCode() + 13 * r.flags.GetHashCode());
                                                               })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if the left hand side pattern is equal to the right hand side pattern.",
                                                       new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(runtime.Regexp)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        Regexp d = (Regexp)IokeObject.dataOf(on);
                                                                                        object other = args[0];

                                                                                        return ((other is IokeObject) &&
                                                                                                (IokeObject.dataOf(other) is Regexp) &&
                                                                                                ((on == context.runtime.Regexp || other == context.runtime.Regexp) ? on == other :
                                                                                                 (d.pattern.Equals(((Regexp)IokeObject.dataOf(other)).pattern) &&
                                                                                                  d.flags.Equals(((Regexp)IokeObject.dataOf(other)).flags)))) ? context.runtime.True : context.runtime.False;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns the pattern use for this regular expression",
                                                       new TypeCheckingNativeMethod.WithNoArguments("pattern", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return context.runtime.NewText(GetPattern(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one argument and tries to match that argument against the current pattern. Returns nil if no match can be done, or a Regexp Match object if a match succeeds",
                                                       new TypeCheckingNativeMethod("match", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        IokeObject target = IokeObject.As(Interpreter.Send(context.runtime.asText, context, args[0]), context);
                                                                                        string arg = Text.GetText(target);
                                                                                        Matcher m = ((Regexp)IokeObject.dataOf(on)).regexp.Matcher(arg);

                                                                                        if(m.Find()) {
                                                                                            IokeObject match = regexpMatch.AllocateCopy(message, context);
                                                                                            match.MimicsWithoutCheck(regexpMatch);
                                                                                            match.Data = new RegexpMatch(IokeObject.As(on, context), m, target);
                                                                                            return match;
                                                                                        } else {
                                                                                            return context.runtime.nil;
                                                                                        }
                                                                                    })));

            obj.AliasMethod("match", "=~", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one argument that should be a text and returns a text that has all regexp meta characters quoted",
                                                       new NativeMethod("quote", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositional("text")
                                                                        .Arguments,
                                                                        (method, on, args, keywords, context, message) => {
                                                                            return context.runtime.NewText(Pattern.Quote(Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]))));
                                                                        })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one or two text arguments that describes the regular expression to create. the first text is the pattern and the second is the flags.",
                                                       new NativeMethod("from", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositional("pattern")
                                                                        .WithOptionalPositional("flags", "")
                                                                        .Arguments,
                                                                        (method, on, args, keywords, context, message) => {
                                                                            string pattern = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                                                                            string flags = "";
                                                                            if(args.Count > 1) {
                                                                                flags = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[1]));
                                                                            }

                                                                            return context.runtime.NewRegexp(pattern, flags, context, message);
                                                                        })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one argument and tries to match that argument against the current pattern. Returns a list of all the texts that were matched.",
                                                       new TypeCheckingNativeMethod("allMatches", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        string arg = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                                                                                        Matcher m = ((Regexp)IokeObject.dataOf(on)).regexp.Matcher(arg);

                                                                                        var result = new SaneArrayList();
                                                                                        MatchIterator iter = m.FindAll();
                                                                                        while(iter.HasMore) {
                                                                                            result.Add(runtime.NewText(iter.NextMatch.Group(0)));
                                                                                        }

                                                                                        return runtime.NewList(result);
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("inspect", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return method.runtime.NewText(Regexp.GetInspect(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a brief text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("notice", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return method.runtime.NewText(Regexp.GetNotice(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all the named groups in this regular expression",
                                                       new TypeCheckingNativeMethod.WithNoArguments("names", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var names = Regexp.GetRegexp(on).GroupNames;
                                                                                                        var theNames = new SaneArrayList();
                                                                                                        foreach(object name in names) {
                                                                                                            theNames.Add(context.runtime.GetSymbol(((string)name)));
                                                                                                        }
                                                                                                        return context.runtime.NewList(theNames);
                                                                                                    })));
        }
Пример #4
0
Файл: Dict.cs Проект: fronx/ioke
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;

            obj.Kind = "Dict";
            obj.Mimics(IokeObject.As(runtime.Mixins.GetCell(null, null, "Enumerable"), null), runtime.nul, runtime.nul);
            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument, that should be a default value, and returns a new mimic of the receiver, with the default value for that new dict set to the argument",
                                                       new TypeCheckingNativeMethod("withDefault", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("defaultValue")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        object newDict = IokeObject.Mimic(on, message, context);
                                                                                        SetDefaultValue(newDict, IokeObject.As(args[0], context));
                                                                                        return newDict;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("creates a new Dict from the arguments provided, combined with the values in the receiver. the arguments provided will override those in the receiver. the rules for arguments are the same as for dict, except that dicts can also be provided. all positional arguments will be added before the keyword arguments.",
                                                       new TypeCheckingNativeMethod("merge", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRest("pairsAndDicts")
                                                                                    .WithKeywordRest("keywordPairs")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        var newMap = new SaneHashtable();
                                                                                        foreach(DictionaryEntry de in GetMap(on)) newMap[de.Key] = de.Value;

                                                                                        foreach(object o in args) {
                                                                                            if(IokeObject.dataOf(o) is Dict) {
                                                                                                foreach(DictionaryEntry de in GetMap(o)) newMap[de.Key] = de.Value;
                                                                                            } else if(IokeObject.dataOf(o) is Pair) {
                                                                                                newMap[Pair.GetFirst(o)] = Pair.GetSecond(o);
                                                                                            } else {
                                                                                                newMap[o] = context.runtime.nil;
                                                                                            }
                                                                                        }
                                                                                        foreach(var entry in keywords) {
                                                                                            string s = entry.Key;
                                                                                            object key = context.runtime.GetSymbol(s.Substring(0, s.Length-1));
                                                                                            object value = entry.Value;
                                                                                            if(value == null) {
                                                                                                value = context.runtime.nil;
                                                                                            }
                                                                                            newMap[key] = value;
                                                                                        }

                                                                                        return context.runtime.NewDict(newMap);
                                                                                    })));

            obj.AliasMethod("merge", "+", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument, the key of the element to return. if the key doesn't map to anything in the dict, returns the default value",
                                                       new TypeCheckingNativeMethod("at", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("key")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        object result = Dict.GetMap(on)[args[0]];
                                                                                        if(result == null) {
                                                                                            return GetDefaultValue(on, context, message);
                                                                                        } else {
                                                                                            return result;
                                                                                        }
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if this dict is empty, false otherwise",
                                                       new TypeCheckingNativeMethod.WithNoArguments("empty?", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return Dict.GetMap(on).Count == 0 ? context.runtime.True : context.runtime.False;
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument, the key to check if it is in the dict.",
                                                       new TypeCheckingNativeMethod("key?", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("key")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        return (Dict.GetMap(on).Contains(args[0])) ? context.runtime.True : context.runtime.False;
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes two arguments, the key of the element to set and the value to set it too. returns the value set",
                                                       new TypeCheckingNativeMethod("[]=", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("key")
                                                                                    .WithRequiredPositional("value")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        Dict.GetMap(on)[args[0]] = args[1];
                                                                                        return args[1];
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns the number of pairs contained in this dict.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("size", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return runtime.NewNumber(Dict.GetMap(on).Count);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("inspect", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return method.runtime.NewText(Dict.GetInspect(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a brief text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("notice", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return method.runtime.NewText(Dict.GetNotice(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns all the keys of this dict",
                                                       new TypeCheckingNativeMethod.WithNoArguments("keys", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return method.runtime.NewSet(Dict.GetKeys(on));
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes either one or two or three arguments. if one argument is given, it should be a message chain that will be sent to each object in the dict. the result will be thrown away. if two arguments are given, the first is an unevaluated name that will be set to each of the entries in the dict in succession, and then the second argument will be evaluated in a scope with that argument in it. if three arguments is given, the first one is an unevaluated name that will be set to the index of each element, and the other two arguments are the name of the argument for the value, and the actual code. the code will evaluate in a lexical context, and if the argument name is available outside the context, it will be shadowed. the method will return the dict. the entries yielded will be mimics of Pair.",
                                                       new NativeMethod("each", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositionalUnevaluated("indexOrArgOrCode")
                                                                        .WithOptionalPositionalUnevaluated("argOrCode")
                                                                        .WithOptionalPositionalUnevaluated("code")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                                                                            outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                                                                            on = runtime.Dict.ConvertToThis(on, message, context);

                                                                            var ls = Dict.GetMap(on);
                                                                            switch(message.Arguments.Count) {
                                                                            case 1: {
                                                                                IokeObject code = IokeObject.As(message.Arguments[0], context);

                                                                                foreach(DictionaryEntry o in ls) {
                                                                                    ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, runtime.NewPair(o.Key, o.Value));
                                                                                }
                                                                                break;
                                                                            }
                                                                            case 2: {
                                                                                LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for List#each", message, context);
                                                                                string name = IokeObject.As(message.Arguments[0], context).Name;
                                                                                IokeObject code = IokeObject.As(message.Arguments[1], context);

                                                                                foreach(DictionaryEntry o in ls) {
                                                                                    c.SetCell(name, runtime.NewPair(o.Key, o.Value));
                                                                                    ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext);
                                                                                }
                                                                                break;
                                                                            }
                                                                            case 3: {
                                                                                LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for List#each", message, context);
                                                                                string iname = IokeObject.As(message.Arguments[0], context).Name;
                                                                                string name = IokeObject.As(message.Arguments[1], context).Name;
                                                                                IokeObject code = IokeObject.As(message.Arguments[2], context);

                                                                                int index = 0;
                                                                                foreach(DictionaryEntry o in ls) {
                                                                                    c.SetCell(name, runtime.NewPair(o.Key, o.Value));
                                                                                    c.SetCell(iname, runtime.NewNumber(index++));
                                                                                    ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext);
                                                                                }
                                                                                break;
                                                                            }
                                                                            }
                                                                            return on;
                                                                        })));
        }
Пример #5
0
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;
            obj.Kind = "Regexp Match";

            obj.RegisterMethod(runtime.NewNativeMethod("Returns the target that this match was created against",
                                                       new TypeCheckingNativeMethod.WithNoArguments("target", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return GetTarget(on);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all the named groups in the regular expression used to create this match",
                                                       new TypeCheckingNativeMethod.WithNoArguments("names", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var names = Regexp.GetRegexp(GetRegexp(on)).GroupNames;
                                                                                                        var theNames = new SaneArrayList();
                                                                                                        foreach(object name in names) {
                                                                                                            theNames.Add(context.runtime.GetSymbol(((string)name)));
                                                                                                        }
                                                                                                        return context.runtime.NewList(theNames);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the part of the target before the text that matched",
                                                       new TypeCheckingNativeMethod.WithNoArguments("beforeMatch", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return context.runtime.NewText(GetMatchResult(on).Prefix);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the part of the target after the text that matched",
                                                       new TypeCheckingNativeMethod.WithNoArguments("afterMatch", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return context.runtime.NewText(GetMatchResult(on).Suffix);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the text that matched",
                                                       new TypeCheckingNativeMethod.WithNoArguments("match", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return context.runtime.NewText(GetMatchResult(on).Group(0));
                                                                                                    })));

            obj.AliasMethod("match", "asText", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("returns the number of groups available in this match",
                                                       new TypeCheckingNativeMethod.WithNoArguments("length", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        return context.runtime.NewNumber(GetMatchResult(on).GroupCount);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all groups captured in this match. if a group is not matched it will be nil in the list. the actual match text is not included in this list.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("captures", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var groups = new SaneArrayList();
                                                                                                        MatchResult mr = GetMatchResult(on);
                                                                                                        int len = mr.GroupCount;
                                                                                                        for(int i=1;i<len;i++) {
                                                                                                            if(mr.IsCaptured(i)) {
                                                                                                                groups.Add(context.runtime.NewText(mr.Group(i)));
                                                                                                            } else {
                                                                                                                groups.Add(context.runtime.nil);
                                                                                                            }
                                                                                                        }

                                                                                                        return context.runtime.NewList(groups);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all groups captured in this match. if a group is not matched it will be nil in the list. the actual match text is the first element in the list.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("asList", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                                                                                                        var groups = new SaneArrayList();
                                                                                                        MatchResult mr = GetMatchResult(on);
                                                                                                        int len = mr.GroupCount;
                                                                                                        for(int i=0;i<len;i++) {
                                                                                                            if(mr.IsCaptured(i)) {
                                                                                                                groups.Add(context.runtime.NewText(mr.Group(i)));
                                                                                                            } else {
                                                                                                                groups.Add(context.runtime.nil);
                                                                                                            }
                                                                                                        }

                                                                                                        return context.runtime.NewList(groups);
                                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one optional argument that should be either a number or a symbol. this should be the name or index of a group to return the start index for. if no index is supplied, 0 is the default. if the group in question wasn't matched, returns -1.",
                                                       new TypeCheckingNativeMethod("start", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithOptionalPositional("index", "0")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        int index = 0;

                                                                                        if(args.Count > 0) {
                                                                                            object arg = args[0];
                                                                                            if(IokeObject.dataOf(arg) is Number) {
                                                                                                index = Number.ExtractInt(arg, message, context);
                                                                                            } else {
                                                                                                string namedIndex = Text.GetText(((Message)IokeObject.dataOf(context.runtime.asText)).SendTo(context.runtime.asText, context, arg));
                                                                                                int ix = -1;
                                                                                                try {
                                                                                                    ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                                                                                                } catch(Exception) {
                                                                                                    return context.runtime.NewNumber(-1);
                                                                                                }
                                                                                                index = ix;
                                                                                            }
                                                                                        }
                                                                                        MatchResult mr = GetMatchResult(on);
                                                                                        if(index < mr.GroupCount && mr.IsCaptured(index)) {
                                                                                            return context.runtime.NewNumber(mr.GetStart(index));
                                                                                        } else {
                                                                                            return context.runtime.NewNumber(-1);
                                                                                        }
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one optional argument that should be either a number or a symbol. this should be the name or index of a group to return the end index for. if no index is supplied, 0 is the default. if the group in question wasn't matched, returns -1.",
                                                       new TypeCheckingNativeMethod("end", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithOptionalPositional("index", "0")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        int index = 0;

                                                                                        if(args.Count > 0) {
                                                                                            object arg = args[0];
                                                                                            if(IokeObject.dataOf(arg) is Number) {
                                                                                                index = Number.ExtractInt(arg, message, context);
                                                                                            } else {
                                                                                                string namedIndex = Text.GetText(((Message)IokeObject.dataOf(context.runtime.asText)).SendTo(context.runtime.asText, context, arg));
                                                                                                int ix = -1;
                                                                                                try {
                                                                                                    ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                                                                                                } catch(Exception) {
                                                                                                    return context.runtime.NewNumber(-1);
                                                                                                }
                                                                                                index = ix;
                                                                                            }
                                                                                        }
                                                                                        MatchResult mr = GetMatchResult(on);
                                                                                        if(index < mr.GroupCount && mr.IsCaptured(index)) {
                                                                                            return context.runtime.NewNumber(mr.GetEnd(index));
                                                                                        } else {
                                                                                            return context.runtime.NewNumber(-1);
                                                                                        }
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one optional argument that should be either a number or a symbol. this should be the name or index of a group to return the start and end index for. if no index is supplied, 0 is the default. if the group in question wasn't matched, returns nil, otherwise a pair of the start and end indices.",
                                                       new TypeCheckingNativeMethod("offset", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithOptionalPositional("index", "0")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        int index = 0;

                                                                                        if(args.Count > 0) {
                                                                                            object arg = args[0];
                                                                                            if(IokeObject.dataOf(arg) is Number) {
                                                                                                index = Number.ExtractInt(arg, message, context);
                                                                                            } else {
                                                                                                string namedIndex = Text.GetText(((Message)IokeObject.dataOf(context.runtime.asText)).SendTo(context.runtime.asText, context, arg));
                                                                                                int ix = -1;
                                                                                                try {
                                                                                                    ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                                                                                                } catch(Exception) {
                                                                                                    return context.runtime.nil;
                                                                                                }
                                                                                                index = ix;
                                                                                            }
                                                                                        }
                                                                                        MatchResult mr = GetMatchResult(on);
                                                                                        if(index < mr.GroupCount && mr.IsCaptured(index)) {
                                                                                            return context.runtime.NewPair(context.runtime.NewNumber(mr.GetStart(index)), context.runtime.NewNumber(mr.GetEnd(index)));
                                                                                        } else {
                                                                                            return context.runtime.nil;
                                                                                        }
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one indexing argument that should be either a number, a range, a text or a symbol. if it's a number or a range of numbers, these will specify the index of the capture to return. 0 is the whole match. negative indices are interpreted in the usual way. if the range is out of range it will only use as many groups as there are. if it's a text or a sym it will be interpreted as a the name of a named group to return. if an index isn't correct or wasn't matched, it returns nil in those places.",
                                                       new TypeCheckingNativeMethod("[]", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("index")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        object arg = args[0];

                                                                                        MatchResult mr = GetMatchResult(on);

                                                                                        if((IokeObject.dataOf(arg) is Symbol) || (IokeObject.dataOf(arg) is Text)) {
                                                                                            string namedIndex = Text.GetText(((Message)IokeObject.dataOf(context.runtime.asText)).SendTo(context.runtime.asText, context, arg));
                                                                                            int ix = -1;
                                                                                            try {
                                                                                                ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                                                                                            } catch(Exception) {
                                                                                                return context.runtime.nil;
                                                                                            }
                                                                                            if(!mr.IsCaptured(ix)) {
                                                                                                return context.runtime.nil;
                                                                                            }
                                                                                            return context.runtime.NewText(mr.Group(ix));
                                                                                        } else {
                                                                                            int size = mr.GroupCount;

                                                                                            if(IokeObject.dataOf(arg) is Range) {
                                                                                                int first = Number.ExtractInt(Range.GetFrom(arg), message, context);

                                                                                                if(first < 0) {
                                                                                                    return context.runtime.NewList(new SaneArrayList());
                                                                                                }

                                                                                                int last = Number.ExtractInt(Range.GetTo(arg), message, context);
                                                                                                bool inclusive = Range.IsInclusive(arg);

                                                                                                if(last < 0) {
                                                                                                    last = size + last;
                                                                                                }

                                                                                                if(last < 0) {
                                                                                                    return context.runtime.NewList(new SaneArrayList());
                                                                                                }

                                                                                                if(last >= size) {
                                                                                                    last = inclusive ? size-1 : size;
                                                                                                }

                                                                                                if(first > last || (!inclusive && first == last)) {
                                                                                                    return context.runtime.NewList(new SaneArrayList());
                                                                                                }

                                                                                                if(!inclusive) {
                                                                                                    last--;
                                                                                                }

                                                                                                var result = new SaneArrayList();
                                                                                                for(int i = first; i < last+1; i++) {
                                                                                                    if(!mr.IsCaptured(i)) {
                                                                                                        result.Add(context.runtime.nil);
                                                                                                    } else {
                                                                                                        result.Add(context.runtime.NewText(mr.Group(i)));
                                                                                                    }
                                                                                                }

                                                                                                return context.runtime.NewList(result);
                                                                                            }

                                                                                            if(!(IokeObject.dataOf(arg) is Number)) {
                                                                                                arg = IokeObject.ConvertToNumber(arg, message, context);
                                                                                            }
                                                                                            int index = ((Number)IokeObject.dataOf(arg)).AsNativeInteger();
                                                                                            if(index < 0) {
                                                                                                index = size + index;
                                                                                            }

                                                                                            if(index >= 0 && index < size && mr.IsCaptured(index)) {
                                                                                                return context.runtime.NewText(mr.Group(index));
                                                                                            } else {
                                                                                                return context.runtime.nil;
                                                                                            }
                                                                                        }
                                                                                    })));

            obj.RegisterMethod(runtime.NewNativeMethod("will get the named group corresponding to the name of the message, or nil if the named group hasn't been matched. will signal a condition if no such group is defined.",
                                                       new TypeCheckingNativeMethod("pass", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                                                                                        MatchResult mr = GetMatchResult(on);
                                                                                        string name = Message.GetName(message);

                                                                                        int ix = -1;
                                                                                        try {
                                                                                            ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(name);
                                                                                        } catch(Exception) {
                                                                                            IokeObject condition = IokeObject.As(IokeObject.GetCellChain(message.runtime.Condition,
                                                                                                                                                         message,
                                                                                                                                                         context,
                                                                                                                                                         "Error",
                                                                                                                                                         "NoSuchCell"), context).Mimic(message, context);
                                                                                            condition.SetCell("message", message);
                                                                                            condition.SetCell("context", context);
                                                                                            condition.SetCell("receiver", on);
                                                                                            condition.SetCell("cellName", message.runtime.GetSymbol(name));

                                                                                            message.runtime.WithReturningRestart("ignore", context, ()=>{condition.runtime.ErrorCondition(condition);});
                                                                                            return context.runtime.nil;
                                                                                        }

                                                                                        if(mr.IsCaptured(ix)) {
                                                                                            return context.runtime.NewText(mr.Group(ix));
                                                                                        } else {
                                                                                            return context.runtime.nil;
                                                                                        }
                                                                                    })));
        }
Пример #6
0
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;

            obj.Kind = "Dict";
            obj.Mimics(IokeObject.As(IokeObject.FindCell(runtime.Mixins, "Sequenced"), null), runtime.nul, runtime.nul);

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a hash for the dictionary",
                                                           new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                return(context.runtime.NewNumber(((Dict)IokeObject.dataOf(on)).dict.GetHashCode()));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if the left hand side dictionary is equal to the right hand side dictionary.",
                                                       new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(runtime.Dict)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                Dict d       = (Dict)IokeObject.dataOf(on);
                object other = args[0];
                return(((other is IokeObject) &&
                        (IokeObject.dataOf(other) is Dict) &&
                        d.dict.Equals(((Dict)IokeObject.dataOf(other)).dict)) ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument, that should be a default value, and returns a new mimic of the receiver, with the default value for that new dict set to the argument",
                                                       new TypeCheckingNativeMethod("withDefault", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("defaultValue")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object newDict = IokeObject.Mimic(on, message, context);
                SetDefaultValue(newDict, IokeObject.As(args[0], context));
                return(newDict);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("creates a new Dict from the arguments provided, combined with the values in the receiver. the arguments provided will override those in the receiver. the rules for arguments are the same as for dict, except that dicts can also be provided. all positional arguments will be added before the keyword arguments.",
                                                       new TypeCheckingNativeMethod("merge", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRest("pairsAndDicts")
                                                                                    .WithKeywordRest("keywordPairs")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                var newMap = new SaneHashtable();
                foreach (DictionaryEntry de in GetMap(on))
                {
                    newMap[de.Key] = de.Value;
                }

                foreach (object o in args)
                {
                    if (IokeObject.dataOf(o) is Dict)
                    {
                        foreach (DictionaryEntry de in GetMap(o))
                        {
                            newMap[de.Key] = de.Value;
                        }
                    }
                    else if (IokeObject.dataOf(o) is Pair)
                    {
                        newMap[Pair.GetFirst(o)] = Pair.GetSecond(o);
                    }
                    else
                    {
                        newMap[o] = context.runtime.nil;
                    }
                }
                foreach (var entry in keywords)
                {
                    string s     = entry.Key;
                    object key   = context.runtime.GetSymbol(s.Substring(0, s.Length - 1));
                    object value = entry.Value;
                    if (value == null)
                    {
                        value = context.runtime.nil;
                    }
                    newMap[key] = value;
                }

                return(context.runtime.NewDict(newMap));
            })));

            obj.AliasMethod("merge", "+", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument, the key of the element to return. if the key doesn't map to anything in the dict, returns the default value",
                                                       new TypeCheckingNativeMethod("at", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("key")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object result = Dict.GetMap(on)[args[0]];
                if (result == null)
                {
                    return(GetDefaultValue(on, context, message));
                }
                else
                {
                    return(result);
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if this dict is empty, false otherwise",
                                                       new TypeCheckingNativeMethod.WithNoArguments("empty?", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(Dict.GetMap(on).Count == 0 ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes one argument, the key to check if it is in the dict.",
                                                       new TypeCheckingNativeMethod("key?", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("key")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                return((Dict.GetMap(on).Contains(args[0])) ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes two arguments, the key of the element to set and the value to set it too. returns the value set",
                                                       new TypeCheckingNativeMethod("[]=", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("key")
                                                                                    .WithRequiredPositional("value")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                Dict.GetMap(on)[args[0]] = args[1];
                return(args[1]);
            })));


            obj.RegisterMethod(runtime.NewNativeMethod("Returns the number of pairs contained in this dict.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("size", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(runtime.NewNumber(Dict.GetMap(on).Count));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("inspect", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(method.runtime.NewText(Dict.GetInspect(on)));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a brief text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("notice", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(method.runtime.NewText(Dict.GetNotice(on)));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns all the keys of this dict",
                                                       new TypeCheckingNativeMethod.WithNoArguments("keys", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(method.runtime.NewSet(Dict.GetKeys(on)));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a new sequence to iterate over this dictionary",
                                                       new TypeCheckingNativeMethod.WithNoArguments("seq", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                IokeObject ob = method.runtime.KeyValueIteratorSequence.AllocateCopy(null, null);
                ob.MimicsWithoutCheck(method.runtime.KeyValueIteratorSequence);
                ob.Data = new Sequence.KeyValueIteratorSequence(Dict.GetMap(on).GetEnumerator());
                return(ob);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("takes either one or two or three arguments. if one argument is given, it should be a message chain that will be sent to each object in the dict. the result will be thrown away. if two arguments are given, the first is an unevaluated name that will be set to each of the entries in the dict in succession, and then the second argument will be evaluated in a scope with that argument in it. if three arguments is given, the first one is an unevaluated name that will be set to the index of each element, and the other two arguments are the name of the argument for the value, and the actual code. the code will evaluate in a lexical context, and if the argument name is available outside the context, it will be shadowed. the method will return the dict. the entries yielded will be mimics of Pair.",
                                                       new NativeMethod("each", DefaultArgumentsDefinition.builder()
                                                                        .WithOptionalPositionalUnevaluated("indexOrArgOrCode")
                                                                        .WithOptionalPositionalUnevaluated("argOrCode")
                                                                        .WithOptionalPositionalUnevaluated("code")
                                                                        .Arguments,
                                                                        (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                on = runtime.Dict.ConvertToThis(on, message, context);

                var ls = Dict.GetMap(on);
                switch (message.Arguments.Count)
                {
                case 0: {
                    return(Interpreter.Send(runtime.seqMessage, context, on));
                }

                case 1: {
                    IokeObject code = IokeObject.As(message.Arguments[0], context);

                    foreach (DictionaryEntry o in ls)
                    {
                        context.runtime.interpreter.Evaluate(code, context, context.RealContext, runtime.NewPair(o.Key, o.Value));
                    }
                    break;
                }

                case 2: {
                    IokeObject c    = context.runtime.NewLexicalContext(context, "Lexical activation context for Dict#each", context);
                    string name     = IokeObject.As(message.Arguments[0], context).Name;
                    IokeObject code = IokeObject.As(message.Arguments[1], context);

                    foreach (DictionaryEntry o in ls)
                    {
                        c.SetCell(name, runtime.NewPair(o.Key, o.Value));
                        context.runtime.interpreter.Evaluate(code, c, c.RealContext, c);
                    }
                    break;
                }

                case 3: {
                    IokeObject c    = context.runtime.NewLexicalContext(context, "Lexical activation context for Dict#each", context);
                    string iname    = IokeObject.As(message.Arguments[0], context).Name;
                    string name     = IokeObject.As(message.Arguments[1], context).Name;
                    IokeObject code = IokeObject.As(message.Arguments[2], context);

                    int index = 0;
                    foreach (DictionaryEntry o in ls)
                    {
                        c.SetCell(name, runtime.NewPair(o.Key, o.Value));
                        c.SetCell(iname, runtime.NewNumber(index++));
                        context.runtime.interpreter.Evaluate(code, c, c.RealContext, c);
                    }
                    break;
                }
                }
                return(on);
            })));
        }
Пример #7
0
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;

            obj.Kind = "Regexp Match";

            obj.RegisterMethod(runtime.NewNativeMethod("Returns the target that this match was created against",
                                                       new TypeCheckingNativeMethod.WithNoArguments("target", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(GetTarget(on));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all the named groups in the regular expression used to create this match",
                                                       new TypeCheckingNativeMethod.WithNoArguments("names", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                var names    = Regexp.GetRegexp(GetRegexp(on)).GroupNames;
                var theNames = new SaneArrayList();
                foreach (object name in names)
                {
                    theNames.Add(context.runtime.GetSymbol(((string)name)));
                }
                return(context.runtime.NewList(theNames));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the part of the target before the text that matched",
                                                       new TypeCheckingNativeMethod.WithNoArguments("beforeMatch", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(context.runtime.NewText(GetMatchResult(on).Prefix));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the part of the target after the text that matched",
                                                       new TypeCheckingNativeMethod.WithNoArguments("afterMatch", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(context.runtime.NewText(GetMatchResult(on).Suffix));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the text that matched",
                                                       new TypeCheckingNativeMethod.WithNoArguments("match", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(context.runtime.NewText(GetMatchResult(on).Group(0)));
            })));

            obj.AliasMethod("match", "asText", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("returns the number of groups available in this match",
                                                       new TypeCheckingNativeMethod.WithNoArguments("length", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(context.runtime.NewNumber(GetMatchResult(on).GroupCount));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all groups captured in this match. if a group is not matched it will be nil in the list. the actual match text is not included in this list.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("captures", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                var groups     = new SaneArrayList();
                MatchResult mr = GetMatchResult(on);
                int len        = mr.GroupCount;
                for (int i = 1; i < len; i++)
                {
                    if (mr.IsCaptured(i))
                    {
                        groups.Add(context.runtime.NewText(mr.Group(i)));
                    }
                    else
                    {
                        groups.Add(context.runtime.nil);
                    }
                }

                return(context.runtime.NewList(groups));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all groups captured in this match. if a group is not matched it will be nil in the list. the actual match text is the first element in the list.",
                                                       new TypeCheckingNativeMethod.WithNoArguments("asList", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                var groups     = new SaneArrayList();
                MatchResult mr = GetMatchResult(on);
                int len        = mr.GroupCount;
                for (int i = 0; i < len; i++)
                {
                    if (mr.IsCaptured(i))
                    {
                        groups.Add(context.runtime.NewText(mr.Group(i)));
                    }
                    else
                    {
                        groups.Add(context.runtime.nil);
                    }
                }

                return(context.runtime.NewList(groups));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one optional argument that should be either a number or a symbol. this should be the name or index of a group to return the start index for. if no index is supplied, 0 is the default. if the group in question wasn't matched, returns -1.",
                                                       new TypeCheckingNativeMethod("start", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithOptionalPositional("index", "0")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                int index = 0;

                if (args.Count > 0)
                {
                    object arg = args[0];
                    if (IokeObject.dataOf(arg) is Number)
                    {
                        index = Number.ExtractInt(arg, message, context);
                    }
                    else
                    {
                        string namedIndex = Text.GetText(Interpreter.Send(context.runtime.asText, context, arg));
                        int ix            = -1;
                        try {
                            ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                        } catch (Exception) {
                            return(context.runtime.NewNumber(-1));
                        }
                        index = ix;
                    }
                }
                MatchResult mr = GetMatchResult(on);
                if (index < mr.GroupCount && mr.IsCaptured(index))
                {
                    return(context.runtime.NewNumber(mr.GetStart(index)));
                }
                else
                {
                    return(context.runtime.NewNumber(-1));
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one optional argument that should be either a number or a symbol. this should be the name or index of a group to return the end index for. if no index is supplied, 0 is the default. if the group in question wasn't matched, returns -1.",
                                                       new TypeCheckingNativeMethod("end", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithOptionalPositional("index", "0")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                int index = 0;

                if (args.Count > 0)
                {
                    object arg = args[0];
                    if (IokeObject.dataOf(arg) is Number)
                    {
                        index = Number.ExtractInt(arg, message, context);
                    }
                    else
                    {
                        string namedIndex = Text.GetText(Interpreter.Send(context.runtime.asText, context, arg));
                        int ix            = -1;
                        try {
                            ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                        } catch (Exception) {
                            return(context.runtime.NewNumber(-1));
                        }
                        index = ix;
                    }
                }
                MatchResult mr = GetMatchResult(on);
                if (index < mr.GroupCount && mr.IsCaptured(index))
                {
                    return(context.runtime.NewNumber(mr.GetEnd(index)));
                }
                else
                {
                    return(context.runtime.NewNumber(-1));
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one optional argument that should be either a number or a symbol. this should be the name or index of a group to return the start and end index for. if no index is supplied, 0 is the default. if the group in question wasn't matched, returns nil, otherwise a pair of the start and end indices.",
                                                       new TypeCheckingNativeMethod("offset", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithOptionalPositional("index", "0")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                int index = 0;

                if (args.Count > 0)
                {
                    object arg = args[0];
                    if (IokeObject.dataOf(arg) is Number)
                    {
                        index = Number.ExtractInt(arg, message, context);
                    }
                    else
                    {
                        string namedIndex = Text.GetText(Interpreter.Send(context.runtime.asText, context, arg));
                        int ix            = -1;
                        try {
                            ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                        } catch (Exception) {
                            return(context.runtime.nil);
                        }
                        index = ix;
                    }
                }
                MatchResult mr = GetMatchResult(on);
                if (index < mr.GroupCount && mr.IsCaptured(index))
                {
                    return(context.runtime.NewPair(context.runtime.NewNumber(mr.GetStart(index)), context.runtime.NewNumber(mr.GetEnd(index))));
                }
                else
                {
                    return(context.runtime.nil);
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one indexing argument that should be either a number, a range, a text or a symbol. if it's a number or a range of numbers, these will specify the index of the capture to return. 0 is the whole match. negative indices are interpreted in the usual way. if the range is out of range it will only use as many groups as there are. if it's a text or a sym it will be interpreted as a the name of a named group to return. if an index isn't correct or wasn't matched, it returns nil in those places.",
                                                       new TypeCheckingNativeMethod("[]", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("index")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg = args[0];

                MatchResult mr = GetMatchResult(on);

                if ((IokeObject.dataOf(arg) is Symbol) || (IokeObject.dataOf(arg) is Text))
                {
                    string namedIndex = Text.GetText(Interpreter.Send(context.runtime.asText, context, arg));
                    int ix            = -1;
                    try {
                        ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(namedIndex);
                    } catch (Exception) {
                        return(context.runtime.nil);
                    }
                    if (!mr.IsCaptured(ix))
                    {
                        return(context.runtime.nil);
                    }
                    return(context.runtime.NewText(mr.Group(ix)));
                }
                else
                {
                    int size = mr.GroupCount;

                    if (IokeObject.dataOf(arg) is Range)
                    {
                        int first = Number.ExtractInt(Range.GetFrom(arg), message, context);

                        if (first < 0)
                        {
                            return(context.runtime.NewList(new SaneArrayList()));
                        }

                        int last       = Number.ExtractInt(Range.GetTo(arg), message, context);
                        bool inclusive = Range.IsInclusive(arg);


                        if (last < 0)
                        {
                            last = size + last;
                        }

                        if (last < 0)
                        {
                            return(context.runtime.NewList(new SaneArrayList()));
                        }

                        if (last >= size)
                        {
                            last = inclusive ? size - 1 : size;
                        }

                        if (first > last || (!inclusive && first == last))
                        {
                            return(context.runtime.NewList(new SaneArrayList()));
                        }

                        if (!inclusive)
                        {
                            last--;
                        }

                        var result = new SaneArrayList();
                        for (int i = first; i < last + 1; i++)
                        {
                            if (!mr.IsCaptured(i))
                            {
                                result.Add(context.runtime.nil);
                            }
                            else
                            {
                                result.Add(context.runtime.NewText(mr.Group(i)));
                            }
                        }

                        return(context.runtime.NewList(result));
                    }

                    if (!(IokeObject.dataOf(arg) is Number))
                    {
                        arg = IokeObject.ConvertToNumber(arg, message, context);
                    }
                    int index = ((Number)IokeObject.dataOf(arg)).AsNativeInteger();
                    if (index < 0)
                    {
                        index = size + index;
                    }

                    if (index >= 0 && index < size && mr.IsCaptured(index))
                    {
                        return(context.runtime.NewText(mr.Group(index)));
                    }
                    else
                    {
                        return(context.runtime.nil);
                    }
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("will get the named group corresponding to the name of the message, or nil if the named group hasn't been matched. will signal a condition if no such group is defined.",
                                                       new TypeCheckingNativeMethod("pass", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                MatchResult mr = GetMatchResult(on);
                string name    = Message.GetName(message);

                int ix = -1;
                try {
                    ix = Regexp.GetRegexp(GetRegexp(on)).GroupId(name);
                } catch (Exception) {
                    IokeObject condition = IokeObject.As(IokeObject.GetCellChain(message.runtime.Condition,
                                                                                 message,
                                                                                 context,
                                                                                 "Error",
                                                                                 "NoSuchCell"), context).Mimic(message, context);
                    condition.SetCell("message", message);
                    condition.SetCell("context", context);
                    condition.SetCell("receiver", on);
                    condition.SetCell("cellName", message.runtime.GetSymbol(name));

                    message.runtime.WithReturningRestart("ignore", context, () => { condition.runtime.ErrorCondition(condition); });
                    return(context.runtime.nil);
                }

                if (mr.IsCaptured(ix))
                {
                    return(context.runtime.NewText(mr.Group(ix)));
                }
                else
                {
                    return(context.runtime.nil);
                }
            })));
        }
Пример #8
0
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;

            obj.Kind = "Regexp";

            IokeObject regexpMatch = new IokeObject(runtime, "contains behavior related to assignment", new RegexpMatch(obj, null, null));

            regexpMatch.MimicsWithoutCheck(runtime.Origin);
            regexpMatch.Init();
            obj.RegisterCell("Match", regexpMatch);

            obj.RegisterMethod(runtime.NewNativeMethod("returns a hash for the regexp",
                                                       new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                Regexp r = (Regexp)IokeObject.dataOf(on);
                return(context.runtime.NewNumber(r.pattern.GetHashCode() + 13 * r.flags.GetHashCode()));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if the left hand side pattern is equal to the right hand side pattern.",
                                                       new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(runtime.Regexp)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                Regexp d     = (Regexp)IokeObject.dataOf(on);
                object other = args[0];

                return(((other is IokeObject) &&
                        (IokeObject.dataOf(other) is Regexp) &&
                        ((on == context.runtime.Regexp || other == context.runtime.Regexp) ? on == other :
                         (d.pattern.Equals(((Regexp)IokeObject.dataOf(other)).pattern) &&
                          d.flags.Equals(((Regexp)IokeObject.dataOf(other)).flags)))) ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns the pattern use for this regular expression",
                                                       new TypeCheckingNativeMethod.WithNoArguments("pattern", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(context.runtime.NewText(GetPattern(on)));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one argument and tries to match that argument against the current pattern. Returns nil if no match can be done, or a Regexp Match object if a match succeeds",
                                                       new TypeCheckingNativeMethod("match", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                IokeObject target = IokeObject.As(Interpreter.Send(context.runtime.asText, context, args[0]), context);
                string arg        = Text.GetText(target);
                Matcher m         = ((Regexp)IokeObject.dataOf(on)).regexp.Matcher(arg);

                if (m.Find())
                {
                    IokeObject match = regexpMatch.AllocateCopy(message, context);
                    match.MimicsWithoutCheck(regexpMatch);
                    match.Data = new RegexpMatch(IokeObject.As(on, context), m, target);
                    return(match);
                }
                else
                {
                    return(context.runtime.nil);
                }
            })));

            obj.AliasMethod("match", "=~", null, null);

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one argument that should be a text and returns a text that has all regexp meta characters quoted",
                                                       new NativeMethod("quote", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositional("text")
                                                                        .Arguments,
                                                                        (method, on, args, keywords, context, message) => {
                return(context.runtime.NewText(Pattern.Quote(Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0])))));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one or two text arguments that describes the regular expression to create. the first text is the pattern and the second is the flags.",
                                                       new NativeMethod("from", DefaultArgumentsDefinition.builder()
                                                                        .WithRequiredPositional("pattern")
                                                                        .WithOptionalPositional("flags", "")
                                                                        .Arguments,
                                                                        (method, on, args, keywords, context, message) => {
                string pattern = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                string flags   = "";
                if (args.Count > 1)
                {
                    flags = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[1]));
                }

                return(context.runtime.NewRegexp(pattern, flags, context, message));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Takes one argument and tries to match that argument against the current pattern. Returns a list of all the texts that were matched.",
                                                       new TypeCheckingNativeMethod("allMatches", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                string arg = Text.GetText(Interpreter.Send(context.runtime.asText, context, args[0]));
                Matcher m  = ((Regexp)IokeObject.dataOf(on)).regexp.Matcher(arg);

                var result         = new SaneArrayList();
                MatchIterator iter = m.FindAll();
                while (iter.HasMore)
                {
                    result.Add(runtime.NewText(iter.NextMatch.Group(0)));
                }

                return(runtime.NewList(result));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("inspect", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(method.runtime.NewText(Regexp.GetInspect(on)));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a brief text inspection of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("notice", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(method.runtime.NewText(Regexp.GetNotice(on)));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns a list of all the named groups in this regular expression",
                                                       new TypeCheckingNativeMethod.WithNoArguments("names", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                var names    = Regexp.GetRegexp(on).GroupNames;
                var theNames = new SaneArrayList();
                foreach (object name in names)
                {
                    theNames.Add(context.runtime.GetSymbol(((string)name)));
                }
                return(context.runtime.NewList(theNames));
            })));
        }