internal void Generate(Subroutine sub)
 {
     if (sub.IsRegex)
         GenerateRegex(sub);
     else
         GenerateSub(sub);
 }
        internal IP5Regex GenerateRegex(Subroutine sub)
        {
            var rx = runtime.NativeRegex ? RegexGenerator.GenerateNetRegex(sub) : RegexGenerator.GenerateRegex(sub);

            regexes[sub] = rx;

            return rx;
        }
Beispiel #3
0
        public LambdaExpression Generate(Subroutine sub, bool is_main)
        {
            IsMain = is_main;
            SubLabel = Expression.Label(typeof(IP5Any));

            for (int i = 0; i < sub.BasicBlocks.Count; ++i)
                if (sub.BasicBlocks[i] != null)
                    BlockLabels[sub.BasicBlocks[i]] = Expression.Label("L" + i.ToString());

            var scopes = GenerateScopes(sub);

            var vars = new List<ParameterExpression>();
            AddVars(vars, Variables);
            AddVars(vars, Lexicals);
            AddVars(vars, Temporaries);
            AddVars(vars, LexStates);
            AddVars(vars, RxStates);

            var block = Expression.Block(typeof(IP5Any), vars, scopes);
            var args = new ParameterExpression[] { Runtime, Context, Pad, Arguments };
            return Expression.Lambda<P5Code.Sub>(Expression.Label(SubLabel, block), args);
        }
 public static IP5Regex GenerateNetRegex(Subroutine sub)
 {
     return new NetRegex(sub.OriginalRegex);
 }
        public static IP5Regex GenerateRegex(Subroutine sub)
        {
            var opmap = new Dictionary<BasicBlock, int>();
            var quantifiers = new List<RxQuantifier>();
            var ops = new List<P5Regex.Op>();
            var targets = new List<int>();
            var exact = new List<string>();
            var classes = new List<RxClass>();
            int captures = 0, saved = 0, count = 0;

            foreach (var bb in sub.BasicBlocks)
                opmap[bb] = count++;

            foreach (var bb in sub.BasicBlocks)
            {
                targets.Add(ops.Count);

                foreach (var op in bb.Opcodes)
                {
                    switch (op.Number)
                    {
                    case Opcode.OpNumber.OP_RX_ANY:
                    case Opcode.OpNumber.OP_RX_ANY_NONEWLINE:
                    case Opcode.OpNumber.OP_RX_FAIL:
                    case Opcode.OpNumber.OP_RX_POP_STATE:
                    case Opcode.OpNumber.OP_RX_BEGINNING:
                    case Opcode.OpNumber.OP_RX_END_OR_NEWLINE:
                    case Opcode.OpNumber.OP_RX_START_MATCH:
                        ops.Add(new P5Regex.Op(op.Number));
                        break;
                    case Opcode.OpNumber.OP_RX_ACCEPT:
                    {
                        var ac = (RegexAccept)op;

                        ops.Add(new P5Regex.Op(ac.Number, ac.Groups));
                        break;
                    }
                    case Opcode.OpNumber.OP_RX_EXACT:
                    case Opcode.OpNumber.OP_RX_EXACT_I:
                    {
                        var ex = (RegexExact)op;

                        ops.Add(new P5Regex.Op(ex.Number, exact.Count));
                        exact.Add(ex.Characters);
                        break;
                    }
                    case Opcode.OpNumber.OP_RX_SAVE_POS:
                    case Opcode.OpNumber.OP_RX_RESTORE_POS:
                    {
                        var st = (RegexState)op;

                        ops.Add(new P5Regex.Op(st.Number, st.Index));
                        ++saved;
                        break;
                    }
                    case Opcode.OpNumber.OP_RX_CLASS:
                    {
                        var cl = (RegexClass)op;
                        string ex = cl.Elements;

                        if ((cl.Flags & 1) != 0)
                            ex = ex.ToLower() + ex.ToUpper();

                        ops.Add(new P5Regex.Op(cl.Number, classes.Count));
                        classes.Add(new RxClass(ex, cl.Flags & ~1));
                        break;
                    }
                    case Opcode.OpNumber.OP_RX_START_GROUP:
                    {
                        var gr = (RegexStartGroup)op;

                        ops.Add(new P5Regex.Op(gr.Number, opmap[gr.To]));
                        break;
                    }
                    case Opcode.OpNumber.OP_RX_TRY:
                    {
                        var tr = (RegexTry)op;

                        ops.Add(new P5Regex.Op(tr.Number, opmap[tr.To]));
                        break;
                    }
                    case Opcode.OpNumber.OP_RX_BACKTRACK:
                    {
                        var tr = (RegexBacktrack)op;

                        ops.Add(new P5Regex.Op(tr.Number, opmap[tr.To]));
                        break;
                    }
                    case Opcode.OpNumber.OP_RX_QUANTIFIER:
                    {
                        var qu = (RegexQuantifier)op;

                        ops.Add(new P5Regex.Op(qu.Number, quantifiers.Count));
                        quantifiers.Add(
                            new RxQuantifier(qu.Min, qu.Max, qu.Greedy != 0,
                                             opmap[qu.To], qu.Group,
                                             qu.SubgroupsStart,
                                             qu.SubgroupsEnd));
                        if (captures <= qu.Group)
                            captures = qu.Group + 1;

                        break;
                    }
                    case Opcode.OpNumber.OP_RX_CAPTURE_START:
                    case Opcode.OpNumber.OP_RX_CAPTURE_END:
                    {
                        var ca = (RegexCapture)op;

                        ops.Add(new P5Regex.Op(ca.Number, ca.Group));
                        if (captures <= ca.Group)
                            captures = ca.Group + 1;

                        break;
                    }
                    case Opcode.OpNumber.OP_JUMP:
                    {
                        var ju = (Jump)op;

                        ops.Add(new P5Regex.Op(ju.Number, opmap[ju.To]));
                        break;
                    }
                    default:
                        throw new System.Exception(string.Format("Unhandled opcode {0:S} in regex generation", op.Number.ToString()));
                    }
                }
            }

            return new P5Regex(ops.ToArray(), targets.ToArray(),
                               exact.ToArray(), quantifiers.ToArray(),
                               classes.ToArray(), captures, saved,
                               sub.OriginalRegex);
        }
 internal P5Code GetSubroutine(Subroutine sub)
 {
     return subroutines[sub];
 }
