Example #1
0
        public static ImmutableArray <Diagnostic> Emit(BoundProgram program, string moduleName, string[] references, string outputPath)
        {
            if (program.Diagnostics.Any())
            {
                return(program.Diagnostics);
            }

            var assemblies = new List <AssemblyDefinition>();
            var result     = new DiagnosticBag();

            foreach (var reference in references)
            {
                try
                {
                    var assembly = AssemblyDefinition.ReadAssembly(reference);
                    assemblies.Add(assembly);
                }
                catch (BadImageFormatException)
                {
                    result.ReportInvalidReference(reference);
                }
            }

            var builtInTypes = new List <(TypeSymbol Type, string MetadataName)> {
                (TypeSymbol.Any, "System.Object"),
                (TypeSymbol.Int, "System.Int32"),
                (TypeSymbol.Bool, "System.Boolean"),
                (TypeSymbol.String, "System.String"),
                (TypeSymbol.Void, "System.Void"),
            };
            var knownTypes = new Dictionary <TypeSymbol, TypeReference>();

            var assemblyName       = new AssemblyNameDefinition(moduleName, new Version(1, 0));
            var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyName, moduleName, ModuleKind.Console);

            foreach (var(typeSymbol, metadataName) in builtInTypes)
            {
                var typeReference = ResolveType(typeSymbol.Name, metadataName);
                knownTypes.Add(typeSymbol, typeReference);
            }

            TypeReference ResolveType(string minskTypeName, string metadataName)
            {
                var foundTypes = assemblies.SelectMany(a => a.Modules)
                                 .SelectMany(m => m.Types)
                                 .Where(t => t.FullName == metadataName)
                                 .ToArray();

                if (foundTypes.Length == 1)
                {
                    var typeReference = assemblyDefinition.MainModule.ImportReference(foundTypes[0]);
                    return(typeReference);
                }
                else if (foundTypes.Length == 0)
                {
                    result.ReportRequiredTypeNotFound(minskTypeName, metadataName);
                }
                else
                {
                    result.ReportBuiltInTypeAmbigous(minskTypeName, metadataName, foundTypes);
                }

                return(null);
            }

            MethodReference ResolveMethod(string typeName, string methodName, string[] parameterTypeNames)
            {
                var foundTypes = assemblies.SelectMany(a => a.Modules)
                                 .SelectMany(m => m.Types)
                                 .Where(t => t.FullName == typeName)
                                 .ToArray();

                if (foundTypes.Length == 1)
                {
                    var foundType = foundTypes[0];
                    var methods   = foundType.Methods.Where(m => m.Name == methodName);

                    foreach (var method in methods)
                    {
                        if (method.Parameters.Count != parameterTypeNames.Length)
                        {
                            continue;
                        }
                        var allParametersMatch = true;
                        for (int i = 0; i < parameterTypeNames.Length; i++)
                        {
                            if (method.Parameters[i].ParameterType.FullName != parameterTypeNames[i])
                            {
                                allParametersMatch = false;
                                break;
                            }
                        }

                        if (!allParametersMatch)
                        {
                            continue;
                        }

                        return(assemblyDefinition.MainModule.ImportReference(method));
                    }

                    result.ReportRequiredMethodNotFound(typeName, methodName, parameterTypeNames);
                    return(null);
                }
                else if (foundTypes.Length == 0)
                {
                    result.ReportRequiredTypeNotFound(null, typeName);
                }
                else
                {
                    result.ReportBuiltInTypeAmbigous(null, typeName, foundTypes);
                }

                return(null);
            }

            var consoleWriteLineReference = ResolveMethod("System.Console", "WriteLine", new[] { "System.String" });

            if (result.Any())
            {
                return(result.ToImmutableArray());
            }

            var objectType     = knownTypes[TypeSymbol.Any];
            var typeDefinition = new TypeDefinition("", "Program", TypeAttributes.Abstract | TypeAttributes.Sealed, objectType);

            assemblyDefinition.MainModule.Types.Add(typeDefinition);

            var voidType   = knownTypes[TypeSymbol.Void];
            var mainMethod = new MethodDefinition("Main", MethodAttributes.Static | MethodAttributes.Private, voidType);

            typeDefinition.Methods.Add(mainMethod);

            var ilProcessor = mainMethod.Body.GetILProcessor();

            ilProcessor.Emit(OpCodes.Ldstr, "Hello world from Minsk");
            ilProcessor.Emit(OpCodes.Call, consoleWriteLineReference);
            ilProcessor.Emit(OpCodes.Ret);

            assemblyDefinition.EntryPoint = mainMethod;
            assemblyDefinition.Write(outputPath);

            return(result.ToImmutableArray());
        }