/// <summary>
        /// Create cil source-code representation of a <see cref="EnumDefinition"/>.
        /// </summary>
        /// <exception cref="Exceptions.InvalidAssemblyNameException">
        /// Thrown when a invalid assembly name is given.
        /// </exception>
        /// <exception cref="Exceptions.InvalidNamespaceException">
        /// Thrown when a invalid namespace identifier is given.
        /// </exception>
        /// <exception cref="Exceptions.OutOfBoundsValueException">
        /// Thrown when enum value does not fit in given storage-type.
        /// </exception>
        /// <param name="enumDefinition">Enum to generate cil source-code for</param>
        /// <param name="assemblyName">Name of the assembly to generate</param>
        /// <param name="namespace">Optional namespace to add the enum to</param>
        /// <param name="headerMode">Mode to use when adding a header</param>
        /// <param name="indentMode">Mode to use for indenting</param>
        /// <param name="spaceIndentSize">When indenting with spaces this controls how many</param>
        /// <param name="newlineMode">Mode to use for ending lines</param>
        /// <param name="storageType">Underlying enum storage-type to use</param>
        /// <param name="curlyBracketMode">Mode to use when writing curly brackets</param>
        /// <returns>String containing the genenerated cil sourcecode</returns>
        public static string ExportCil(
            this EnumDefinition enumDefinition,
            string assemblyName,
            string @namespace                   = null,
            HeaderMode headerMode               = HeaderMode.Default,
            CodeBuilder.IndentMode indentMode   = CodeBuilder.IndentMode.Spaces,
            int spaceIndentSize                 = 4,
            CodeBuilder.NewlineMode newlineMode = CodeBuilder.NewlineMode.Unix,
            StorageType storageType             = StorageType.Implicit,
            CurlyBracketMode curlyBracketMode   = CurlyBracketMode.NewLine)
        {
            if (enumDefinition == null)
            {
                throw new ArgumentNullException(nameof(enumDefinition));
            }

            if (string.IsNullOrEmpty(assemblyName) || !IdentifierValidator.Validate(assemblyName))
            {
                throw new InvalidAssemblyNameException(assemblyName);
            }

            if (!string.IsNullOrEmpty(@namespace) && !IdentifierValidator.ValidateNamespace(@namespace))
            {
                throw new InvalidNamespaceException(@namespace);
            }

            foreach (var oobEntry in enumDefinition.Entries.Where(e => !storageType.Validate(e.Value)))
            {
                throw new OutOfBoundsValueException(storageType, oobEntry.Value);
            }

            var builder = new CodeBuilder(indentMode, spaceIndentSize, newlineMode);

            if (headerMode != HeaderMode.None)
            {
                builder.AddHeader();
                builder.WriteEndLine();
            }

            // Add reference to mscorlib.
            builder.WriteLine(".assembly extern mscorlib { }");
            builder.WriteEndLine();

            // Add assembly info.
            builder.Write($".assembly {assemblyName}");
            StartScope(builder, curlyBracketMode);
            builder.WriteLine(".ver 1:0:0:0");
            EndScope(builder);
            builder.WriteEndLine();

            // Add module info.
            builder.WriteLine($".module {assemblyName}.dll");
            builder.WriteEndLine();

            // Add enum class.
            builder.AddEnum(enumDefinition, storageType, curlyBracketMode, @namespace);

            return(builder.Build());
        }
        /// <summary>
        /// Create csharp source-code representation of a <see cref="EnumDefinition"/>.
        /// </summary>
        /// <exception cref="Exceptions.InvalidNamespaceException">
        /// Thrown when a invalid namespace identifier is given.
        /// </exception>
        /// <exception cref="Exceptions.OutOfBoundsValueException">
        /// Thrown when enum value does not fit in given storage-type.
        /// </exception>
        /// <param name="enumDefinition">Enum to generate csharp source-code for</param>
        /// <param name="namespace">Optional namespace to add the enum to</param>
        /// <param name="headerMode">Mode to use when adding a header</param>
        /// <param name="indentMode">Mode to use for indenting</param>
        /// <param name="spaceIndentSize">When indenting with spaces this controls how many</param>
        /// <param name="newlineMode">Mode to use for ending lines</param>
        /// <param name="storageType">Underlying enum storage-type to use</param>
        /// <param name="curlyBracketMode">Mode to use when writing curly brackets</param>
        /// <returns>String containing the genenerated csharp sourcecode</returns>
        public static string ExportCSharp(
            this EnumDefinition enumDefinition,
            string @namespace                   = null,
            HeaderMode headerMode               = HeaderMode.Default,
            CodeBuilder.IndentMode indentMode   = CodeBuilder.IndentMode.Spaces,
            int spaceIndentSize                 = 4,
            CodeBuilder.NewlineMode newlineMode = CodeBuilder.NewlineMode.Unix,
            StorageType storageType             = StorageType.Implicit,
            CurlyBracketMode curlyBracketMode   = CurlyBracketMode.NewLine)
        {
            if (enumDefinition == null)
            {
                throw new ArgumentNullException(nameof(enumDefinition));
            }

            if (!string.IsNullOrEmpty(@namespace) && !IdentifierValidator.ValidateNamespace(@namespace))
            {
                throw new InvalidNamespaceException(@namespace);
            }

            foreach (var oobEntry in enumDefinition.Entries.Where(e => !storageType.Validate(e.Value)))
            {
                throw new OutOfBoundsValueException(storageType, oobEntry.Value);
            }

            var builder = new CodeBuilder(indentMode, spaceIndentSize, newlineMode);

            if (headerMode != HeaderMode.None)
            {
                builder.AddHeader();
                builder.WriteEndLine();
            }

            builder.WriteLine("using System.CodeDom.Compiler;");
            builder.WriteEndLine();

            if (string.IsNullOrEmpty(@namespace))
            {
                builder.AddEnum(enumDefinition, storageType, curlyBracketMode);
            }
            else
            {
                builder.AddNamespace(
                    @namespace,
                    b => b.AddEnum(enumDefinition, storageType, curlyBracketMode),
                    curlyBracketMode);
            }

            return(builder.Build());
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Create a pe class-library representation of a <see cref="EnumDefinition"/>.
        /// </summary>
        /// <exception cref="Exceptions.InvalidAssemblyNameException">
        /// Thrown when a invalid assembly name is given.
        /// </exception>
        /// <exception cref="Exceptions.InvalidNamespaceException">
        /// Thrown when a invalid namespace identifier is given.
        /// </exception>
        /// <exception cref="Exceptions.OutOfBoundsValueException">
        /// Thrown when enum value does not fit in given storage-type.
        /// </exception>
        /// <param name="enumDefinition">Enum to generate a class-library for</param>
        /// <param name="assemblyName">Name of the assembly to generate</param>
        /// <param name="namespace">Optional namespace to add the enum to</param>
        /// <param name="storageType">Underlying enum storage-type to use</param>
        /// <returns>Binary pe file containing the generated class-library</returns>
        public static byte[] ExportClassLibrary(
            this EnumDefinition enumDefinition,
            string assemblyName,
            string @namespace       = null,
            StorageType storageType = StorageType.Implicit)
        {
            if (enumDefinition == null)
            {
                throw new ArgumentNullException(nameof(enumDefinition));
            }

            if (string.IsNullOrEmpty(assemblyName) || !IdentifierValidator.Validate(assemblyName))
            {
                throw new InvalidAssemblyNameException(assemblyName);
            }

            if (!string.IsNullOrEmpty(@namespace) && !IdentifierValidator.ValidateNamespace(@namespace))
            {
                throw new InvalidNamespaceException(@namespace);
            }

            foreach (var oobEntry in enumDefinition.Entries.Where(e => !storageType.Validate(e.Value)))
            {
                throw new OutOfBoundsValueException(storageType, oobEntry.Value);
            }

            // Define assembly and module.
            using (var assemblyDefinition = AssemblyDefinition.CreateAssembly(
                       assemblyName: new AssemblyNameDefinition(assemblyName, new Version(1, 0, 0, 0)),
                       moduleName: $"{assemblyName}.dll",
                       ModuleKind.Dll))
            {
                // Set the module id to a hash of the enum-definition, this way it should be pretty
                // unique while still being deterministic.
                assemblyDefinition.MainModule.Mvid = new Guid(enumDefinition.Get128BitHash());

                // Get the required references.
                var enumUnderlyingType = storageType.GetCecilTypeReference(
                    typeSystem: assemblyDefinition.MainModule.TypeSystem);
                var enumBaseType = new TypeReference(
                    @namespace: "System",
                    name: "Enum",
                    module: assemblyDefinition.MainModule,
                    scope: assemblyDefinition.MainModule.TypeSystem.CoreLibrary);

                // Create type definition for the enum.
                var enumTypeDefinition = new TypeDefinition(
                    @namespace,
                    name: enumDefinition.Identifier,
                    attributes: TypeAttributes.Public | TypeAttributes.Sealed,
                    baseType: enumBaseType);

                // Add the storage field of the enum.
                enumTypeDefinition.Fields.Add(new FieldDefinition(
                                                  name: "value__",
                                                  FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName,
                                                  fieldType: enumUnderlyingType));

                // Add the enum entries.
                foreach (var entry in enumDefinition.Entries)
                {
                    var entryField = new FieldDefinition(
                        name: entry.Name,
                        attributes:
                        FieldAttributes.Public |
                        FieldAttributes.Static |
                        FieldAttributes.Literal |
                        FieldAttributes.HasDefault,
                        fieldType: enumTypeDefinition);

                    // Set the value of the entry.
                    entryField.Constant = storageType.Cast(entry.Value);

                    enumTypeDefinition.Fields.Add(entryField);
                }

                // Add enum to module.
                assemblyDefinition.MainModule.Types.Add(enumTypeDefinition);

                // Write the pe dll file.
                using (var memoryStream = new MemoryStream())
                {
                    // Supply '0' as the timestamp to make the export deterministic.
                    var writerParams = new WriterParameters
                    {
                        Timestamp = 0
                    };

                    assemblyDefinition.Write(memoryStream, writerParams);
                    return(memoryStream.ToArray());
                }
            }
        }
        /// <summary>
        /// Create fsharp source-code representation of a <see cref="EnumDefinition"/>.
        /// </summary>
        /// <exception cref="Exceptions.InvalidNamespaceException">
        /// Thrown when a invalid namespace identifier is given.
        /// </exception>
        /// <exception cref="Exceptions.OutOfBoundsValueException">
        /// Thrown when enum value does not fit in given storage-type.
        /// </exception>
        /// <param name="enumDefinition">Enum to generate fsharp source-code for</param>
        /// <param name="namespace">Namespace to add the enum to</param>
        /// <param name="headerMode">Mode to use when adding a header</param>
        /// <param name="indentSize">How many spaces should be used for indents</param>
        /// <param name="newlineMode">Mode to use for ending lines</param>
        /// <param name="storageType">Underlying enum storage-type to use</param>
        /// <returns>String containing the genenerated fsharp sourcecode</returns>
        public static string ExportFSharp(
            this EnumDefinition enumDefinition,
            string @namespace,
            HeaderMode headerMode = HeaderMode.Default,
            int indentSize        = 4,
            CodeBuilder.NewlineMode newlineMode = CodeBuilder.NewlineMode.Unix,
            StorageType storageType             = StorageType.Implicit)
        {
            if (enumDefinition == null)
            {
                throw new ArgumentNullException(nameof(enumDefinition));
            }

            if (!IdentifierValidator.ValidateNamespace(@namespace))
            {
                throw new InvalidNamespaceException(@namespace);
            }

            foreach (var oobEntry in enumDefinition.Entries.Where(e => !storageType.Validate(e.Value)))
            {
                throw new OutOfBoundsValueException(storageType, oobEntry.Value);
            }

            var builder = new CodeBuilder(CodeBuilder.IndentMode.Spaces, indentSize, newlineMode);

            if (headerMode != HeaderMode.None)
            {
                builder.AddHeader();
                builder.WriteEndLine();
            }

            // Add namespace.
            builder.WriteLine($"namespace {@namespace}");
            builder.WriteEndLine();

            // Open System.CodeDom.Compiler (for the 'GeneratedCode' attribute)
            builder.WriteLine("open System.CodeDom.Compiler");
            builder.WriteEndLine();

            // Add type comment.
            if (!string.IsNullOrEmpty(enumDefinition.Comment))
            {
                builder.AddSummary(enumDefinition.Comment);
            }

            // Add enum definition.
            var assemblyName = typeof(FSharpExporter).Assembly.GetName();

            builder.WriteLine($"[<GeneratedCode(\"{assemblyName.Name}\", \"{assemblyName.Version}\")>]");
            builder.WriteLine($"type {enumDefinition.Identifier} =");

            // Add entries.
            foreach (var entry in enumDefinition.Entries)
            {
                var literalSuffix = storageType == StorageType.Implicit ?
                                    string.Empty :
                                    storageType.GetFSharpLiteralSuffix();

                builder.WriteLine($"| {entry.Name} = {entry.Value}{literalSuffix}", additionalIndent: 1);
            }

            return(builder.Build());
        }