Beispiel #7
0
 protected abstract Expression Defined(Subroutine sub, Opcode op);
        public Type CompleteGeneration(Subroutine[] subroutines,
                                       Runtime runtime)
        {
            // force generation of anonymous subroutine templates before all
            // other subroutines
            FieldInfo main = AddSubInitialization(subroutines, true, null);
            AddSubInitialization(subroutines, false, main);

            AddInitMethod(main);

            return ClassBuilder.CreateType();
        }
 internal SubInfo(string method, Subroutine sub, FieldInfo codefield)
 {
     MethodName = method;
     CodeField = codefield;
     Subroutine = sub;
 }
Beispiel #10
0
        private Expression GenerateScopes(Subroutine sub)
        {
            Scopes = new ScopeInfo[sub.Scopes.Count];

            for (int i = 0; i < Scopes.Length; ++i)
                Scopes[i].FirstBlockFor = -1;

            for (int i = sub.Scopes.Count - 1; i >= 0; --i)
                GenerateScope(sub, sub.Scopes[i]);

            return Expression.Block(typeof(IP5Any), Scopes[0].Body);
        }
        public void AddRegexInfo(Subroutine sub)
        {
            FieldInfo field = ClassBuilder.DefineField(
                "regex_" + MethodIndex++.ToString(), typeof(IP5Regex),
                FieldAttributes.Private|FieldAttributes.Static);

            Subroutines[sub] = new SubInfo(null, sub, field);
        }
Beispiel #12
0
 protected abstract Expression UnaryOperator(Subroutine sub, Opcode op, ExpressionType operation);
