diff --git a/src/Generator/Generator.cs b/src/Generator/Generator.cs index 52e44804..729f961b 100644 --- a/src/Generator/Generator.cs +++ b/src/Generator/Generator.cs @@ -1,241 +1,242 @@ -using System; +using Cxxi.Templates; +using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; -using Cxxi; -using Cxxi.Templates; - -public partial class Generator +namespace Cxxi { - public List Transformations { get; set; } - - Library Library; - Options Options; - - public Generator(Library library, Options options) - { - Transformations = new List(); - - Library = library; - Options = options; - } - - public void Process() - { - TransformModule(); - ProcessModules(); - } - - // Generates the binding code. - public void Generate() - { - GenerateModules(); - } - - int UniqueType = 0; - - void CleanupText(ref string debugText) + public partial class Generator { - // Strip off newlines from the debug text. - if (String.IsNullOrWhiteSpace(debugText)) - debugText = String.Empty; + public List Transformations { get; set; } - // TODO: Make this transformation in the output. - debugText = Regex.Replace(debugText, " ( )+", " "); - debugText = Regex.Replace(debugText, "\n", ""); - } + Library Library; + Options Options; - void ProcessType(Declaration type) - { - // If after all the transformations the type still does - // not have a name, then generate one. + public Generator(Library library, Options options) + { + Transformations = new List(); - if (String.IsNullOrWhiteSpace(type.Name)) - type.Name = String.Format("UnnamedType{0}", UniqueType++); + Library = library; + Options = options; + } - CleanupText(ref type.DebugText); - } + public void Process() + { + TransformModule(); + ProcessModules(); + } - void ProcessTypes(List types) where T : Declaration - { - foreach (T type in types) - ProcessType(type); - } + // Generates the binding code. + public void Generate() + { + GenerateModules(); + } - void ProcessClasses(List Classes) - { - ProcessTypes(Classes); + int UniqueType = 0; - foreach (var @class in Classes) - ProcessTypes(@class.Fields); - } + void CleanupText(ref string debugText) + { + // Strip off newlines from the debug text. + if (String.IsNullOrWhiteSpace(debugText)) + debugText = String.Empty; - void ProcessFunctions(List Functions) - { - ProcessTypes(Functions); + // TODO: Make this transformation in the output. + debugText = Regex.Replace(debugText, " ( )+", " "); + debugText = Regex.Replace(debugText, "\n", ""); + } - foreach (var function in Functions) + void ProcessType(Declaration type) { - if (function.ReturnType == null) - { - // Ignore and warn about unknown types. - function.Ignore = true; - - var s = "Function '{0}' was ignored due to unknown return type..."; - Console.WriteLine( String.Format(s, function.Name) ); - } + // If after all the transformations the type still does + // not have a name, then generate one. - ProcessTypes(function.Parameters); - } - } + if (String.IsNullOrWhiteSpace(type.Name)) + type.Name = String.Format("UnnamedType{0}", UniqueType++); - void ProcessModules() - { - if (String.IsNullOrEmpty(Library.Name)) - Library.Name = ""; + CleanupText(ref type.DebugText); + } - // Process everything in the global namespace for now. - foreach (var module in Library.Modules) + void ProcessTypes(List types) where T : Declaration { - ProcessNamespace(module); + foreach (T type in types) + ProcessType(type); } - } - void ProcessNamespace(Namespace @namespace) - { - ProcessTypes(@namespace.Enums); - ProcessFunctions(@namespace.Functions); - ProcessClasses(@namespace.Classes); - } + void ProcessClasses(List Classes) + { + ProcessTypes(Classes); - void TransformModule() - { - if (String.IsNullOrEmpty(Library.Name)) - Library.Name = ""; + foreach (var @class in Classes) + ProcessTypes(@class.Fields); + } - // Process everything in the global namespace for now. - foreach (var module in Library.Modules) + void ProcessFunctions(List Functions) { - foreach (Enumeration @enum in module.Enums) - TransformEnum(@enum); + ProcessTypes(Functions); - foreach (Function function in module.Functions) - TransformFunction(function); + foreach (var function in Functions) + { + if (function.ReturnType == null) + { + // Ignore and warn about unknown types. + function.Ignore = true; - foreach (Class @class in module.Classes) - TransformClass(@class); + var s = "Function '{0}' was ignored due to unknown return type..."; + Console.WriteLine(String.Format(s, function.Name)); + } + + ProcessTypes(function.Parameters); + } } - } - void TransformType(Declaration type) - { - foreach (var transform in Transformations) - transform.ProcessDeclaration(type); - } + void ProcessModules() + { + if (String.IsNullOrEmpty(Library.Name)) + Library.Name = ""; - void TransformClass(Class @class) - { - TransformType(@class); + // Process everything in the global namespace for now. + foreach (var module in Library.Modules) + { + ProcessNamespace(module); + } + } - foreach (var field in @class.Fields) - TransformType(field); - } + void ProcessNamespace(Namespace @namespace) + { + ProcessTypes(@namespace.Enums); + ProcessFunctions(@namespace.Functions); + ProcessClasses(@namespace.Classes); + } - void TransformFunction(Function function) - { - TransformType(function); + void TransformModule() + { + if (String.IsNullOrEmpty(Library.Name)) + Library.Name = ""; - foreach (var param in function.Parameters) - TransformType(param); - } + // Process everything in the global namespace for now. + foreach (var module in Library.Modules) + { + foreach (Enumeration @enum in module.Enums) + TransformEnum(@enum); + foreach (Function function in module.Functions) + TransformFunction(function); - void TransformEnum(Enumeration @enum) - { - TransformType(@enum); + foreach (Class @class in module.Classes) + TransformClass(@class); + } + } - foreach (var transform in Transformations) + void TransformType(Declaration type) { - foreach (var item in @enum.Items) - transform.ProcessEnumItem(item); + foreach (var transform in Transformations) + transform.ProcessDeclaration(type); } - // If the enumeration only has power of two values, assume it's - // a flags enum. + void TransformClass(Class @class) + { + TransformType(@class); - bool isFlags = true; - bool hasBigRange = false; + foreach (var field in @class.Fields) + TransformType(field); + } - foreach (var item in @enum.Items) + void TransformFunction(Function function) { - if (item.Name.Length >= 1 && Char.IsDigit(item.Name[0])) - item.Name = String.Format("_{0}", item.Name); + TransformType(function); - long value = item.Value; - if (value >= 4) - hasBigRange = true; - if (value <= 1 || value.IsPowerOfTwo()) - continue; - isFlags = false; + foreach (var param in function.Parameters) + TransformType(param); } - // Only apply this heuristic if there are enough values to have a - // reasonable chance that it really is a bitfield. - if (isFlags && hasBigRange) + void TransformEnum(Enumeration @enum) { - @enum.Modifiers |= Enumeration.EnumModifiers.Flags; - } + TransformType(@enum); - // If we still do not have a valid name, then try to guess one - // based on the enum value names. + foreach (var transform in Transformations) + { + foreach (var item in @enum.Items) + transform.ProcessEnumItem(item); + } - if (!String.IsNullOrWhiteSpace(@enum.Name)) - return; + // If the enumeration only has power of two values, assume it's + // a flags enum. - var names = new List(); - - foreach (var item in @enum.Items) - names.Add(item.Name); + bool isFlags = true; + bool hasBigRange = false; - var prefix = names.ToArray().CommonPrefix(); + foreach (var item in @enum.Items) + { + if (item.Name.Length >= 1 && Char.IsDigit(item.Name[0])) + item.Name = String.Format("_{0}", item.Name); + + long value = item.Value; + if (value >= 4) + hasBigRange = true; + if (value <= 1 || value.IsPowerOfTwo()) + continue; + isFlags = false; + } - // Try a simple heuristic to make sure we end up with a valid name. - if (prefix.Length >= 3) - { - prefix = prefix.Trim().Trim(new char[] { '_' }); - @enum.Name = prefix; + // Only apply this heuristic if there are enough values to have a + // reasonable chance that it really is a bitfield. + + if (isFlags && hasBigRange) + { + @enum.Modifiers |= Enumeration.EnumModifiers.Flags; + } + + // If we still do not have a valid name, then try to guess one + // based on the enum value names. + + if (!String.IsNullOrWhiteSpace(@enum.Name)) + return; + + var names = new List(); + + foreach (var item in @enum.Items) + names.Add(item.Name); + + var prefix = names.ToArray().CommonPrefix(); + + // Try a simple heuristic to make sure we end up with a valid name. + if (prefix.Length >= 3) + { + prefix = prefix.Trim().Trim(new char[] { '_' }); + @enum.Name = prefix; + } } - } - void GenerateModules() - { - // Process everything in the global namespace for now. - foreach (var module in Library.Modules) + void GenerateModules() { - if (module.Ignore || !module.HasDeclarations) - continue; + // Process everything in the global namespace for now. + foreach (var module in Library.Modules) + { + if (module.Ignore || !module.HasDeclarations) + continue; - // Generate the code from templates. - var template = new CSharpModule(); - template.Library = Library; - template.Options = Options; - template.Module = module; + // Generate the code from templates. + var template = new CSharpModule(); + template.Library = Library; + template.Options = Options; + template.Module = module; - if (!Directory.Exists(Options.OutputDir)) - Directory.CreateDirectory(Options.OutputDir); + if (!Directory.Exists(Options.OutputDir)) + Directory.CreateDirectory(Options.OutputDir); - var file = Path.GetFileNameWithoutExtension(module.FileName) + ".cs"; - var path = Path.Combine(Options.OutputDir, file); + var file = Path.GetFileNameWithoutExtension(module.FileName) + ".cs"; + var path = Path.Combine(Options.OutputDir, file); - // Normalize path. - path = Path.GetFullPath(path); + // Normalize path. + path = Path.GetFullPath(path); - string code = template.TransformText(); + string code = template.TransformText(); - Console.WriteLine(" Generated '" + file + "'."); - File.WriteAllText(path, code); + Console.WriteLine(" Generated '" + file + "'."); + File.WriteAllText(path, code); + } } } } \ No newline at end of file diff --git a/src/Generator/Program.cs b/src/Generator/Program.cs index 4a569039..4091d8bc 100644 --- a/src/Generator/Program.cs +++ b/src/Generator/Program.cs @@ -69,14 +69,20 @@ class Program Library library; Options options; - public void GenerateCode() + public void GenerateCode(LibraryTransform libTransform) { Console.WriteLine("Generating wrapper code..."); if (library.Modules.Count > 0) { var gen = new Generator(library, options); - TransformSDL(gen); + + libTransform.Preprocess(gen); + + gen.Process(); + + libTransform.Postprocess(gen); + gen.Generate(); } } @@ -126,7 +132,8 @@ class Program library = new Library(options.OutputNamespace); ParseCode(); - GenerateCode(); + + GenerateCode(new SDLTransforms()); } static void Main(String[] args) diff --git a/src/Generator/SDL.cs b/src/Generator/SDL.cs index 737751ba..d51d1aab 100644 --- a/src/Generator/SDL.cs +++ b/src/Generator/SDL.cs @@ -6,7 +6,7 @@ namespace Cxxi /// class SDLTransforms : LibraryTransform { - public override void Transform(Generator g) + public void Preprocess(Generator g) { g.IgnoreEnumWithMatchingItem("SDL_FALSE"); g.IgnoreEnumWithMatchingItem("DUMMY_ENUM_VALUE"); @@ -40,9 +40,10 @@ namespace Cxxi g.RemovePrefix("SDLK_"); g.RemovePrefix("KMOD_"); g.RemovePrefix("LOG_CATEGORY_"); + } - g.Process(); - + public void Postprocess(Generator g) + { g.SetNameOfEnumWithName("PIXELTYPE", "PixelType"); g.SetNameOfEnumWithName("BITMAPORDER", "BitmapOrder"); g.SetNameOfEnumWithName("PACKEDORDER", "PackedOrder"); diff --git a/src/Generator/Transform.cs b/src/Generator/Transform.cs index 661f16ef..29cefdf6 100644 --- a/src/Generator/Transform.cs +++ b/src/Generator/Transform.cs @@ -1,262 +1,272 @@ -using Cxxi; -using System; +using System; using System.Globalization; using System.Text.RegularExpressions; -/// -/// Used to massage the library types into something more .NET friendly. -/// -public interface LibraryTransform -{ - public void Transform(Generator g); -} - -/// -/// Used to provide different types of code transformation on a module -/// declarations and types before the code generation process is started. -/// -public abstract class ModuleTransform +namespace Cxxi { /// - /// Processes a declaration. + /// Used to massage the library types into something more .NET friendly. /// - public virtual bool ProcessDeclaration(Declaration declaration) + public interface LibraryTransform { - return false; + /// + /// Do transformations that should happen before processing here. + /// + void Preprocess(Generator g); + + /// + /// Do transformations that should happen after processing here. + /// + void Postprocess(Generator g); } /// - /// Processes an enum item. + /// Used to provide different types of code transformation on a module + /// declarations and types before the code generation process is started. /// - public virtual bool ProcessEnumItem(Enumeration.Item item) + public abstract class ModuleTransform { - return false; - } -} - -/// -/// Renames a declaration based on a regular expression pattern. -/// -public class RenameTransform : ModuleTransform -{ - public string Pattern; - public string Replacement; + /// + /// Processes a declaration. + /// + public virtual bool ProcessDeclaration(Declaration declaration) + { + return false; + } - public RenameTransform(string pattern, string replacement) - { - Pattern = pattern; - Replacement = replacement; + /// + /// Processes an enum item. + /// + public virtual bool ProcessEnumItem(Enumeration.Item item) + { + return false; + } } - public override bool ProcessDeclaration(Declaration type) + /// + /// Renames a declaration based on a regular expression pattern. + /// + public class RenameTransform : ModuleTransform { - return Rename(ref type.Name); - } + public string Pattern; + public string Replacement; - public override bool ProcessEnumItem(Enumeration.Item item) - { - return Rename(ref item.Name); - } + public RenameTransform(string pattern, string replacement) + { + Pattern = pattern; + Replacement = replacement; + } - bool Rename(ref string name) - { - string replace = Regex.Replace(name, Pattern, Replacement); + public override bool ProcessDeclaration(Declaration type) + { + return Rename(ref type.Name); + } - if (!name.Equals(replace)) + public override bool ProcessEnumItem(Enumeration.Item item) { - name = replace; - return true; + return Rename(ref item.Name); } - return false; - } -} + bool Rename(ref string name) + { + string replace = Regex.Replace(name, Pattern, Replacement); -public partial class Generator -{ - #region Transform Operations - - public void RemovePrefix(string prefix) - { - Transformations.Add(new RenameTransform(prefix, String.Empty)); + if (!name.Equals(replace)) + { + name = replace; + return true; + } + + return false; + } } - public void RemoveType(Declaration type) + public partial class Generator { + #region Transform Operations - } - - #endregion - - #region Enum Helpers + public void RemovePrefix(string prefix) + { + Transformations.Add(new RenameTransform(prefix, String.Empty)); + } - public Enumeration FindEnum(string name) - { - foreach (var module in Library.Modules) + public void RemoveType(Declaration type) { - var @enum = module.FindEnum(name); - if (@enum != null) - return @enum; + } - return null; - } + #endregion - public void IgnoreEnumWithMatchingItem(string Pattern) - { - Enumeration @enum = GetEnumWithMatchingItem(Pattern); - if (@enum != null) - @enum.Ignore = true; - } + #region Enum Helpers - public void SetNameOfEnumWithMatchingItem(string Pattern, string Name) - { - Enumeration @enum = GetEnumWithMatchingItem(Pattern); - if (@enum != null) - @enum.Name = Name; - } + public Enumeration FindEnum(string name) + { + foreach (var module in Library.Modules) + { + var @enum = module.FindEnum(name); + if (@enum != null) + return @enum; + } - public void SetNameOfEnumWithName(string enumName, string name) - { - Enumeration @enum = FindEnum(enumName); - if (@enum != null) - @enum.Name = name; - } + return null; + } - public Enumeration GetEnumWithMatchingItem(string Pattern) - { - foreach (var module in Library.Modules) + public void IgnoreEnumWithMatchingItem(string Pattern) { - Enumeration @enum = module.FindEnumWithItem(Pattern); - if (@enum == null) continue; - return @enum; + Enumeration @enum = GetEnumWithMatchingItem(Pattern); + if (@enum != null) + @enum.Ignore = true; } - return null; - } + public void SetNameOfEnumWithMatchingItem(string Pattern, string Name) + { + Enumeration @enum = GetEnumWithMatchingItem(Pattern); + if (@enum != null) + @enum.Name = Name; + } - public Enumeration.Item GenerateEnumItemFromMacro(MacroDefine macro) - { - var item = new Enumeration.Item(); - item.Name = macro.Name; - item.Expression = macro.Expression; - item.Value = ParseMacroExpression(macro.Expression); + public void SetNameOfEnumWithName(string enumName, string name) + { + Enumeration @enum = FindEnum(enumName); + if (@enum != null) + @enum.Name = name; + } - return item; - } + public Enumeration GetEnumWithMatchingItem(string Pattern) + { + foreach (var module in Library.Modules) + { + Enumeration @enum = module.FindEnumWithItem(Pattern); + if (@enum == null) continue; + return @enum; + } - public Enumeration GenerateEnumFromMacros(string name, params string[] macros) - { - Enumeration @enum = new Enumeration(); - @enum.Name = name; + return null; + } + + public Enumeration.Item GenerateEnumItemFromMacro(MacroDefine macro) + { + var item = new Enumeration.Item(); + item.Name = macro.Name; + item.Expression = macro.Expression; + item.Value = ParseMacroExpression(macro.Expression); - var pattern = String.Join("|", macros); - var regex = new Regex(pattern); + return item; + } - foreach (var module in Library.Modules) + public Enumeration GenerateEnumFromMacros(string name, params string[] macros) { - foreach (var macro in module.Macros) - { - var match = regex.Match(macro.Name); - if (!match.Success) continue; + Enumeration @enum = new Enumeration(); + @enum.Name = name; - var item = GenerateEnumItemFromMacro(macro); - @enum.AddItem(item); - } + var pattern = String.Join("|", macros); + var regex = new Regex(pattern); - if (@enum.Items.Count > 0) + foreach (var module in Library.Modules) { - module.Enums.Add(@enum); - break; + foreach (var macro in module.Macros) + { + var match = regex.Match(macro.Name); + if (!match.Success) continue; + + var item = GenerateEnumItemFromMacro(macro); + @enum.AddItem(item); + } + + if (@enum.Items.Count > 0) + { + module.Enums.Add(@enum); + break; + } } + + return @enum; } - return @enum; - } + #endregion - #endregion + #region Class Helpers - #region Class Helpers + public Class FindClass(string name) + { + foreach (var module in Library.Modules) + { + var @class = module.FindClass(name); + if (@class != null) + return @class; + } - public Class FindClass(string name) - { - foreach (var module in Library.Modules) + return null; + } + + public void SetNameOfClassWithName(string className, string name) { - var @class = module.FindClass(name); + Class @class = FindClass(className); if (@class != null) - return @class; + @class.Name = name; } - return null; - } + #endregion - public void SetNameOfClassWithName(string className, string name) - { - Class @class = FindClass(className); - if (@class != null) - @class.Name = name; - } + #region Function Helpers - #endregion + public Function FindFunction(string name) + { + foreach (var module in Library.Modules) + { + var function = module.FindFunction(name); + if (function != null) + return function; + } - #region Function Helpers + return null; + } - public Function FindFunction(string name) - { - foreach (var module in Library.Modules) + public void IgnoreFunctionWithName(string name) { - var function = module.FindFunction(name); + Function function = FindFunction(name); if (function != null) - return function; + function.Ignore = true; } - return null; - } - - public void IgnoreFunctionWithName(string name) - { - Function function = FindFunction(name); - if (function != null) - function.Ignore = true; - } - - #endregion + #endregion - #region Module Helpers + #region Module Helpers - public Module IgnoreModuleWithName(string Pattern) - { - Module module = Library.Modules.Find( - m => Regex.Match(m.FilePath, Pattern).Success); + public Module IgnoreModuleWithName(string Pattern) + { + Module module = Library.Modules.Find( + m => Regex.Match(m.FilePath, Pattern).Success); - if (module != null) - module.Ignore = true; + if (module != null) + module.Ignore = true; - return module; - } + return module; + } - #endregion + #endregion - static bool ParseToNumber(string num, out long val) - { - if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase)) + static bool ParseToNumber(string num, out long val) { - num = num.Substring(2); + if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase)) + { + num = num.Substring(2); - return long.TryParse(num, NumberStyles.HexNumber, - CultureInfo.CurrentCulture, out val); + return long.TryParse(num, NumberStyles.HexNumber, + CultureInfo.CurrentCulture, out val); + } + + return long.TryParse(num, out val); } - return long.TryParse(num, out val); - } + static long ParseMacroExpression(string Expression) + { + long val; + if (ParseToNumber(Expression, out val)) + return val; + // TODO: Handle string expressions + return 0; + } - static long ParseMacroExpression(string Expression) - { - long val; - if (ParseToNumber(Expression, out val)) - return val; - // TODO: Handle string expressions - return 0; } - } \ No newline at end of file