Ejemplo n.º 1
0
 public void add_jump_unoptimized(Opcode op, BasicBlock first)
 {
     Opcodes.Add(op);
     if (Dead == 2)
         return;
     do_add_jump(first);
 }
Ejemplo n.º 2
0
        public bool is_declared(string name, Opcode.Sigil sigil)
        {
            var glob = SymbolTable.GetGlob(this, name, false);

            // TODO implement imported check, and setting imported
            //      flag in assignment
            return false;
        }
Ejemplo n.º 3
0
 public StackFrame(string pack, string file, int l, P5Code code,
                   Opcode.ContextValues cxt, bool eval)
 {
     Package = pack;
     File = file;
     Line = l;
     Code = code;
     Context = cxt;
     IsEval = eval;
 }
Ejemplo n.º 4
0
        public static IP5Any DoFile(Runtime runtime,
                                    Opcode.ContextValues context,
                                    P5Scalar file)
        {
            var file_s = file.AsString(runtime);

            var ret = LoadFile(runtime, context, file_s);
            if (ret == null)
                return new P5Scalar(runtime);

            return ret;
        }
Ejemplo n.º 5
0
        public static IP5Any LoadFile(Runtime runtime,
                                      Opcode.ContextValues context,
                                      string file)
        {
            IP5Any ret = null;

            foreach (var loader in runtime.ModuleLoaders)
            {
                ret = loader.TryLoad(runtime, context, file);

                if (ret != null)
                    return ret;
            }

            return ret;
        }
Ejemplo n.º 6
0
        // TODO generate from Perl code
        public void add_jump(Opcode op, BasicBlock first)
        {
            if (Opcodes.Count == 0 && Predecessors.Count > 0 && first != this)
            {
                while (first.Successors.Count > 0 && first.Opcodes.Count == 0)
                    first = first.Successors[0];

                var pred = new List<BasicBlock>(Predecessors);
                foreach (var p in pred)
                    p._change_successor(this, first);

                add_successor(first);
            }
            else
                add_jump_unoptimized(op, first);
        }
Ejemplo n.º 7
0
        public static IP5Any RequireFile(Runtime runtime,
                                         Opcode.ContextValues context,
                                         P5Scalar file)
        {
            if (file.IsInteger(runtime) || file.IsFloat(runtime))
            {
                var value = file.AsFloat(runtime);
                var version = runtime.SymbolTable.GetScalar(runtime, "]", false);
                var version_f = version.AsFloat(runtime);

                if (version_f >= value)
                    return new P5Scalar(runtime, true);

                var msg = string.Format("Perl {0:F} required--this is only {1:F} stopped.", value, version_f);

                throw new P5Exception(runtime, msg);
            }

            var file_s = file.AsString(runtime);
            var inc = runtime.SymbolTable.GetHash(runtime, "INC", true);

            if (inc.ExistsKey(runtime, file_s))
                return new P5Scalar(runtime, 1);

            var ret = LoadFile(runtime, context, file_s);
            if (ret == null)
            {
                var message = new System.Text.StringBuilder();
                var inc_a = runtime.SymbolTable.GetArray(runtime, "INC", true);

                message.Append(string.Format("Can't locate {0:S} in @INC (@INC contains:", file_s));
                foreach (var dir in inc_a)
                {
                    message.Append(" ");
                    message.Append(dir.AsString(runtime));
                }
                message.Append(")");

                throw new P5Exception(runtime, message.ToString());
            }

            return ret;
        }
Ejemplo n.º 8
0
 public IP5Value get_symbol(string name, Opcode.Sigil sigil)
 {
     switch (sigil)
     {
     case Opcode.Sigil.SCALAR:
         return SymbolTable.GetScalar(this, name, false);
     case Opcode.Sigil.ARRAY:
         return SymbolTable.GetArray(this, name, false);
     case Opcode.Sigil.HASH:
         return SymbolTable.GetHash(this, name, false);
     case Opcode.Sigil.SUB:
         return SymbolTable.GetCode(this, name, false);
     case Opcode.Sigil.GLOB:
         return SymbolTable.GetGlob(this, name, false);
     case Opcode.Sigil.HANDLE:
         return SymbolTable.GetHandle(this, name, false);
     default:
         return null;
     }
 }
Ejemplo n.º 9
0
        private Expression MakeNonFlatArray(Subroutine sub, Type type, Opcode op)
        {
            var data = new List<Expression>();
            var temp = Expression.Variable(typeof(List<IP5Any>));
            var method = typeof(List<IP5Any>).GetMethod("Add");

            data.Add(
                Expression.Assign(
                    temp,
                    Expression.New(
                        typeof(List<IP5Any>).GetConstructor(ProtoInt),
                        Expression.Constant(op.Childs.Length))));

            foreach (var i in op.Childs)
                data.Add(
                    Expression.Call(temp, method, Generate(sub, i)));

            data.Add(
                Expression.New(
                    type.GetConstructor(
                        new Type[] { typeof(Runtime), typeof(List<IP5Any>) }),
                    Runtime,
                    temp));

            return Expression.Block(
                type, new ParameterExpression[] { temp }, data);
        }
Ejemplo n.º 10
0
 protected abstract Expression ScalarAssign(Subroutine sub, Opcode.ContextValues cxt, Expression lvalue, Expression rvalue);
Ejemplo n.º 11
0
 protected abstract Expression StringRelOperator(Subroutine sub, Opcode op, ExpressionType operation);
Ejemplo n.º 12
0
        public IP5Any TryLoad(Runtime runtime, Opcode.ContextValues context, string file)
        {
            var path = Builtins.SearchFile(runtime, file);
            if (path == null)
                return null;

            P5Code mod;
            if (path.EndsWith(".pb"))
            {
                var cu = Serializer.ReadCompilationUnit(runtime, path);
                mod = new DynamicGenerator(runtime).GenerateAndLoad(cu);
            }
            else
            {
                var parser = runtime.parser;
                mod = parser.ParseFile(runtime, path, false);
            }

            var ret = mod.Call(runtime, context, null);

            var inc = runtime.SymbolTable.GetHash(runtime, "INC", true);
            inc.SetItem(runtime, file, new P5Scalar(runtime, path));

            return ret;
        }
Ejemplo n.º 13
0
        public IP5Any TryLoad(Runtime runtime, Opcode.ContextValues context, string file)
        {
            System.Type module = assembly.GetType(file);
            if (module == null)
                return null;

            object main_sub = module.GetMethod("InitModule")
                                    .Invoke(null, new object[] { runtime });
            P5Code main  = main_sub as P5Code;

            var res = main.Call(runtime, context, null);

            var inc = runtime.SymbolTable.GetHash(runtime, "INC", true);
            inc.SetItem(runtime, file, new P5Scalar(runtime, module.FullName));

            return res;
        }