Beispiel #13
0
        private Expression GenerateGlobalSubstitution(Subroutine sub, RegexReplace rm)
        {
            var scalar = Expression.Variable(typeof(P5Scalar));
            var init_scalar =
                Expression.Assign(scalar, Generate(sub, rm.Childs[0]));
            var pos = Expression.Variable(typeof(int));
            var count = Expression.Variable(typeof(int));
            var matched = Expression.Variable(typeof(bool));
            var str = Expression.Variable(typeof(string));
            var replace = Expression.Variable(typeof(string));
            var repl_list = Expression.Variable(typeof(List<RxReplacement>));
            var init_str =
                Expression.Assign(
                    str,
                    Expression.Call(
                        scalar,
                        typeof(IP5Any).GetMethod("AsString"),
                        Runtime));
            var match = Expression.Call(
                Generate(sub, rm.Childs[1]),
                typeof(IP5Regex).GetMethod("MatchString"),
                Runtime,
                str,
                pos,
                Expression.Constant(false),
                GetSavedRxState(rm.Index));
            var rxstate = Expression.Field(
                Runtime,
                typeof(Runtime).GetField("LastMatch"));
            var rx_end =
                Expression.Field(
                    rxstate,
                    typeof(RxResult).GetField("End"));
            var rx_start =
                Expression.Field(
                    rxstate,
                    typeof(RxResult).GetField("Start"));

            var if_match = new List<Expression>();

            if_match.Add(Expression.PreIncrementAssign(count));
            if_match.Add(Expression.Assign(matched, Expression.Constant(true)));
            if_match.Add(Expression.Assign(pos, rx_end));

            // at this point all nested scopes have been generated
            if_match.Add(Expression.Assign(
                             replace,
                             Expression.Call(
                                 ValueBlocks[rm.To],
                                 typeof(IP5Any).GetMethod("AsString"),
                                 Runtime)));

            if_match.Add(
                Expression.Call(
                    repl_list,
                    typeof(List<RxReplacement>).GetMethod("Add"),
                    Expression.New(
                        typeof(RxReplacement).GetConstructor(
                            new Type[] { typeof(string), typeof(int), typeof(int) }),
                        replace, rx_start, rx_end)));

            var break_to = Expression.Label(typeof(void));
            var loop =
                Expression.Loop(
                    Expression.Block(
                        Expression.IfThenElse(
                            match,
                            Expression.Block(typeof(void), if_match),
                            Expression.Break(break_to))),
                    break_to);

            // TODO save last match

            var vars = new List<ParameterExpression>();
            vars.Add(scalar);
            vars.Add(pos);
            vars.Add(count);
            vars.Add(matched);
            vars.Add(str);
            vars.Add(replace);
            vars.Add(repl_list);

            var body = new List<Expression>();
            body.Add(init_scalar);
            body.Add(init_str);
            body.Add(Expression.Assign(pos, Expression.Constant(-1)));
            body.Add(Expression.Assign(count, Expression.Constant(0)));
            body.Add(Expression.Assign(matched, Expression.Constant(false)));
            body.Add(Expression.Assign(
                         repl_list,
                         Expression.New(
                             typeof(List<RxReplacement>).GetConstructor(
                                 new Type[0]))));
            body.Add(loop);

            // replace substrings
            body.Add(
                Expression.Call(
                    typeof(P5Regex).GetMethod("ReplaceSubstrings"),
                    Runtime,
                    scalar,
                    str,
                    repl_list));

            // return value
            var result =
                Expression.New(
                    typeof(P5Scalar).GetConstructor(ProtoRuntimeInt),
                    Runtime,
                    count);

            body.Add(
                Expression.Condition(
                    Expression.Equal(
                        OpContext(rm),
                        Expression.Constant(Opcode.ContextValues.LIST)),
                    Expression.New(
                        typeof(P5List).GetConstructor(ProtoRuntimeAny),
                        Runtime,
                        result),
                    result, typeof(IP5Any)));

            return Expression.Block(typeof(IP5Any), vars, body);
        }
Beispiel #14
0
 protected abstract Expression UnaryIncrement(Subroutine sub, Opcode op, ExpressionType operation);
Beispiel #15
0
 protected abstract Expression StringRelOperator(Subroutine sub, Opcode op, ExpressionType operation);
Beispiel #16
0
 protected abstract Expression ScalarAssign(Subroutine sub, Opcode.ContextValues cxt, Expression lvalue, Expression rvalue);
        public void AddMethod(Subroutine sub)
        {
            var sg = new StaticSubGenerator(this, Subroutines);
            var body = sg.Generate(sub, Subroutines[sub].IsMain);

            MethodBuilder method_builder =
                ClassBuilder.DefineMethod(
                    Subroutines[sub].MethodName,
                    MethodAttributes.Static|MethodAttributes.Public);
            body.CompileToMethod(method_builder,
                                 DebugInfoGenerator.CreatePdbGenerator());
        }
