예제 #1
0
파일: Message.cs 프로젝트: fronx/ioke
        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);
                                                                                        })));
        }
예제 #2
0
파일: Message.cs 프로젝트: fronx/ioke
        public static IokeObject FromTree(Runtime runtime, ITree tree)
        {
            //             Console.Error.WriteLine(" fromTree(" + tree.ToStringTree() + ")");
            Message m = null;
            int argStart = 0;

            if(!tree.IsNil) {
                switch(tree.Type) {
                case iokeParser.RegexpLiteral: {
                    string s = tree.Text;
                    char first = s[0];
                    char second = s[1];
                    char last = s[s.Length-1];
                    if(first == '#' && last != '{') {
                        if(second == 'r') {
                            int lastIndex = s.LastIndexOf(']');
                            m = new Message(runtime, "internal:createRegexp", s.Substring(3, lastIndex-3));
                            m.arguments.Add(s.Substring(lastIndex+1));
                        } else {
                            int lastIndex = s.LastIndexOf('/');
                            m = new Message(runtime, "internal:createRegexp", s.Substring(2, lastIndex-2));
                            m.arguments.Add(s.Substring(lastIndex+1));
                        }
                        m.Line = tree.Line;
                        m.Position = tree.CharPositionInLine;
                        return runtime.CreateMessage(m);
                    } else if(first == '}' && last == '{') {
                        m = new Message(runtime, "internal:createText", s.Substring(1, s.Length-3), Type.MIDDLE_RE_INTERPOLATION);
                        m.Line = tree.Line;
                        m.Position = tree.CharPositionInLine;
                        return runtime.CreateMessage(m);
                    } else if(first == '}') {
                        int lastIndex = s.LastIndexOf('/');
                        if(lastIndex == -1) {
                            lastIndex = s.LastIndexOf(']');
                        }
                        m = new Message(runtime, "internal:createText", s.Substring(1, lastIndex-1), Type.END_RE_INTERPOLATION);
                        m.arguments.Add(s.Substring(lastIndex+1));
                        m.Line = tree.Line;
                        m.Position = tree.CharPositionInLine;
                        return runtime.CreateMessage(m);
                    } else {
                        m = new Message(runtime, "internal:createText", s.Substring(2, s.Length-4), Type.START_RE_INTERPOLATION);
                        m.Line = tree.Line;
                        m.Position = tree.CharPositionInLine;
                        return runtime.CreateMessage(m);
                    }
                }
                case iokeParser.StringLiteral: {
                    string s = tree.Text;
                    char first = s[0];
                    char last = s[s.Length-1];
                    if(first == '"' && last == '"') {
                        m = new Message(runtime, "internal:createText", s.Substring(1, s.Length-2));
                        m.Line = tree.Line;
                        m.Position = tree.CharPositionInLine;
                        return runtime.CreateMessage(m);
                    } else if(first == '#' && last == ']') {
                        m = new Message(runtime, "internal:createText", s.Substring(2, s.Length-3));
                        m.Line = tree.Line;
                        m.Position = tree.CharPositionInLine;
                        return runtime.CreateMessage(m);
                    } else {
                        if(first == '}' && (last == '"' || last == ']')) { // This is an ending
                            m = new Message(runtime, "internal:createText", s.Substring(1, s.Length-2), Type.END_INTERPOLATION);
                            m.Line = tree.Line;
                            m.Position = tree.CharPositionInLine;
                            return runtime.CreateMessage(m);
                        } else if(first == '"') { // This is a beginning
                            m = new Message(runtime, "internal:createText", s.Substring(1, s.Length-3), Type.START_INTERPOLATION);
                            m.Line = tree.Line;
                            m.Position = tree.CharPositionInLine;
                            return runtime.CreateMessage(m);
                        } else if(first == '#') { // This is a beginning
                            m = new Message(runtime, "internal:createText", s.Substring(2, s.Length-4), Type.START_INTERPOLATION);
                            m.Line = tree.Line;
                            m.Position = tree.CharPositionInLine;
                            return runtime.CreateMessage(m);
                        } else { // This is in the middle
                            m = new Message(runtime, "internal:createText", s.Substring(1, s.Length-3), Type.MIDDLE_INTERPOLATION);
                            m.Line = tree.Line;
                            m.Position = tree.CharPositionInLine;
                            return runtime.CreateMessage(m);
                        }
                    }
                }
                case iokeParser.NumberLiteral:
                    m = new Message(runtime, "internal:createNumber", tree.Text);
                    m.Line = tree.Line;
                    m.Position = tree.CharPositionInLine;
                    return runtime.CreateMessage(m);
                case iokeParser.DecimalLiteral:
                    m = new Message(runtime, "internal:createDecimal", tree.Text);
                    m.Line = tree.Line;
                    m.Position = tree.CharPositionInLine;
                    return runtime.CreateMessage(m);
                case iokeParser.UnitLiteral: {
                    string text = tree.Text;
                    int ending = text.Length-1;
                    while(!Char.IsDigit(text[ending])) {
                        ending--;
                    }
                    Message mex = new Message(runtime, "internal:createNumber", text.Substring(0, ending+1));
                    mex.Line = tree.Line;
                    mex.Position = tree.CharPositionInLine;
                    m = new Message(runtime, "internal:createUnit", runtime.CreateMessage(mex));
                    m.Line = tree.Line;
                    m.Position = tree.CharPositionInLine;
                    return runtime.CreateMessage(m);
                }
                case iokeParser.UnitDecimalLiteral: {
                    string text = tree.Text;
                    int ending = text.Length-1;
                    while(!Char.IsDigit(text[ending])) {
                        ending--;
                    }
                    Message mex = new Message(runtime, "internal:createDecimal", text.Substring(0, ending+1));
                    mex.Line = tree.Line;
                    mex.Position = tree.CharPositionInLine;
                    m = new Message(runtime, "internal:createUnit", mex);
                    m.Line = tree.Line;
                    m.Position = tree.CharPositionInLine;
                    return runtime.CreateMessage(m);
                }
                case iokeParser.Identifier:
                    m = new Message(runtime, tree.Text);
                    m.Line = tree.Line;
                    m.Position = tree.CharPositionInLine;
                    return runtime.CreateMessage(m);
                case iokeParser.Terminator:
                    m = new Message(runtime, ".", null, Type.TERMINATOR);
                    m.Line = tree.Line;
                    m.Position = tree.CharPositionInLine;
                    return runtime.CreateMessage(m);
                case iokeParser.Comma:
                    m = new Message(runtime, ",", null, Type.SEPARATOR);
                    m.Line = tree.Line;
                    m.Position = tree.CharPositionInLine;
                    return runtime.CreateMessage(m);
                case iokeParser.MESSAGE: {
                    string text = tree.GetChild(0).Text;
                    m = new Message(runtime, text);
                    int count = tree.ChildCount;
                    argStart = 1;
                    if(count > 1) {
                        int diff = tree.GetChild(1).CharPositionInLine - (tree.CharPositionInLine+text.Length);
                        if(diff != 0) {
                            m.type = Type.DETACH;
                        }
                        argStart = 2;
                    }

                    break;
                }
                default:
                    Console.Error.WriteLine("ERROR: Can't handle " + tree + " : " + tree.Type);
                    return null;
                }

                m.Line = tree.Line;
                m.Position = tree.CharPositionInLine;
            }

            IokeObject mx = m == null ? (IokeObject)null : runtime.CreateMessage(m);

            object head = null;
            IList<IokeObject> currents = new SaneList<IokeObject>();

            IList<IList<IokeObject>> oldCurrents = new SaneList<IList<IokeObject>>();
            IList<object> oldHeads = new SaneList<object>();
            IList<IokeObject> oldMx = new SaneList<IokeObject>();

            for(int i=argStart,j=tree.ChildCount; i<j; i++) {
                IokeObject created = FromTree(runtime, tree.GetChild(i));

                switch(Message.typeOf(created)) {
                case Type.START_INTERPOLATION:{
                    Message mvv = new Message(runtime, "internal:concatenateText");
                    mvv.Line = tree.Line;
                    mvv.Position = tree.CharPositionInLine;
                    oldCurrents.Insert(0, currents);
                    oldHeads.Insert(0, head);
                    oldMx.Insert(0, mx);

                    currents = new SaneList<IokeObject>();
                    head = created;
                    mx = runtime.CreateMessage(mvv);

                    created = runtime.CreateMessage(new Message(runtime, ",", null, Type.SEPARATOR));
                    break;
                }
                case Type.START_RE_INTERPOLATION:{
                    Message mvv = new Message(runtime, "internal:compositeRegexp");
                    mvv.Line = tree.Line;
                    mvv.Position = tree.CharPositionInLine;
                    oldCurrents.Insert(0, currents);
                    oldHeads.Insert(0, head);
                    oldMx.Insert(0, mx);

                    currents = new SaneList<IokeObject>();
                    head = created.Arguments[0];
                    mx = runtime.CreateMessage(mvv);

                    created = runtime.CreateMessage(new Message(runtime, ",", null, Type.SEPARATOR));
                    break;
                }
                case Type.MIDDLE_INTERPOLATION:
                    mx.Arguments.Add(head);

                    currents.Clear();
                    head = created;

                    created = runtime.CreateMessage(new Message(runtime, ",", null, Type.SEPARATOR));
                    break;
                case Type.MIDDLE_RE_INTERPOLATION:
                    mx.Arguments.Add(head);

                    currents.Clear();
                    head = created.Arguments[0];

                    created = runtime.CreateMessage(new Message(runtime, ",", null, Type.SEPARATOR));
                    break;
                case Type.END_INTERPOLATION:
                    mx.Arguments.Add(head);
                    mx.Arguments.Add(created);

                    currents = oldCurrents[0];
                    oldCurrents.RemoveAt(0);

                    head = oldHeads[0];
                    oldHeads.RemoveAt(0);

                    created = mx;

                    mx = oldMx[0];
                    oldMx.RemoveAt(0);

                    break;
                case Type.END_RE_INTERPOLATION:
                    mx.Arguments.Add(head);
                    mx.Arguments.Add(created.Arguments[0]);
                    mx.Arguments.Add(created.Arguments[1]);

                    currents = oldCurrents[0];
                    oldCurrents.RemoveAt(0);

                    head = oldHeads[0];
                    oldHeads.RemoveAt(0);

                    created = mx;

                    mx = oldMx[0];
                    oldMx.RemoveAt(0);
                    break;
                }

                if(Message.typeOf(created) == Type.TERMINATOR && head == null && currents.Count == 0) {
                    continue;
                }

                if(Message.typeOf(created) == Type.SEPARATOR && mx != null) {
                    mx.Arguments.Add(head);
                    currents.Clear();
                    head = null;
                } else {
                    if(Message.typeOf(created) == Type.TERMINATOR && currents.Count > 1) {
                        while(currents.Count > 1) {
                            currents.RemoveAt(0);
                        }
                    }
                    Message.SetPrev(created, currents.Count > 0 ? currents[0] : null);

                    if(head == null && Message.typeOf(created) != Type.TERMINATOR) {
                        head = created;
                    }

                    if(currents.Count > 0) {
                        Message.SetNextOfLast(currents[0], created);
                        currents[0] = created;
                    } else {
                        currents.Insert(0, created);
                    }
                }
            }

            if(mx != null && head != null) {
                mx.Arguments.Add(head);
            }

            return mx == null ? (IokeObject)head : mx;
        }