using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.Diagnostics; using System.IO; using System.Runtime.ConstrainedExecution; namespace cscz { public enum GenerationMode { PrivateVariablesWithProperties, PublicVariables, PublicAutoProperties } public class ClassGenerator { /// /// A mapping of namespaces to using shortcuts. /// public Dictionary UsingShortcuts = new Dictionary() { ["c"] = "System.Collections.Generic", ["cc"] = "System.Collections.Concurrent", ["r"] = "System.Text.RegularExpressions", ["n"] = "System.Net", ["s"] = "System.Net.Sockets", ["x"] = "Microsoft.Xna.Framework", ["xg"] = "Microsoft.Xna.Framework.Graphics", ["xs"] = "Microsoft.Xna.Framework.Storage", ["xi"] = "Microsoft.Xna.Framework.Input", ["oo"] = "OpenTK.Graphics.OpenGL" }; /// /// The using statements to add to the generated class. /// public List UsingStatements = new List() { "System" }; public List Signatures = new List(); public string ClassName = "Carrot"; public string Namespace = string.Empty; public GenerationMode GenerationMode = GenerationMode.PublicVariables; /// /// Whether to make data members private and create public properties for them instead of making the /// data members public. /// This is read only. Please refer to GenerationMode in order to change this field. /// public bool CreateProperties { get { if (GenerationMode == GenerationMode.PrivateVariablesWithProperties) return true; return false; } } public ClassGenerator () { } public void ParseString(string source) { StringReader lines = new StringReader(source); string nextLine = string.Empty; do { nextLine = lines.ReadLine(); if(nextLine == null) break; if(nextLine.Length == 0) continue; nextLine = nextLine.Trim(); // It's a using statement if(nextLine.StartsWith("- ")) { string[] parts = Regex.Split(nextLine, @"\s+"); UsingStatements.Add(parts[1]); } else if(nextLine.StartsWith("#")) { // It's the class name ClassName = UppercaseFirstLetter(nextLine.TrimStart(new char[] { '#' })).Trim(); // Parse the namespace, if one is present if(ClassName.Contains(".")) { Namespace = ClassName.Substring(0, ClassName.LastIndexOf(".")); ClassName = ClassName.Substring(ClassName.LastIndexOf(".") + 1); } } else { Signatures.Add(nextLine.Trim()); } } while(nextLine != null); } public override string ToString() { StringWriter usingStatements = new StringWriter(); // Generate the using statements foreach(string usingStatement in UsingStatements) usingStatements.WriteLine("using {0};", expandUsingShortcut(usingStatement)); // Generate the class itself StringWriter classCode = new StringWriter(); // Class name classCode.WriteLine("class {0} ", ClassName); classCode.WriteLine("{"); // Class body parts declaration StringBuilder constructorSignature = new StringBuilder(string.Format("\tpublic {0}(", ClassName)); // This has to be a StringBuilder because of the Remove() class later on StringWriter properties = new StringWriter(); StringWriter constructorBody = new StringWriter(); // Data member signature handling foreach (string signature in Signatures) { string[] signatureParts = Regex.Split(signature, @"\s+"); string datatypeName = signatureParts[0]; string privateDataMemberName = LowercaseFirstLetter(signatureParts[1]); string publicDataMemberName = UppercaseFirstLetter(signatureParts[1]); constructorSignature.AppendFormat("{0} in{1}, ", datatypeName, publicDataMemberName); if (CreateProperties) { // Private data member classCode.WriteLine("\tprivate {0} {1};", datatypeName, privateDataMemberName); // Public property associated with above private data member properties.WriteLine("\tpublic {0} {1}", datatypeName, publicDataMemberName); properties.WriteLine("\t{"); properties.WriteLine("\t\tget {{ return {0}; }}", privateDataMemberName); properties.WriteLine("\t\tset {{ {0} = value; }}", privateDataMemberName); properties.WriteLine("\t}"); // Constructor body constructorBody.WriteLine("\t\t{0} = in{0};", publicDataMemberName); } else { // Constuctor body classCode.WriteLine("\tpublic {0} {1};", datatypeName, publicDataMemberName); constructorBody.WriteLine("\t\t{0} = in{0};", publicDataMemberName); } } // Add the properties to the output classCode.WriteLine(properties.ToString()); // Add the constructor to the output constructorSignature.Remove(constructorSignature.Length - 2, 2); // Remove the last ", " constructorSignature.Append(")"); classCode.WriteLine(constructorSignature.ToString()); classCode.WriteLine("\t{"); classCode.Write(constructorBody.ToString()); classCode.WriteLine("\t}"); // Close the class off and end the file classCode.WriteLine("}"); StringWriter result = new StringWriter(); result.WriteLine(usingStatements); if(Namespace == string.Empty) { result.WriteLine(classCode); } else { result.WriteLine("namespace {0}", Namespace); result.WriteLine("{"); result.WriteLine("\t" + classCode.ToString().Replace("\n", "\n\t")); result.WriteLine("}"); } return result.ToString(); } protected string expandUsingShortcut(string shortcut) { if (UsingShortcuts.ContainsKey(shortcut)) return UsingShortcuts[shortcut]; else return shortcut; } private string UppercaseFirstLetter(string str) { if (str == null) return null; if (str.Length > 1) return char.ToUpper(str[0]) + str.Substring(1); return str.ToUpper(); } private string LowercaseFirstLetter(string str) { if (str == null) return null; if (str.Length > 1) return char.ToLower(str[0]) + str.Substring(1); return str.ToLower(); } } }