Beispiel #18
0
        private Expression GenerateSubstitution(Subroutine sub, RegexReplace rm)
        {
            var scalar = Expression.Variable(typeof(P5Scalar));
            var str = Expression.Variable(typeof(string));
            var replace = Expression.Variable(typeof(IP5Any));
            var init_scalar =
                Expression.Assign(scalar, Generate(sub, rm.Childs[0]));
            var init_str =
                Expression.Assign(
                    str,
                    Expression.Call(
                        scalar,
                        typeof(IP5Any).GetMethod("AsString"),
                        Runtime));

            var replace_list = new List<Expression>();

            // at this point all nested scopes have been generated
            replace_list.Add(
                Expression.Assign(replace, ValueBlocks[rm.To]));

            // replace in string
            var rxstate = Expression.Field(
                Runtime,
                typeof(Runtime).GetField("LastMatch"));

            replace_list.Add(
                Expression.Call(
                    scalar,
                    typeof(P5Scalar).GetMethod("SpliceSubstring", new[] { typeof(Runtime), typeof(int), typeof(int), typeof(IP5Any) }),
                    Runtime,
                    Expression.Field(
                        rxstate,
                        typeof(RxResult).GetField("Start")),
                    Expression.Subtract(
                        Expression.Field(
                            rxstate,
                            typeof(RxResult).GetField("End")),
                        Expression.Field(
                            rxstate,
                            typeof(RxResult).GetField("Start"))),
                    replace));

            // return true at end of replacement
            replace_list.Add(Expression.Constant(true));

            var match = Expression.Call(
                Generate(sub, rm.Childs[1]),
                typeof(IP5Regex).GetMethod("MatchString"),
                Runtime,
                str,
                Expression.Constant(-1),
                Expression.Constant(false),
                GetSavedRxState(rm.Index));
            var repl = Expression.Condition(
                match,
                Expression.Block(typeof(bool), replace_list),
                Expression.Constant(false));

            var vars = new List<ParameterExpression>();
            vars.Add(scalar);
            vars.Add(str);
            vars.Add(replace);

            var exps = new List<Expression>();
            exps.Add(init_scalar);
            exps.Add(init_str);
            exps.Add(
                Expression.New(
                    typeof(P5Scalar).GetConstructor(ProtoRuntimeBool),
                    Runtime,
                    repl));

            return Expression.Block(typeof(P5Scalar), vars, exps);
        }
        public void AddRegex(Subroutine sub)
        {
            IP5Regex regex = NativeRegex ? RegexGenerator.GenerateNetRegex(sub) : RegexGenerator.GenerateRegex(sub);
            var stream = new MemoryStream();
            var formatter = new BinaryFormatter();

            formatter.Serialize(stream, regex);

            var bytes = new List<Expression>();
            foreach (var b in stream.ToArray())
                bytes.Add(Expression.Constant(b));

            var byteField = AddField(
                Expression.NewArrayInit(typeof(byte), bytes),
                typeof(byte[]));
            var memStream = Expression.New(
                typeof(MemoryStream).GetConstructor(
                    new Type[] { typeof(byte[]) }),
                Expression.Field(null, byteField));
            var deserializer = Expression.New(
                typeof(BinaryFormatter).GetConstructor(
                    new Type[0]));
            var init = Expression.Convert(
                Expression.Call(
                    deserializer,
                    typeof(BinaryFormatter).GetMethod(
                        "Deserialize",
                        new Type[] { typeof(System.IO.Stream) }),
                    memStream),
                typeof(IP5Regex));

            Initializers.Add(
                Expression.Assign(
                    Expression.Field(null, Subroutines[sub].CodeField),
                    init));
        }
Beispiel #20
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);
        }
        public void AddSubInfo(Subroutine sub)
        {
            bool is_main = sub.IsMain;
            string suffix = is_main          ? "main" :
                            sub.Name != null ? sub.Name :
                                               "anonymous";
            string method_name = "sub_" + suffix + "_" +
                                     MethodIndex++.ToString();
            FieldInfo field = ClassBuilder.DefineField(
                method_name + "_code", typeof(P5Code),
                FieldAttributes.Private|FieldAttributes.Static);

            Subroutines[sub] = new SubInfo(method_name, sub, field);
        }
