public override object Activate(IokeObject self, IokeObject dynamicContext, IokeObject message, object on) { if(code == null) { IokeObject condition = IokeObject.As(IokeObject.GetCellChain(dynamicContext.runtime.Condition, message, dynamicContext, "Error", "Invocation", "NotActivatable"), dynamicContext).Mimic(message, dynamicContext); condition.SetCell("message", message); condition.SetCell("context", dynamicContext); condition.SetCell("receiver", on); condition.SetCell("method", self); condition.SetCell("report", dynamicContext.runtime.NewText("You tried to activate a method without any code - did you by any chance activate the LexicalMacro kind by referring to it without wrapping it inside a call to cell?")); dynamicContext.runtime.ErrorCondition(condition); return null; } LexicalContext c = new LexicalContext(self.runtime, on, "Lexical macro activation context", message, this.context); c.SetCell("outerScope", context); c.SetCell("call", dynamicContext.runtime.NewCallFrom(c, message, dynamicContext, IokeObject.As(on, dynamicContext))); return ((Message)IokeObject.dataOf(this.code)).EvaluateCompleteWith(this.code, c, on); }
public override object ActivateWithCallAndData(IokeObject self, IokeObject dynamicContext, IokeObject message, object on, object call, IDictionary<string, object> data) { LexicalContext c = new LexicalContext(self.runtime, on, "Lexical activation context", message, this.context); foreach(var d in data) { string s = d.Key; c.SetCell(s.Substring(0, s.Length-1), d.Value); } arguments.AssignArgumentValues(c, dynamicContext, message, on, ((Call)IokeObject.dataOf(call))); return ((Message)IokeObject.dataOf(this.message)).EvaluateCompleteWith(this.message, c, on); }
public static void Init(IokeObject obj) { Runtime runtime = obj.runtime; obj.Kind = "DefaultBehavior FlowControl"; obj.RegisterMethod(runtime.NewNativeMethod("evaluates the first arguments, and then evaluates the second argument if the result was true, otherwise the last argument. returns the result of the call, or the result if it's not true.", new NativeMethod("if", DefaultArgumentsDefinition.builder() .WithRequiredPositional("condition") .WithOptionalPositionalUnevaluated("then") .WithOptionalPositionalUnevaluated("else") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); object test = ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 0, context); LexicalContext itContext = new LexicalContext(context.runtime, context.RealContext, "Lexical activation context", message, context); itContext.SetCell("it", test); if(IokeObject.IsObjectTrue(test)) { if(message.Arguments.Count > 1) { return ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 1, itContext); } else { return test; } } else { if(message.Arguments.Count > 2) { return ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 2, itContext); } else { return test; } } }))); obj.RegisterMethod(runtime.NewNativeMethod("evaluates the first arguments, and then evaluates the second argument if the result was false, otherwise the last argument. returns the result of the call, or the result if it's true.", new NativeMethod("unless", DefaultArgumentsDefinition.builder() .WithRequiredPositional("condition") .WithOptionalPositionalUnevaluated("then") .WithOptionalPositionalUnevaluated("else") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); object test = ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 0, context); LexicalContext itContext = new LexicalContext(context.runtime, context.RealContext, "Lexical activation context", message, context); itContext.SetCell("it", test); if(IokeObject.IsObjectTrue(test)) { if(message.Arguments.Count > 2) { return ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 2, itContext); } else { return test; } } else { if(message.Arguments.Count > 1) { return ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 1, itContext); } else { return test; } } }))); obj.RegisterMethod(runtime.NewNativeMethod("takes zero or more place and value pairs and one code argument, establishes a new lexical scope and binds the places to the values given. if the place is a simple name, it will just be created as a new binding in the lexical scope. if it is a place specification, that place will be temporarily changed - but guaranteed to be changed back after the lexical scope is finished. the let-form returns the final result of the code argument.", new NativeMethod("let", DefaultArgumentsDefinition.builder() .WithRestUnevaluated("placesAndValues") .WithRequiredPositionalUnevaluated("code") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); var args = message.Arguments; LexicalContext lc = new LexicalContext(context.runtime, context.RealContext, "Let lexical activation context", message, context); int ix = 0; int end = args.Count-1; var valuesToUnbind = new LinkedList<object[]>(); try { while(ix < end) { IokeObject place = IokeObject.As(args[ix++], context); if(Message.GetNext(place) == null && place.Arguments.Count == 0) { object value = ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, ix++, context); lc.SetCell(Message.GetName(place), value); } else { place = Message.DeepCopy(place); IokeObject realPlace = place; while(Message.GetNext(realPlace) != null) { if(Message.GetNext(Message.GetNext(realPlace)) == null) { IokeObject temp = Message.GetNext(realPlace); Message.SetNext(realPlace, null); realPlace = temp; } else { realPlace = Message.GetNext(realPlace); } } object wherePlace = context.RealContext; if(place != realPlace) { wherePlace = Message.GetEvaluatedArgument(place, context); } object originalValue = runtime.WithReturningRescue(context, null, () => {return ((Message)IokeObject.dataOf(realPlace)).SendTo(realPlace, context, wherePlace);}); if(realPlace.Arguments.Count != 0) { string newName = realPlace.Name + "="; var arguments = new SaneArrayList(realPlace.Arguments); arguments.Add(args[ix++]); IokeObject msg = context.runtime.NewMessageFrom(realPlace, newName, arguments); ((Message)IokeObject.dataOf(msg)).SendTo(msg, context, wherePlace); valuesToUnbind.AddFirst(new object[]{wherePlace, originalValue, realPlace}); } else { object value = ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, ix++, context); IokeObject.Assign(wherePlace, realPlace.Name, value, context, message); valuesToUnbind.AddFirst(new object[]{wherePlace, originalValue, realPlace}); } } } return ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, end, lc); } finally { while(valuesToUnbind.Count > 0) { try { object[] vals = valuesToUnbind.First.Value; valuesToUnbind.RemoveFirst(); IokeObject wherePlace = IokeObject.As(vals[0], context); object value = vals[1]; IokeObject realPlace = IokeObject.As(vals[2], context); if(realPlace.Arguments.Count != 0) { string newName = realPlace.Name + "="; var arguments = new SaneArrayList(realPlace.Arguments); if(value == null) { if(newName.Equals("cell=")) { ((Message)IokeObject.dataOf(context.runtime.removeCellMessage)).SendTo(context.runtime.removeCellMessage, context, wherePlace, new SaneArrayList(realPlace.Arguments)); } else { arguments.Add(context.runtime.CreateMessage(Message.Wrap(context.runtime.nil))); IokeObject msg = context.runtime.NewMessageFrom(realPlace, newName, arguments); ((Message)IokeObject.dataOf(msg)).SendTo(msg, context, wherePlace); } } else { arguments.Add(context.runtime.CreateMessage(Message.Wrap(IokeObject.As(value, context)))); IokeObject msg = context.runtime.NewMessageFrom(realPlace, newName, arguments); ((Message)IokeObject.dataOf(msg)).SendTo(msg, context, wherePlace); } } else { if(value == null) { IokeObject.RemoveCell(wherePlace, context, message, realPlace.Name); } else { IokeObject.Assign(wherePlace, realPlace.Name, value, context, message); } } } catch(System.Exception) {} } } }))); obj.RegisterMethod(runtime.NewNativeMethod("breaks out of the enclosing context. if an argument is supplied, this will be returned as the result of the object breaking out of", new NativeMethod("break", DefaultArgumentsDefinition.builder() .WithOptionalPositional("value", "nil") .Arguments, (method, context, message, on, outer) => { IList args = new SaneArrayList(); outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary<string, object>()); object value = runtime.nil; if(message.Arguments.Count > 0) { value = ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 0, context); } throw new ControlFlow.Break(value); }))); obj.RegisterMethod(runtime.NewNativeMethod("returns from the enclosing method/macro. if an argument is supplied, this will be returned as the result of the method/macro breaking out of.", new NativeMethod("return", DefaultArgumentsDefinition.builder() .WithOptionalPositional("value", "nil") .Arguments, (method, context, message, on, outer) => { object value = runtime.nil; IList args = new SaneArrayList(); outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary<string, object>()); if(args.Count > 0) { value = args[0]; } IokeObject ctx = context; while(ctx is LexicalContext) { ctx = ((LexicalContext)ctx).surroundingContext; } throw new ControlFlow.Return(value, ctx); }))); obj.RegisterMethod(runtime.NewNativeMethod("breaks out of the enclosing context and continues from that point again.", new NativeMethod.WithNoArguments("continue", (method, context, message, on, outer) => { outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary<string, object>()); throw new ControlFlow.Continue(); }))); obj.RegisterMethod(runtime.NewNativeMethod("until the first argument evaluates to something true, loops and evaluates the next argument", new NativeMethod("until", DefaultArgumentsDefinition.builder() .WithOptionalPositionalUnevaluated("condition") .WithRestUnevaluated("body") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); if(message.Arguments.Count == 0) { return runtime.nil; } bool body = message.Arguments.Count > 1; object ret = runtime.nil; bool doAgain = false; do { doAgain = false; try { while(!IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 0, context))) { if(body) { ret = ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 1, context); } } } catch(ControlFlow.Break e) { ret = e.Value; } catch(ControlFlow.Continue) { doAgain = true; } } while(doAgain); return ret; }))); obj.RegisterMethod(runtime.NewNativeMethod("while the first argument evaluates to something true, loops and evaluates the next argument", new NativeMethod("while", DefaultArgumentsDefinition.builder() .WithOptionalPositionalUnevaluated("condition") .WithRestUnevaluated("body") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); if(message.Arguments.Count == 0) { return runtime.nil; } bool body = message.Arguments.Count > 1; object ret = runtime.nil; bool doAgain = false; do { doAgain = false; try { while(IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 0, context))) { if(body) { ret = ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 1, context); } } } catch(ControlFlow.Break e) { ret = e.Value; } catch(ControlFlow.Continue) { doAgain = true; } } while(doAgain); return ret; }))); obj.RegisterMethod(runtime.NewNativeMethod("loops forever - executing it's argument over and over until interrupted in some way.", new NativeMethod("loop", DefaultArgumentsDefinition.builder() .WithRestUnevaluated("body") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); if(message.Arguments.Count > 0) { while(true) { try { while(true) { ((Message)IokeObject.dataOf(message)).GetEvaluatedArgument(message, 0, context); } } catch(ControlFlow.Break e) { return e.Value; } catch(ControlFlow.Continue) { } } } else { while(true){} } }))); obj.RegisterMethod(runtime.NewNativeMethod("will execute and return the value of the first argument. after the code has run, all the remaining blocks of code are guaranteed to run in order even if a non-local flow control happens inside the main code. if any code in the ensure blocks generate a new non-local flow control, the rest of the ensure blocks in that specific ensure invocation are not guaranteed to run.", new NativeMethod("ensure", DefaultArgumentsDefinition.builder() .WithRequiredPositionalUnevaluated("code") .WithRestUnevaluated("ensureBlocks") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); var args = message.Arguments; int argCount = args.Count; object result = runtime.nil; try { IokeObject msg = IokeObject.As(args[0], context); result = ((Message)IokeObject.dataOf(msg)).EvaluateCompleteWithoutExplicitReceiver(msg, context, context.RealContext); } finally { foreach(object o in ArrayList.Adapter(args).GetRange(1, argCount-1)) { IokeObject msg = IokeObject.As(o, context); ((Message)IokeObject.dataOf(msg)).EvaluateCompleteWithoutExplicitReceiver(msg, context, context.RealContext); } } return result; }))); }
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; }))); }
public override void Init(IokeObject obj) { Runtime runtime = obj.runtime; obj.Kind = "Set"; obj.Mimics(IokeObject.As(runtime.Mixins.GetCell(null, null, "Sequenced"), null), runtime.nul, runtime.nul); obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a hash for the set", new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); return context.runtime.NewNumber(((IokeSet)IokeObject.dataOf(on))._set.GetHashCode()); }))); obj.RegisterMethod(runtime.NewNativeMethod("returns true if the left hand side set is equal to the right hand side set.", new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(runtime.Set) .WithRequiredPositional("other") .Arguments, (method, on, args, keywords, context, message) => { IokeSet d = (IokeSet)IokeObject.dataOf(on); object other = args[0]; return ((other is IokeObject) && (IokeObject.dataOf(other) is IokeSet) && d._set.Equals(((IokeSet)IokeObject.dataOf(other))._set)) ? context.runtime.True : context.runtime.False; }))); 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(IokeSet.GetInspect(on)); }))); obj.RegisterMethod(runtime.NewNativeMethod("Converts this set to use identity semantics, and then returns it.", new TypeCheckingNativeMethod.WithNoArguments("withIdentitySemantics!", obj, (method, on, args, keywords, context, message) => { IokeSet ss = (IokeSet)IokeObject.dataOf(on); ss._set = new SaneHashSet<object>(ss._set, new IdentityHashTable.IdentityEqualityComparer()); return 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(IokeSet.GetNotice(on)); }))); obj.RegisterMethod(runtime.NewNativeMethod("returns true if this set is empty, false otherwise", new TypeCheckingNativeMethod.WithNoArguments("empty?", obj, (method, on, args, keywords, context, message) => { return ((IokeSet)IokeObject.dataOf(on)).Set.Count == 0 ? context.runtime.True : context.runtime.False; }))); obj.RegisterMethod(runtime.NewNativeMethod("Adds the argument to this set, if it's not already in the set. Returns the set after adding the object.", new TypeCheckingNativeMethod("<<", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("value") .Arguments, (method, on, args, keywords, context, message) => { ((IokeSet)IokeObject.dataOf(on))._set.Add(args[0]); return on; }))); obj.RegisterMethod(runtime.NewNativeMethod("Removes the argument from the set, if it's in the set. Returns the set after removing the object.", new TypeCheckingNativeMethod("remove!", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("value") .Arguments, (method, on, args, keywords, context, message) => { ((IokeSet)IokeObject.dataOf(on))._set.Remove(args[0]); return on; }))); obj.RegisterMethod(runtime.NewNativeMethod("returns a new set that contains the receivers elements and the elements of the set sent in as the argument.", new TypeCheckingNativeMethod("+", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("otherSet").WhichMustMimic(obj) .Arguments, (method, on, args, keywords, context, message) => { var newSet = new SaneHashSet<object>(); newSet.UnionWith(((IokeSet)IokeObject.dataOf(on)).Set); newSet.UnionWith(((IokeSet)IokeObject.dataOf(args[0])).Set); return context.runtime.NewSet(newSet); }))); 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 ((IokeSet)IokeObject.dataOf(on)).Set.Contains(args[0]) ? context.runtime.True : context.runtime.False; }))); obj.RegisterMethod(runtime.NewNativeMethod("returns a new sequence to iterate over this set", new TypeCheckingNativeMethod.WithNoArguments("seq", obj, (method, on, args, keywords, context, message) => { IokeObject ob = method.runtime.IteratorSequence.AllocateCopy(null, null); ob.MimicsWithoutCheck(method.runtime.IteratorSequence); ob.Data = new Sequence.IteratorSequence(((IokeSet)IokeObject.dataOf(on))._set.GetEnumerator()); return ob; }))); obj.RegisterMethod(runtime.NewNativeMethod("takes either one, two or three arguments. if one argument is given, it should be a message chain that will be sent to each object in the set. 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 set 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 set. the iteration order is not defined.", new NativeMethod("each", DefaultArgumentsDefinition.builder() .WithOptionalPositionalUnevaluated("indexOrArgOrCode") .WithOptionalPositionalUnevaluated("argOrCode") .WithOptionalPositionalUnevaluated("code") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); object onAsSet = context.runtime.Set.ConvertToThis(on, message, context); var _set = ((IokeSet)IokeObject.dataOf(onAsSet))._set; switch(message.Arguments.Count) { case 0: { return ((Message)IokeObject.dataOf(runtime.seqMessage)).SendTo(runtime.seqMessage, context, on); } case 1: { IokeObject code = IokeObject.As(message.Arguments[0], context); foreach(object o in _set) { ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, o); } break; } case 2: { LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for Set#each", message, context); string name = IokeObject.As(message.Arguments[0], context).Name; IokeObject code = IokeObject.As(message.Arguments[1], context); foreach(object o in _set) { c.SetCell(name, o); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); } break; } case 3: { LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for Set#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(object o in _set) { c.SetCell(name, o); c.SetCell(iname, runtime.NewNumber(index++)); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); } break; } } return onAsSet; }))); }
public override void Init(IokeObject obj) { obj.Kind = "Message"; obj.Mimics(IokeObject.As(obj.runtime.Mixins.GetCell(null, null, "Enumerable"), null), obj.runtime.nul, obj.runtime.nul); obj.RegisterMethod(obj.runtime.NewNativeMethod("Will rearrange this message and all submessages to follow regular C style operator precedence rules. Will use Message OperatorTable to guide this operation. The operation is mutating, but should not change anything if done twice.", new NativeMethod.WithNoArguments("shuffleOperators", (method, context, message, on, outer) => { IOperatorShuffler levels = method.runtime.operatorShufflerFactory.Create(IokeObject.As(on, context), context, message); var expressions = new SaneList<IokeObject>(); if(on is IokeObject) { expressions.Insert(0, IokeObject.As(on, context)); while(expressions.Count > 0) { IokeObject n = expressions[0]; expressions.RemoveAt(0); do { levels.Attach(n, expressions); foreach(object o in n.Arguments) { if(o is IokeObject) { expressions.Insert(0, IokeObject.As(o, context)); } } } while((n = Message.GetNext(n)) != null); levels.NextMessage(expressions); } } return on; }))); 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 ((Message)IokeObject.dataOf(msg)).EvaluateCompleteWithReceiver(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); return ((Message)IokeObject.dataOf(_m)).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: { LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for Message#walk", message, 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() .WithRequiredPositionalUnevaluated("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 1: { IokeObject code = IokeObject.As(message.Arguments[0], context); object o = onAsMessage; while(o != null) { ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, o); o = GetNext(o); } 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); object o = onAsMessage; while(o != null) { c.SetCell(name, o); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); o = GetNext(o); } 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; object o = onAsMessage; while(o != null) { c.SetCell(name, o); c.SetCell(iname, runtime.NewNumber(index++)); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); 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 ((Message)IokeObject.dataOf(msg)).SendTo(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]; IokeObject.As(on, method).Arguments.Clear(); 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); }))); }
private static void WalkWithoutExplicitReceiver(object onAsMessage, LexicalContext c, string name, IokeObject code) { object o = onAsMessage; while(o != null) { c.SetCell(name, o); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); foreach(object arg in ((IokeObject)o).Arguments) { WalkWithoutExplicitReceiver(arg, c, name, code); } o = GetNext(o); } }
public override void Init(IokeObject obj) { Runtime runtime = obj.runtime; obj.Kind = "Range"; obj.Mimics(IokeObject.As(runtime.Mixins.GetCell(null, null, "Enumerable"), null), runtime.nul, runtime.nul); obj.RegisterMethod(runtime.NewNativeMethod("will return a new inclusive Range based on the two arguments", new NativeMethod("inclusive", DefaultArgumentsDefinition.builder() .WithRequiredPositional("from") .WithRequiredPositional("to") .Arguments, (method, context, message, on, outer) => { var args = new SaneArrayList(); outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary<string, object>()); object from = args[0]; object to = args[1]; bool comparing = IokeObject.IsMimic(from, IokeObject.As(context.runtime.Mixins.Cells["Comparing"], context), context); bool inverted = false; if(comparing) { object result = ((Message)IokeObject.dataOf(context.runtime.spaceShipMessage)).SendTo(context.runtime.spaceShipMessage, context, from, to); if(result != context.runtime.nil && Number.ExtractInt(result, message, context) == 1) { inverted = true; } } return runtime.NewRange(IokeObject.As(from, context), IokeObject.As(to, context), true, inverted); }))); obj.RegisterMethod(runtime.NewNativeMethod("will return a new exclusive Range based on the two arguments", new NativeMethod("exclusive", DefaultArgumentsDefinition.builder() .WithRequiredPositional("from") .WithRequiredPositional("to") .Arguments, (method, context, message, on, outer) => { var args = new SaneArrayList(); outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary<string, object>()); object from = args[0]; object to = args[1]; bool comparing = IokeObject.IsMimic(from, IokeObject.As(context.runtime.Mixins.Cells["Comparing"], context), context); bool inverted = false; if(comparing) { object result = ((Message)IokeObject.dataOf(context.runtime.spaceShipMessage)).SendTo(context.runtime.spaceShipMessage, context, from, to); if(result != context.runtime.nil && Number.ExtractInt(result, message, context) == 1) { inverted = true; } } return runtime.NewRange(IokeObject.As(from, context), IokeObject.As(to, context), false, inverted); }))); obj.RegisterMethod(runtime.NewNativeMethod("returns true if the receiver is an exclusive range, false otherwise", new NativeMethod.WithNoArguments("exclusive?", (method, context, message, on, outer) => { outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary<string, object>()); return ((Range)IokeObject.dataOf(on)).inclusive ? context.runtime.False : context.runtime.True; }))); obj.RegisterMethod(runtime.NewNativeMethod("returns true if the receiver is an inclusive range, false otherwise", new NativeMethod.WithNoArguments("inclusive?", (method, context, message, on, outer) => { outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary<string, object>()); return ((Range)IokeObject.dataOf(on)).inclusive ? context.runtime.True : context.runtime.False; }))); obj.RegisterMethod(runtime.NewNativeMethod("returns the 'from' part of the range", new TypeCheckingNativeMethod.WithNoArguments("from", obj, (method, on, args, keywords, context, message) => { return ((Range)IokeObject.dataOf(on)).from; }))); obj.RegisterMethod(runtime.NewNativeMethod("returns the 'to' part of the range", new NativeMethod.WithNoArguments("to", (method, context, message, on, outer) => { outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary<string, object>()); return ((Range)IokeObject.dataOf(on)).to; }))); 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 range. 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 range 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 range.", new NativeMethod("each", DefaultArgumentsDefinition.builder() .WithRequiredPositionalUnevaluated("indexOrArgOrCode") .WithOptionalPositionalUnevaluated("argOrCode") .WithOptionalPositionalUnevaluated("code") .Arguments, (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); IokeObject from = IokeObject.As(((Range)IokeObject.dataOf(on)).from, context); IokeObject to = IokeObject.As(((Range)IokeObject.dataOf(on)).to, context); bool inclusive = ((Range)IokeObject.dataOf(on)).inclusive; IokeObject messageToSend = context.runtime.succMessage; if(((Range)IokeObject.dataOf(on)).inverted) { messageToSend = context.runtime.predMessage; } switch(message.Arguments.Count) { case 1: { IokeObject code = IokeObject.As(message.Arguments[0], context); object current = from; while(!IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(context.runtime.eqMessage)).SendTo(context.runtime.eqMessage, context, current, to))) { ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, current); current = ((Message)IokeObject.dataOf(messageToSend)).SendTo(messageToSend, context, current); } if(inclusive) { ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, current); } break; } case 2: { LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for Range#each", message, context); string name = IokeObject.As(message.Arguments[0], context).Name; IokeObject code = IokeObject.As(message.Arguments[1], context); object current = from; while(!IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(context.runtime.eqMessage)).SendTo(context.runtime.eqMessage, context, current, to))) { c.SetCell(name, current); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); current = ((Message)IokeObject.dataOf(messageToSend)).SendTo(messageToSend, context, current); } if(inclusive) { c.SetCell(name, current); ((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; object current = from; while(!IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(context.runtime.eqMessage)).SendTo(context.runtime.eqMessage, context, current, to))) { c.SetCell(name, current); c.SetCell(iname, runtime.NewNumber(index++)); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); current = ((Message)IokeObject.dataOf(messageToSend)).SendTo(messageToSend, context, current); } if(inclusive) { c.SetCell(name, current); c.SetCell(iname, runtime.NewNumber(index++)); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); } break; } } return on; }))); obj.RegisterMethod(runtime.NewNativeMethod("returns true if the argument is within the confines of this range. how this comparison is done depends on if the object mimics Comparing. If it does, < and > will be used. If not, all the available entries in this range will be enumerated using 'succ'/'pred' until either the end or the element we're looking for is found. in that case, comparison is done with '=='", new NativeMethod("===", DefaultArgumentsDefinition.builder() .WithRequiredPositional("other") .Arguments, (method, context, message, on, outer) => { var args = new SaneArrayList(); outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, args, new SaneDictionary<string, object>()); object other = args[0]; IokeObject from = IokeObject.As(((Range)IokeObject.dataOf(on)).from, context); IokeObject to = IokeObject.As(((Range)IokeObject.dataOf(on)).to, context); bool comparing = IokeObject.IsMimic(from, IokeObject.As(context.runtime.Mixins.Cells["Comparing"], context)); bool inclusive = ((Range)IokeObject.dataOf(on)).inclusive; if(comparing) { IokeObject firstMessage = context.runtime.lteMessage; IokeObject secondMessageInclusive = context.runtime.gteMessage; IokeObject secondMessageExclusive = context.runtime.gtMessage; if(((Range)IokeObject.dataOf(on)).inverted) { firstMessage = context.runtime.gteMessage; secondMessageInclusive = context.runtime.lteMessage; secondMessageExclusive = context.runtime.ltMessage; } if(IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(firstMessage)).SendTo(firstMessage, context, from, other)) && ((inclusive && IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(secondMessageInclusive)).SendTo(secondMessageInclusive, context, to, other))) || IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(secondMessageExclusive)).SendTo(secondMessageExclusive, context, to, other)))) { return context.runtime.True; } else { return context.runtime.False; } } else { IokeObject messageToSend = context.runtime.succMessage; if(((Range)IokeObject.dataOf(on)).inverted) { messageToSend = context.runtime.predMessage; } object current = from; while(!IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(context.runtime.eqMessage)).SendTo(context.runtime.eqMessage, context, current, to))) { if(IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(context.runtime.eqMessage)).SendTo(context.runtime.eqMessage, context, current, other))) { return context.runtime.True; } current = ((Message)IokeObject.dataOf(messageToSend)).SendTo(messageToSend, context, current); } if(inclusive && IokeObject.IsObjectTrue(((Message)IokeObject.dataOf(context.runtime.eqMessage)).SendTo(context.runtime.eqMessage, context, to, other))) { return context.runtime.True; } return context.runtime.False; } }))); obj.RegisterMethod(runtime.NewNativeMethod("Returns a text inspection of the object", new NativeMethod.WithNoArguments("inspect", (method, context, message, on, outer) => { outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary<string, object>()); return method.runtime.NewText(Range.GetInspect(on)); }))); obj.RegisterMethod(runtime.NewNativeMethod("Returns a brief text inspection of the object", new NativeMethod.WithNoArguments("notice", (method, context, message, on, outer) => { outer.ArgumentsDefinition.GetEvaluatedArguments(context, message, on, new SaneArrayList(), new SaneDictionary<string, object>()); return method.runtime.NewText(Range.GetNotice(on)); }))); }
public override void Init(IokeObject obj) { Runtime runtime = obj.runtime; obj.Kind = "List"; obj.Mimics(IokeObject.As(runtime.Mixins.GetCell(null, null, "Enumerable"), null), runtime.nul, runtime.nul); 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() .WithRequiredPositionalUnevaluated("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 1: { IokeObject code = IokeObject.As(message.Arguments[0], context); foreach(object o in ls) { ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, o); } 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(object o in ls) { c.SetCell(name, o); ((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(object o in ls) { c.SetCell(name, o); c.SetCell(iname, runtime.NewNumber(index++)); ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); } 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] = ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, ls[i]); } break; } case 2: { LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for List#map!", message, 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] = ((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext); } 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(((Message)IokeObject.dataOf(code)).EvaluateCompleteWithReceiver(code, context, context.RealContext, o1))) { ls.RemoveAt(i); i--; count--; } } break; } case 2: { LexicalContext c = new LexicalContext(context.runtime, context, "Lexical activation context for List#map!", message, 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(((Message)IokeObject.dataOf(code)).EvaluateCompleteWithoutExplicitReceiver(code, c, c.RealContext))) { ls.RemoveAt(i); i--; count--; } } break; } } return on; }))); }