private static void ParseForEachLoop(Scope scope, LuaLexer code) { ParameterExpression varEnumerable = Expression.Variable(typeof(System.Collections.IEnumerable), "#enumerable"); ParameterExpression varEnumerator = Expression.Variable(typeof(System.Collections.IEnumerator), "#enumerator"); // foreach name in exp do block end; code.Next(); // foreach // fetch the loop variable LoopScope loopScope = new LoopScope(scope); Token tLoopVar; Type typeLoopVar; ParseIdentifierAndType(scope, code, out tLoopVar, out typeLoopVar); ParameterExpression loopVar = loopScope.RegisterVariable(typeLoopVar, tLoopVar.Value); // get the enumerable expression FetchToken(LuaToken.KwIn, code); Expression exprEnum = Lua.EnsureType(ParseExpression(scope, code, InvokeResult.None, scope.EmitExpressionDebug), typeof(object)); // parse the loop body FetchToken(LuaToken.KwDo, code); ParseBlock(loopScope, code); FetchToken(LuaToken.KwEnd, code); loopScope.InsertExpression(0, Expression.Assign(loopVar, ConvertExpression(scope.Runtime, tLoopVar, Expression.Property(varEnumerator, Lua.EnumeratorCurrentPropertyInfo), loopVar.Type))); scope.AddExpression( Expression.Block(new ParameterExpression[] { varEnumerable, varEnumerator, loopVar }, // local enumerable = exprEnum as IEnumerator Expression.Assign(varEnumerable, Expression.TypeAs(exprEnum, typeof(System.Collections.IEnumerable))), // if enumerable == nil then error Expression.IfThen(Expression.Equal(varEnumerable, Expression.Constant(null, typeof(object))), Lua.ThrowExpression(Properties.Resources.rsExpressionNotEnumerable)), // local enum = exprEnum.GetEnumerator() Expression.Assign(varEnumerator, Expression.Call(varEnumerable, Lua.EnumerableGetEnumeratorMethodInfo)), // while enum.MoveNext() do Expression.Label(loopScope.ContinueLabel), Expression.IfThenElse(Expression.Call(varEnumerator, Lua.EnumeratorMoveNextMethodInfo), Expression.Empty(), Expression.Goto(loopScope.BreakLabel)), // loopVar = enum.Current loopScope.ExpressionBlock, // end; Expression.Goto(loopScope.ContinueLabel), Expression.Label(loopScope.BreakLabel) )); }
private static void ParseForLoop(Scope scope, LuaLexer code) { // for name FetchToken(LuaToken.KwFor, code); Token tLoopVar; Type typeLoopVar; ParseIdentifierAndType(scope, code, out tLoopVar, out typeLoopVar); if (code.Current.Typ == LuaToken.Assign) { // = exp, exp [, exp] do block end FetchToken(LuaToken.Assign, code); Expression loopStart = ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug); FetchToken(LuaToken.Comma, code); Expression loopEnd = ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug); Expression loopStep; if (code.Current.Typ == LuaToken.Comma) { code.Next(); loopStep = ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug); } else loopStep = Expression.Constant(1, loopStart.Type); LoopScope loopScope = new LoopScope(scope); ParameterExpression loopVarParameter = loopScope.RegisterVariable(typeLoopVar == typeof(object) ? LuaEmit.LiftType(LuaEmit.LiftType(loopStart.Type, loopEnd.Type), loopStep.Type) : typeLoopVar, tLoopVar.Value); FetchToken(LuaToken.KwDo, code); ParseBlock(loopScope, code); FetchToken(LuaToken.KwEnd, code); scope.AddExpression(GenerateForLoop(loopScope, tLoopVar, loopVarParameter, loopStart, loopEnd, loopStep)); } else { // {, name} in explist do block end // fetch all loop variables LoopScope loopScope = new LoopScope(scope); List<ParameterExpression> loopVars = new List<ParameterExpression>(); loopVars.Add(loopScope.RegisterVariable(typeLoopVar, tLoopVar.Value)); while (code.Current.Typ == LuaToken.Comma) { code.Next(); ParseIdentifierAndType(scope, code, out tLoopVar, out typeLoopVar); loopVars.Add(loopScope.RegisterVariable(typeLoopVar, tLoopVar.Value)); } // get the loop expressions FetchToken(LuaToken.KwIn, code); Expression[] explist = ParseExpressionList(scope, code).ToArray(); // parse the loop body FetchToken(LuaToken.KwDo, code); ParseBlock(loopScope, code); FetchToken(LuaToken.KwEnd, code); scope.AddExpression(GenerateForLoop(loopScope, tLoopVar, loopVars, explist)); } }