Beispiel #22
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);
        }
        FieldInfo AddSubInitialization(Subroutine[] subroutines,
                                       bool anonymous, FieldInfo main)
        {
            var code_ctor = typeof(P5Code).GetConstructor(
                new[] { typeof(string), typeof(int[]), typeof(System.Type), typeof(string), typeof(bool) });
            var lexinfo_new_params = new Type[] {
                typeof(string), typeof(Opcode.Sigil), typeof(int),
                typeof(int), typeof(int), typeof(bool), typeof(bool),
            };
            var lexinfo_new = typeof(LexicalInfo).GetConstructor(lexinfo_new_params);
            var get_type =
                typeof(Type).GetMethod(
                    "GetType", new Type[] { typeof(string) });

            foreach (var sub in subroutines)
            {
                var si = Subroutines[sub];
                if (si.Subroutine.IsRegex)
                    continue;
                if (anonymous != (si.SubName == null))
                    continue;

                // new P5Code(System.Delegate.CreateDelegate(method, null)
                Expression proto;
                if (si.Prototype == null)
                    proto = Expression.Constant(null, typeof(int[]));
                else if (   si.Prototype.Length == 3
                         && si.Prototype[0] == 0
                         && si.Prototype[1] == 0
                         && si.Prototype[2] == 0)
                    proto = Expression.Field(null, typeof(P5Code).GetField("EMPTY_PROTO"));
                else
                {
                    Expression[] values = new Expression[si.Prototype.Length];

                    for (int i = 0; i < si.Prototype.Length; ++i)
                        values[i] = Expression.Constant(si.Prototype[i]);

                    proto = Expression.NewArrayInit(typeof(int), values);
                }

                Expression initcode =
                    Expression.New(code_ctor, new Expression[] {
                            Expression.Constant(si.SubName ?? "ANONCODE"),
                            proto,
                            Expression.Call(
                                get_type,
                                Expression.Constant(ClassBuilder.FullName)),
                            Expression.Constant(si.MethodName),
                            Expression.Constant(si.IsMain),
                        });

                Initializers.Add(
                    Expression.Assign(
                        Expression.Field(null, si.CodeField),
                        initcode));

                // code.ScratchPad = P5ScratchPad.CreateSubPad(runtime,
                //                       lexicals, main.ScratchPad)
                Expression[] alllex = new Expression[si.Lexicals.Count];
                for (int i = 0; i < alllex.Length; ++i)
                {
                    LexicalInfo lex = si.Lexicals[i];

                    alllex[i] = Expression.New(
                        lexinfo_new,
                        new Expression[] {
                            Expression.Constant(lex.Name),
                            Expression.Constant(lex.Slot),
                            Expression.Constant(lex.Level),
                            Expression.Constant(lex.Index),
                            Expression.Constant(lex.OuterIndex),
                            Expression.Constant(lex.InPad),
                            Expression.Constant(lex.FromMain),
                        });
                }
                Expression lexicals =
                    Expression.NewArrayInit(typeof(LexicalInfo), alllex);
                Expression init_pad =
                    Expression.Assign(
                        Expression.Property(
                            Expression.Field(null, si.CodeField),
                            "ScratchPad"),
                        Expression.Call(
                            typeof(P5ScratchPad).GetMethod("CreateSubPad"),
                            InitRuntime,
                            lexicals,
                            main != null ?
                            (Expression)Expression.Property(
                                    Expression.Field(null, main),
                                    "ScratchPad") :
                            (Expression)Expression.Constant(null, typeof(P5ScratchPad))));
                Initializers.Add(init_pad);

                if (si.IsMain)
                {
                    // code.NewScope(runtime);
                    Expression set_main_pad =
                        Expression.Call(
                            Expression.Field(null, si.CodeField),
                            typeof(P5Code).GetMethod("NewScope"),
                            InitRuntime);

                    Initializers.Add(set_main_pad);
                    main = si.CodeField;
                }
                else if (   si.SubName != null
                         && (   si.SubName == "BEGIN"
                             || si.SubName.EndsWith("::BEGIN")))
                {
                    // TODO need to set the line number for caller()
                    Expression empty_list =
                        Expression.New(
                            typeof(P5Array).GetConstructor(
                                new Type[] { typeof(Runtime) }),
                            InitRuntime);
                    Expression call_begin =
                        Expression.Call(
                            Expression.Field(null, si.CodeField),
                            typeof(P5Code).GetMethod("Call"),
                            InitRuntime,
                            Expression.Constant(Opcode.ContextValues.VOID),
                            empty_list);

                    Initializers.Add(call_begin);
                }
                else if (si.SubName != null)
                {
                    // runtime.SymbolTable.SetCode(runtime, sub_name, code)
                    Expression add_to_symboltable =
                        Expression.Call(
                            Expression.Field(
                                InitRuntime,
                                typeof(Runtime).GetField("SymbolTable")),
                            typeof(P5SymbolTable).GetMethod("DefineCode"),
                            InitRuntime,
                            Expression.Constant(si.SubName),
                            Expression.Field(null, si.CodeField));
                    Initializers.Add(add_to_symboltable);
                }
            }

            return main;
        }
