Click here to Skip to main content
15,886,518 members
Articles / Programming Languages / C#

Creating a CodeDOM: Modeling the Semantics of Code (Part 2)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (17 votes)
9 Nov 2012CDDL24 min read 41.1K   756   33  
Creating a CodeDOM for C#
// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using System;
using System.Collections.Generic;

using Nova.Rendering;

namespace Nova.CodeDOM
{
    /// <summary>
    /// These modifiers are usable on various code objects to specify access and special behaviors.
    /// </summary>
    /// <remarks>
    /// The order of appearance in this enum determines the display order of the modifiers.
    /// </remarks>
    [Flags]
    public enum Modifiers
    {
        //                          * = only if nested                                 Event,
        None      = 0x00000000,  // Class  Struct  Interface  Delegate  Enum  Method  Property  Indexer  Field  Constant  Ctor  Operator  Accessor  Destructor
        Public    = 0x00000001,  //   Y       Y        Y         Y       Y       Y        Y        Y       Y       Y       Y       Y
        Protected = 0x00000002,  //   *       *        *         *       *       Y        Y        Y       Y       Y       Y                 Y
        Internal  = 0x00000004,  //   Y       Y        Y         Y       Y       Y        Y        Y       Y       Y       Y                 Y
        // Protected + Internal  //   *       *        *         *       *       Y        Y        Y       Y       Y       Y                 Y
        Private   = 0x00000008,  //   *       *        *         *       *       Y        Y        Y       Y       Y       Y                 Y
        Static    = 0x00000010,  //   Y                                          Y        Y                Y               Y       Y
        New       = 0x00000020,  //   *                          *       *       Y        Y        Y       Y       Y
        Abstract  = 0x00000040,  //   Y                                          Y        Y        Y
        Sealed    = 0x00000080,  //   Y                                          Y        Y        Y
        Virtual   = 0x00000100,  //                                              Y        Y        Y
        Override  = 0x00000200,  //                                              Y        Y        Y
        Extern    = 0x00000400,  //                                              Y        Y        Y                       Y       Y                    Y
        Unsafe    = 0x00000800,  //   Y       Y        Y         Y               Y        Y        Y       Y       Y       Y       Y         Y
        // NOTE: Partial must appear as the last modifier for both types and methods.
        Partial   = 0x00001000,  //   Y       Y        Y                         Y
        Implicit  = 0x00004000,  //                                                                                                Y (conv ops only)
        Explicit  = 0x00008000,  //                                                                                                Y (conv ops only)
        Const     = 0x00010000,  //                                                                                Y (also local vars)
        ReadOnly  = 0x00020000,  //                                                                        Y
        Volatile  = 0x00040000,  //                                                                        Y
        Event     = 0x00100000   //                                                                        Y

        // RULES:
        // - Namespaces have no access modifiers (they are implicitly public).
        // - Top-level type declarations can be only 'internal' or 'public', and default to 'internal'.
        // - Nested type declarations in a class or struct default to 'private'.
        // - Interface and enum members are implicitly 'public' (no access modifiers are allowed).
        // - Class can't be both 'abstract' and 'sealed'.
        // - If any method of a class is 'abstract', the class must be 'abstract'.
        // - A non-abstract Class with an 'abstract' base must implement all 'abstract' members.
        // - An 'abstract' class must implement all interface members, although it may map them onto 'abstract' methods.
        // - Structs are implicitly 'sealed', and can't have default constructors or a destructor.
        // - Struct members can't have 'protected' or 'protected internal' access.
        // - An 'abstract' method can't be 'static', 'virtual' (it's implicitly virtual), or 'extern'.
        // - An 'abstract' or 'extern' method has no body.
        // - An 'abstract' property behaves like an 'abstract' method.
        // - An 'abstract' property can't be 'static'.
        // - Nested types can access 'private' members of their parent.
        // - A 'readonly' field may only be assigned in the declaration or in a constructor of the parent class.
        // - 'const' or type declaration members of a class are implicitly 'static'.
        // - 'const' reference types can only be null or a string.
        // - 'virtual' can't be used with 'static', 'abstract', or 'override'.
        // - 'volatile' fields must be a reference type, or an integral type (excluding long/ulong), or a float.
    }

    #region /* STATIC HELPER CLASS */

    /// <summary>
    /// Static helper methods for Modifiers.
    /// </summary>
    public static class ModifiersHelpers
    {
        #region /* STATIC FIELDS */

        private static readonly string[] _names;
        private static readonly Array _values;
        private static readonly Dictionary<string, Modifiers> _nameToModifierMap = new Dictionary<string, Modifiers>();

        #endregion

        #region /* STATIC CONSTRUCTOR */

        // Setup arrays of names, values, and a map of names to values.
        static ModifiersHelpers()
        {
            _names = Enum.GetNames(typeof(Modifiers));
            _values = Enum.GetValues(typeof(Modifiers));
            for (int i = 0; i < _values.Length; ++i)
            {
                _names[i] = _names[i].ToLower();
                _nameToModifierMap.Add(_names[i], (Modifiers)_values.GetValue(i));
            }
        }

        #endregion

        #region /* STATIC HELPER METHODS */

        /// <summary>
        /// Format Modifiers as a string.
        /// </summary>
        public static string AsString(Modifiers modifiers)
        {
            if (modifiers == Modifiers.None)
                return "";
            using (CodeWriter writer = new CodeWriter())
            {
                AsText(modifiers, writer);
                return writer.ToString();
            }
        }

        /// <summary>
        /// Convert Modifiers to text.
        /// </summary>
        public static void AsText(Modifiers modifiers, CodeWriter writer)
        {
            if (modifiers != Modifiers.None)
            {
                for (int i = 1; i < _values.Length; ++i)
                {
                    if (modifiers.HasFlag((Modifiers)_values.GetValue(i)))
                        writer.Write(_names[i] + ' ');
                }
            }
        }

        /// <summary>
        /// Returns true if the specified text is a valid modifier name.
        /// </summary>
        public static bool IsModifier(string modifier)
        {
            return (modifier != null && _nameToModifierMap.ContainsKey(modifier));
        }

        #endregion
    }

    #endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer (Senior)
United States United States
I've been writing software since the late 70's, currently focusing mainly on C#.NET. I also like to travel around the world, and I own a Chocolate Factory (sadly, none of my employees are oompa loompas).

Comments and Discussions