Ejemplo n.º 14
0
 protected string MethodForSlot(Opcode.Sigil slot)
 {
     switch (slot)
     {
     case Opcode.Sigil.SCALAR:
         return "GetScalar";
     case Opcode.Sigil.ARRAY:
         return "GetArray";
     case Opcode.Sigil.HASH:
         return "GetHash";
     case Opcode.Sigil.STASH:
         return "GetStash";
     case Opcode.Sigil.SUB:
         return "GetCode";
     case Opcode.Sigil.GLOB:
         return "GetGlob";
     case Opcode.Sigil.HANDLE:
         return "GetHandle";
     default:
         throw new System.Exception(string.Format("Unhandled slot {0:D}", slot));
     }
 }
Ejemplo n.º 15
0
 public P5ArrayAssignmentBinder(Runtime runtime, Opcode.ContextValues cxt, bool common)
 {
     Runtime = runtime;
     Context = cxt;
     Common = common;
 }
Ejemplo n.º 16
0
        public static IP5Any HashEach(Runtime runtime, Opcode.ContextValues cxt, P5Hash hash)
        {
            P5Scalar key, value;

            if (hash.NextKey(runtime, out key, out value))
            {
                if (cxt == Opcode.ContextValues.SCALAR)
                    return key;
                else
                    return new P5List(runtime, key, value);
            }
            else
            {
                if (cxt == Opcode.ContextValues.SCALAR)
                    return new P5Scalar(runtime);
                else
                    return new P5List(runtime);
            }
        }
Ejemplo n.º 17
0
        public static IP5Any Reverse(Runtime runtime, Opcode.ContextValues context,
                                     P5Array args)
        {
            if (context == Opcode.ContextValues.LIST)
                return args.Reversed(runtime);

            int count = args.GetCount(runtime);
            char[] value;

            if (count == 0)
                value = runtime.SymbolTable.GetStashScalar(runtime, "_", true).AsString(runtime).ToCharArray();
            else if (count == 1)
                value = args.GetItem(runtime, 0).AsString(runtime).ToCharArray();
            else
            {
                var t = new System.Text.StringBuilder();

                foreach (var i in args)
                    t.Append(i.AsString(runtime));

                value = t.ToString().ToCharArray();
            }

            // TODO does not handle UCS-4
            System.Array.Reverse(value);

            return new P5Scalar(runtime, new string(value));
        }
Ejemplo n.º 18
0
        private Expression MakeFlatArray(Subroutine sub, Type type, Opcode op)
        {
            var data = new List<Expression>();
            var temp = Expression.Variable(type);
            var method = type.GetMethod("PushFlatten");

            data.Add(
                Expression.Assign(
                    temp,
                    Expression.New(
                        type.GetConstructor(ProtoRuntimeInt),
                        Runtime,
                        Expression.Constant(op.Childs.Length))));

            foreach (var i in op.Childs)
                data.Add(
                    Expression.Call(temp, method, Runtime, Generate(sub, i)));

            data.Add(temp);

            return Expression.Block(
                type, new ParameterExpression[] { temp }, data);
        }
Ejemplo n.º 19
0
        private Expression GetLexicalValue(int index, Opcode.Sigil slot)
        {
            var lex = GetLexical(index, slot);
            var type = TypeForSlot(slot);

            // the condition is necessary because a jump might bypass
            // a declaration; if the subroutine does not contain any goto, or
            // if the goto inizializes all jumped-over variables, then the
            // condition can be removed
            return Expression.Condition(
                Expression.NotEqual(
                    lex,
                    Expression.Constant(null, type)),
                lex,
                Expression.Assign(
                    lex,
                    Expression.New(
                        type.GetConstructor(ProtoRuntime),
                        Runtime)));
        }
Ejemplo n.º 20
0
 private Expression GetLexical(int index, Opcode.Sigil slot)
 {
     return GetLexical(index, TypeForSlot(slot));
 }
Ejemplo n.º 21
0
 protected abstract Expression UnaryOperator(Subroutine sub, Opcode op, ExpressionType operation);
Ejemplo n.º 22
0
 protected abstract Expression UnaryIncrement(Subroutine sub, Opcode op, ExpressionType operation);
Ejemplo n.º 23
0
        public static IP5Any Return(Runtime runtime, Opcode.ContextValues cxt,
                                    IP5Any value)
        {
            if (cxt == Opcode.ContextValues.SCALAR)
                return value.AsScalar(runtime);
            if (cxt == Opcode.ContextValues.LIST)
                return value as P5Array ?? new P5List(runtime, value);

            return P5List.EmptyList;
        }
Ejemplo n.º 24
0
 private Expression OpContext(Opcode op)
 {
     if (op.Context == (int)Opcode.ContextValues.CALLER)
         return Context;
     else
         return Expression.Constant(
             (Opcode.ContextValues)op.Context,
             typeof(Opcode.ContextValues));
 }
Ejemplo n.º 25
0
        public static P5Scalar WantArray(Runtime runtime, Opcode.ContextValues cxt)
        {
            if (cxt == Opcode.ContextValues.VOID)
                return new P5Scalar(runtime);

            return new P5Scalar(runtime, cxt == Opcode.ContextValues.LIST);
        }
Ejemplo n.º 26
0
 private string PropertyForSlot(Opcode.Sigil slot)
 {
     switch (slot)
     {
     case Opcode.Sigil.SCALAR:
         return "Scalar";
     case Opcode.Sigil.ARRAY:
         return "Array";
     case Opcode.Sigil.HASH:
         return "Hash";
     case Opcode.Sigil.SUB:
         return "Code";
     case Opcode.Sigil.HANDLE:
         return "Handle";
     default:
         throw new System.Exception(string.Format("Unhandled slot {0:D}", slot));
     }
 }
Ejemplo n.º 27
0
 public IP5Any MatchGlobal(Runtime runtime, IP5Any value, int flags,
                           Opcode.ContextValues cxt, ref RxResult oldState)
 {
     return P5Regex.MatchGlobalHelper(this, runtime, value, flags,
                                      cxt, ref oldState);
 }