Beispiel #24
0
 protected abstract Expression ArrayAssign(Subroutine sub, Opcode.ContextValues cxt, Expression lvalue, Expression rvalue, bool common);
 internal IP5Regex GetRegex(Subroutine sub)
 {
     return regexes[sub];
 }
Beispiel #26
0
        public void GenerateScope(Subroutine sub, Scope scope)
        {
            // TODO should not rely on block order
            BasicBlock first_block = null;
            var exps = new List<Expression>();

            CurrentScope = scope;

            for (int i = 0; i < sub.BasicBlocks.Count; ++i)
            {
                var block = sub.BasicBlocks[i];
                if (block == null || block.Dead != 0) // TODO enumeration
                    continue;

                if (block.Scope > scope.Id)
                {
                    int scopeId = block.Scope;

                    // if scope has no blocks on its own, still needs to
                    // insert inner scopes, so it can't just test whether this
                    // block's scope is directly inside the current scope, but
                    // it must handle the case when a scope is entirely
                    // composed by blocks in inner scopes
                    if (Scopes[scopeId].FirstBlockFor != -1)
                        scopeId = Scopes[scopeId].FirstBlockFor;

                    if (sub.Scopes[scopeId].Outer == scope.Id &&
                        !Scopes[scopeId].Used)
                    {
                        Scopes[scopeId].Used = true;

                        if (Scopes[scopeId].Body != null)
                        {
                            if (first_block != null)
                                exps.Add(Expression.Label(Scopes[scopeId].Start));

                            exps.AddRange(Scopes[scopeId].Body);
                        }

                        if (first_block == null)
                        {
                            first_block = Scopes[block.Scope].FirstBlock;
                            Scopes[block.Scope].FirstBlockFor = scope.Id;
                        }
                    }
                }
                else if (block.Scope == scope.Id)
                {
                    if (first_block == null)
                        first_block = block;
                    else
                        exps.Add(Expression.Label(BlockLabels[block]));

                    GenerateBlock(sub, block, exps);
                }
            }

            List<Expression> body = null;

            if ((scope.Flags & Scope.SCOPE_EVAL) != 0)
            {
                exps.Insert(0,
                    Expression.Call(
                        Expression.Field(Runtime, "CallStack"),
                        typeof(Stack<StackFrame>).GetMethod("Push"),
                        Expression.New(
                            typeof(StackFrame).GetConstructor(new Type[] {
                                    typeof(string), typeof(string),
                                    typeof(int), typeof(P5Code),
                                    typeof(Opcode.ContextValues),
                                    typeof(bool)}),
                            Expression.Constant(sub.LexicalStates[scope.LexicalState].Package),
                            Expression.Constant(scope.Start.File),
                            Expression.Constant(scope.Start.Line),
                            Expression.Constant(null, typeof(P5Code)),
                            Expression.Constant((Opcode.ContextValues)scope.Context),
                            Expression.Constant(true)
                            )));

                var except = new List<Expression>();
                var ex = Expression.Variable(typeof(P5Exception));
                for (int j = scope.Opcodes.Count - 1; j >= 0; --j)
                    GenerateOpcodes(sub, scope.Opcodes[j], except);
                except.Add(
                    Expression.Call(
                        Runtime,
                        typeof(Runtime).GetMethod("SetException"),
                        ex));
                GenerateBlock(sub, scope.Exception, except);

                var block = Expression.TryCatchFinally(
                    Expression.Block(typeof(IP5Any), exps),
                    Expression.Call(
                        Expression.Field(Runtime, "CallStack"),
                        typeof(Stack<StackFrame>).GetMethod("Pop")),
                    Expression.Catch(
                        ex,
                        Expression.Block(typeof(IP5Any), except))
                    );

                body = new List<Expression>();
                body.Add(block);
            }
            else if (scope.Opcodes.Count > 0)
            {
                var fault = new List<Expression>();
                for (int j = scope.Opcodes.Count - 1; j >= 0; --j)
                    GenerateOpcodes(sub, scope.Opcodes[j], fault);
                fault.Add(Expression.Rethrow(typeof(IP5Any)));

                var block = Expression.TryCatch(
                    Expression.Block(typeof(IP5Any), exps),
                    Expression.Catch(
                        typeof(System.Exception),
                        Expression.Block(typeof(IP5Any), fault)));

                body = new List<Expression>();
                body.Add(block);
            }
            else if (first_block != null)
                body = exps;

            if (first_block != null)
                Scopes[scope.Id].Start = BlockLabels[first_block];

            Scopes[scope.Id].FirstBlock = first_block;

            if ((scope.Flags & Scope.SCOPE_VALUE) != 0)
                ValueBlocks[first_block] = Expression.Block(
                    typeof(IP5Any), body);
            else
                Scopes[scope.Id].Body = body;
        }
