private void EmitReturnStatement(CodeMethodReturnStatement Return) { Depth++; Debug("Emitting return statement"); if (Method.ReturnType != typeof(void)) { Type Top; if (Return.Expression == null) { // Default to an empty string if this method expects a return value Generator.Emit(OpCodes.Ldstr, ""); Top = typeof(string); } else { Top = EmitExpression(Return.Expression); } if (Top != null) { ForceTopStack(Top, Method.ReturnType); } } else if (Return.Expression != null) { throw new CompileException(Return, "Can not return value from void method " + Method.Name); } Generator.Emit(OpCodes.Ret); Depth--; }
private void EmitArgumentReference(CodeArgumentReferenceExpression Argument) { Depth++; Debug("Emitting argument reference"); Generator.Emit(OpCodes.Ldarg, 0); // for now only used to refer to the sole object[] parameter Depth--; }
void EmitIterationStatement(CodeIterationStatement Iterate) { Depth++; Debug("Emitting iteration statement"); // Used for break and continue later on var Meta = new LoopMetadata { Begin = Generator.DefineLabel(), End = Generator.DefineLabel(), }; Loops.Push(Meta); EmitStatement(Iterate.InitStatement, false); // The beginning of our loop: check the limit Generator.MarkLabel(Meta.Begin); EmitExpression(Iterate.TestExpression, false); Generator.Emit(OpCodes.Brfalse, Meta.End); // Emit the actual statements within EmitStatementCollection(Iterate.Statements); // Increase the counter by one EmitStatement(Iterate.IncrementStatement, false); // Start all over again Generator.Emit(OpCodes.Br, Meta.Begin); Generator.MarkLabel(Meta.End); Loops.Pop(); Depth--; }
void EmitArrayIndexerExpression(CodeArrayIndexerExpression Indexer) { var index = (CodeArrayIndexerExpression)Indexer; Generator.Emit(OpCodes.Ldloc, VarsProperty); EmitExpression(index.Indices[0]); Generator.Emit(OpCodes.Callvirt, GetVariable); }
private Type EmitArrayInitializer(Type ElementType, CodeExpression Expr, int Index) { Generator.Emit(OpCodes.Dup); Generator.Emit(OpCodes.Ldc_I4, Index); Type Generated = EmitExpression(Expr); ForceTopStack(Generated, ElementType); Generator.Emit(OpCodes.Stelem_Ref); return(ElementType.MakeArrayType()); }
private void ConditionalBox(Type Top) { if (Top == null) { throw new Exception("Top type can not be null"); } if (Top != typeof(object)) { Generator.Emit(OpCodes.Box, Top); } }
private void EmitGotoStatement(CodeGotoStatement Goto) { Depth++; Debug("Emitting goto: " + Goto.Label); LabelMetadata Meta = LookupLabel(Goto.Label); Generator.Emit(OpCodes.Br, Meta.Label); Meta.From = Goto; Depth--; }
public void Emit() { EmitStatementCollection(Member.Statements); if (Method.ReturnType != typeof(void)) { Generator.Emit(OpCodes.Ldstr, ""); } Generator.Emit(OpCodes.Ret); CheckLabelsResolved(); }
Type EmitPropertyReferenceExpression(CodePropertyReferenceExpression prop) { // HACK: property get method target var info = typeof(Rusty.Core).GetProperty(prop.PropertyName); if (Mirror != null) { info = Mirror.GrabProperty(info); } Generator.Emit(OpCodes.Call, info.GetGetMethod()); return(info.PropertyType); }
private Type EmitVariableReference(CodeVariableReferenceExpression Expr) { if (!Locals.ContainsKey(Expr.VariableName)) { throw new CompileException(Expr, "Undefined variable: " + Expr.VariableName); } LocalBuilder Builder = Locals[Expr.VariableName]; Generator.Emit(OpCodes.Ldloc, Builder); return(Builder.LocalType); }
private void EmitAssignStatement(CodeAssignStatement Assign, bool ForceTypes) { Depth++; Debug("Emitting assignment statement"); Type Top = EmitAssignment(Assign.Left, Assign.Right, ForceTypes); if (Top != typeof(void)) { Generator.Emit(OpCodes.Pop); } Depth--; }
private void EmitVariableDeclarationStatement(CodeVariableDeclarationStatement Statement) { if (Locals.ContainsKey(Statement.Name)) { throw new CompileException(Statement, "Attempt to redefine local variable " + Statement.Name); } Type Top = EmitExpression(Statement.InitExpression); LocalBuilder Local = Generator.DeclareLocal(Top); Locals.Add(Statement.Name, Local); Generator.Emit(OpCodes.Stloc, Local); }
Type EmitExpressionStatement(CodeExpressionStatement Expression, bool ForceTypes) { Depth++; Debug("Emitting expression statement"); Type Generated = EmitExpression(Expression.Expression, ForceTypes); if (Generated != typeof(void)) { Generator.Emit(OpCodes.Pop); } Depth--; return(Generated); }
private void ForceTopStack(Type Top, Type Wanted, bool ForceTypes) { Depth++; if (Top != Wanted) { Debug("Forcing top stack " + Top + " to " + Wanted); if (Wanted == typeof(string)) { ConditionalBox(Top); Generator.Emit(OpCodes.Call, ForceString); } else if (Wanted == typeof(decimal)) { ConditionalBox(Top); Generator.Emit(OpCodes.Call, ForceDecimal); } else if (Wanted == typeof(long)) { ConditionalBox(Top); Generator.Emit(OpCodes.Call, ForceLong); } else if (Wanted == typeof(int)) { ConditionalBox(Top); Generator.Emit(OpCodes.Call, ForceInt); } else if (Wanted == typeof(bool)) { ConditionalBox(Top); Generator.Emit(OpCodes.Call, ForceBool); } else if (Wanted == typeof(object)) { ConditionalBox(Top); } else if (Wanted == typeof(object[]) && Top.IsArray) { } else { Debug("WARNING: Can not force " + Wanted); } } Depth--; }
Type EmitTernaryOperator(CodeTernaryOperatorExpression ternary) { Label FalseLabel = Generator.DefineLabel(); Label EndLabel = Generator.DefineLabel(); Type Top; EmitExpression(ternary.Condition); Generator.Emit(OpCodes.Brfalse, FalseLabel); Top = EmitExpression(ternary.TrueBranch); ForceTopStack(Top, typeof(object)); Generator.Emit(OpCodes.Br, EndLabel); Generator.MarkLabel(FalseLabel); Top = EmitExpression(ternary.FalseBranch); ForceTopStack(Top, typeof(object)); Generator.MarkLabel(EndLabel); return(typeof(object)); }
Type EmitCodeFieldReference(CodeFieldReferenceExpression field) { Depth++; Debug("Emitting field reference: " + field.FieldName); Type target = Type.GetType((field.TargetObject as CodeTypeReferenceExpression).Type.BaseType); FieldInfo fi = target.GetField(field.FieldName); try { Generator.Emit(OpCodes.Ldc_I4, (int)fi.GetValue(null)); } catch (InvalidCastException) { throw new CompileException(field, "Enumerator " + target.Name + " does not have base type of int32"); } Depth--; return(fi.FieldType); }
private void EmitConditionStatement(CodeConditionStatement Condition) { Label False = Generator.DefineLabel(); Label End = Generator.DefineLabel(); // TODO: emitting condition statements could probably be done more efficiently EmitExpression(Condition.Condition); Generator.Emit(OpCodes.Ldc_I4_0); Generator.Emit(OpCodes.Beq, False); // Execute code for true and jump to end EmitStatementCollection(Condition.TrueStatements); Generator.Emit(OpCodes.Br, End); // Execute code for false and move on Generator.MarkLabel(False); EmitStatementCollection(Condition.FalseStatements); Generator.MarkLabel(End); }
Type EmitPrimitive(CodePrimitiveExpression Primitive) { Type T; if (Primitive.Value == null) { T = null; } else { T = Primitive.Value.GetType(); } if (T != null && T.IsArray) { var Contents = Primitive.Value as object[]; Type Element = T.GetElementType(); Generator.Emit(OpCodes.Ldc_I4, Contents.Length); Generator.Emit(OpCodes.Newarr, Element); int i = 0; foreach (var Value in Contents) { Generator.Emit(OpCodes.Dup); Generator.Emit(OpCodes.Ldc_I4, i); EmitLiteral(Element, Value); Generator.Emit(OpCodes.Stelem_Ref); i++; } return(T); } else { return(EmitLiteral(T, Primitive.Value)); } }
Type EmitDelegateCreateExpression(CodeDelegateCreateExpression del) { Depth++; Debug("Emitting delegate: " + del.MethodName); // HACK: use generic method lookup for emitting delegates if (!Methods.ContainsKey(del.MethodName)) { throw new CompileException(del, "Delegate function does not exist in local scope"); } var method = (MethodInfo)Methods[del.MethodName].Method; Generator.Emit(OpCodes.Ldnull); Generator.Emit(OpCodes.Ldftn, method); var type = del.DelegateType.UserData[Parser.RawData] as Type ?? Type.GetType(del.DelegateType.BaseType); if (type == null) { throw new CompileException(del, "Invalid delegate type"); } if (Mirror != null) { type = Mirror.GrabType(type); } var ctor = type.GetConstructors()[0]; Generator.Emit(OpCodes.Newobj, ctor); Depth--; return(type); }
Type EmitMethodInvoke(CodeMethodInvokeExpression invoke) { Depth++; Debug("Emitting method " + invoke.Method.MethodName); MethodInfo target = null; Type[] types = null; #region Lookup target function MethodInfo actual = null; if (invoke.Method.TargetObject != null) { target = GetMethodInfo(invoke.Method); if (Mirror != null) { actual = Mirror.GrabMethod(target); } } // Case insensitive method search in local scope if (target == null) { foreach (var name in Methods.Keys) { if (invoke.Method.MethodName.Equals(name, StringComparison.OrdinalIgnoreCase)) { invoke.Method.MethodName = name; } } } // First we check the local methods if (target == null && Methods.ContainsKey(invoke.Method.MethodName)) { types = ParameterTypes[invoke.Method.MethodName]; target = Methods[invoke.Method.MethodName].Method; } // Then the methods provided by rusty if (target == null) { target = Lookup.BestMatch(invoke.Method.MethodName, invoke.Parameters.Count); if (Mirror != null) { actual = Mirror.GrabMethod(target); } } // Lastly, the native methods if (target == null && invoke.Method.TargetObject != null) { target = GetMethodInfo(invoke.Method); if (Mirror != null) { actual = Mirror.GrabMethod(target); } } if (target == null) { throw new CompileException(invoke, "Could not look up method " + invoke.Method.MethodName); } bool hasParams = false; if (types == null) // Rusty-defined or native method { ParameterInfo[] Params = target.GetParameters(); types = new Type[Params.Length]; for (int i = 0; i < Params.Length; i++) { types[i] = Params[i].ParameterType; } hasParams = types.Length == 0 ? false : types[types.Length - 1] == typeof(object[]); } #endregion #region Emit parameters int p = 0; var ByRef = new Dictionary <LocalBuilder, CodeExpression>(); for (p = 0; p < invoke.Parameters.Count; p++) { Depth++; Debug("Emitting parameter " + p); // Collapse superfluous arguments in array if last argument is object[] // _and_ it's not a call into a user-defined function. if (hasParams) { if (p == types.Length - 1) { Type Generated = EmitExpression(invoke.Parameters[p]); // If the last argument is object[], we don't bother about params if (Generated == typeof(object[])) { break; } LocalBuilder Temp = Generator.DeclareLocal(typeof(object)); ForceTopStack(Generated, typeof(object)); Generator.Emit(OpCodes.Stloc, Temp); EmitArrayCreation(typeof(object), invoke.Parameters.Count - p); Generator.Emit(OpCodes.Dup); Generator.Emit(OpCodes.Ldc_I4, 0); Generator.Emit(OpCodes.Ldloc, Temp); Generator.Emit(OpCodes.Stelem_Ref); Depth--; continue; } else if (p > types.Length - 1) { EmitArrayInitializer(typeof(object), invoke.Parameters[p], p - types.Length + 1); Depth--; continue; } } if (p < types.Length) { Type Generated = EmitExpression(invoke.Parameters[p]); if (types[p].IsByRef) { // Variables passed by reference need to be stored in a local Debug("Parameter " + p + " was by reference"); LocalBuilder Temporary = Generator.DeclareLocal(types[p].GetElementType()); ForceTopStack(typeof(object), types[p].GetElementType()); Generator.Emit(OpCodes.Stloc, Temporary); Generator.Emit(OpCodes.Ldloca_S, Temporary); if (invoke.Parameters[p] is CodeArrayIndexerExpression) { ByRef.Add(Temporary, invoke.Parameters[p]); } } else { ForceTopStack(Generated, types[p]); } } Depth--; } // Anything not specified pads to the default IL value while (p < types.Length) { if (types[p].IsByRef) { Type NotRef = types[p].GetElementType(); EmitLiteral(NotRef, GetDefaultValue(target.GetParameters()[p])); LocalBuilder Temporary = Generator.DeclareLocal(NotRef); Generator.Emit(OpCodes.Stloc, Temporary); Generator.Emit(OpCodes.Ldloca, Temporary); } else { EmitLiteral(types[p], GetDefaultValue(target.GetParameters()[p])); } p++; } #endregion if (actual == null) { Generator.Emit(OpCodes.Call, target); } else { Generator.Emit(OpCodes.Call, actual); } #region Save back the variables // Save the variables passed to reference back in Rusty's variable handling foreach (var Builder in ByRef.Keys) { if (ByRef[Builder] is CodeArrayIndexerExpression) { var Ref = ByRef[Builder] as CodeArrayIndexerExpression; Generator.Emit(OpCodes.Ldloc, VarsProperty); EmitExpression(Ref.Indices[0]); Generator.Emit(OpCodes.Ldloc, Builder); if (Builder.LocalType != typeof(object)) { ForceTopStack(Builder.LocalType, typeof(object)); } Generator.Emit(OpCodes.Callvirt, SetVariable); Generator.Emit(OpCodes.Pop); } } #endregion Depth--; return(target.ReturnType); }
private Type EmitAssignment(CodeExpression Left, CodeExpression Right, bool ForceTypes) { Depth++; Debug("Emitting assignment expression"); Type Generated = typeof(void); if (Left is CodeVariableReferenceExpression) { // local IL variables generated by parser var Reference = Left as CodeVariableReferenceExpression; LocalBuilder Var; if (Locals.ContainsKey(Reference.VariableName)) { Var = Locals[Reference.VariableName]; } else { Var = Generator.DeclareLocal(typeof(int)); Locals.Add(Reference.VariableName, Var); } EmitExpression(Right, ForceTypes); Generator.Emit(OpCodes.Stloc, Var); Generator.Emit(OpCodes.Pop); } else if (Left is CodeArrayIndexerExpression) { var index = (CodeArrayIndexerExpression)Left; Generator.Emit(OpCodes.Ldloc, VarsProperty); EmitExpression(index.Indices[0]); Type resultType = EmitExpression(Right, ForceTypes); if (resultType.IsValueType) { Generator.Emit(OpCodes.Box, resultType); } Generator.Emit(OpCodes.Callvirt, SetVariable); Generated = typeof(object); } else if (Left is CodePropertyReferenceExpression) { var prop = (CodePropertyReferenceExpression)Left; // HACK: property set method target var info = typeof(Rusty.Core).GetProperty(prop.PropertyName); if (Mirror != null) { info = Mirror.GrabProperty(info); } var set = info == null ? null : info.GetSetMethod(); if (set == null) { Generator.Emit(OpCodes.Ldnull); } else { EmitExpression(Right); Generator.Emit(OpCodes.Dup); Generator.Emit(OpCodes.Call, set); } Generated = typeof(object); } else { throw new CompileException(Left, "Left hand is unassignable"); } Depth--; return(Generated); }
Type EmitLiteral(Type T, object Value) { Depth++; Type Generated = T; if (Value == null) { Debug("Pushing null"); Generator.Emit(OpCodes.Ldnull); Generated = typeof(Nullable); } else if (T == typeof(string)) { Debug("Pushing primitive string : \"" + (Value as string) + "\""); if (((string)Value).Length == 0) { Generator.Emit(OpCodes.Ldsfld, typeof(string).GetField("Empty")); } else { Generator.Emit(OpCodes.Ldstr, Value as string); } } else if (T == typeof(int)) { var val = (int)Value; Debug("Pushing primitive integer : " + val); switch (val) { case -1: Generator.Emit(OpCodes.Ldc_I4_M1); break; case 0: Generator.Emit(OpCodes.Ldc_I4_0); break; case 1: Generator.Emit(OpCodes.Ldc_I4_1); break; case 2: Generator.Emit(OpCodes.Ldc_I4_2); break; case 3: Generator.Emit(OpCodes.Ldc_I4_3); break; case 4: Generator.Emit(OpCodes.Ldc_I4_4); break; case 5: Generator.Emit(OpCodes.Ldc_I4_5); break; case 6: Generator.Emit(OpCodes.Ldc_I4_6); break; case 7: Generator.Emit(OpCodes.Ldc_I4_7); break; case 8: Generator.Emit(OpCodes.Ldc_I4_8); break; default: Generator.Emit(OpCodes.Ldc_I4, val); break; } } else if (T == typeof(decimal)) { Debug("Pushing decimal : " + ((decimal)Value)); // HACK: push real decimals without downcasting // i.e. new decimal(decimal.GetBits((decimal)Value)); Generator.Emit(OpCodes.Ldc_R8, ((double)((decimal)Value))); Generated = typeof(double); } else if (T == typeof(object[])) { Debug("Pushing object[" + ((object[])Value).Length + "]"); var array = new CodeArrayCreateExpression(); array.CreateType = new CodeTypeReference(typeof(object)); foreach (var sub in (object[])Value) { array.Initializers.Add(new CodePrimitiveExpression(sub)); } EmitDynamicName(array); } else if (T == typeof(bool)) { var val = (bool)Value; Debug("Pushing bool: " + Value); Generator.Emit(val ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); } else if (T == typeof(double)) { Debug("Pushing double: " + ((double)Value)); Generator.Emit(OpCodes.Ldc_R8, ((double)Value)); } else if (T == typeof(long)) { Debug("Pushing long: " + (long)Value); Generator.Emit(OpCodes.Ldc_I8, (long)Value); } else if (T.IsGenericType && T.GetGenericTypeDefinition() == typeof(Nullable <>)) { Debug("Pushing nullable: " + Value); EmitLiteral(Value == null ? typeof(Nullable) : T.GetGenericArguments()[0], Value); } else { Debug("Unhandled primitive: " + T); Generated = null; } Depth--; return(Generated); }
private Type EmitArrayCreation(Type ArrayType, int Count) { Generator.Emit(OpCodes.Ldc_I4, Count); Generator.Emit(OpCodes.Newarr, ArrayType); return(ArrayType.MakeArrayType()); }
Type EmitBinaryOperator(CodeBinaryOperatorExpression Binary, bool ForceTypes) { bool Shortcut = Binary.Operator == CodeBinaryOperatorType.BooleanAnd || Binary.Operator == CodeBinaryOperatorType.BooleanOr; Label EndLabel = Generator.DefineLabel(); if (Binary.Operator == CodeBinaryOperatorType.Assign) { return(EmitAssignment(Binary.Left, Binary.Right, ForceTypes)); } Type Generated; Depth++; Debug("Emitting binary operator, left hand side"); Generated = EmitExpression(Binary.Left); if (Shortcut && Generated == typeof(bool)) { Debug("Short-circuiting expression for " + Binary.Operator); Generator.Emit(OpCodes.Dup); if (Binary.Operator == CodeBinaryOperatorType.BooleanAnd) { Generator.Emit(OpCodes.Brfalse, EndLabel); // BooleanAnd jumps if left branch evals false } else if (Binary.Operator == CodeBinaryOperatorType.BooleanOr) { Generator.Emit(OpCodes.Brtrue, EndLabel); // BooleanOr jumps if left branch evals true } } if (ForceTypes) { ForceTopStack(Generated, typeof(float)); } Debug("Emitting binary operator, right hand side"); Generated = EmitExpression(Binary.Right); if (ForceTypes) { ForceTopStack(Generated, typeof(float)); } if (Shortcut) { if (Binary.Operator == CodeBinaryOperatorType.BooleanAnd) { Generator.Emit(OpCodes.And); } else if (Binary.Operator == CodeBinaryOperatorType.BooleanOr) { Generator.Emit(OpCodes.Or); } // Handy side-effect: one bool caused by the "dup" stays on the stack // Resulting in the whole expression evaluating correctly anyway. Generator.MarkLabel(EndLabel); Depth--; return(typeof(bool)); } switch (Binary.Operator) { case CodeBinaryOperatorType.Add: Generator.Emit(OpCodes.Add); Generated = typeof(float); break; case CodeBinaryOperatorType.Subtract: Generator.Emit(OpCodes.Sub); Generated = typeof(float); break; case CodeBinaryOperatorType.Multiply: Generator.Emit(OpCodes.Mul); Generated = typeof(float); break; case CodeBinaryOperatorType.Divide: Generator.Emit(OpCodes.Div); Generated = typeof(float); break; case CodeBinaryOperatorType.LessThan: Generator.Emit(OpCodes.Clt); Generated = typeof(bool); break; case CodeBinaryOperatorType.GreaterThan: Generator.Emit(OpCodes.Cgt); Generated = typeof(bool); break; case CodeBinaryOperatorType.ValueEquality: Generator.Emit(OpCodes.Ceq); Generated = typeof(bool); break; default: Debug("Unhandled operator: " + Binary.Operator); Generated = null; break; } Depth--; return(Generated); }