Ejemplo n.º 28
0
        public Expression Generate(Subroutine sub, Opcode op)
        {
            switch(op.Number)
            {
            case Opcode.OpNumber.OP_FRESH_STRING:
            case Opcode.OpNumber.OP_CONSTANT_STRING:
            {
                var cs = (ConstantString)op;

                return
                    Expression.New(
                        typeof(P5Scalar).GetConstructor(ProtoRuntimeString),
                        new Expression[] {
                            Runtime,
                            Expression.Constant(cs.Value) });
            }
            case Opcode.OpNumber.OP_CONSTANT_UNDEF:
            {
                var ctor = typeof(P5Scalar).GetConstructor(ProtoRuntime);

                return Expression.New(ctor, new Expression[] { Runtime });
            }
            case Opcode.OpNumber.OP_CONSTANT_INTEGER:
                return ConstantInteger(((ConstantInt)op).Value);
            case Opcode.OpNumber.OP_CONSTANT_FLOAT:
                return ConstantFloat(((ConstantFloat)op).Value);
            case Opcode.OpNumber.OP_CONSTANT_SUB:
            {
                var cs = (ConstantSub)op;

                return ConstantSub(cs.Value);
            }
            case Opcode.OpNumber.OP_UNDEF:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("Undef"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_GLOBAL:
            {
                Global gop = (Global)op;
                bool create;

                if (gop.Slot == Opcode.Sigil.STASH)
                    create = (gop.Context & (int)Opcode.ContextValues.NOCREATE) == 0;
                else
                    create = true;

                var global = AccessGlobal(Runtime, gop.Slot, gop.Name, create);

                if (create)
                    return global;
                else
                    return UndefIfNull(global);
            }
            case Opcode.OpNumber.OP_GLOB_SLOT:
            {
                GlobSlot gop = (GlobSlot)op;
                string name = PropertyForSlot(gop.Slot);
                return
                    Expression.Property(
                        Expression.Convert(
                            Generate(sub, op.Childs[0]),
                            typeof(P5Typeglob)),
                        name);
            }
            case Opcode.OpNumber.OP_SWAP_GLOB_SLOT_SET:
            {
                GlobSlot gop = (GlobSlot)op;
                string name = PropertyForSlot(gop.Slot);
                var property =
                    Expression.Property(
                        Expression.Convert(
                            Generate(sub, op.Childs[1]),
                            typeof(P5Typeglob)),
                        name);

                return
                    Expression.Assign(
                        property,
                        Expression.Convert(
                            Generate(sub, op.Childs[0]),
                            property.Type));
            }
            case Opcode.OpNumber.OP_MAKE_LIST:
            {
                if ((op.Context & (int)Opcode.ContextValues.LVALUE) != 0)
                    return MakeNonFlatArray(sub, typeof(P5LvalueList), op);
                else
                    return MakeFlatArray(sub, typeof(P5List), op);
            }
            case Opcode.OpNumber.OP_MAKE_ARRAY:
                return MakeFlatArray(sub, typeof(P5Array), op);
            case Opcode.OpNumber.OP_DOT_DOT:
            {
                // TODO needs to handle the flip/flop mode in scalar context
                return
                    Expression.Call(
                        typeof(Builtins).GetMethod("MakeRange"),
                        Runtime,
                        Generate(sub, op.Childs[0]),
                        Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_ANONYMOUS_ARRAY:
                return Expression.Call(
                    typeof(Builtins).GetMethod("AnonymousArray"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_ANONYMOUS_HASH:
                return Expression.Call(
                    typeof(Builtins).GetMethod("AnonymousHash"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_PRINT:
            {
                Expression handle = Generate(sub, op.Childs[0]);

                if (handle.Type != typeof(P5Handle))
                    handle = Expression.Call(
                        handle,
                        typeof(IP5Any).GetMethod("DereferenceHandle"),
                        Runtime);

                return Expression.Call(
                    typeof(Builtins).GetMethod("Print"),
                    Runtime,
                    handle,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_READLINE:
            {
                return
                    Expression.Call(
                        typeof(Builtins).GetMethod("Readline"),
                        Runtime,
                        Expression.Call(
                            Generate(sub, op.Childs[0]),
                            typeof(IP5Any).GetMethod("DereferenceHandle"),
                            Runtime),
                        OpContext(op));
            }
            case Opcode.OpNumber.OP_END:
            {
                return
                    Expression.Return(
                        SubLabel,
                        Expression.Constant(null, typeof(IP5Any)),
                        typeof(IP5Any));
            }
            case Opcode.OpNumber.OP_STOP:
            {
                // TODO remove STOP
                return Generate(sub, op.Childs[0]);
            }
            case Opcode.OpNumber.OP_DIE:
            {
                return Expression.Block(
                    Expression.Throw(
                        Expression.Call(
                            typeof(Builtins).GetMethod("Die"),
                            Runtime,
                            Generate(sub, op.Childs[0]))),
                    // this is only to trick the type checker into
                    // thinking that this is a "normal" expression
                    Expression.Constant(null, typeof(IP5Any)));
            }
            case Opcode.OpNumber.OP_WARN:
            {
                return Expression.Call(
                    typeof(Builtins).GetMethod("Warn"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_SPRINTF:
            {
                return Expression.Call(
                    typeof(Builtins).GetMethod("Sprintf"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_DO_FILE:
            {
                return
                    Expression.Call(
                        typeof(Builtins).GetMethod("DoFile"),
                        Runtime,
                        OpContext(op),
                        Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_REQUIRE_FILE:
            {
                return
                    Expression.Call(
                        typeof(Builtins).GetMethod("RequireFile"),
                        Runtime,
                        OpContext(op),
                        Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_WANTARRAY:
            {
                return
                    Expression.Call(
                        typeof(Builtins).GetMethod("WantArray"),
                        Runtime,
                        Context);
            }
            case Opcode.OpNumber.OP_SCALAR:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("AsScalar"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_RETURN:
                return ReturnExpression(Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_DYNAMIC_GOTO:
            {
                // TODO handle goto $LABEL
                var exit_scope = new List<Expression>();
                var value = Expression.Parameter(typeof(P5Code));
                var code =
                    Expression.Call(
                        Generate(sub, op.Childs[0]),
                        typeof(IP5Any).GetMethod("DereferenceSubroutine"),
                        Runtime);

                exit_scope.Add(
                    Expression.Assign(value, code));

                for (var s = CurrentScope; s != null; s = s.Outer != -1 ? sub.Scopes[s.Outer] : null)
                    for (int j = s.Opcodes.Count - 1; j >= 0; --j)
                        GenerateOpcodes(sub, s.Opcodes[j], exit_scope);

                exit_scope.Add(
                    Expression.Call(
                        Expression.Field(Runtime, "CallStack"),
                        typeof(Stack<StackFrame>).GetMethod("Pop")));

                // TODO this is not a real tail call: the .Net stack grows
                exit_scope.Add(
                    ReturnExpression(
                        Expression.Call(
                            value,
                            typeof(P5Code).GetMethod("Call"),
                            Runtime,
                            Context,
                            Arguments)));

                return Expression.Block(typeof(IP5Any), new[] { value }, exit_scope);
            }
            case Opcode.OpNumber.OP_ASSIGN_LIST:
            {
                var lvalue = Generate(sub, op.Childs[1]);
                var rvalue = Generate(sub, op.Childs[0]);
                bool common = ((ListAssign)op).Common != 0;

                return ArrayAssign(sub, (Opcode.ContextValues)op.Context,
                                   lvalue, rvalue, common);
            }
            case Opcode.OpNumber.OP_SWAP_ASSIGN_LIST:
            {
                var lvalue = Generate(sub, op.Childs[0]);
                var rvalue = Generate(sub, op.Childs[1]);
                bool common = ((ListAssign)op).Common != 0;

                return ArrayAssign(sub, (Opcode.ContextValues)op.Context,
                                   lvalue, rvalue, common);
            }
            case Opcode.OpNumber.OP_ASSIGN:
            {
                var lvalue = Generate(sub, op.Childs[1]);
                var rvalue = Generate(sub, op.Childs[0]);

                return ScalarAssign(sub, (Opcode.ContextValues)op.Context,
                                    lvalue, rvalue);
            }
            case Opcode.OpNumber.OP_SWAP_ASSIGN:
            {
                var lvalue = Generate(sub, op.Childs[0]);
                var rvalue = Generate(sub, op.Childs[1]);

                return ScalarAssign(sub, (Opcode.ContextValues)op.Context,
                                    lvalue, rvalue);
            }
            case Opcode.OpNumber.OP_GET:
            {
                GetSet gs = (GetSet)op;

                return GetVariable(gs.Index, TypeForSlot(gs.Slot));
            }
            case Opcode.OpNumber.OP_SET:
            {
                GetSet gs = (GetSet)op;
                var e = Generate(sub, op.Childs[0]);

                return Expression.Assign(
                    GetVariable(gs.Index, TypeForSlot(gs.Slot)),
                    e);
            }
            case Opcode.OpNumber.OP_JUMP:
                return Expression.Goto(BlockLabels[((Jump)op).To], typeof(IP5Any));
            case Opcode.OpNumber.OP_JUMP_IF_NULL:
            {
                Expression cmp = Expression.Equal(
                    Generate(sub, op.Childs[0]),
                    Expression.Constant(null, typeof(object)));
                Expression jump = Expression.Goto(
                    BlockLabels[((CondJump)op).To],
                    typeof(IP5Any));

                return Expression.IfThen(cmp, jump);
            }
            case Opcode.OpNumber.OP_JUMP_IF_S_EQ:
            {
                return GenerateJump(sub, op, "AsString",
                                    ExpressionType.Equal);
            }
            case Opcode.OpNumber.OP_JUMP_IF_S_NE:
            {
                return GenerateJump(sub, op, "AsString",
                                    ExpressionType.NotEqual);
            }
            case Opcode.OpNumber.OP_JUMP_IF_F_EQ:
            {
                return GenerateJump(sub, op, "AsFloat",
                                    ExpressionType.Equal);
            }
            case Opcode.OpNumber.OP_JUMP_IF_F_NE:
            {
                return GenerateJump(sub, op, "AsFloat",
                                    ExpressionType.NotEqual);
            }
            case Opcode.OpNumber.OP_JUMP_IF_F_GE:
            {
                return GenerateJump(sub, op, "AsFloat",
                                    ExpressionType.GreaterThanOrEqual);
            }
            case Opcode.OpNumber.OP_JUMP_IF_F_LE:
            {
                return GenerateJump(sub, op, "AsFloat",
                                    ExpressionType.LessThanOrEqual);
            }
            case Opcode.OpNumber.OP_JUMP_IF_F_GT:
            {
                return GenerateJump(sub, op, "AsFloat",
                                    ExpressionType.GreaterThan);
            }
            case Opcode.OpNumber.OP_JUMP_IF_F_LT:
            {
                return GenerateJump(sub, op, "AsFloat",
                                    ExpressionType.LessThan);
            }
            case Opcode.OpNumber.OP_JUMP_IF_TRUE:
            {
                Expression cmp = Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("AsBoolean"),
                    Runtime);
                Expression jump = Expression.Goto(
                    BlockLabels[((CondJump)op).To],
                    typeof(IP5Any));

                return Expression.IfThen(cmp, jump);
            }
            case Opcode.OpNumber.OP_LOG_NOT:
                return UnaryOperator(sub, op, ExpressionType.Not);
            case Opcode.OpNumber.OP_MINUS:
                return UnaryOperator(sub, op, ExpressionType.Negate);
            case Opcode.OpNumber.OP_DEFINED:
                return Defined(sub, op);
            case Opcode.OpNumber.OP_ORD:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Ord"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_CHR:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Chr"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_UC:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Uppercase"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_LC:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Lowercase"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_OCT:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Oct"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_HEX:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Hex"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_INDEX:
            {
                Expression start;

                if (op.Childs.Length == 3)
                    start = Expression.Call(
                        Generate(sub, op.Childs[2]),
                        typeof(IP5Any).GetMethod("AsInteger"),
                        Runtime);
                else
                    start = Expression.Constant(0);

                return Expression.Call(
                    typeof(Builtins).GetMethod("Index"),
                    Runtime,
                    Generate(sub, op.Childs[0]),
                    Generate(sub, op.Childs[1]),
                    start);
            }
            case Opcode.OpNumber.OP_CONCATENATE:
            {
                Expression s1 =
                    Expression.Call(Generate(sub, op.Childs[0]),
                                    typeof(IP5Any).GetMethod("AsString"),
                                    Runtime);
                Expression s2 =
                    Expression.Call(Generate(sub, op.Childs[1]),
                                    typeof(IP5Any).GetMethod("AsString"),
                                    Runtime);
                return
                    Expression.New(
                        typeof(P5Scalar).GetConstructor(ProtoRuntimeString),
                        Runtime,
                        Expression.Call(
                            typeof(string).GetMethod("Concat", ProtoStringString), s1, s2));
            }
            case Opcode.OpNumber.OP_CONCATENATE_ASSIGN:
            {
                return Expression.Call(
                    Expression.Convert(
                        Generate(sub, op.Childs[0]),
                        typeof(P5Scalar)),
                    typeof(P5Scalar).GetMethod("ConcatAssign"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_ARRAY_LENGTH:
            {
                Expression len =
                    Expression.Call(
                        Expression.Convert(
                            Generate(sub, op.Childs[0]),
                            typeof(IP5Array)),
                        typeof(IP5Array).GetMethod("GetCount"),
                        Runtime);
                Expression len_1 = Expression.Subtract(len, Expression.Constant(1));
                return Expression.New(
                    typeof(P5Scalar).GetConstructor(ProtoRuntimeInt),
                    new Expression[] { Runtime, len_1 });
            }
            case Opcode.OpNumber.OP_BIT_NOT:
                return UnaryOperator(sub, op, ExpressionType.OnesComplement);
            case Opcode.OpNumber.OP_BIT_OR:
                return BinaryOperator(sub, op, ExpressionType.Or);
            case Opcode.OpNumber.OP_BIT_OR_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.OrAssign);
            case Opcode.OpNumber.OP_BIT_AND:
                return BinaryOperator(sub, op, ExpressionType.And);
            case Opcode.OpNumber.OP_BIT_AND_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.AndAssign);
            case Opcode.OpNumber.OP_BIT_XOR:
                return BinaryOperator(sub, op, ExpressionType.ExclusiveOr);
            case Opcode.OpNumber.OP_BIT_XOR_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.ExclusiveOrAssign);
            case Opcode.OpNumber.OP_NUM_LE:
                return NumericRelOperator(sub, op, ExpressionType.LessThanOrEqual);
            case Opcode.OpNumber.OP_NUM_LT:
                return NumericRelOperator(sub, op, ExpressionType.LessThan);
            case Opcode.OpNumber.OP_NUM_EQ:
                return NumericRelOperator(sub, op, ExpressionType.Equal);
            case Opcode.OpNumber.OP_NUM_NE:
                return NumericRelOperator(sub, op, ExpressionType.NotEqual);
            case Opcode.OpNumber.OP_NUM_GE:
                return NumericRelOperator(sub, op, ExpressionType.GreaterThanOrEqual);
            case Opcode.OpNumber.OP_NUM_GT:
                return NumericRelOperator(sub, op, ExpressionType.GreaterThan);
            case Opcode.OpNumber.OP_STR_LE:
                return StringRelOperator(sub, op, ExpressionType.LessThanOrEqual);
            case Opcode.OpNumber.OP_STR_LT:
                return StringRelOperator(sub, op, ExpressionType.LessThan);
            case Opcode.OpNumber.OP_STR_EQ:
                return StringRelOperator(sub, op, ExpressionType.Equal);
            case Opcode.OpNumber.OP_STR_NE:
                return StringRelOperator(sub, op, ExpressionType.NotEqual);
            case Opcode.OpNumber.OP_STR_GE:
                return StringRelOperator(sub, op, ExpressionType.GreaterThanOrEqual);
            case Opcode.OpNumber.OP_STR_GT:
                return StringRelOperator(sub, op, ExpressionType.GreaterThan);
            case Opcode.OpNumber.OP_ADD:
                return BinaryOperator(sub, op, ExpressionType.Add);
            case Opcode.OpNumber.OP_ADD_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.AddAssign);
            case Opcode.OpNumber.OP_SUBTRACT:
                return BinaryOperator(sub, op, ExpressionType.Subtract);
            case Opcode.OpNumber.OP_SUBTRACT_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.SubtractAssign);
            case Opcode.OpNumber.OP_MULTIPLY:
                return BinaryOperator(sub, op, ExpressionType.Multiply);
            case Opcode.OpNumber.OP_MULTIPLY_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.MultiplyAssign);
            case Opcode.OpNumber.OP_DIVIDE:
                return BinaryOperator(sub, op, ExpressionType.Divide);
            case Opcode.OpNumber.OP_DIVIDE_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.DivideAssign);
            case Opcode.OpNumber.OP_SHIFT_LEFT:
                return BinaryOperator(sub, op, ExpressionType.LeftShift);
            case Opcode.OpNumber.OP_SHIFT_LEFT_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.LeftShiftAssign);
            case Opcode.OpNumber.OP_SHIFT_RIGHT:
                return BinaryOperator(sub, op, ExpressionType.RightShift);
            case Opcode.OpNumber.OP_SHIFT_RIGHT_ASSIGN:
                return BinaryOperator(sub, op, ExpressionType.RightShiftAssign);
            case Opcode.OpNumber.OP_PREINC:
                return UnaryIncrement(sub, op, ExpressionType.PreIncrementAssign);
            case Opcode.OpNumber.OP_PREDEC:
                return UnaryIncrement(sub, op, ExpressionType.PreDecrementAssign);
            case Opcode.OpNumber.OP_POSTINC:
                return UnaryIncrement(sub, op, ExpressionType.PostIncrementAssign);
            case Opcode.OpNumber.OP_POSTDEC:
                return UnaryIncrement(sub, op, ExpressionType.PostDecrementAssign);
            case Opcode.OpNumber.OP_REVERSE:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Reverse"),
                    Runtime,
                    OpContext(op),
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_REPEAT_ARRAY:
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Array).GetMethod("Repeat"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            case Opcode.OpNumber.OP_REPEAT_SCALAR:
                return Expression.Call(
                    Expression.Call(
                        Generate(sub, op.Childs[0]),
                        typeof(IP5Any).GetMethod("AsScalar"),
                        Runtime),
                    typeof(P5Scalar).GetMethod("Repeat"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            case Opcode.OpNumber.OP_SORT:
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Array).GetMethod("Sort"),
                    Runtime);
            case Opcode.OpNumber.OP_ARRAY_ELEMENT:
            {
                var ea = (ElementAccess)op;

                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Array).GetMethod("GetItemOrUndef"),
                    Runtime,
                    Generate(sub, op.Childs[1]),
                    Expression.Constant(ea.Create != 0));
            }
            case Opcode.OpNumber.OP_HASH_ELEMENT:
            {
                var ea = (ElementAccess)op;

                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Hash).GetMethod("GetItemOrUndef"),
                    Runtime,
                    Generate(sub, op.Childs[1]),
                    Expression.Constant(ea.Create != 0));
            }
            case Opcode.OpNumber.OP_DELETE_HASH:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Hash).GetMethod("Delete"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_EXISTS_ARRAY:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Array).GetMethod("Exists"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_EXISTS_HASH:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Hash).GetMethod("Exists"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_PUSH_ELEMENT:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Array).GetMethod("PushFlatten"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_ARRAY_PUSH:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Array).GetMethod("PushList"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_ARRAY_UNSHIFT:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Array).GetMethod("UnshiftList"),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_ARRAY_POP:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Array).GetMethod("PopElement"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_ARRAY_SHIFT:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Array).GetMethod("ShiftElement"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_QUOTEMETA:
            {
                return Expression.Call(
                    typeof(Builtins).GetMethod("QuoteMeta"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_STRINGIFY:
            {
                return Expression.New(
                    typeof(P5Scalar).GetConstructor(ProtoRuntimeString),
                    Runtime,
                    Expression.Call(
                        Generate(sub, op.Childs[0]),
                        typeof(IP5Any).GetMethod("AsString"),
                        Runtime));
            }
            case Opcode.OpNumber.OP_LENGTH:
            {
                return Expression.New(
                    typeof(P5Scalar).GetConstructor(ProtoRuntimeInt),
                    Runtime,
                    Expression.Call(
                        Generate(sub, op.Childs[0]),
                        typeof(IP5Any).GetMethod("StringLength"),
                        Runtime));
            }
            case Opcode.OpNumber.OP_JOIN:
            {
                return Expression.Call(
                    typeof(Builtins).GetMethod("JoinList"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_ITERATOR:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Array).GetMethod("GetEnumerator", ProtoRuntime),
                    Runtime);
            }
            case Opcode.OpNumber.OP_ITERATOR_NEXT:
            {
                Expression iter = Generate(sub, op.Childs[0]);
                Expression has_next =
                    Expression.Call(
                        iter, typeof(IEnumerator).GetMethod("MoveNext"));

                return Expression.Condition(
                    has_next,
                    Expression.Property(iter, "Current"),
                    Expression.Constant(null, typeof(IP5Any)));
            }
            case Opcode.OpNumber.OP_SPLICE:
            {
                var args = new List<Expression>();

                args.Add(Runtime);
                args.Add(Generate(sub, op.Childs[0]));

                if (op.Childs.Length > 1)
                    args.Add(Generate(sub, op.Childs[1]));
                else
                    args.Add(Expression.Constant(null, typeof(IP5Any)));

                if (op.Childs.Length > 2)
                    args.Add(Generate(sub, op.Childs[2]));
                else
                    args.Add(Expression.Constant(null, typeof(IP5Any)));

                if (op.Childs.Length > 3)
                {
                    var list = new List<Expression>();

                    for (int i = 3; i < op.Childs.Length; ++i)
                        list.Add(Generate(sub, op.Childs[i]));

                    args.Add(Expression.NewArrayInit(typeof(IP5Any), list));
                }

                if (op.Childs.Length <= 3)
                    return Expression.Call(
                        typeof(Builtins).GetMethod("ArraySplice"), args);
                else
                    return Expression.Call(
                        typeof(Builtins).GetMethod("ArrayReplace"), args);
            }
            case Opcode.OpNumber.OP_ARRAY_SLICE:
            {
                var ea = (ElementAccess)op;

                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Array).GetMethod("Slice"),
                    Runtime,
                    Generate(sub, op.Childs[1]),
                    Expression.Constant(ea.Create != 0));
            }
            case Opcode.OpNumber.OP_HASH_SLICE:
            {
                var ea = (ElementAccess)op;

                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Hash).GetMethod("Slice"),
                    Runtime,
                    Generate(sub, op.Childs[1]),
                    Expression.Constant(ea.Create != 0));
            }
            case Opcode.OpNumber.OP_LIST_SLICE:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5List).GetMethod("Slice", new Type[] {
                            typeof(Runtime), typeof(P5Array) }),
                    Runtime,
                    Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_KEYS:
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Hash).GetMethod("Keys"),
                    Runtime);
            case Opcode.OpNumber.OP_VALUES:
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Hash).GetMethod("Values"),
                    Runtime);
            case Opcode.OpNumber.OP_EACH:
                return Expression.Call(
                    typeof(Builtins).GetMethod("HashEach"),
                    Runtime,
                    OpContext(op),
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_TEMPORARY:
            {
                Temporary tm = (Temporary)op;

                return GetTemporary(tm.Index, TypeForSlot(tm.Slot));
            }
            case Opcode.OpNumber.OP_TEMPORARY_SET:
            {
                Temporary tm = (Temporary)op;
                Expression exp = Generate(sub, op.Childs[0]);

                return Expression.Assign(GetTemporary(tm.Index, TypeForSlot(tm.Slot)), exp);
            }
            case Opcode.OpNumber.OP_TEMPORARY_CLEAR:
            {
                Temporary tm = (Temporary)op;
                var type = TypeForSlot(tm.Slot);

                return Expression.Assign(GetTemporary(tm.Index, type),
                                         Expression.Constant(null, type));
            }
            case Opcode.OpNumber.OP_LEXICAL:
            {
                Lexical lx = (Lexical)op;

                return lx.LexicalIndex == 0 && !IsMain ? Arguments : GetLexicalValue(lx.LexicalIndex, lx.Slot);
            }
            case Opcode.OpNumber.OP_LEXICAL_CLEAR:
            {
                Lexical lx = (Lexical)op;
                Expression lexvar = GetLexical(lx.LexicalIndex, lx.Slot);

                return Expression.Assign(lexvar, Expression.Constant(null, lexvar.Type));
            }
            case Opcode.OpNumber.OP_LEXICAL_SET:
            {
                Lexical lx = (Lexical)op;
                Expression lexvar = GetLexical(lx.LexicalIndex, lx.Slot);

                return Expression.Assign(
                    lexvar,
                    Expression.Convert(Generate(sub, op.Childs[0]), lexvar.Type));
            }
            case Opcode.OpNumber.OP_LEXICAL_PAD:
            {
                Lexical lx = (Lexical)op;

                return GetLexicalPadValue(lx.LexicalInfo);
            }
            case Opcode.OpNumber.OP_LEXICAL_PAD_CLEAR:
            {
                Lexical lx = (Lexical)op;
                Expression lexvar = GetLexicalPad(lx.LexicalInfo);

                return Expression.Assign(lexvar, Expression.Constant(null, lexvar.Type));
            }
            case Opcode.OpNumber.OP_LEXICAL_PAD_SET:
            {
                Lexical lx = (Lexical)op;
                Expression lexvar = GetLexicalPad(lx.LexicalInfo);

                return Expression.Assign(
                    lexvar,
                    Expression.Convert(Generate(sub, op.Childs[0]), lexvar.Type));
            }
            case Opcode.OpNumber.OP_LOCALIZE_LEXICAL_PAD:
            {
                LocalLexical lx = (LocalLexical)op;
                Expression lexvar = GetLexicalPad(lx.LexicalInfo);
                var saved = GetTemporary(lx.Index, typeof(IP5Any));

                return Expression.Assign(saved, lexvar);
            }
            case Opcode.OpNumber.OP_RESTORE_LEXICAL_PAD:
            {
                var exps = new List<Expression>();
                LocalLexical lx = (LocalLexical)op;
                Expression lexvar = GetLexicalPad(lx.LexicalInfo);
                var saved = GetTemporary(lx.Index, typeof(IP5Any));

                exps.Add(
                    Expression.IfThen(
                        Expression.NotEqual(
                            saved,
                            Expression.Constant(null, saved.Type)),
                        Expression.Assign(lexvar, saved)));
                exps.Add(Expression.Assign(
                             saved,
                             Expression.Constant(null, saved.Type)));

                return Expression.Block(typeof(void), exps);
            }
            case Opcode.OpNumber.OP_LOCALIZE_LEXICAL:
            {
                LocalLexical lx = (LocalLexical)op;
                Expression lexvar = GetLexical(lx.LexicalIndex, TypeForSlot(lx.Slot));
                var saved = GetTemporary(lx.Index, TypeForSlot(lx.Slot));

                return Expression.Assign(saved, lexvar);
            }
            case Opcode.OpNumber.OP_RESTORE_LEXICAL:
            {
                var exps = new List<Expression>();
                LocalLexical lx = (LocalLexical)op;
                Expression lexvar = GetLexical(lx.LexicalIndex, TypeForSlot(lx.Slot));
                var saved = GetTemporary(lx.Index, TypeForSlot(lx.Slot));

                exps.Add(
                    Expression.IfThen(
                        Expression.NotEqual(
                            saved,
                            Expression.Constant(null, saved.Type)),
                        Expression.Assign(lexvar, saved)));
                exps.Add(Expression.Assign(
                             saved,
                             Expression.Constant(null, saved.Type)));

                return Expression.Block(typeof(void), exps);
            }
            case Opcode.OpNumber.OP_VEC:
            {
                return Expression.New(
                    typeof(P5Vec).GetConstructor(new[] { typeof(Runtime), typeof(IP5Any), typeof(IP5Any), typeof(IP5Any) }),
                    Runtime,
                    Generate(sub, op.Childs[0]),
                    Generate(sub, op.Childs[1]),
                    Generate(sub, op.Childs[2]));
            }
            case Opcode.OpNumber.OP_SUBSTR:
            {
                Expression value = Expression.Convert(
                    Generate(sub, op.Childs[0]), typeof(P5Scalar));
                Expression offset = Expression.Call(
                    Generate(sub, op.Childs[1]),
                    typeof(IP5Any).GetMethod("AsInteger"),
                    Runtime);
                Expression length = null;

                if (op.Childs.Length >= 3)
                    length = Expression.Call(
                        Generate(sub, op.Childs[2]),
                        typeof(IP5Any).GetMethod("AsInteger"),
                        Runtime);

                if (op.Childs.Length == 4)
                    return Expression.Call(
                        value,
                        typeof(P5Scalar).GetMethod("SpliceSubstring", new[] { typeof(Runtime), typeof(int), typeof(int), typeof(IP5Any) }),
                        Runtime,
                        offset, length,
                        Generate(sub, op.Childs[3]));
                else if (op.Childs.Length == 3)
                    return Expression.New(
                        typeof(P5Substr).GetConstructor(new[] { typeof(Runtime), typeof(IP5Any), typeof(int), typeof(int) }),
                        Runtime, value, offset, length);
                else if (op.Childs.Length == 2)
                    return Expression.New(
                        typeof(P5Substr).GetConstructor(new[] { typeof(Runtime), typeof(IP5Any), typeof(int) }),
                        Runtime, value, offset);

                throw new System.Exception(); // can't happen
            }
            case Opcode.OpNumber.OP_BLESS:
            {
                return
                    Expression.Call(
                        typeof(Builtins).GetMethod("Bless"),
                        Runtime,
                        Expression.Convert(Generate(sub, op.Childs[0]), typeof(P5Scalar)),
                        Generate(sub, op.Childs[1]));
            }
            case Opcode.OpNumber.OP_CALL_METHOD:
            {
                CallMethod cm = (CallMethod)op;

                return
                    Expression.Call(
                        Generate(sub, op.Childs[0]),
                        typeof(P5Array).GetMethod("CallMethod"),
                        Runtime, OpContext(op),
                        Expression.Constant(cm.Method));
            }
            case Opcode.OpNumber.OP_CALL_METHOD_INDIRECT:
            {
                return
                    Expression.Call(
                        Generate(sub, op.Childs[1]),
                        typeof(P5Array).GetMethod("CallMethodIndirect"),
                        Runtime, OpContext(op),
                        Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_FIND_METHOD:
            {
                CallMethod cm = (CallMethod)op;

                return
                    Expression.Call(
                        Generate(sub, op.Childs[0]),
                        typeof(IP5Any).GetMethod("FindMethod"),
                        Runtime, Expression.Constant(cm.Method));
            }
            case Opcode.OpNumber.OP_CALL:
            {
                return
                    Expression.Call(
                        Generate(sub, op.Childs[1]), typeof(P5Code).GetMethod("Call"),
                        Runtime, OpContext(op), Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_REFTYPE:
            {
                return Expression.Call(
                    ForceScalar(Generate(sub, op.Childs[0])),
                    typeof(P5Scalar).GetMethod("ReferenceType"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_REFERENCE:
            {
                return Expression.New(
                    typeof(P5Scalar).GetConstructor(
                        new Type[] { typeof(Runtime), typeof(IP5Referrable) }),
                    new Expression[] { Runtime, Generate(sub, op.Childs[0]) });
            }
            case Opcode.OpNumber.OP_VIVIFY_SCALAR:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("VivifyScalar"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_VIVIFY_ARRAY:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("VivifyArray"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_VIVIFY_HASH:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("VivifyHash"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_DEREFERENCE_SCALAR:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("DereferenceScalar"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_DEREFERENCE_ARRAY:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("DereferenceArray"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_DEREFERENCE_HASH:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("DereferenceHash"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_DEREFERENCE_GLOB:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("DereferenceGlob"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_DEREFERENCE_SUB:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(IP5Any).GetMethod("DereferenceSubroutine"),
                    Runtime);
            }
            case Opcode.OpNumber.OP_MAKE_CLOSURE:
            {
                return Expression.Call(
                    Generate(sub, op.Childs[0]),
                    typeof(P5Code).GetMethod("MakeClosure"),
                    Runtime, Pad);
            }
            case Opcode.OpNumber.OP_MAKE_QR:
            {
                return Expression.New(
                    typeof(P5Scalar).GetConstructor(new System.Type[] { typeof(Runtime), typeof(IP5Referrable) }),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_LOCALIZE_GLOB_SLOT:
            {
                var exps = new List<Expression>();
                var vars = new List<ParameterExpression>();
                var lop = (LocalGlobSlot)op;
                var st = typeof(Runtime).GetField("SymbolTable");
                var glob = Expression.Variable(typeof(P5Typeglob));
                var saved = Expression.Variable(TypeForSlot(lop.Slot));
                var temp = GetTemporary(lop.Index, typeof(IP5Any));

                // FIXME do not walk twice the symbol table
                exps.Add(
                    Expression.Assign(
                        glob,
                        Expression.Call(
                            Expression.Field(Runtime, st),
                            typeof(P5SymbolTable).GetMethod("GetGlob"),
                            Runtime,
                            Expression.Constant(lop.Name),
                            Expression.Constant(true))));
                exps.Add(
                    Expression.Assign(
                        temp,
                        Expression.Call(
                            Expression.Field(Runtime, st),
                            typeof(P5SymbolTable).GetMethod(MethodForSlot(lop.Slot)),
                            Runtime,
                            Expression.Constant(lop.Name),
                            Expression.Constant(true))));
                exps.Add(
                    Expression.Assign(
                        saved,
                        Expression.Convert(
                            Expression.Call(
                                temp,
                                typeof(IP5Any).GetMethod("Localize"),
                                Runtime),
                            saved.Type)));
                exps.Add(
                    Expression.Assign(
                        Expression.Property(
                            glob,
                            PropertyForSlot(lop.Slot)),
                        saved));
                exps.Add(saved);

                vars.Add(glob);
                vars.Add(saved);

                return Expression.Block(typeof(IP5Any), vars, exps);
            }
            case Opcode.OpNumber.OP_RESTORE_GLOB_SLOT:
            {
                var exps = new List<Expression>();
                var vars = new List<ParameterExpression>();
                var lop = (LocalGlobSlot)op;
                var st = typeof(Runtime).GetField("SymbolTable");
                var glob = Expression.Variable(typeof(P5Typeglob));
                var saved = GetTemporary(lop.Index, typeof(IP5Any));

                exps.Add(
                    Expression.Assign(
                        glob,
                        Expression.Call(
                            Expression.Field(Runtime, st),
                            typeof(P5SymbolTable).GetMethod("GetGlob"),
                            Runtime,
                            Expression.Constant(lop.Name),
                            Expression.Constant(true))));
                exps.Add(
                    Expression.Assign(
                        Expression.Property(
                            glob,
                            PropertyForSlot(lop.Slot)),
                        Expression.Convert(
                            saved,
                            TypeForSlot(lop.Slot))));
                exps.Add(
                    Expression.Assign(
                        saved,
                        Expression.Constant(null, saved.Type)));

                vars.Add(glob);

                return Expression.IfThen(
                    Expression.NotEqual(
                        saved,
                        Expression.Constant(null, typeof(IP5Any))),
                    Expression.Block(typeof(IP5Any), vars, exps));
            }
            case Opcode.OpNumber.OP_LOCALIZE_ARRAY_ELEMENT:
            {
                var le = (LocalElement)op;

                return Expression.Call(
                    typeof(Builtins).GetMethod("LocalizeArrayElement"),
                    Runtime,
                    Generate(sub, le.Childs[0]),
                    Generate(sub, le.Childs[1]),
                    GetTemporary(le.Index, typeof(SavedValue)));
            }
            case Opcode.OpNumber.OP_RESTORE_ARRAY_ELEMENT:
            {
                var le = (LocalElement)op;

                return Expression.Call(
                    typeof(Builtins).GetMethod("RestoreArrayElement"),
                    Runtime,
                    GetTemporary(le.Index, typeof(SavedValue)));
            }
            case Opcode.OpNumber.OP_LOCALIZE_HASH_ELEMENT:
            {
                var le = (LocalElement)op;

                return Expression.Call(
                    typeof(Builtins).GetMethod("LocalizeHashElement"),
                    Runtime,
                    Generate(sub, le.Childs[0]),
                    Generate(sub, le.Childs[1]),
                    GetTemporary(le.Index, typeof(SavedValue)));
            }
            case Opcode.OpNumber.OP_RESTORE_HASH_ELEMENT:
            {
                var le = (LocalElement)op;

                return Expression.Call(
                    typeof(Builtins).GetMethod("RestoreHashElement"),
                    Runtime,
                    GetTemporary(le.Index, typeof(SavedValue)));
            }
            case Opcode.OpNumber.OP_LEXICAL_STATE_SET:
            {
                var ls = (LexState)op;
                var state = sub.LexicalStates[ls.Index];

                // force package creation
                if (state.Package != null)
                    DefinePackage(state.Package);

                return Expression.Block(
                    typeof(void),
                    Expression.Assign(
                        Expression.Field(Runtime, "Package"),
                        Expression.Constant(state.Package)),
                    Expression.Assign(
                        Expression.Field(Runtime, "Hints"),
                        Expression.Constant(state.Hints)));
            }
            case Opcode.OpNumber.OP_LEXICAL_STATE_SAVE:
            {
                var ls = (LexState)op;
                var slot = GetSavedLexState(ls.Index);

                return Expression.Block(
                    typeof(void),
                    Expression.Assign(
                        Expression.Field(slot, "Package"),
                        Expression.Field(Runtime, "Package")),
                    Expression.Assign(
                        Expression.Field(slot, "Hints"),
                        Expression.Field(Runtime, "Hints")));
            }
            case Opcode.OpNumber.OP_LEXICAL_STATE_RESTORE:
            {
                var ls = (LexState)op;
                var slot = GetSavedLexState(ls.Index);

                return Expression.Block(
                    typeof(void),
                    Expression.Assign(
                        Expression.Field(Runtime, "Package"),
                        Expression.Field(slot, "Package")),
                    Expression.Assign(
                        Expression.Field(Runtime, "Hints"),
                        Expression.Field(slot, "Hints")));
            }
            case Opcode.OpNumber.OP_CALLER:
            {
                return op.Childs.Length == 0 ?
                    Expression.Call(
                        Runtime,
                        typeof(Runtime).GetMethod("CallerNoArg"),
                        OpContext(op)) :
                    Expression.Call(
                        Runtime,
                        typeof(Runtime).GetMethod("CallerWithArg"),
                        Generate(sub, op.Childs[0]),
                        OpContext(op));
            }
            case Opcode.OpNumber.OP_CONSTANT_REGEX:
            {
                var cs = (ConstantSub)op;

                return ConstantRegex(cs.Value);
            }
            case Opcode.OpNumber.OP_EVAL_REGEX:
            {
                RegexEval re = (RegexEval)op;

                return Expression.Call(
                    typeof(Builtins).GetMethod("CompileRegex"),
                    Runtime,
                    Expression.Call(
                        Generate(sub, re.Childs[0]),
                        typeof(IP5Any).GetMethod("AsScalar"),
                        Runtime),
                    Expression.Constant(re.Flags));
            }
            case Opcode.OpNumber.OP_POS:
            {
                return Expression.New(
                    typeof(P5Pos).GetConstructor(ProtoRuntimeAny),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            }
            case Opcode.OpNumber.OP_RX_STATE_RESTORE:
            {
                RegexState rs = (RegexState)op;

                return Expression.Assign(
                    Expression.Field(Runtime, "LastMatch"),
                    GetSavedRxState(rs.Index));
            }
            case Opcode.OpNumber.OP_MATCH:
            {
                RegexMatch rm = (RegexMatch)op;
                bool global = (rm.Flags & Opcode.RX_GLOBAL) != 0;
                var meth = typeof(IP5Regex).GetMethod(global ? "MatchGlobal" : "Match");

                return
                    Expression.Call(
                        Generate(sub, op.Childs[1]),
                        meth,
                        Runtime,
                        Generate(sub, op.Childs[0]),
                        Expression.Constant(rm.Flags & Opcode.RX_KEEP),
                        OpContext(rm),
                        GetSavedRxState(rm.Index));
            }
            case Opcode.OpNumber.OP_REPLACE:
            {
                RegexReplace rm = (RegexReplace)op;
                bool global = (rm.Flags & Opcode.RX_GLOBAL) != 0;

                if (global)
                    return GenerateGlobalSubstitution(sub, rm);
                else
                    return GenerateSubstitution(sub, rm);
            }
            case Opcode.OpNumber.OP_RX_SPLIT_SKIPSPACES:
                return Expression.Call(
                    typeof(Builtins).GetMethod("SplitSpaces"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_TRANSLITERATE:
            {
                RegexTransliterate rt = (RegexTransliterate)op;

                return
                    Expression.New(
                        typeof(P5Scalar).GetConstructor(ProtoRuntimeInt),
                        Runtime,
                        Expression.Call(
                            typeof(Builtins).GetMethod("Transliterate"),
                            Runtime,
                            Generate(sub, rt.Childs[0]),
                            Expression.Constant(rt.Match),
                            Expression.Constant(rt.Replacement),
                            Expression.Constant(rt.Flags)));
            }
            case Opcode.OpNumber.OP_UNLINK:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Unlink"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_OPEN:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Open"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_CLOSE:
                return Expression.Call(
                    typeof(Builtins).GetMethod("Close"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            case Opcode.OpNumber.OP_FT_ISFILE:
                return Expression.Call(
                    typeof(Builtins).GetMethod("IsFile"),
                    Runtime,
                    Generate(sub, op.Childs[0]));
            default:
                throw new System.Exception(string.Format("Unhandled opcode {0:S} in generation", op.Number.ToString()));
            }
        }
Ejemplo n.º 29
0
 private Type TypeForSlot(Opcode.Sigil slot)
 {
     return slot == Opcode.Sigil.SCALAR   ? typeof(P5Scalar) :
            slot == Opcode.Sigil.INDEXABLE? typeof(IP5Array) :
            slot == Opcode.Sigil.HASH     ? typeof(P5Hash) :
            slot == Opcode.Sigil.ITERATOR ? typeof(IEnumerator<IP5Any>) :
            slot == Opcode.Sigil.GLOB     ? typeof(P5Typeglob) :
            slot == Opcode.Sigil.SUB      ? typeof(P5Code) :
            slot == Opcode.Sigil.HANDLE   ? typeof(P5Handle) :
            slot == Opcode.Sigil.ARRAY    ? typeof(P5Array) :
                                            typeof(void);
 }
Ejemplo n.º 30
0
 protected abstract Expression Defined(Subroutine sub, Opcode op);