Beispiel #27
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()));
            }
        }
Beispiel #28
0
 protected abstract Expression ConstantSub(Subroutine sub);
        internal P5Code GenerateSub(Subroutine sub)
        {
            if (subroutines.ContainsKey(sub))
                return subroutines[sub];

            if (sub.Inner != null)
                foreach (var inner in sub.Inner)
                    Generate(inner);

            var sg = new DynamicSubGenerator(runtime, this);
            var body = sg.Generate(sub, sub.IsMain);
            var deleg = body.Compile();
            P5Code code;

            if (sub.IsConstant)
            {
                // TODO abstract away
                var const_op = sub.BasicBlocks[sub.BasicBlocks.Count - 2].Opcodes[1].Childs[0];
                if (const_op.Number == Opcode.OpNumber.OP_MAKE_LIST)
                    const_op = const_op.Childs[0];
                object value;
                int flags;

                if (const_op.Number == Opcode.OpNumber.OP_CONSTANT_STRING)
                {
                    value = ((ConstantString)const_op).Value;
                    flags = 1; // CONST_STRING
                }
                else if (const_op.Number == Opcode.OpNumber.OP_CONSTANT_INTEGER)
                {
                    value = ((ConstantInt)const_op).Value;
                    flags = 10; // CONST_NUMBER|NUM_INTEGER
                }
                else if (const_op.Number == Opcode.OpNumber.OP_CONSTANT_FLOAT)
                {
                    value = ((ConstantFloat)const_op).Value;
                    flags = 18; // CONST_NUMBER|NUM_FLOAT
                }
                else if (sub.IsConstantPrototype)
                {
                    value = null;
                    flags = -1;
                }
                else
                    throw new System.Exception("Invalid constant value");

                code = new P5Code(sub.Name, deleg, value, flags);
            }
            else
                code = new P5Code(sub.Name, sub.Prototype, deleg, sub.IsMain);

            if (sub.IsMain)
                code.ScratchPad = P5ScratchPad.CreateMainPad(runtime,
                                                             sub.Lexicals,
                                                             main_pad);
            else
                code.ScratchPad = P5ScratchPad.CreateSubPad(runtime,
                                                            sub.Lexicals,
                                                            main_pad);

            if (sub.Name != null)
            {
                if (sub.Name == "BEGIN" || sub.Name.EndsWith("::BEGIN"))
                    // TODO need to set the line number for caller()
                    code.Call(runtime, Opcode.ContextValues.VOID,
                              new P5Array(runtime));
                else
                    runtime.SymbolTable.DefineCode(runtime, sub.Name, code);
            }

            subroutines[sub] = code;

            return code;
        }
Beispiel #30
0
 public void GenerateOpcodes(Subroutine sub, IList<Opcode> ops,
                            List<Expression> expressions)
 {
     foreach (var o in ops)
     {
         if (o.Position.File != null)
             UpdateFileLine(o, expressions);
         expressions.Add(Generate(sub, o));
     }
 }