} // func T private bool TokenTest(string sToken, params KeyValuePair<LuaToken, string>[] token) { using (LuaLexer l = new LuaLexer("test.lua", new StringReader(sToken))) { l.Next(); for (int i = 0; i < token.Length; i++) { Debug.Write(String.Format("Test: {0} = {1} ==>", l.Current.Typ, token[i].Key)); if (l.Current.Typ != token[i].Key) { Debug.WriteLine("tokens FAILED"); return false; } else if (l.Current.Value != token[i].Value) { Debug.WriteLine("values '{0}' != '{1}' FAILED", l.Current.Value, token[i].Value); return false; } Debug.WriteLine("OK"); l.Next(); } if (l.Current.Typ != LuaToken.Eof) return false; return true; } } // func TokenTest
/// <summary>Parses the chunk to an function.</summary> /// <param name="runtime">Binder</param> /// <param name="options">Compile options for the script.</param> /// <param name="lHasEnvironment">Creates the _G parameter.</param> /// <param name="code">Lexer for the code.</param> /// <param name="typeDelegate">Type for the delegate. <c>null</c>, for an automatic type</param> /// <param name="returnType">Defines the return type of the chunk.</param> /// <param name="args">Arguments of the function.</param> /// <returns>Expression-Tree for the code.</returns> public static LambdaExpression ParseChunk(Lua runtime, LuaCompileOptions options, bool lHasEnvironment, LuaLexer code, Type typeDelegate, Type returnType, IEnumerable<KeyValuePair<string, Type>> args) { List<ParameterExpression> parameters = new List<ParameterExpression>(); if (returnType == null) returnType = typeof(LuaResult); var globalScope = new GlobalScope(runtime, options, returnType, returnType == typeof(LuaResult) ? Expression.Property(null, Lua.ResultEmptyPropertyInfo) : null); // Registers the global LuaTable if (lHasEnvironment) parameters.Add(globalScope.RegisterParameter(typeof(LuaTable), csEnv)); if (args != null) { foreach (var c in args) parameters.Add(globalScope.RegisterParameter(c.Value, c.Key)); // Add alle arguments } // Get the first token if (code.Current == null) code.Next(); // Get the name for the chunk and clean it from all unwanted chars string sChunkName = CreateNameFromFile(code.Current.Start.FileName); if ((globalScope.EmitDebug & LuaDebugLevel.RegisterMethods) == LuaDebugLevel.RegisterMethods) sChunkName = Lua.RegisterUniqueName(sChunkName); // Create the block ParseBlock(globalScope, code); if (code.Current.Typ != LuaToken.Eof) throw ParseError(code.Current, Properties.Resources.rsParseEof); // Create the function return typeDelegate == null ? Expression.Lambda(globalScope.ExpressionBlock, sChunkName, parameters) : Expression.Lambda(typeDelegate, globalScope.ExpressionBlock, sChunkName, parameters); }
private static Expression ParseExpressionBitXOr(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // exprBitXOr ::= exprBitAnd { ~ exprBitAnd } var expr = ParseExpressionBitAnd(scope, code, result, ref lWrap); while (code.Current.Typ == LuaToken.Dilde) { code.Next(); expr = BinaryOperationExpression(scope.Runtime, code.Current, ExpressionType.ExclusiveOr, expr, ParseExpressionBitAnd(scope, code, InvokeResult.Object, ref lWrap) ); lWrap |= true; } return expr; }
private static Expression ParseLamdaDefinition(Scope parent, LuaLexer code, string sName, bool lSelfParameter, Action<Type> functionTypeCollected) { List<ParameterExpression> parameters = new List<ParameterExpression>(); LambdaScope scope = new LambdaScope(parent); // Lese die Parameterliste ein FetchToken(LuaToken.BracketOpen, code); if (lSelfParameter) parameters.Add(scope.RegisterParameter(typeof(object), "self")); if (code.Current.Typ == LuaToken.Identifier || code.Current.Typ == LuaToken.DotDotDot) { if (code.Current.Typ == LuaToken.DotDotDot) { code.Next(); ParseLamdaDefinitionArgList(scope, parameters); } else { Token tName; Type typeArgument; ParseIdentifierAndType(scope, code, out tName, out typeArgument); parameters.Add(scope.RegisterParameter(typeArgument, tName.Value)); while (code.Current.Typ == LuaToken.Comma) { code.Next(); if (code.Current.Typ == LuaToken.DotDotDot) { code.Next(); ParseLamdaDefinitionArgList(scope, parameters); // last argument break; } else { ParseIdentifierAndType(scope, code, out tName, out typeArgument); parameters.Add(scope.RegisterParameter(typeArgument, tName.Value)); } } } } FetchToken(LuaToken.BracketClose, code); // Is there a specific result if (code.Current.Typ == LuaToken.Colon) { var t = code.Current; code.Next(); Type typeResult = ParseType(scope, code, true); scope.ResetReturnLabel(typeResult, null); } else scope.ResetReturnLabel(typeof(LuaResult), Expression.Property(null, Lua.ResultEmptyPropertyInfo)); // register the delegate if (functionTypeCollected != null) { functionTypeCollected( Expression.GetFuncType( (from p in parameters select p.Type).Concat(new Type[] { scope.ReturnType }).ToArray() ) ); } // Lese den Code-Block ParseBlock(scope, code); FetchToken(LuaToken.KwEnd, code); return Expression.Lambda( scope.ExpressionBlock, (parent.EmitDebug & LuaDebugLevel.RegisterMethods) == LuaDebugLevel.RegisterMethods ? Lua.RegisterUniqueName(sName) : sName, parameters); }
private static Expression ParseExpressionBitAnd(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // exprBitAnd ::= exprCmp { & exprCmp } var expr = ParseExpressionCmp(scope, code, result, ref lWrap); while (code.Current.Typ == LuaToken.BitAnd) { code.Next(); expr = BinaryOperationExpression(scope.Runtime, code.Current, ExpressionType.And, expr, ParseExpressionCmp(scope, code, InvokeResult.Object, ref lWrap) ); lWrap |= true; } return expr; }
private static Expression ParseExpressionShift(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // exprBitAnd ::= exprCmp { ( << | >> ) exprCmp } var expr = ParseExpressionPlus(scope, code, result, ref lWrap); while (true) { LuaToken tokenTyp = code.Current.Typ; ExpressionType exprTyp; if (tokenTyp == LuaToken.ShiftLeft) exprTyp = ExpressionType.LeftShift; else if (tokenTyp == LuaToken.ShiftRight) exprTyp = ExpressionType.RightShift; else return expr; code.Next(); expr = BinaryOperationExpression(scope.Runtime, code.Current, exprTyp, expr, ParseExpressionPlus(scope, code, InvokeResult.Object, ref lWrap)); lWrap |= true; } }
private static Expression ParseExpressionUnary(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // expUn ::= { 'not' | - | # | ~ } expPow LuaToken typ = code.Current.Typ; if (typ == LuaToken.KwNot || typ == LuaToken.Minus || typ == LuaToken.Dilde || typ == LuaToken.Cross) { code.Next(); Expression expr = ParseExpressionUnary(scope, code, InvokeResult.Object, ref lWrap); lWrap |= true; ExpressionType exprType; if (typ == LuaToken.KwNot) exprType = ExpressionType.Not; else if (typ == LuaToken.Minus) exprType = ExpressionType.Negate; else if (typ == LuaToken.Dilde) exprType = ExpressionType.OnesComplement; else exprType = ExpressionType.ArrayLength; lWrap |= true; return UnaryOperationExpression(scope.Runtime, code.Current, exprType, expr); } else return ParseExpressionPower(scope, code, result, ref lWrap); }
private static Token FetchToken(LuaToken typ, LuaLexer code, bool lOptional = false) { if (code.Current.Typ == typ) { var t = code.Current; code.Next(); return t; } else if (lOptional) return null; else throw ParseError(code.Current, String.Format(Properties.Resources.rsParseUnexpectedToken, LuaLexer.GetTokenName(code.Current.Typ), LuaLexer.GetTokenName(typ))); }
private static Expression ParseExpressionPlus(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // expPlus ::= expMul { ( + | - ) expMul} var expr = ParseExpressionMultiply(scope, code, result, ref lWrap); while (true) { LuaToken tokenTyp = code.Current.Typ; ExpressionType exprTyp; if (tokenTyp == LuaToken.Plus) exprTyp = ExpressionType.Add; else if (tokenTyp == LuaToken.Minus) exprTyp = ExpressionType.Subtract; else return expr; code.Next(); expr = BinaryOperationExpression(scope.Runtime, code.Current, exprTyp, expr, ParseExpressionMultiply(scope, code, InvokeResult.Object, ref lWrap)); lWrap |= true; } }
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 Expression ParseExpressionCon(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // exprCon::= exprShift { '..' exprShift } List<Expression> exprs = new List<Expression>(); exprs.Add(ParseExpressionShift(scope, code, result, ref lWrap)); while (code.Current.Typ == LuaToken.DotDot) { code.Next(); exprs.Add(ParseExpressionShift(scope, code, InvokeResult.Object, ref lWrap)); } // Erzeuge Concat if (exprs.Count > 1) { lWrap |= true; return ConcatOperationExpression(scope.Runtime, code.Current, exprs.ToArray()); } else return exprs[0]; }
private static PrefixMemberInfo ParseSuffix(Scope scope, LuaLexer code, PrefixMemberInfo info) { // suffix_opt ::= [ suffix ] // suffix ::= { '[' exp ']' | '.' Identifier | args | ':' Identifier args } // args ::= tablector | string | '(' explist ')' while (true) { switch (code.Current.Typ) { case LuaToken.BracketSquareOpen: // Index code.Next(); info.GenerateGet(scope, InvokeResult.Object); if (code.Current.Typ == LuaToken.BracketSquareClose) info.Indices = new Expression[0]; else info.Indices = ParseExpressionList(scope, code).ToArray(); FetchToken(LuaToken.BracketSquareClose, code); break; case LuaToken.Dot: // Property of an class code.Next(); info.GenerateGet(scope, InvokeResult.Object); info.SetMember(FetchToken(LuaToken.Identifier, code), false); break; case LuaToken.BracketOpen: // List of arguments info.GenerateGet(scope, InvokeResult.Object); info.Arguments = ParseArgumentList(scope, code); break; case LuaToken.BracketCurlyOpen: // LuaTable as an argument info.GenerateGet(scope, InvokeResult.Object); info.Arguments = new ArgumentsList(ParseTableConstructor(scope, code)); break; case LuaToken.String: // String as an argument info.GenerateGet(scope, InvokeResult.Object); info.Arguments = new ArgumentsList(Expression.Constant(FetchToken(LuaToken.String, code).Value, typeof(object))); break; case LuaToken.Colon: // Methodenaufruf code.Next(); // Lese den Namen um den Member zu belegen info.GenerateGet(scope, InvokeResult.Object); info.SetMember(FetchToken(LuaToken.Identifier, code), true); // Parse die Parameter switch (code.Current.Typ) { case LuaToken.BracketOpen: // Argumentenliste info.Arguments = ParseArgumentList(scope, code); break; case LuaToken.BracketCurlyOpen: // LuaTable als Argument info.Arguments = new ArgumentsList(ParseTableConstructor(scope, code) ); break; case LuaToken.String: // String als Argument info.Arguments = new ArgumentsList(Expression.Constant(FetchToken(LuaToken.String, code).Value, typeof(string))); break; } break; default: return 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 bool ParseStatement(Scope scope, LuaLexer code) { switch (code.Current.Typ) { case LuaToken.Identifier: // Expression case LuaToken.DotDotDot: case LuaToken.BracketOpen: case LuaToken.String: case LuaToken.Number: case LuaToken.KwFalse: case LuaToken.KwTrue: case LuaToken.KwNil: case LuaToken.BracketCurlyOpen: case LuaToken.Minus: case LuaToken.KwCast: ParseExpressionStatement(scope, code, false); return true; case LuaToken.ColonColon: // Start of a label ParseLabel(scope, code); return true; case LuaToken.KwGoto: ParseGoto(scope, code); return true; case LuaToken.KwDo: ParseDoLoop(scope, code); return true; case LuaToken.KwWhile: ParseWhileLoop(scope, code); return true; case LuaToken.KwRepeat: ParseRepeatLoop(scope, code); return true; case LuaToken.KwIf: ParseIfStatement(scope, code); return true; case LuaToken.KwFor: ParseForLoop(scope, code); return true; case LuaToken.KwForEach: ParseForEachLoop(scope, code); return true; case LuaToken.KwFunction: ParseFunction(scope, code, false); return true; case LuaToken.KwLocal: code.Next(); if (code.Current.Typ == LuaToken.KwFunction) ParseFunction(scope, code, true); else ParseExpressionStatement(scope, code, true); return true; case LuaToken.KwConst: code.Next(); ParseConst(scope, code); return true; case LuaToken.InvalidString: throw ParseError(code.Current, Properties.Resources.rsParseInvalidString); case LuaToken.InvalidComment: throw ParseError(code.Current, Properties.Resources.rsParseInvalidComment); case LuaToken.InvalidChar: throw ParseError(code.Current, Properties.Resources.rsParseInvalidChar); default: return false; } }
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 Expression ParsePrefixCast(Scope scope, LuaLexer code) { LuaType luaType; Token t = code.Current; code.Next(); FetchToken(LuaToken.BracketOpen, code); // Read the type luaType = ParseType(scope, code, true); FetchToken(LuaToken.Comma, code); bool lWrap = scope.EmitExpressionDebug; Expression expr = ParseExpression(scope, code, InvokeResult.Object, ref lWrap); FetchToken(LuaToken.BracketClose, code); return ConvertExpression(scope.Runtime, t, expr, luaType); }
private static Expression ParseExpressionCmp(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // expCmd ::= expCon { ( < | > | <= | >= | ~= | == ) expCon } Token tStart = code.Current; var expr = ParseExpressionCon(scope, code, result, ref lWrap); while (true) { LuaToken tokenTyp = code.Current.Typ; ExpressionType exprTyp; if (tokenTyp == LuaToken.Lower) exprTyp = ExpressionType.LessThan; else if (tokenTyp == LuaToken.Greater) exprTyp = ExpressionType.GreaterThan; else if (tokenTyp == LuaToken.LowerEqual) exprTyp = ExpressionType.LessThanOrEqual; else if (tokenTyp == LuaToken.GreaterEqual) exprTyp = ExpressionType.GreaterThanOrEqual; else if (tokenTyp == LuaToken.NotEqual) exprTyp = ExpressionType.NotEqual; else if (tokenTyp == LuaToken.Equal) exprTyp = ExpressionType.Equal; else return expr; code.Next(); expr = BinaryOperationExpression(scope.Runtime, code.Current, exprTyp, expr, ParseExpressionCon(scope, code, InvokeResult.Object, ref lWrap)); lWrap |= true; } }
private static Expression ParseExpressionMultiply(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // expMul ::= expUn { ( * | / | // | % ) expUn } var expr = ParseExpressionUnary(scope, code, result, ref lWrap); while (true) { LuaToken tokenTyp = code.Current.Typ; ExpressionType exprTyp; if (tokenTyp == LuaToken.Star) exprTyp = ExpressionType.Multiply; else if (tokenTyp == LuaToken.Slash) exprTyp = ExpressionType.Divide; else if (tokenTyp == LuaToken.SlashShlash) exprTyp = Lua.IntegerDivide; else if (tokenTyp == LuaToken.Percent) exprTyp = ExpressionType.Modulo; else return expr; code.Next(); expr = BinaryOperationExpression(scope.Runtime, code.Current, exprTyp, expr, ParseExpressionUnary(scope, code, InvokeResult.Object, ref lWrap)); lWrap |= true; } }
private static LuaType ParseType(Scope scope, LuaLexer code, bool lNeedType) { // is the first token an alias LuaType currentType = ParseFirstType(scope, code); while (code.Current.Typ == LuaToken.Dot || code.Current.Typ == LuaToken.Plus || code.Current.Typ == LuaToken.BracketSquareOpen) { if (code.Current.Typ == LuaToken.BracketSquareOpen) { List<LuaType> genericeTypes = new List<LuaType>(); code.Next(); if (code.Current.Typ != LuaToken.BracketSquareClose) { genericeTypes.Add(ParseType(scope, code, lNeedType)); while (code.Current.Typ == LuaToken.Comma) { code.Next(); genericeTypes.Add(ParseType(scope, code, lNeedType)); } } FetchToken(LuaToken.BracketSquareClose, code); if (genericeTypes.Count == 0) // create a array at the end { if (currentType.Type == null) throw ParseError(code.Current, String.Format(Properties.Resources.rsParseUnknownType, currentType.FullName)); currentType = LuaType.GetType(currentType.GetIndex("[]", false, () => currentType.Type.MakeArrayType())); } else // build a generic type { var typeGeneric = LuaType.GetType(currentType.FullName + "`" + genericeTypes.Count.ToString()).Type; if (typeGeneric == null) throw ParseError(code.Current, String.Format(Properties.Resources.rsParseUnknownType, currentType.FullName)); currentType = LuaType.GetType(currentType.GetGenericItem(typeGeneric, genericeTypes.ToArray())); } } else { code.Next(); currentType = LuaType.GetType(currentType.GetIndex(FetchToken(LuaToken.Identifier, code).Value, false, null)); } } if (lNeedType && currentType.Type == null) throw ParseError(code.Current, String.Format(Properties.Resources.rsParseUnknownType, currentType.FullName)); return currentType; }
private static PrefixMemberInfo ParsePrefix(Scope scope, LuaLexer code) { // prefix ::= Identifier suffix_opt | '(' exp ')' suffix | literal | tablector Token tStart = code.Current; PrefixMemberInfo info; switch (tStart.Typ) { case LuaToken.BracketOpen: // Parse eine Expression { code.Next(); var expr = ConvertObjectExpression(scope.Runtime, tStart, ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug)); FetchToken(LuaToken.BracketClose, code); info = new PrefixMemberInfo(tStart, expr, null, null, null); } break; case LuaToken.DotDotDot: case LuaToken.Identifier: case LuaToken.KwForEach: var t = code.Current; if (t.Value == csClr) // clr is a special package, that always exists { code.Next(); info = new PrefixMemberInfo(tStart, Expression.Property(null, Lua.TypeClrPropertyInfo), null, null, null); } else { string sMemberName; if (t.Typ == LuaToken.DotDotDot) sMemberName = csArgList; else if (t.Typ == LuaToken.KwCast) sMemberName = "cast"; else if (t.Typ == LuaToken.KwForEach) sMemberName = "foreach"; else sMemberName = t.Value; var p = scope.LookupExpression(sMemberName); if (t.Typ == LuaToken.DotDotDot && p == null) throw ParseError(t, Properties.Resources.rsParseNoArgList); code.Next(); if (p == null) // No local variable found info = new PrefixMemberInfo(tStart, scope.LookupExpression(csEnv), t.Value, null, null); else info = new PrefixMemberInfo(tStart, p, null, null, null); } break; case LuaToken.KwCast: info = new PrefixMemberInfo(tStart, ParsePrefixCast(scope, code), null, null, null); break; case LuaToken.String: // Literal String info = new PrefixMemberInfo(tStart, Expression.Constant(FetchToken(LuaToken.String, code).Value, typeof(string)), null, null, null); break; case LuaToken.Number: // Literal Zahl info = new PrefixMemberInfo(tStart, ParseNumber(scope.Runtime, FetchToken(LuaToken.Number, code)), null, null, null); break; case LuaToken.KwTrue: // Literal TRUE code.Next(); info = new PrefixMemberInfo(tStart, Expression.Constant(true, typeof(bool)), null, null, null); break; case LuaToken.KwFalse: // Literal FALSE code.Next(); info = new PrefixMemberInfo(tStart, Expression.Constant(false, typeof(bool)), null, null, null); break; case LuaToken.KwNil: // Literal NIL code.Next(); info = new PrefixMemberInfo(tStart, Expression.Constant(null, typeof(object)), null, null, null); break; case LuaToken.BracketCurlyOpen: // tablector info = new PrefixMemberInfo(tStart, ParseTableConstructor(scope, code), null, null, null); break; case LuaToken.KwFunction: // Function definition code.Next(); info = new PrefixMemberInfo(tStart, ParseLamdaDefinition(scope, code, "lambda", false, null), null, null, null); break; default: throw ParseError(code.Current, Properties.Resources.rsParseUnexpectedTokenPrefix); } return ParseSuffix(scope, code, info); }
private static IEnumerable<Expression> ParseExpressionList(Scope scope, LuaLexer code) { while (true) { yield return ParseExpression(scope, code, InvokeResult.LuaResult, scope.EmitExpressionDebug); // Noch eine Expression if (code.Current.Typ == LuaToken.Comma) code.Next(); else break; } }
private static ArgumentsList ParseArgumentList(Scope scope, LuaLexer code) { FetchToken(LuaToken.BracketOpen, code); // exprArgumentList := '(' [ exprArg { , exprArg } ] ')' var argumentsList = new ArgumentsList(); while (code.Current.Typ != LuaToken.BracketClose) { Token tName = null; if (code.LookAhead.Typ == LuaToken.Assign) // named argument { tName = FetchToken(LuaToken.Identifier, code); code.Next(); // equal } // parse the expression var tFirst = code.Current; var expr = ParseExpression(scope, code, InvokeResult.LuaResult, scope.EmitExpressionDebug); if (tName == null) argumentsList.AddPositionalArgument(tFirst, expr); else argumentsList.AddNamedArgument(tName, expr); // optinal comma FetchToken(LuaToken.Comma, code, true); } code.Next(); return argumentsList; }
private static Expression ParseExpressionOr(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // exprOr ::= exprAnd { or exprAnd } var expr = ParseExpressionAnd(scope, code, result, ref lWrap); while (code.Current.Typ == LuaToken.KwOr) { code.Next(); expr = BinaryOperationExpression(scope.Runtime, code.Current, ExpressionType.OrElse, expr, ParseExpressionAnd(scope, code, InvokeResult.Object, ref lWrap)); lWrap |= true; } return expr; }
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 ParseExpressionPower(Scope scope, LuaLexer code, InvokeResult result, ref bool lWrap) { // expPow ::= cast [ ^ expPow ] Expression expr = ParseExpressionCast(scope, code, result, ref lWrap); if (code.Current.Typ == LuaToken.Caret) { code.Next(); lWrap |= true; return BinaryOperationExpression(scope.Runtime, code.Current, ExpressionType.Power, expr, ParseExpressionPower(scope, code, InvokeResult.Object, ref lWrap)); } else return expr; }
private static void ParseConst(Scope scope, LuaLexer code) { // const ::= variable '=' ( expr | clr '.' Type ) Token tVarName; Type typeVar; ParseIdentifierAndType(scope, code, out tVarName, out typeVar); if (code.Current.Typ == LuaToken.Identifier || code.Current.Value == "typeof") { code.Next(); // Parse the type scope.RegisterConst(tVarName.Value, Expression.Constant(ParseType(scope, code, false))); } else { FetchToken(LuaToken.Assign, code); Expression exprConst = ParseExpression(scope, code, InvokeResult.Object, false); // No Debug-Emits if (typeVar != typeof(object)) exprConst = ConvertExpression(scope.Runtime, tVarName, exprConst, typeVar); // Try to eval the statement if (exprConst.Type == typeof(object) || exprConst.Type == typeof(LuaResult)) // dynamic calls, no constant possible throw ParseError(tVarName, Properties.Resources.rsConstExpressionNeeded); else try { object r = EvaluateExpression(exprConst); if (r == null) // Eval via compile { Type typeFunc = Expression.GetFuncType(exprConst.Type); LambdaExpression exprEval = Expression.Lambda(typeFunc, exprConst); Delegate dlg = exprEval.Compile(); r = dlg.DynamicInvoke(); } scope.RegisterConst(tVarName.Value, Expression.Constant(r, exprConst.Type)); } catch (Exception e) { throw ParseError(tVarName, String.Format(Properties.Resources.rsConstExpressionEvalError, e.Message)); } } }
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 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 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 Expression ParseElseStatement(Scope scope, LuaLexer code) { if (code.Current.Typ == LuaToken.KwElseif) { code.Next(); var expr = ConvertExpression(scope.Runtime, code.Current, ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug), typeof(bool)); FetchToken(LuaToken.KwThen, code); return Expression.IfThenElse(expr, ParseIfElseBlock(scope, code), ParseElseStatement(scope, code)); } else if (code.Current.Typ == LuaToken.KwElse) { code.Next(); var block = ParseIfElseBlock(scope, code); FetchToken(LuaToken.KwEnd, code); return block; } else if (code.Current.Typ == LuaToken.KwEnd) { code.Next(); return Expression.Empty(); } else throw ParseError(code.Current, Properties.Resources.rsParseUnexpectedTokenElse); }