void PrintCode(CodeCompileUnit[] units, TextWriter writer) { var gen = new Generator(); var options = new CodeGeneratorOptions { IndentString = " " }; try { foreach (var unit in units) gen.GenerateCodeFromCodeObject(unit, writer, options); } catch (Exception e) { Console.Error.WriteLine(e.Message); } }
private 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 Lookup target function #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 Emit parameters 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 Save back the variables Depth--; return(target.ReturnType); }