Browse Source

Renamed a few functions and factored out the SDL transforms.

pull/1/head
triton 13 years ago
parent
commit
b84196c0b7
  1. 355
      src/Generator/Generator.cs
  2. 13
      src/Generator/Program.cs
  3. 7
      src/Generator/SDL.cs
  4. 378
      src/Generator/Transform.cs

355
src/Generator/Generator.cs

@ -1,241 +1,242 @@ @@ -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<ModuleTransform> Transformations { get; set; }
Library Library;
Options Options;
public Generator(Library library, Options options)
{
Transformations = new List<ModuleTransform>();
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<ModuleTransform> 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<ModuleTransform>();
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<T>(List<T> types) where T : Declaration
{
foreach (T type in types)
ProcessType(type);
}
// Generates the binding code.
public void Generate()
{
GenerateModules();
}
void ProcessClasses(List<Class> 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<Function> 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<T>(List<T> 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<Class> 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<Function> 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<string>();
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<string>();
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);
}
}
}
}

13
src/Generator/Program.cs

@ -69,14 +69,20 @@ class Program @@ -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 @@ -126,7 +132,8 @@ class Program
library = new Library(options.OutputNamespace);
ParseCode();
GenerateCode();
GenerateCode(new SDLTransforms());
}
static void Main(String[] args)

7
src/Generator/SDL.cs

@ -6,7 +6,7 @@ namespace Cxxi @@ -6,7 +6,7 @@ namespace Cxxi
/// </summary>
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 @@ -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");

378
src/Generator/Transform.cs

@ -1,262 +1,272 @@ @@ -1,262 +1,272 @@
using Cxxi;
using System;
using System;
using System.Globalization;
using System.Text.RegularExpressions;
/// <summary>
/// Used to massage the library types into something more .NET friendly.
/// </summary>
public interface LibraryTransform
{
public void Transform(Generator g);
}
/// <summary>
/// Used to provide different types of code transformation on a module
/// declarations and types before the code generation process is started.
/// </summary>
public abstract class ModuleTransform
namespace Cxxi
{
/// <summary>
/// Processes a declaration.
/// Used to massage the library types into something more .NET friendly.
/// </summary>
public virtual bool ProcessDeclaration(Declaration declaration)
public interface LibraryTransform
{
return false;
/// <summary>
/// Do transformations that should happen before processing here.
/// </summary>
void Preprocess(Generator g);
/// <summary>
/// Do transformations that should happen after processing here.
/// </summary>
void Postprocess(Generator g);
}
/// <summary>
/// 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.
/// </summary>
public virtual bool ProcessEnumItem(Enumeration.Item item)
public abstract class ModuleTransform
{
return false;
}
}
/// <summary>
/// Renames a declaration based on a regular expression pattern.
/// </summary>
public class RenameTransform : ModuleTransform
{
public string Pattern;
public string Replacement;
/// <summary>
/// Processes a declaration.
/// </summary>
public virtual bool ProcessDeclaration(Declaration declaration)
{
return false;
}
public RenameTransform(string pattern, string replacement)
{
Pattern = pattern;
Replacement = replacement;
/// <summary>
/// Processes an enum item.
/// </summary>
public virtual bool ProcessEnumItem(Enumeration.Item item)
{
return false;
}
}
public override bool ProcessDeclaration(Declaration type)
/// <summary>
/// Renames a declaration based on a regular expression pattern.
/// </summary>
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;
}
}
Loading…
Cancel
Save