Example #1
0
        protected override void OnGenerate()
        {
            var var = (CommonTree) T.Children[0];
            if (var.Type == 0)
            {
                Errors.ErrorParse((CommonErrorNode) var);
                return;
            }
            var exp = (CommonTree) T.Children[1];
            if (exp.Type == 0)
            {
                Errors.ErrorParse((CommonErrorNode) exp);
                return;
            }

            var defaultBlock = (CommonTree) T.Children[2];
            var blocks = new Dictionary<LoopDirective, CommonTree>();
            for (var i = 3; i < T.Children.Count; i++)
            {
                var targeted = (CommonTree) T.Children[i];
                var ins = targeted.Children[0];
                var tBlock = (CommonTree) targeted.Children[1];
                LoopDirective d;
                if (!Enum.TryParse(ins.Text, true, out d))
                {
                    Errors.ErrorUnknownLoopDirective(ins.Text);
                    continue;
                }
                blocks[d] = tBlock;
            }
            if (Errors.ContainsError())
                return;

            var endOfLoop = Ctx.Sink.DefineLabel();
            var continuePoint = Ctx.Sink.DefineLabel();
            var top = Ctx.Sink.DefineLabel();
            var endOfBlock = Ctx.Sink.DefineLabel();
            var oddEvenVar = Ctx.Sink.DeclareLocal(typeof (int));

            var iter = Ctx.Sink.DeclareLocal(typeof (IEnumerator));
            var current = Ctx.Sink.DeclareLocal(typeof (ITemplateType));

            Ctx.PushNewJumpScope(continuePoint, endOfLoop);
            try
            {
                //init part here
                var enumerableExp = new Expression(exp);
                Errors.AddRange(enumerableExp.Generate(Ctx));
                Ctx.Sink.FastEmitStoreLocal(current.LocalIndex);

                Ctx.Sink.Emit(OpCodes.Ldarg_0);
                Ctx.Sink.FastEmitLoadLocal(current.LocalIndex);
                Ctx.EmitVTFunctionCall("CheckIsEnumerable");
                Ctx.Sink.Emit(OpCodes.Brfalse, endOfBlock);

                Ctx.Sink.Emit(OpCodes.Ldarg_0);
                Ctx.Sink.FastEmitLoadLocal(current.LocalIndex);
                Ctx.EmitVTFunctionCall("PrimeIter");
                Ctx.Sink.FastEmitStoreLocal(iter.LocalIndex);

                Ctx.Sink.FastEmitConstInt(0);
                Ctx.Sink.FastEmitStoreLocal(oddEvenVar.LocalIndex);

                var noDataSkip = Ctx.Sink.DefineLabel();
                Ctx.Sink.FastEmitLoadLocal(iter.LocalIndex);
                Ctx.EmitIterMoveNext();
                Ctx.Sink.Emit(OpCodes.Brfalse, noDataSkip);

                var skipStart = Ctx.Sink.DefineLabel();

                Ctx.Sink.Emit(OpCodes.Ldarg_0);
                Ctx.Sink.FastEmitLoadLocal(iter.LocalIndex);
                Ctx.EmitVTFunctionCall("CurrentToTType");
                Ctx.Sink.FastEmitStoreLocal(current.LocalIndex);
                var s = new Statement(var);
                Errors.AddRange(s.GenerateSet(Ctx, current.LocalIndex));

                TryEmitBlock(LoopDirective.BeforeAll, blocks);
                Ctx.Sink.Emit(OpCodes.Br, skipStart);

                Ctx.Sink.MarkLabel(top);
                Ctx.Sink.Emit(OpCodes.Nop);

                Ctx.Sink.Emit(OpCodes.Ldarg_0);
                Ctx.Sink.FastEmitLoadLocal(iter.LocalIndex);
                Ctx.EmitVTFunctionCall("CurrentToTType");
                Ctx.Sink.FastEmitStoreLocal(current.LocalIndex);
                s = new Statement(var);
                s.GenerateSet(Ctx, current.LocalIndex);

                Ctx.Sink.MarkLabel(skipStart);
                Ctx.Sink.Emit(OpCodes.Nop);

                if (blocks.ContainsKey(LoopDirective.Between))
                {
                    var skipFirstBetween = Ctx.Sink.DefineLabel();
                    Ctx.Sink.FastEmitLoadLocal(oddEvenVar.LocalIndex);
                    Ctx.Sink.FastEmitConstInt(0);
                    Ctx.Sink.Emit(OpCodes.Ceq);
                    Ctx.Sink.Emit(OpCodes.Brtrue, skipFirstBetween);
                    TryEmitBlock(LoopDirective.Between, blocks);
                    Ctx.Sink.MarkLabel(skipFirstBetween);
                }

                TryEmitBlock(LoopDirective.Before, blocks);

                //even odd
                if (blocks.ContainsKey(LoopDirective.Even)
                    || blocks.ContainsKey(LoopDirective.Odd))
                {
                    var oddBlock = Ctx.Sink.DefineLabel();
                    var endOddEvenBlock = Ctx.Sink.DefineLabel();

                    Ctx.Sink.FastEmitLoadLocal(oddEvenVar.LocalIndex);
                    Ctx.Sink.FastEmitConstInt(2);
                    Ctx.Sink.Emit(OpCodes.Rem);
                    Ctx.Sink.FastEmitConstInt(0);
                    Ctx.Sink.Emit(OpCodes.Ceq);
                    Ctx.Sink.Emit(OpCodes.Brfalse, oddBlock);

                    TryEmitBlock(LoopDirective.Even, blocks);
                    Ctx.Sink.Emit(OpCodes.Br, endOddEvenBlock);

                    Ctx.Sink.MarkLabel(oddBlock);
                    TryEmitBlock(LoopDirective.Odd, blocks);
                    Ctx.Sink.MarkLabel(endOddEvenBlock);
                }

                var defaultBlk = new Block(defaultBlock.Children[0]);
                Errors.AddRange(defaultBlk.Generate(Ctx));

                TryEmitBlock(LoopDirective.Each, blocks);

                TryEmitBlock(LoopDirective.After, blocks);

                Ctx.Sink.MarkLabel(continuePoint);

                //increment odd even var
                Ctx.Sink.Emit(OpCodes.Ldc_I4_1);
                Ctx.Sink.FastEmitLoadLocal(oddEvenVar.LocalIndex);
                Ctx.Sink.Emit(OpCodes.Add);
                Ctx.Sink.FastEmitStoreLocal(oddEvenVar.LocalIndex);

                //increment
                //check condidtion
                Ctx.Sink.FastEmitLoadLocal(iter.LocalIndex);
                Ctx.EmitIterMoveNext();
                Ctx.Sink.Emit(OpCodes.Brtrue, top);

                Ctx.Sink.MarkLabel(endOfLoop);

                TryEmitBlock(LoopDirective.AfterAll, blocks);

                Ctx.Sink.Emit(OpCodes.Br, endOfBlock);

                Ctx.Sink.MarkLabel(noDataSkip);
                TryEmitBlock(LoopDirective.NoData, blocks);
                Ctx.Sink.MarkLabel(endOfBlock);
            }
            finally
            {
                Ctx.PopJumpScope();
            }
        }
Example #2
0
 private void TryEmitBlock(LoopDirective d, Dictionary<LoopDirective, CommonTree> blocks)
 {
     CommonTree block;
     if (!blocks.TryGetValue(d, out block))
     {
         Ctx.Sink.Emit(OpCodes.Nop);
         return;
     }
     var b = new Block(block);
     Errors.AddRange(b.Generate(Ctx));
 }