/// <summary> /// Called when the item is a for numerical item. /// </summary> /// <param name="target">The object that was passed to IParseItem.Accept.</param> /// <returns>The passed target or a modification of it.</returns> /// <exception cref="System.ArgumentNullException">If target is null.</exception> public IParseItem Visit(ForNumItem target) { if (target == null) throw new ArgumentNullException("target"); ILGenerator gen = compiler.CurrentGenerator; target.Break.UserData = target.Break.UserData ?? gen.DefineLabel(); Label start = gen.DefineLabel(); Label end = (Label)target.Break.UserData; Label sj = gen.DefineLabel(), err = gen.DefineLabel(); LocalBuilder d = compiler.CreateTemporary(typeof(double?)); LocalBuilder val = compiler.CreateTemporary(typeof(double)); LocalBuilder step = compiler.CreateTemporary(typeof(double)); LocalBuilder limit = compiler.CreateTemporary(typeof(double)); using (compiler.LocalBlock()) { // d = {Start}.AsDouble(); target.Start.Accept(this); gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("AsDouble")); gen.Emit(OpCodes.Stloc, d); // if (d.HasValue) goto sj; gen.Emit(OpCodes.Ldloca, d); gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_HasValue")); gen.Emit(OpCodes.Brtrue, sj); // err: gen.MarkLabel(err); // throw new InvalidOperationException("The Start, Limit, and Step of a for loop must result in numbers."); gen.Emit(OpCodes.Ldstr, Resources.LoopMustBeNumbers); gen.Emit(OpCodes.Newobj, typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) })); gen.Emit(OpCodes.Throw); // sj: gen.MarkLabel(sj); // val = d.Value; gen.Emit(OpCodes.Ldloca, d); gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_Value")); gen.Emit(OpCodes.Stloc, val); if (target.Step != null) { // d = {Step}.AsDouble(); target.Step.Accept(this); gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("AsDouble")); gen.Emit(OpCodes.Stloc, d); // if (!d.HasValue) goto err; gen.Emit(OpCodes.Ldloca, d); gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_HasValue")); gen.Emit(OpCodes.Brfalse, err); // step = d.Value; gen.Emit(OpCodes.Ldloca, d); gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_Value")); } else { // step = 1.0; gen.Emit(OpCodes.Ldc_R8, 1.0); } gen.Emit(OpCodes.Stloc, step); // d = {Limit}.AsDouble(); target.Limit.Accept(this); gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("AsDouble")); gen.Emit(OpCodes.Stloc, d); // if (!d.HasValue) goto err; gen.Emit(OpCodes.Ldloca, d); gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_HasValue")); gen.Emit(OpCodes.Brfalse, err); // limit = d.Value; gen.Emit(OpCodes.Ldloca, d); gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_Value")); gen.Emit(OpCodes.Stloc, limit); compiler.RemoveTemporary(d); // start: gen.MarkLabel(start); // if (!((step > 0) & (val <= limit)) | ((step <= 0) & (val >= limit))) goto end; gen.Emit(OpCodes.Ldloc, step); gen.Emit(OpCodes.Ldc_R8, 0.0); gen.Emit(OpCodes.Cgt); gen.Emit(OpCodes.Ldloc, val); gen.Emit(OpCodes.Ldloc, limit); gen.Emit(OpCodes.Cgt); gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Xor); gen.Emit(OpCodes.And); gen.Emit(OpCodes.Ldloc, step); gen.Emit(OpCodes.Ldc_R8, 0.0); gen.Emit(OpCodes.Cgt); gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Xor); gen.Emit(OpCodes.Ldloc, val); gen.Emit(OpCodes.Ldloc, limit); gen.Emit(OpCodes.Clt); gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Xor); gen.Emit(OpCodes.And); gen.Emit(OpCodes.Or); gen.Emit(OpCodes.Brfalse, end); // {name} = E.Runtime.CreateValue((object)val); var field = compiler.DefineLocal(target.Name); field.StartSet(); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetMethod("get_Runtime")); gen.Emit(OpCodes.Ldloc, val); gen.Emit(OpCodes.Box, typeof(double)); gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod("CreateValue")); field.EndSet(); // {Block} target.Block.Accept(this); // val += step; gen.Emit(OpCodes.Ldloc, val); gen.Emit(OpCodes.Ldloc, step); gen.Emit(OpCodes.Add); gen.Emit(OpCodes.Stloc, val); compiler.RemoveTemporary(val); compiler.RemoveTemporary(step); compiler.RemoveTemporary(limit); // goto start; gen.Emit(OpCodes.Br, start); // end: gen.MarkLabel(end); } return target; }
/// <summary> /// Called when the item is a for numerical item. /// </summary> /// <param name="target">The object that was passed to IParseItem.Accept.</param> /// <returns>The passed target or a modification of it.</returns> /// <exception cref="System.ArgumentNullException">If target is null.</exception> public IParseItem Visit(ForNumItem target) { if (target == null) throw new ArgumentNullException("target"); using (tree.Block(true)) { tree.DefineLocal(new[] { target.Name }); tree.DefineLabel(target.Break); target.Block.Accept(this); if (target.Start != null) target.Start.Accept(this); if (target.Limit != null) target.Limit.Accept(this); if (target.Step != null) target.Step.Accept(this); } return target; }
/// <summary> /// Reads part of a numerical for loop from the input. The input is /// currently on the equals sign '=' and the debug token currently /// contains the parts read for the 'for' loop. 'name' contains the /// name of the variable. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="debug">The token that currently holds what was read /// so far in the for statement and should after contain the entire loop.</param> /// <param name="name">The token that contains the name of the variable.</param> /// <returns>The loop object that was read.</returns> protected virtual ForNumItem ReadNumberFor(ITokenizer input, ref Token debug, Token name) { // read "=" var temp = Read(input, ref debug); if (temp.Value != "=") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "=", "ReadNumberFor")); // get the 'start' value var start = ReadExp(input, ref debug); // read ',' temp = Read(input, ref debug); if (temp.Value != ",") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, temp.Value, "for", ","), input.Name, temp); // get the 'limit' var limit = ReadExp(input, ref debug); // read ',' IParseExp step = null; if (input.Peek().Value == ",") { Read(input, ref debug); // read the 'step' step = ReadExp(input, ref debug); } ForNumItem i = new ForNumItem(new NameItem(name.Value) { Debug = name }, start, limit, step); // check for 'do' name = Read(input, ref debug); if (name.Value != "do") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "for", "do"), input.Name, name); // read the block i.Block = ReadBlock(input, ref debug); // read 'end' name = Read(input, ref debug); if (name.Value != "end") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "for", "end"), input.Name, name); i.Debug = debug; return i; }