internal static PreparedFunctions Prepare( TranslateContext translateContext, Func <MethodDefinition, bool> predict) { IPrepareContext prepareContext = translateContext; var allTypes = translateContext.Assembly.Modules .SelectMany(module => module.Types) .Where(type => type.IsValidDefinition()) .ToArray(); var types = allTypes .Where(type => !(type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly)) .ToArray(); // Lookup type references. foreach (var type in types) { prepareContext.RegisterType(type); } // Lookup fields. foreach (var field in types.SelectMany(type => type.Fields)) { prepareContext.RegisterType(field.FieldType); } // Construct result. return(new PreparedFunctions(allTypes .SelectMany(type => type.Methods) .Where(predict) .ToDictionary( method => method, method => PrepareMethod(prepareContext, method), CecilHelper.MemberReferenceComparer <MethodDefinition> .Instance))); }
public static void Translate( TextWriter logw, CodeTextStorage storage, bool readSymbols, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, string assemblyPath) { logw.Write("IL2C: Preparing assembly: \"{0}\" ...", Path.GetFullPath(assemblyPath)); var translateContext = new TranslateContext(assemblyPath, readSymbols, targetPlatform); var preparedFunctions = AssemblyPreparer.Prepare(translateContext); logw.WriteLine(" done."); using (var _ = storage.EnterScope("include")) { AssemblyWriter.WriteHeader( storage, translateContext, preparedFunctions); } using (var _ = storage.EnterScope("src")) { AssemblyWriter.WriteSourceCode( storage, translateContext, preparedFunctions, enableBundler, debugInformationOptions); } }
internal static void WriteConstStrings( CodeTextWriter twSource, TranslateContext translateContext) { IExtractContext extractContext = translateContext; var constStrings = extractContext. ExtractConstStrings(). ToArray(); if (constStrings.Length >= 1) { twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-1] Const strings:"); twSource.SplitLine(); foreach (var(symbolName, value) in extractContext.ExtractConstStrings()) { var expr = Utilities.GetCLanguageExpression(value); twSource.WriteLine( "IL2C_CONST_STRING({0}, {1});", symbolName, expr); } twSource.SplitLine(); } }
public static void CallStaticMethodTest() { var mainMethod = testType.GetMethod("CallTestMethod"); var translateContext = new TranslateContext(testTypeAssembly.Location); var tw = new StringWriter(); var prepared = AssemblyPreparer.Prepare( translateContext, method => method.MemberEquals(mainMethod)); AssemblyWriter.InternalConvertFromMethod(tw, translateContext, prepared, mainMethod, " "); var sourceCode = tw.ToString(); var expected = new StringWriter(); expected.WriteLine(@"int32_t IL2C_TestTargetClass_CallTestMethod(void)"); expected.WriteLine(@"{"); expected.WriteLine(@" int32_t local0;"); expected.WriteLine(@""); expected.WriteLine(@" int32_t __stack0_int32_t;"); expected.WriteLine(@" int32_t __stack1_int32_t;"); expected.WriteLine(@""); expected.WriteLine(@" __stack0_int32_t = 1;"); expected.WriteLine(@" __stack1_int32_t = 2;"); expected.WriteLine(@" __stack0_int32_t = IL2C_TestTargetClass_CallStaticMethodTestType_Test(__stack0_int32_t, (int16_t)__stack1_int32_t);"); expected.WriteLine(@" local0 = __stack0_int32_t;"); expected.WriteLine(@" goto L_0000;"); expected.WriteLine(@"L_0000:"); expected.WriteLine(@" __stack0_int32_t = local0;"); expected.WriteLine(@" return __stack0_int32_t;"); expected.WriteLine(@"}"); Assert.AreEqual(expected.ToString(), sourceCode); }
public static void WriteHeader( CodeTextWriter twHeader, TranslateContext translateContext, PreparedInformations prepared) { InternalWriteHeader( twHeader, translateContext, prepared, true); }
public static PreparedInformations Prepare(TranslateContext translateContext) { return(Prepare( translateContext, // All types type => true, // The methods except type initializer. method => !(method.IsConstructor && method.IsStatic))); }
public static void WriteSourceCode( CodeTextWriter twSource, TranslateContext translateContext, PreparedInformations prepared, DebugInformationOptions debugInformationOption = DebugInformationOptions.Full) { InternalWriteSourceCode( twSource, translateContext, prepared, debugInformationOption, true); }
internal static PreparedInformations Prepare( TranslateContext translateContext, Func <ITypeInformation, bool> predictType, Func <IMethodInformation, bool> predictMethod) { IPrepareContext prepareContext = translateContext; var allTypes = translateContext.Assembly.Modules. SelectMany(module => module.Types.Concat(module.Types.SelectMany(type => type.NestedTypes))). Where(predictType). Distinct(). ToArray(); // Lookup type references. foreach (var type in allTypes) { // Register used type. prepareContext.RegisterType(type, type.CLanguageMemberScope); if (type.BaseType != null) { prepareContext.RegisterType(type.BaseType, type.CLanguageMemberScope); } foreach (var interfaceType in type.InterfaceTypes) { prepareContext.RegisterType(type.BaseType, type.CLanguageMemberScope); } } // Lookup fields. foreach (var field in allTypes.SelectMany(type => type.Fields)) { // Register field type. prepareContext.RegisterType(field.FieldType, field.CLanguageMemberScope); // Register include file from the native value. if (field.NativeValue != null) { prepareContext.RegisterImportIncludeFile(field.NativeValue.IncludeFileName); } } // Construct result. return(new PreparedInformations( allTypes, (from type in allTypes from method in type.DeclaredMethods where predictMethod(method) let preparedMethod = PrepareMethod(prepareContext, method) where preparedMethod != null select preparedMethod). ToDictionary( preparedMethod => preparedMethod.Method, preparedMethod => preparedMethod))); }
internal static void WriteDeclaredValues( CodeTextWriter twSource, TranslateContext translateContext) { IExtractContext extractContext = translateContext; var declaredValues = extractContext. ExtractDeclaredValues(). ToArray(); if (declaredValues.Length >= 1) { twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [12-1] Declared values:"); foreach (var information in extractContext.ExtractDeclaredValues()) { twSource.SplitLine(); foreach (var declaredFields in information.DeclaredFields) { twSource.WriteLine( "// {0}", declaredFields.FriendlyName); } var targetType = (information.HintTypes.Length == 1) ? information.HintTypes[0] : extractContext.MetadataContext.ByteType.MakeArray(); Debug.Assert(targetType.IsArray); var elementType = targetType.ElementType.ResolveToRuntimeType(); var values = Utilities.ResourceDataToSpecificArray(information.ResourceData, elementType); var lhs = targetType.GetCLanguageTypeName(information.SymbolName, true); var expr = Utilities.GetCLanguageExpression(values); twSource.WriteLine( "static const {0} =", lhs); using (var _ = twSource.Shift()) { twSource.WriteLine( "{0};", expr); } } twSource.SplitLine(); } }
public static void ConditionalBranchTest() { var mainMethod = testType.GetMethod("ConditionalBranchMainBody"); var translateContext = new TranslateContext(testTypeAssembly.Location); var tw = new StringWriter(); var prepared = AssemblyPreparer.Prepare( translateContext, method => method.MemberEquals(mainMethod)); AssemblyWriter.InternalConvertFromMethod(tw, translateContext, prepared, mainMethod, " "); var sourceCode = tw.ToString(); var expected = new StringWriter(); expected.WriteLine(@"int32_t IL2C_TestTargetClass_ConditionalBranchMainBody(int32_t a)"); expected.WriteLine(@"{"); expected.WriteLine(@" bool local0;"); expected.WriteLine(@" int32_t local1;"); expected.WriteLine(); expected.WriteLine(@" int32_t __stack0_int32_t;"); expected.WriteLine(@" int32_t __stack1_int32_t;"); expected.WriteLine(); expected.WriteLine(@" __stack0_int32_t = a;"); expected.WriteLine(@" __stack1_int32_t = 0;"); expected.WriteLine(@" __stack0_int32_t = (__stack0_int32_t > __stack1_int32_t) ? 1 : 0;"); expected.WriteLine(@" local0 = __stack0_int32_t ? true : false;"); expected.WriteLine(@" __stack0_int32_t = local0 ? 1 : 0;"); expected.WriteLine(@" if (__stack0_int32_t == 0) goto L_0000;"); expected.WriteLine(@" __stack0_int32_t = a;"); expected.WriteLine(@" __stack1_int32_t = 1;"); expected.WriteLine(@" __stack0_int32_t = __stack0_int32_t + __stack1_int32_t;"); expected.WriteLine(@" local1 = __stack0_int32_t;"); expected.WriteLine(@" goto L_0001;"); expected.WriteLine(@"L_0000:"); expected.WriteLine(@" __stack0_int32_t = a;"); expected.WriteLine(@" __stack1_int32_t = 2;"); expected.WriteLine(@" __stack0_int32_t = __stack0_int32_t + __stack1_int32_t;"); expected.WriteLine(@" local1 = __stack0_int32_t;"); expected.WriteLine(@" goto L_0001;"); expected.WriteLine(@"L_0001:"); expected.WriteLine(@" __stack0_int32_t = local1;"); expected.WriteLine(@" return __stack0_int32_t;"); expected.WriteLine(@"}"); Assert.AreEqual(expected.ToString(), sourceCode); }
public static string[] WriteSourceCode( CodeTextStorage storage, TranslateContext translateContext, PreparedInformations prepared, bool enableBundler, DebugInformationOptions debugInformationOption) { var sourceFilePaths = new List <string>(); var assemblyName = translateContext.Assembly.Name; // Write assembly level common internal header. HeaderWriter.WriteCommonInternalHeader( storage, translateContext, prepared, assemblyName); // Write assembly level common internal source code. sourceFilePaths.Add( SourceCodeWriter.WriteCommonInternalSourceCode( storage, translateContext, prepared, assemblyName)); // Write source code bundler. if (enableBundler) { SourceCodeWriter.WriteBundlerSourceCode( storage, prepared, assemblyName); } using (var _ = storage.EnterScope(assemblyName, false)) { // Write source codes. sourceFilePaths.AddRange( SourceCodeWriter.WriteSourceCodes( storage, translateContext, prepared, debugInformationOption)); } return(sourceFilePaths.ToArray()); }
public static void SimpleOverallByInt64SummationTest() { var mainMethod = testType.GetMethod("Int64MainBody"); var translateContext = new TranslateContext(testTypeAssembly.Location); var tw = new StringWriter(); var prepared = AssemblyPreparer.Prepare( translateContext, method => method.MemberEquals(mainMethod)); AssemblyWriter.InternalConvertFromMethod(tw, translateContext, prepared, mainMethod, " "); var sourceCode = tw.ToString(); var expected = new StringWriter(); expected.WriteLine(@"int64_t IL2C_TestTargetClass_Int64MainBody(void)"); expected.WriteLine(@"{"); expected.WriteLine(@" int64_t local0;"); expected.WriteLine(@" int64_t local1;"); expected.WriteLine(@" int64_t local2;"); expected.WriteLine(@" int64_t local3;"); expected.WriteLine(); expected.WriteLine(@" int32_t __stack0_int32_t;"); expected.WriteLine(@" int64_t __stack0_int64_t;"); expected.WriteLine(@" int64_t __stack1_int64_t;"); expected.WriteLine(); expected.WriteLine(@" __stack0_int32_t = 1;"); expected.WriteLine(@" __stack0_int64_t = __stack0_int32_t;"); expected.WriteLine(@" local0 = __stack0_int64_t;"); expected.WriteLine(@" __stack0_int32_t = 2;"); expected.WriteLine(@" __stack0_int64_t = __stack0_int32_t;"); expected.WriteLine(@" local1 = __stack0_int64_t;"); expected.WriteLine(@" __stack0_int64_t = local0;"); expected.WriteLine(@" __stack1_int64_t = local1;"); expected.WriteLine(@" __stack0_int64_t = __stack0_int64_t + __stack1_int64_t;"); expected.WriteLine(@" local2 = __stack0_int64_t;"); expected.WriteLine(@" __stack0_int64_t = local2;"); expected.WriteLine(@" local3 = __stack0_int64_t;"); expected.WriteLine(@" goto L_0000;"); expected.WriteLine(@"L_0000:"); expected.WriteLine(@" __stack0_int64_t = local3;"); expected.WriteLine(@" return __stack0_int64_t;"); expected.WriteLine(@"}"); Assert.AreEqual(expected.ToString(), sourceCode); }
internal static void InternalWriteHeader( CodeTextWriter twHeader, TranslateContext translateContext, PreparedInformations prepared, bool includeAssemblyHeader) { IExtractContext extractContext = translateContext; var assemblyName = Utilities.GetMangledName(extractContext.Assembly.FriendlyName); twHeader.WriteLine("#ifndef __{0}_H__", assemblyName); twHeader.WriteLine("#define __{0}_H__", assemblyName); twHeader.SplitLine(); twHeader.WriteLine("#pragma once"); twHeader.SplitLine(); twHeader.WriteLine("#include <il2c.h>"); if (includeAssemblyHeader) { twHeader.SplitLine(); foreach (var fileName in extractContext.EnumerateRequiredIncludeFileNames()) { twHeader.WriteLine("#include <{0}>", fileName); } } // All types exclude privates PrototypeWriter.InternalConvertToPrototypes( twHeader, prepared.Types, type => type.IsCLanguagePublicScope, field => field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly, method => (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly) && prepared.Functions.ContainsKey(method)); twHeader.SplitLine(); twHeader.WriteLine("#endif"); twHeader.SplitLine(); }
public static void WriteHeader( TextWriter twHeader, TranslateContext translateContext, PreparedFunctions preparedFunctions, string indent) { IExtractContext extractContext = translateContext; var assemblyName = extractContext.Assembly.Name.Name; var safeSymbolName = assemblyName.Replace('.', '_').Replace('-', '_'); twHeader.WriteLine("#ifndef __MODULE_{0}__", safeSymbolName); twHeader.WriteLine("#define __MODULE_{0}__", safeSymbolName); twHeader.WriteLine(); foreach (var fileName in extractContext.EnumerateRequiredIncludeFileNames()) { twHeader.WriteLine("#include <{0}>", fileName); } var types = extractContext.Assembly.Modules .SelectMany(module => module.Types) .SelectMany(type => new[] { type }.Concat(type.NestedTypes)) // All types exclude privates .Where(type => type.IsValidDefinition() && (type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly)) .ToArray(); InternalConvertToPrototypes( twHeader, types, extractContext, preparedFunctions, method => method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly, indent); twHeader.WriteLine(); twHeader.WriteLine("#endif"); }
internal static PreparedInformations Prepare( TranslateContext translateContext, Func <ITypeInformation, bool> predictType, Func <IMethodInformation, bool> predictMethod) { IPrepareContext prepareContext = translateContext; var allTypes = translateContext.Assembly.Modules. SelectMany(module => module.Types). Where(predictType). Distinct(). ToArray(); // Lookup type references. foreach (var type in allTypes) { prepareContext.RegisterType(type); } // Lookup fields. foreach (var field in allTypes.SelectMany(type => type.Fields)) { prepareContext.RegisterType(field.FieldType); } // Construct result. return(new PreparedInformations( allTypes, (from type in allTypes from method in type.DeclaredMethods where predictMethod(method) let preparedMethod = PrepareMethod(prepareContext, method) where preparedMethod != null select preparedMethod). ToDictionary( preparedMethod => preparedMethod.Method, preparedMethod => preparedMethod))); }
public static void WriteHeader( CodeTextStorage storage, TranslateContext translateContext, PreparedInformations prepared) { var assemblyName = translateContext.Assembly.Name; // Write assembly level common header. HeaderWriter.WriteCommonHeader( storage, translateContext, prepared, assemblyName); using (var _ = storage.EnterScope(assemblyName, false)) { // Write public headers. HeaderWriter.WriteHeaders( storage, translateContext, prepared); } }
public static void AccessValueTypeFieldTest() { Assert.Fail("TODO:"); var mainMethod = testType.GetMethod("AccessValueTypeFieldMethod"); var translateContext = new TranslateContext(testTypeAssembly.Location); var tw = new StringWriter(); var targetType = typeof(TestTargetClass.AccessValueTypeFieldTestType); var prepared = AssemblyPreparer.Prepare( translateContext, method => method.MemberEquals(mainMethod)); AssemblyWriter.InternalConvertFromMethod(tw, translateContext, prepared, mainMethod, " "); var sourceCode = tw.ToString(); var expected = new StringWriter(); expected.WriteLine(@""); Assert.AreEqual(expected.ToString(), sourceCode); }
public static void WriteSourceCode( TextWriter twSource, TranslateContext translateContext, PreparedFunctions preparedFunctions, string indent, DebugInformationOptions debugInformationOption = DebugInformationOptions.Full) { IExtractContext extractContext = translateContext; foreach (var fileName in extractContext.EnumerateRequiredPrivateIncludeFileNames()) { twSource.WriteLine("#include \"{0}\"", fileName); } var assemblyName = extractContext.Assembly.Name.Name; twSource.WriteLine("#include \"{0}.h\"", assemblyName); twSource.WriteLine(); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// Const strings:"); twSource.WriteLine(); foreach (var kv in extractContext.ExtractConstStrings()) { var escaped = Utilities.GetEscapedCString(kv.Value); twSource.WriteLine( "IL2C_CONST_STRING({0}, L\"{1}\");", kv.Key, escaped); } var allTypes = extractContext.Assembly.Modules .SelectMany(module => module.Types) .SelectMany(type => new[] { type }.Concat(type.NestedTypes)) .Where(type => type.IsValidDefinition()) .ToArray(); // All types exclude publics and internals (for file scope prototypes) var types = allTypes .Where(type => !(type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly)) .ToArray(); InternalConvertToPrototypes( twSource, types, extractContext, preparedFunctions, method => !(method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly), indent); twSource.WriteLine(); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// Static fields:"); foreach (var type in allTypes.Where(type => !type.IsEnum)) { twSource.WriteLine(); // All static fields foreach (var field in type.Fields .Where(field => field.IsStatic)) { twSource.WriteLine( "{0};", Utilities.GetStaticFieldPrototypeString(field, true, extractContext)); } } twSource.WriteLine(); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// Methods:"); foreach (var type in allTypes.Where(type => !type.IsEnum)) { twSource.WriteLine(); twSource.WriteLine("////////////////////////////////////////////////////////////"); twSource.WriteLine("// Type: {0}", type.GetFullMemberName()); // All methods and constructor exclude type initializer foreach (var method in type.Methods .Where(method => !method.IsConstructor || !method.IsStatic)) { InternalConvertFromMethod( twSource, extractContext, preparedFunctions, method, indent, debugInformationOption); } if (type.IsClass || type.IsValueType) { InternalConvertTypeHelper( twSource, extractContext, type, indent); } else if (type.IsInterface) { InternalConvertTypeHelperForInterface( twSource, type, indent); } } }
internal static void InternalWriteSourceCode( CodeTextWriter twSource, TranslateContext translateContext, PreparedInformations prepared, DebugInformationOptions debugInformationOption, bool includeAssemblyHeader) { IExtractContextHost extractContext = translateContext; if (includeAssemblyHeader) { foreach (var fileName in extractContext.EnumerateRequiredPrivateIncludeFileNames()) { twSource.WriteLine("#include \"{0}\"", fileName); } twSource.WriteLine("#include \"{0}.h\"", extractContext.Assembly.Name); twSource.SplitLine(); } WriteConstStrings(twSource, translateContext); WriteDeclaredValues(twSource, translateContext); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-2] File scope prototypes:"); twSource.SplitLine(); // All types exclude publics and internals (for file scope prototypes) PrototypeWriter.InternalConvertToPrototypes( twSource, prepared.Types, type => !type.IsCLanguagePublicScope, field => !(field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly), method => (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly) && prepared.Functions.ContainsKey(method)); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-3] Declare static fields:"); twSource.SplitLine(); foreach (var type in prepared.Types. Where(type => !type.IsEnum)) { // All static fields foreach (var field in type.Fields. Where(field => field.IsStatic)) { twSource.WriteLine( "{0};", field.GetCLanguageStaticPrototype(true)); } twSource.SplitLine(); } foreach (var type in prepared.Types) { twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-4] Type: {0}", type.FriendlyName); twSource.SplitLine(); // All methods and constructor exclude type initializer foreach (var method in type.DeclaredMethods) { FunctionWriter.InternalConvertFromMethod( twSource, extractContext, prepared, method, debugInformationOption); } if (type.IsClass || type.IsValueType) { TypeHelperWriter.InternalConvertTypeHelper( twSource, type); } else if (type.IsInterface) { TypeHelperWriter.InternalConvertTypeHelperForInterface( twSource, type); } } twSource.SplitLine(); }
public static async Task ExecuteTestAsync(TestCaseInformation caseInfo) { Assert.IsTrue(caseInfo.Method.IsPublic && caseInfo.Method.IsStatic); // Split current thread context. await Task.Yield(); /////////////////////////////////////////////// // Step 1-1: Create translation context. var translateContext = new TranslateContext(caseInfo.Method.DeclaringType.Assembly.Location, false); // Step 1-2: Prepare target methods. var targetTypes = new HashSet <string>( new[] { caseInfo.Method }. Concat(caseInfo.AdditionalMethods). Select(method => method.DeclaringType). Concat(caseInfo.AdditionalTypes). Select(type => type.FullName). Distinct()); var targetMethods = new[] { caseInfo.Method }. Concat(caseInfo.AdditionalMethods). GroupBy(method => method.Name). ToDictionary(g => g.Key, g => g.ToArray()); var prepared = AssemblyPreparer.Prepare( translateContext, t => targetTypes.Contains(t.FriendlyName), m => targetMethods.ContainsKey(m.Name)); // Step 1-3: Extract prepared target type/caseInfo.Method informations. var targetType = translateContext.Assembly.Modules .First().Types .First(t => t.FriendlyName == caseInfo.Method.DeclaringType.FullName); var targetMethod = targetType.DeclaredMethods .First(m => m.Name == caseInfo.Method.Name); var targetAdditionalMethods = targetType.DeclaredMethods .Where(m => (caseInfo.AdditionalMethods.FirstOrDefault(am => m.Name == am.Name) != null)) .ToArray(); // Step 1-4: Translate caseInfo.Method bodies. var header = CodeTextWriter.Create(new StringWriter(), " "); AssemblyWriter.InternalWriteHeader( header, translateContext, prepared, false); header.Flush(); var body = CodeTextWriter.Create(new StringWriter(), " "); AssemblyWriter.InternalWriteSourceCode( body, translateContext, prepared, DebugInformationOptions.Full, false); body.Flush(); // Step 1-5: Write Visual C++ project file and Visual Studio Code launch config from template. // Note: It's only debugging purpose. The test doesn't use. var translatedPath = Path.GetFullPath( Path.Combine( Path.GetDirectoryName(caseInfo.Method.DeclaringType.Assembly.Location), caseInfo.CategoryName, caseInfo.Id, caseInfo.Name)); var vcxprojTemplatePath = Path.Combine(translatedPath, "test.vcxproj"); await TestUtilities.CopyResourceToTextFileAsync(vcxprojTemplatePath, "test.vcxproj"); var launchTemplatePath = Path.Combine(translatedPath, ".vscode", "launch.json"); await TestUtilities.CopyResourceToTextFileAsync(launchTemplatePath, "launch.json"); // Step 1-6: Write source code into a file from template. var expectedType = targetMethod.ReturnType; var sourceCodeStream = new MemoryStream(); await TestUtilities.CopyResourceToStreamAsync( sourceCodeStream, // If the target caseInfo.Method result is void-type, we have to use void-type tolerant template. (expectedType.IsVoidType || (caseInfo.Assert == TestCaseAsserts.CauseBreak))? "test_void.c" : "test.c"); sourceCodeStream.Position = 0; var sourceCode = new StreamReader(sourceCodeStream); var constants = caseInfo.Arguments. Zip(targetMethod.Parameters, (arg, p) => new Constant( p.ParameterName, p.TargetType, arg?.GetType(), Utilities.GetCLanguageExpression(arg)) ). ToArray(); var argumentList = constants. Select(constant => new Constant( "_" + constant.SymbolName, constant.TargetType, null, GetCLangaugeSafeConversionExpression(constant.TargetType, constant.ExpressionType, constant.SymbolName))). ToArray(); var arguments = argumentList; var locals = argumentList. Select(argument => new Constant( argument.SymbolName, argument.TargetType, argument.ExpressionType, Utilities.GetCLanguageExpression(expectedType.InternalStaticEmptyValue))). ToArray(); if (!(expectedType.IsVoidType || (caseInfo.Assert == TestCaseAsserts.CauseBreak))) { // VERY DIRTY: constants = constants.Concat(new Constant[] { new Constant( "expected", expectedType, caseInfo.Expected?.GetType(), Utilities.GetCLanguageExpression(caseInfo.Expected)), }). ToArray(); arguments = constants. Select(constant => new Constant( "_" + constant.SymbolName, constant.TargetType, null, GetCLangaugeSafeConversionExpression(constant.TargetType, constant.ExpressionType, constant.SymbolName))). ToArray(); locals = arguments. Select(argument => new Constant( argument.SymbolName, argument.TargetType, argument.ExpressionType, Utilities.GetCLanguageExpression(argument.TargetType.InternalStaticEmptyValue))). Concat(new Constant[] { new Constant( "_actual", expectedType, caseInfo.Expected?.GetType(), Utilities.GetCLanguageExpression(expectedType.InternalStaticEmptyValue)), }). ToArray(); } // Construct test definitions. var expectedSymbolName = locals. Any(entry => (entry.SymbolName == "_expected") && entry.TargetType.IsReferenceType) ? "frame__._expected" : "_expected"; var actualSymbolName = locals. Any(entry => (entry.SymbolName == "_actual") && entry.TargetType.IsReferenceType) ? "frame__._actual" : "_actual"; var replaceValues = new Dictionary <string, object> { { "testName", targetMethod.FriendlyName }, { "type", targetMethod.ReturnType.CLanguageTypeName }, { "body", body.Parent.ToString() }, { "constants", string.Join(" ", constants. Select(entry => string.Format("{0} {1} = {2};", (entry.ExpressionType != null) ? Utilities.GetCLanguageTypeName(entry.ExpressionType) : entry.TargetType.CLanguageTypeName, entry.SymbolName, entry.Expression))) }, { "locals", string.Join(" ", locals. Where(entry => !entry.TargetType.IsReferenceType). Select(entry => string.Format("{0} {1} = {2};", entry.TargetType.CLanguageTypeName, entry.SymbolName, entry.Expression))) }, { "frames", string.Join(" ", locals. Where(entry => entry.TargetType.IsReferenceType). Select(entry => string.Format("{0} {1};", entry.TargetType.CLanguageTypeName, entry.SymbolName))) }, { "frameCount", locals. Where(entry => entry.TargetType.IsClass).Count() }, { "arguments", string.Join(" ", arguments. Select(entry => string.Format("{0}{1} = {2};", entry.TargetType.IsReferenceType ? "frame__." : string.Empty, entry.SymbolName, entry.Expression))) }, { "actual", actualSymbolName }, { "function", targetMethod.CLanguageFunctionName }, { "argumentList", string.Join(", ", argumentList. Select(arg => string.Format( "{0}{1}", arg.TargetType.IsReferenceType ? "frame__." : string.Empty, arg.SymbolName))) }, { "equality", GetCLanguageCompareExpression(expectedType, expectedSymbolName, actualSymbolName) }, { "format", GetCLanguagePrintFormatFromType(targetMethod.ReturnType) }, { "expectedExpression", GetCLanguagePrintArgumentExpression(expectedType, expectedSymbolName) }, { "actualExpression", GetCLanguagePrintArgumentExpression(expectedType, actualSymbolName) }, }; var sourcePath = Path.Combine(translatedPath, "test.c"); var headerPath = Path.Combine(translatedPath, "test.h"); await Task.WhenAll( TestUtilities.WriteTextFileAsync(sourcePath, sourceCode, replaceValues), TestUtilities.WriteTextFileAsync(headerPath, header.Parent.ToString())); /////////////////////////////////////////////// // Step 2: Test and verify result by real IL code at this runtime. object rawResult; switch (caseInfo.Assert) { case TestCaseAsserts.IgnoreValidateInvokeResult: try { rawResult = caseInfo.Method.Invoke(null, caseInfo.Arguments); } catch { // ignore. rawResult = null; } break; case TestCaseAsserts.CauseBreak: rawResult = null; break; default: rawResult = caseInfo.Method.Invoke(null, caseInfo.Arguments); Assert.AreEqual(caseInfo.Expected, rawResult); break; } /////////////////////////////////////////////// // Step 3: Test compiled C source code and execute. string sanitized = null; try { var il2cRuntimeSourcePaths = new[] { // Use combined runtime source. 5 times faster! Path.Combine(il2cRuntimePath, "il2c_combined.c") }; #if DEBUG var executedResult = await GccDriver.CompileAndRunAsync(false, sourcePath, il2cRuntimePath); #else var executedResult = await GccDriver.CompileAndRunAsync(true, sourcePath, il2cRuntimePath); #endif sanitized = executedResult.Trim(' ', '\r', '\n'); } catch (Exception ex) { if ((caseInfo.Assert == TestCaseAsserts.CauseBreak) && ex.Message.Contains("ExitCode=-2147483645")) { return; } throw; } Assert.IsFalse(caseInfo.Assert == TestCaseAsserts.CauseBreak, "Code didn't break."); /////////////////////////////////////////////// // Step 4: Verify result. Assert.AreEqual("Success", sanitized); }
public static async Task ExecuteTestAsync(TestCaseInformation caseInfo) { Assert.IsTrue(caseInfo.Method.IsPublic && caseInfo.Method.IsStatic); // Split current thread context. await Task.Delay(1); #if DEBUG const string configuration = "Debug"; #else const string configuration = "Release"; #endif /////////////////////////////////////////////// // Step 1-1: Create translation context. var translateContext = new TranslateContext( caseInfo.Method.DeclaringType.Assembly.Location, true, TargetPlatforms.Generic); // Step 1-2: Prepare target methods. var targetTypes = new HashSet <string>( new[] { caseInfo.Method }. Concat(caseInfo.AdditionalMethods). Select(method => method.DeclaringType). Concat(caseInfo.AdditionalTypes). Select(type => type.FullName). Distinct()); var targetMethods = new[] { caseInfo.Method }. Concat(caseInfo.AdditionalMethods). GroupBy(method => method.Name). ToDictionary(g => g.Key, g => g.ToArray()); var prepared = AssemblyPreparer.Prepare( translateContext, t => targetTypes.Contains(t.FriendlyName), m => targetMethods.ContainsKey(m.Name)); // Step 1-3: Extract prepared target type/caseInfo.Method informations. var targetType = translateContext.Assembly.Modules .First().Types .First(t => t.FriendlyName == caseInfo.Method.DeclaringType.FullName); var targetMethod = targetType.DeclaredMethods .First(m => m.Name == caseInfo.Method.Name); var targetAdditionalMethods = targetType.DeclaredMethods .Where(m => (caseInfo.AdditionalMethods.FirstOrDefault(am => m.Name == am.Name) != null)) .ToArray(); // Step 1-4: Create storing director for test artifacts // HACK: It's reliability for Windows MAX_PATH limitation. var basePath = Path.GetFullPath( Path.Combine( Path.GetDirectoryName(caseInfo.Method.DeclaringType.Assembly.Location), "..", "..", "..", "..", "..", "test-artifacts", configuration)); while (true) { try { if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); } break; } catch { } } // Step 1-4: Translate caseInfo.Method bodies. var translatedPath = Path.Combine( basePath, caseInfo.CategoryName, caseInfo.Id, caseInfo.UniqueName); var logw = new StringWriter(); var storage = new CodeTextStorage(logw, translatedPath, false, " "); AssemblyWriter.WriteHeader( storage, translateContext, prepared); var sourceFiles = AssemblyWriter.WriteSourceCode( storage, translateContext, prepared, true, DebugInformationOptions.CommentOnly); // Step 1-5: Write source code into a file from template. var expectedType = targetMethod.ReturnType; var sourceCodeStream = new MemoryStream(); await TestUtilities.CopyResourceToStreamAsync( sourceCodeStream, // If the target caseInfo.Method result is void-type, we have to use void-type tolerant template. (expectedType.IsVoidType || (caseInfo.Assert == TestCaseAsserts.CauseBreak))? "test_void.c" : "test.c"); sourceCodeStream.Position = 0; var sourceCode = new StreamReader(sourceCodeStream); var constants = caseInfo.Arguments. Zip(targetMethod.Parameters, (arg, p) => new Constant( p.ParameterName, p.TargetType, arg?.GetType(), Utilities.GetCLanguageExpression(arg)) ). ToArray(); var argumentList = constants. Select(constant => new Constant( "_" + constant.SymbolName, constant.TargetType, null, GetCLangaugeSafeConversionExpression(constant.TargetType, constant.ExpressionType, constant.SymbolName))). ToArray(); var arguments = argumentList; var locals = argumentList. Select(argument => new Constant( argument.SymbolName, argument.TargetType, argument.ExpressionType, Utilities.GetCLanguageExpression(expectedType.InternalStaticEmptyValue))). ToArray(); if (!(expectedType.IsVoidType || (caseInfo.Assert == TestCaseAsserts.CauseBreak))) { // VERY DIRTY: constants = constants.Concat(new Constant[] { new Constant( "expected", expectedType, caseInfo.Expected?.GetType(), Utilities.GetCLanguageExpression(caseInfo.Expected)), }). ToArray(); arguments = constants. Select(constant => new Constant( "_" + constant.SymbolName, constant.TargetType, null, GetCLangaugeSafeConversionExpression(constant.TargetType, constant.ExpressionType, constant.SymbolName))). ToArray(); locals = arguments. Select(argument => new Constant( argument.SymbolName, argument.TargetType, argument.ExpressionType, Utilities.GetCLanguageExpression(argument.TargetType.InternalStaticEmptyValue))). Concat(new Constant[] { new Constant( "_actual", expectedType, caseInfo.Expected?.GetType(), Utilities.GetCLanguageExpression(expectedType.InternalStaticEmptyValue)), }). ToArray(); } // Construct test definitions. var expectedSymbolName = locals. Any(entry => (entry.SymbolName == "_expected") && entry.TargetType.IsReferenceType) ? "frame__._expected" : "_expected"; var actualSymbolName = locals. Any(entry => (entry.SymbolName == "_actual") && entry.TargetType.IsReferenceType) ? "frame__._actual" : "_actual"; var replaceValues = new Dictionary <string, object> { { "assemblyName", targetMethod.DeclaringType.DeclaringModule.DeclaringAssembly.Name }, { "testName", targetMethod.FriendlyName }, { "type", targetMethod.ReturnType.CLanguageTypeName }, { "constants", string.Join(" ", constants. Select(entry => string.Format("{0} {1} = {2};", (entry.ExpressionType != null) ? Utilities.GetCLanguageTypeName(entry.ExpressionType) : entry.TargetType.CLanguageTypeName, entry.SymbolName, entry.Expression))) }, { "locals", string.Join(" ", locals. Where(entry => !entry.TargetType.IsReferenceType). Select(entry => string.Format("{0} {1} = {2};", entry.TargetType.CLanguageTypeName, entry.SymbolName, entry.Expression))) }, { "frames", string.Join(" ", locals. Where(entry => entry.TargetType.IsReferenceType). Select(entry => string.Format("{0} {1};", entry.TargetType.CLanguageTypeName, entry.SymbolName))) }, { "frameCount", locals. Where(entry => entry.TargetType.IsClass).Count() }, { "arguments", string.Join(" ", arguments. Select(entry => string.Format("{0}{1} = {2};", entry.TargetType.IsReferenceType ? "frame__." : string.Empty, entry.SymbolName, entry.Expression))) }, { "actual", actualSymbolName }, { "function", targetMethod.CLanguageFunctionFullName }, { "argumentList", string.Join(", ", argumentList. Select(arg => string.Format( "{0}{1}", arg.TargetType.IsReferenceType ? "frame__." : string.Empty, arg.SymbolName))) }, { "equality", GetCLanguageCompareExpression(expectedType, expectedSymbolName, actualSymbolName) }, { "format", GetCLanguagePrintFormatFromType(targetMethod.ReturnType) }, { "expectedExpression", GetCLanguagePrintArgumentExpression(expectedType, expectedSymbolName) }, { "actualExpression", GetCLanguagePrintArgumentExpression(expectedType, actualSymbolName) }, { "sourcePath", translateContext.Assembly.Name + "_bundle.c" } }; // Step 1-6: Write Visual C++ project file and Visual Studio Code launch config from template. // Note: It's only debugging purpose. The test doesn't use. var vcxprojTemplatePath = Path.Combine(translatedPath, "test.vcxproj"); await TestUtilities.CopyResourceToTextFileAsync(vcxprojTemplatePath, "test.vcxproj", replaceValues); TestContext.AddTestAttachment(vcxprojTemplatePath, "Generated VC++ project"); var launchTemplatePath = Path.Combine(translatedPath, ".vscode", "launch.json"); await TestUtilities.CopyResourceToTextFileAsync(launchTemplatePath, "launch.json", replaceValues); var sourcePath = Path.Combine(translatedPath, "test.c"); await TestUtilities.WriteTextFileAsync(sourcePath, sourceCode, replaceValues); /////////////////////////////////////////////// // Step 2: Test and verify result by real IL code at this runtime. object rawResult; switch (caseInfo.Assert) { case TestCaseAsserts.IgnoreValidateInvokeResult: break; case TestCaseAsserts.CauseBreak: rawResult = null; break; default: CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; rawResult = caseInfo.Method.Invoke(null, caseInfo.Arguments); Assert.AreEqual(caseInfo.Expected, rawResult); break; } /////////////////////////////////////////////// // Step 3: Test compiled C source code and execute. string sanitized = null; try { var executedResult = await CMakeDriver.BuildDirectlyAsync( binPath, configuration, sourcePath, il2cRuntimePath); sanitized = executedResult.Trim(' ', '\r', '\n'); } catch (Exception ex) { if ((caseInfo.Assert == TestCaseAsserts.CauseBreak) && ex.Message.Contains("ExitCode=-2147483645")) { return; } throw; } Assert.IsFalse(caseInfo.Assert == TestCaseAsserts.CauseBreak, "Code didn't break."); /////////////////////////////////////////////// // Step 4: Verify result. Assert.AreEqual("Success", sanitized); }
public static PreparedFunctions Prepare(TranslateContext translateContext) { return(Prepare( translateContext, method => !method.IsConstructor || !method.IsStatic)); }
public static void Translate( TextWriter tw, string assemblyPath, string outputPath, bool readSymbols, bool enableCpp, DebugInformationOptions debugInformationOptions) { tw.Write("IL2C: Preparing assembly: \"{0}\" ...", Path.GetFullPath(assemblyPath)); if (Directory.Exists(outputPath) == false) { try { Directory.CreateDirectory(outputPath); } catch { } } var translateContext = new TranslateContext(assemblyPath, readSymbols); var preparedFunctions = AssemblyPreparer.Prepare(translateContext); tw.WriteLine(" done."); var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); var filePath = Path.Combine(outputPath, assemblyName); var sourceFilePath = filePath + (enableCpp ? ".cpp" : ".c"); tw.Write("IL2C: Writing source code: \"{0}\" ...", Path.GetFullPath(sourceFilePath)); using (var fsSource = new FileStream( sourceFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { var twSource = CodeTextWriter.Create(fsSource, " "); AssemblyWriter.WriteSourceCode( twSource, translateContext, preparedFunctions, debugInformationOptions); twSource.Flush(); } tw.WriteLine(" done."); var headerFilePath = filePath + ".h"; tw.Write("IL2C: Writing header: \"{0}\" ...", Path.GetFullPath(headerFilePath)); using (var fsHeader = new FileStream( headerFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { var twHeader = CodeTextWriter.Create(fsHeader, " "); AssemblyWriter.WriteHeader(twHeader, translateContext, preparedFunctions); twHeader.Flush(); } tw.WriteLine(" done."); }