⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emitcodegen.cs

📁 charp compiler
💻 CS
📖 第 1 页 / 共 5 页
字号:
/***************************************************************************\
*
* File: EmitCodeGen.cs
*
* Description:
* EmitCodeGen.cs defines the "System.Reflection.Emit" CodeGen for the 
* compiler.
*
*
* History:
*  8/14/2001: JStall:       Created
*
* Copyright (C) 2001.  All rights reserved.
*
\***************************************************************************/


//-----------------------------------------------------------------------------
// @todo - Split EmitCodeGen into 2 parts. 
//-----------------------------------------------------------------------------

// ...
// There is a bug in the enum builder (10/12/2001) that won't let us
// set the enum fields to the proper type. 
// We can workaround by directly using a typebuilder. When the bug is fixed,
// we should switch back over to EnumBuilders.
// This only affects CodeGen.
#define Bug_In_EnumBuilder

using System;
using System.Collections;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;

using Blue.Public;
using Utilities = Blue.Utilities;
using ErrorLog = Blue.Utilities.ErrorLog;
using Log = Blue.Log;

namespace Blue.CodeGen
{


/***************************************************************************\
*****************************************************************************
*
* class EmitCodeGen
*
* EmitCodeGen implements the CodeGen interface for using 
* System.Reflection.Emit.
*
*****************************************************************************
\***************************************************************************/

public class EmitCodeGen :
    ICLRtypeProvider,
    ICodeGenDriver
{

#region Enums

    //
    // Enums
    //
/*
    [FlagsAttribute()]
    internal enum ClassAttributes
    {
        Public      = 0x00000001,
    }
*/
    private enum TargetType
    {
        Console,
        Windows,
        Dll
    }

#endregion Enums


#region Construction

    /***************************************************************************\
    *
    * EmitCodeGen.EmitCodeGen
    *
    * EmitCodeGen() initializes a new CodeGen object.
    *
    \***************************************************************************/

    internal
    EmitCodeGen(
        Blue.Public.IOptions opt)              // Options
    {
        // Set default target type. An option handler may change it on us.
        m_TargetType        = TargetType.Console;
        

        //
        // Register OptionHandlers.
        //
        opt.AddHandler("target", "t", new OptionHandler(this.Option_Target),
            "Target module format (windows, console, library)", 
            "Select what type of executable to produce\n"+
            "/target:library - produce a dll\n"+
            "/target:windows - produce a windows executable.\n"+
            "/target:console - (default) produce a console executable\n");
                                
        #if false
            Option_DebugInfo(""); // force debugging info in all cases
        #endif
        opt.AddHandler("debug", null, new OptionHandler(this.Option_DebugInfo), 
                "Generate .PDB symbols file for debugging", 
                "Generate a .pdb file for debugging purposes. Default is off.\n"+
                "ex:\n"+
                "/debug");
                                
        opt.AddHandler("main", "m", new OptionHandler(this.Option_SetMain), 
            "Specify class containing Main method", 
            "Explicitly specify which class has the Main method.\n"+
            "ex:\n"+
            "/main:MyClass");
            
        opt.AddHandler("out", null, new OptionHandler(this.Option_Out), 
            "Specify the output name to generate", 
            "ex:\n"+
            "/out:Dogfood.exe"
            );
    }

#endregion Construction




#region Print Errors
    internal enum ErrorCodes
    {
        cDuplicateMain,
        cNoMain,
        cIOException,
        cEntryClassNotFound,
    }
    
    private class CodeGenErrorException : ErrorException
    {
        // Codegen errors aren't associated with a particular file range, so we omit location
        internal CodeGenErrorException(ErrorCodes c, string s) : 
            base (c, null, s)
        {
            // All Codegen errors will come through this body.
        }
    }    
    
    private void PrintError(CodeGenErrorException e)
    {        
        Blue.Driver.StdErrorLog.PrintError(e);
    }

    void PrintError_DuplicateMain()
    {
        PrintError(
            new CodeGenErrorException(ErrorCodes.cDuplicateMain, "Duplicate Main entry points. Use /m switch to specify which class to use.")
        );
    }
    
    void PrintError_NoMain()
    {
        PrintError(
            new CodeGenErrorException(ErrorCodes.cNoMain, "No Main function found")
        );
    }
    
    void PrintError_IOException(string stHint)
    {
        PrintError(
            new CodeGenErrorException(ErrorCodes.cIOException, stHint)
        );
    }
    
    void PrintError_EntryClassNotFound(string stClass)
    {
        PrintError(
            new CodeGenErrorException(
                ErrorCodes.cEntryClassNotFound,
               "The class '" + stClass+"' specified by the /m switch does not exist."
            )
        );
    }


#endregion

#region Implementation for SymbolEngine.ICLRtypeProvider
    // ...
    // There's a bug in ModuleBuilder.GetType(), so we have to use our own 
    // version for now.
    System.Type ModuleBuilder_GetType(ModuleBuilder m, string stType)
    {
    #if false
        // This should work, but is broken for nested types.
        return m.GetType(stType);
    #else        
        // Here's our hack to use in the meantime
        // Note, we have to deal with appended characters like [], and &
        // This is a hack that will work for now. When reflection-emit fixes the 
        // bug, we can get rid of this.
        Type [] al = m.GetTypes();
        foreach(Type t in al)
        {
            if (t.FullName == stType)
                return t;
        }
        return null;    
    #endif
    }


    // Must let the Type provider know what assemblies are imported so that
    // we can search them for types.
    void SetImportedAssemblies(Assembly [] asmImports)
    {
        Debug.Assert(asmImports != null);
        m_asmImports = asmImports;
        m_MscorLib = Assembly.Load("MsCorLib.dll");
    }
    Assembly m_MscorLib;
    Assembly [] m_asmImports;
    
    

        
    // Find a compound type (like T&, T[], T[][]&, T[,] ..)
    // May be in either the module we're building or an imported assembly.
    protected System.Type FindType(string stFullName)
    {
        System.Type tRef = null;
        
        System.Type tNatural = m_MscorLib.GetType(stFullName);
                        
        // Look in the module we're building.
        //tRef = ModuleBuilder_GetType(m_bldModule, stFullName);
        tRef = m_bldModule.GetType(stFullName);
        
        Debug.Assert((tNatural == null) || (tRef == null), "type can only be baked or unbaked, not both");
        
        if (tNatural != null)
            return tNatural;
        
        
        if (tRef != null)
            return tRef;
            
                    
                
        // Look in an imported modules
        Assembly[] alist = m_asmImports;
        foreach(Assembly a in alist)
        {
            Type t = a.GetType(stFullName);
            if (t != null)
                return t;
        }


        // Not found, there's an error:
        // - we have an illegal compound type?
        // - the elem type of the compound type doesn't exist?
        // Or perhaps we require Resolution to catch this, if so the assert is ok.
        Debug.Assert(tRef != null); // @legit
        return null;
    }

    /***************************************************************************\
    *
    * EmitCodeGen.GetReferenceType
    * - Returns a CLR type that is a reference to the type we pas in.
    \***************************************************************************/
    public virtual System.Type CreateCLRReferenceType(System.Type tElem)
    {
        Debug.Assert(!tElem.IsByRef, "Can't create a reference to a reference");
        string st = tElem.FullName + "&";
                
        System.Type tRef = this.FindType(st);
        
        Debug.Assert(tRef != null);
        return tRef;
    }
    
    /***************************************************************************\
    *
    * EmitCodeGen.CreateCLRArrayType
    * 
    \***************************************************************************/
    public virtual System.Type 
    CreateCLRArrayType(
        SymbolEngine.ArrayTypeEntry symBlueType
    )
    {        
        // Get name of an array, like T[], T[,,][,][]
        string st = symBlueType.ToString();

               
        System.Type t = this.FindType(st);

        // Semantic checking should have caught this.
        Debug.Assert(t != null);

       
        return t;
    }
    
    /***************************************************************************\
    *
    * EmitCodeGen.SetCLRClassType
    * 
    \***************************************************************************/
    public virtual System.Reflection.FieldInfo
    CreateCLRField(
        SymbolEngine.FieldExpEntry symBlueField
        )
    {
        FieldAttributes attr = (FieldAttributes) 0;
        
        AST.Modifiers mods = symBlueField.Node.Mods;
        
        if (mods.IsPublic)
            attr |= FieldAttributes.Public;
        else if (mods.IsProtected)
            attr |= FieldAttributes.Family;
        else if (mods.IsPrivate)
            attr |= FieldAttributes.Private;
        else if (mods.IsInternal)
            attr |= FieldAttributes.Assembly;
            
        
        if (mods.IsReadOnly)
            attr |= FieldAttributes.InitOnly;
            
        if (mods.IsStatic)
            attr |= FieldAttributes.Static;
                
        // Get class that we're defined in
        TypeBuilder bldClass = symBlueField.SymbolClass.CLRType as TypeBuilder;
        Debug.Assert(bldClass != null);

        // Create the field
        FieldInfo f = bldClass.DefineField(symBlueField.Name, symBlueField.FieldType.CLRType, attr);
        Debug.Assert(f != null);

        return f;
    }

    // 
    public virtual System.Reflection.FieldInfo
        CreateCLRLiteralField(
        SymbolEngine.LiteralFieldExpEntry sym)
    {
        
        Type t = sym.SymbolClass.CLRType;
#if Bug_In_EnumBuilder
        TypeBuilder bld = t as TypeBuilder;
        Debug.Assert(bld != null);
        
        FieldAttributes mods = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
        FieldBuilder f = bld.DefineField(sym.Name, bld, mods);                
        f.SetConstant(sym.Data);
#else
        if (t is EnumBuilder)
        {
            EnumBuilder bld = t as EnumBuilder;
            f = bld.DefineLiteral(sym.Name, sym.Data);
        } 
        else if (t is TypeBuilder)
        {
           Debug.Assert(false, "Literals not supported on non-enum Types");
        }
#endif
        // The new field should have the following properties:
        Debug.Assert(f.IsStatic);
        Debug.Assert(f.IsPublic);
        Debug.Assert(f.IsLiteral);
        Debug.Assert(f.FieldType == bld); // this is where the EnumBuilder breaks

        return f;
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -