private static void ParseExpressionStatement(Scope scope, LuaLexer code, bool lLocal) { List<ParameterExpression> registerLocals = null; List<PrefixMemberInfo> prefixes = new List<PrefixMemberInfo>(); // parse the assgiee list (var0, var1, var2, ...) while (true) { if (lLocal) // parse local variables { Token tVar; Type typeVar; ParseIdentifierAndType(scope, code, out tVar, out typeVar); ParameterExpression exprVar = scope.LookupExpression(tVar.Value, true) as ParameterExpression; if (exprVar == null) { exprVar = Expression.Variable(typeVar, tVar.Value); if (registerLocals == null) registerLocals = new List<ParameterExpression>(); registerLocals.Add(exprVar); } else if (exprVar.Type != typeVar) throw ParseError(tVar, Properties.Resources.rsParseTypeRedef); prefixes.Add(new PrefixMemberInfo(tVar, exprVar, null, null, null)); } else // parse a assignee { // parse as a prefix prefixes.Add(ParsePrefix(scope, code)); } // is there another prefix if (code.Current.Typ == LuaToken.Comma) code.Next(); else break; } // Optional assign if (code.Current.Typ == LuaToken.Assign) { code.Next(); // parse all expressions IEnumerator<Expression> expr = ParseExpressionList(scope, code).GetEnumerator(); expr.MoveNext(); if (prefixes.Count == 1) // one expression, one variable? { scope.AddExpression( prefixes[0].GenerateSet(scope, expr.Current != null ? expr.Current : Expression.Constant(null, typeof(object))) ); } else if (expr.Current == null) // No expression, assign null { for (int i = 0; i < prefixes.Count; i++) scope.AddExpression(prefixes[i].GenerateSet(scope, Expression.Constant(null, typeof(object)))); } else // assign on an unknown number of expressions { #region -- unknown number -- List<ParameterExpression> assignTempVars = new List<ParameterExpression>(); List<Expression> assignExprs = new List<Expression>(); int iExpressionVarOffset; // Safe the prefixes in variables for (int k = 0; k < prefixes.Count; k++) { var p = prefixes[k]; if (p.Member != null || prefixes[k].Indices != null) { p.Instance = ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, p.Instance); if (p.Indices != null) { for (int l = 0; l < p.Indices.Length; l++) p.Indices[l] = ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, p.Indices[l]); } } } // collect the results of the expressions iExpressionVarOffset = assignTempVars.Count; do { ParseExpressionStatementExchangeToTempVar(assignTempVars, assignExprs, expr.Current); } while (expr.MoveNext()); // Assign the Result to the prefixes int i = 0; int j = 0; ParameterExpression lastVariable = null; while (i < prefixes.Count) { if (i < assignTempVars.Count - iExpressionVarOffset) // are the variables { if (i == assignTempVars.Count - iExpressionVarOffset - 1 && assignTempVars[i + iExpressionVarOffset].Type == typeof(LuaResult)) // check if the last expression is a LuaResult { lastVariable = assignTempVars[i + iExpressionVarOffset]; assignExprs.Add(prefixes[i].GenerateSet(scope, GetResultExpression(scope.Runtime, code.Current, lastVariable, j++))); } else { assignExprs.Add(prefixes[i].GenerateSet(scope, assignTempVars[i + iExpressionVarOffset])); } } else if (lastVariable != null) // we enroll the last expression { assignExprs.Add(prefixes[i].GenerateSet(scope, GetResultExpression(scope.Runtime, code.Current, lastVariable, j++))); } else // no variable left { assignExprs.Add(prefixes[i].GenerateSet(scope, Expression.Default(typeof(object)))); } i++; } // add the block scope.AddExpression(Expression.Block(assignTempVars, assignExprs)); #endregion } // Führe die restlichen Expressions aus while (expr.MoveNext()) scope.AddExpression(expr.Current); } else if (!lLocal) { for (int i = 0; i < prefixes.Count; i++) { if (prefixes[i].Arguments == null) // do not execute getMember throw ParseError(prefixes[i].Position, Properties.Resources.rsParseAssignmentExpected); scope.AddExpression(prefixes[i].GenerateGet(scope, InvokeResult.None)); } } // register the variables if (registerLocals != null) { for (int i = 0; i < registerLocals.Count; i++) scope.RegisterVariable(registerLocals[i]); } }
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 ParseBreak(Scope scope, LuaLexer code) { FetchToken(LuaToken.KwBreak, code); // Erzeuge die Expression scope.AddExpression(Expression.Goto(scope.LookupLabel(null, csBreakLabel))); // Optionales Semicolon FetchToken(LuaToken.Semicolon, code, true); }
private static void ParseDoLoop(Scope scope, LuaLexer code) { // doloop ::= do '(' name { ',' name } = expr { ',' expr } ')' block end // create empty block, that can used as an loop Scope outerScope = new Scope(scope); Expression[] exprFinally = null; // fetch do FetchToken(LuaToken.KwDo, code); if (code.Current.Typ == LuaToken.BracketOpen) // look for disposable variables { code.Next(); ParseExpressionStatement(outerScope, code, true); // Build finally-Block for the declared variables exprFinally = ( from c in outerScope.Variables select Expression.IfThen( Expression.TypeIs(c, typeof(IDisposable)), Expression.Call(Expression.Convert(c, typeof(IDisposable)), Lua.DisposeDisposeMethodInfo) )).ToArray(); FetchToken(LuaToken.BracketClose, code); } LoopScope loopScope = new LoopScope(outerScope); // Add the Contine label after the declaration loopScope.AddExpression(Expression.Label(loopScope.ContinueLabel)); // parse the block ParseBlock(loopScope, code); // create the break label loopScope.AddExpression(Expression.Label(loopScope.BreakLabel)); FetchToken(LuaToken.KwEnd, code); if (exprFinally != null && exprFinally.Length > 0) { outerScope.AddExpression( Expression.TryFinally( loopScope.ExpressionBlock, Expression.Block(exprFinally) ) ); scope.AddExpression(outerScope.ExpressionBlock); } else scope.AddExpression(loopScope.ExpressionBlock); }
private static void ParseWhileLoop(Scope scope, LuaLexer code) { // while expr do block end; LoopScope loopScope = new LoopScope(scope); // get the expression FetchToken(LuaToken.KwWhile, code); loopScope.AddExpression(Expression.Label(loopScope.ContinueLabel)); loopScope.AddExpression( Expression.IfThenElse( ConvertExpression(scope.Runtime, code.Current, ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug), typeof(bool)), Expression.Empty(), Expression.Goto(loopScope.BreakLabel) ) ); // append the block FetchToken(LuaToken.KwDo, code); ParseBlock(loopScope, code); FetchToken(LuaToken.KwEnd, code); // goto continue loopScope.AddExpression(Expression.Goto(loopScope.ContinueLabel)); loopScope.AddExpression(Expression.Label(loopScope.BreakLabel)); scope.AddExpression(loopScope.ExpressionBlock); }
private static void ParseBlock(Scope scope, LuaLexer code) { // Lese die Statement int iLastDebugInfo = -1; bool lLoop = true; while (lLoop) { bool lDebugInfoEmitted = false; if ((scope.EmitDebug & LuaDebugLevel.Line) != 0) // debug info for line { if (code.Current.Start.Line != iLastDebugInfo) { iLastDebugInfo = code.Current.Start.Line; scope.AddExpression(GetDebugInfo(code.Current, code.Current)); lDebugInfoEmitted = true; } } switch (code.Current.Typ) { case LuaToken.Eof: // End of file lLoop = false; break; case LuaToken.KwReturn: // The return-statement is only allowed on the end of a scope ParseReturn(scope, code); break; case LuaToken.KwBreak: // The break-statement is only allowed on the end of a scope ParseBreak(scope, code); lLoop = false; break; case LuaToken.Semicolon: // End of statement => ignore code.Next(); break; default: if (!lDebugInfoEmitted && (scope.EmitDebug & LuaDebugLevel.Expression) != 0) // Start every statement with a debug point scope.AddExpression(GetDebugInfo(code.Current, code.Current)); if (!ParseStatement(scope, code)) // Parse normal statements lLoop = false; break; } } if (scope.EmitDebug != LuaDebugLevel.None) scope.AddExpression(Expression.ClearDebugInfo(code.Current.Start.Document)); // Clear debug info }
private static Expression ParseTableConstructor(Scope scope, LuaLexer code) { // table ::= '{' [field] { fieldsep field } [fieldsep] '}' // fieldsep ::= ',' | ';' FetchToken(LuaToken.BracketCurlyOpen, code); if (code.Current.Typ != LuaToken.BracketCurlyClose) { int iIndex = 1; Scope scopeTable = new Scope(scope); // Create the variable for the table ParameterExpression tableVar = scopeTable.RegisterVariable(typeof(LuaTable), "#table"); scopeTable.AddExpression(Expression.Assign(tableVar, CreateEmptyTableExpression())); // fiest field ParseTableField(tableVar, scopeTable, code, ref iIndex); // collect more table fields while (code.Current.Typ == LuaToken.Comma || code.Current.Typ == LuaToken.Semicolon) { code.Next(); // Optional last separator if (code.Current.Typ == LuaToken.BracketCurlyClose) break; // Parse the field ParseTableField(tableVar, scopeTable, code, ref iIndex); } scopeTable.AddExpression(tableVar); scopeTable.ExpressionBlockType = typeof(LuaTable); // Closing bracket FetchToken(LuaToken.BracketCurlyClose, code); return scopeTable.ExpressionBlock; } else { FetchToken(LuaToken.BracketCurlyClose, code); return CreateEmptyTableExpression(); } }
private static void ParseTableField(ParameterExpression tableVar, Scope scope, LuaLexer code, ref int iIndex) { // field ::= '[' exp ']' '=' exp | Name '=' exp | exp if (code.Current.Typ == LuaToken.BracketSquareOpen) { // Parse the index code.Next(); var index = ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug); FetchToken(LuaToken.BracketSquareClose, code); FetchToken(LuaToken.Assign, code); // Expression that results in a value scope.AddExpression( IndexSetExpression(scope.Runtime, code.Current, tableVar, new Expression[] { index }, ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug) ) ); } else if (code.Current.Typ == LuaToken.Identifier && code.LookAhead.Typ == LuaToken.Assign) { // Read the identifier Token tMember = code.Current; code.Next(); FetchToken(LuaToken.Assign, code); // Expression scope.AddExpression( IndexSetExpression(scope.Runtime, code.Current, tableVar, new Expression[] { Expression.Constant(tMember.Value) }, ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug) ) ); } else { Token tStart = code.Current; Expression expr = ParseExpression(scope, code, InvokeResult.None, scope.EmitExpressionDebug); // Last assign, enroll parameter if (code.Current.Typ == LuaToken.BracketCurlyClose && LuaEmit.IsDynamicType(expr.Type)) { scope.AddExpression( Expression.Call(Lua.TableSetObjectsMethod, tableVar, Expression.Convert(expr, typeof(object)), Expression.Constant(iIndex, typeof(int)) ) ); } else // Normal index set { scope.AddExpression( IndexSetExpression(scope.Runtime, code.Current, tableVar, new Expression[] { Expression.Constant(iIndex++, typeof(object)) }, expr) ); } } }
private static void ParseRepeatLoop(Scope scope, LuaLexer code) { LoopScope loopScope = new LoopScope(scope); // continue label loopScope.AddExpression(Expression.Label(loopScope.ContinueLabel)); // loop content FetchToken(LuaToken.KwRepeat, code); ParseBlock(loopScope, code); // get the loop expression FetchToken(LuaToken.KwUntil, code); loopScope.AddExpression( Expression.IfThenElse( ConvertExpression(scope.Runtime, code.Current, ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug), typeof(bool)), Expression.Empty(), Expression.Goto(loopScope.ContinueLabel) ) ); loopScope.AddExpression(Expression.Label(loopScope.BreakLabel)); scope.AddExpression(loopScope.ExpressionBlock); }
private static void ParseReturn(Scope scope, LuaLexer code) { // eat return code.Next(); // Build the return expression for all parameters Expression exprReturnValue; if (IsExpressionStart(code)) // there is a return value { if (scope.ReturnType == typeof(LuaResult)) { exprReturnValue = GetLuaResultExpression(scope, code.Current, ParseExpressionList(scope, code).ToArray()); } else if (scope.ReturnType.IsArray) { Type typeArray = scope.ReturnType.GetElementType(); exprReturnValue = Expression.NewArrayInit( typeArray, from c in ParseExpressionList(scope, code) select ConvertExpression(scope.Runtime, code.Current, c, typeArray)); } else { List<Expression> exprList = new List<Expression>(ParseExpressionList(scope, code)); if (exprList.Count == 1) exprReturnValue = ConvertExpression(scope.Runtime, code.Current, exprList[0], scope.ReturnType); else { ParameterExpression tmpVar = Expression.Variable(scope.ReturnType); exprList[0] = Expression.Assign(tmpVar, ConvertExpression(scope.Runtime, code.Current, exprList[0], scope.ReturnType)); exprList.Add(tmpVar); exprReturnValue = Expression.Block(scope.ReturnType, new ParameterExpression[] { tmpVar }, exprList); } } } else // use the default-value { if (scope.ReturnType == typeof(LuaResult)) exprReturnValue = Expression.Property(null, Lua.ResultEmptyPropertyInfo); else if (scope.ReturnType.IsArray) exprReturnValue = Expression.NewArrayInit(scope.ReturnType.GetElementType()); else exprReturnValue = Expression.Default(scope.ReturnType); } if (code.Current.Typ == LuaToken.Semicolon) code.Next(); scope.AddExpression(Expression.Goto(scope.LookupLabel(scope.ReturnType, csReturnLabel), exprReturnValue)); }
private static void ParseLabel(Scope scope, LuaLexer code) { // ::identifier:: FetchToken(LuaToken.ColonColon, code); // Erzeuge das Label scope.AddExpression(Expression.Label(scope.LookupLabel(null, FetchToken(LuaToken.Identifier, code).Value))); FetchToken(LuaToken.ColonColon, code); }
private static void ParseIfStatement(Scope scope, LuaLexer code) { // if expr then block { elseif expr then block } [ else block ] end FetchToken(LuaToken.KwIf, code); var expr = ConvertExpression(scope.Runtime, code.Current, ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug), typeof(bool)); FetchToken(LuaToken.KwThen, code); scope.AddExpression(Expression.IfThenElse(expr, ParseIfElseBlock(scope, code), ParseElseStatement(scope, code))); }
private static void ParseGoto(Scope scope, LuaLexer code) { // goto Identifier FetchToken(LuaToken.KwGoto, code); var t = FetchToken(LuaToken.Identifier, code); scope.AddExpression(Expression.Goto(scope.LookupLabel(null, t.Value))); }
private static void ParseFunction(Scope scope, LuaLexer code, bool lLocal) { FetchToken(LuaToken.KwFunction, code); if (lLocal) // Local function, only one identifier is allowed { var t = FetchToken(LuaToken.Identifier, code); ParameterExpression funcVar = null; Expression exprFunction = ParseLamdaDefinition(scope, code, t.Value, false, typeDelegate => funcVar = scope.RegisterVariable(typeDelegate, t.Value) ); scope.AddExpression(Expression.Assign(funcVar, exprFunction)); } else // Function that is assigned to a table. A chain of identifiers is allowed. { Expression assignee = null; Token tCurrent = FetchToken(LuaToken.Identifier, code); string sMember = tCurrent.Value; // Collect the chain of members while (code.Current.Typ == LuaToken.Dot) { code.Next(); // Create the get-member for the current assignee assignee = ParseFunctionAddChain(scope, tCurrent, assignee, sMember); sMember = FetchToken(LuaToken.Identifier, code).Value; } // add a method to the table. methods get a hidden parameter and will bo marked bool lMethodMember; if (code.Current.Typ == LuaToken.Colon) { code.Next(); // add the last member to the assignee chain assignee = ParseFunctionAddChain(scope, tCurrent, assignee, sMember); // fetch the method name sMember = FetchToken(LuaToken.Identifier, code).Value; lMethodMember = true; } else { if (assignee == null) assignee = scope.LookupExpression(csEnv); // create a global function lMethodMember = false; } // generate lambda scope.AddExpression(MemberSetExpression(scope.Runtime, tCurrent, assignee, sMember, lMethodMember, ParseLamdaDefinition(scope, code, sMember, lMethodMember, null))); } }
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)); } }