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(); } }
protected override void OnGenerate() { Errors.Clear(); var child = (CommonTree) T.Children[0]; switch (child.Type) { case 0: { Ctx.EmitNullRef(); Errors.ErrorParse((CommonErrorNode) child); break; } case TemplateLexer.Pragma: { var a = new Pragma(child); Errors.AddRange(a.Generate(Ctx)); break; } case TemplateLexer.Assert: { Ctx.Sink.Emit(OpCodes.Ldarg_0); var a = new Assert(child); Errors.AddRange(a.Generate(Ctx)); Ctx.EmitAppendToBuffer(); break; } case TemplateLexer.Continue: { if (!Ctx.InJumpableBlock) { Errors.ErrorInvalidJump("continue", child.Token); break; } Ctx.Sink.Emit(OpCodes.Br, Ctx.GetContinueLabel()); break; } case TemplateLexer.Break: { if (!Ctx.InJumpableBlock) { Errors.ErrorInvalidJump("break", child.Token); break; } Ctx.Sink.Emit(OpCodes.Br, Ctx.GetBreakLabel()); break; } case TemplateLexer.Stop: { Ctx.Sink.Emit(OpCodes.Br, Ctx.EndOfTemplate); break; } case TemplateLexer.Parse: { var args = (CommonTree) child.Children[0]; if (args.Type == 0) { Errors.ErrorParse((CommonErrorNode) args); break; } Ctx.Sink.Emit(OpCodes.Ldarg_0); Ctx.EmitArgList(args); Ctx.EmitVTFunctionCall("InvokeParse"); break; } case TemplateLexer.Include: { var args = (CommonTree) child.Children[0]; if (args.Type == 0) { Errors.ErrorParse((CommonErrorNode) args); break; } Ctx.Sink.Emit(OpCodes.Ldarg_0); Ctx.EmitArgList(args); Ctx.EmitVTFunctionCall("InvokeInclude"); break; } case TemplateLexer.Set: { var target = child.Children[0]; if (target.Type == 0) { Errors.ErrorParse((CommonErrorNode) target); break; } var source = child.Children[1]; if (source.Type == 0) { Errors.ErrorParse((CommonErrorNode) source); break; } var s = new Statement(target); var exp = new Expression(source); Errors.AddRange(s.GenerateSet(Ctx, exp)); break; } case TemplateLexer.If: { var ifControl = new If(child); Errors.AddRange(ifControl.Generate(Ctx)); break; } case TemplateLexer.Loop: { var loop = new Loop(child); Errors.AddRange(loop.Generate(Ctx)); break; } case TemplateLexer.Foreach: { var loop = new Foreach(child); Errors.AddRange(loop.Generate(Ctx)); break; } } }