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 @@
using System; using Cxxi.Templates;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Cxxi; namespace Cxxi
using Cxxi.Templates;
public partial class Generator
{ {
public List<ModuleTransform> Transformations { get; set; } public partial class Generator
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)
{ {
// Strip off newlines from the debug text. public List<ModuleTransform> Transformations { get; set; }
if (String.IsNullOrWhiteSpace(debugText))
debugText = String.Empty;
// TODO: Make this transformation in the output. Library Library;
debugText = Regex.Replace(debugText, " ( )+", " "); Options Options;
debugText = Regex.Replace(debugText, "\n", "");
}
void ProcessType(Declaration type) public Generator(Library library, Options options)
{ {
// If after all the transformations the type still does Transformations = new List<ModuleTransform>();
// not have a name, then generate one.
if (String.IsNullOrWhiteSpace(type.Name)) Library = library;
type.Name = String.Format("UnnamedType{0}", UniqueType++); Options = options;
}
CleanupText(ref type.DebugText); public void Process()
} {
TransformModule();
ProcessModules();
}
void ProcessTypes<T>(List<T> types) where T : Declaration // Generates the binding code.
{ public void Generate()
foreach (T type in types) {
ProcessType(type); GenerateModules();
} }
void ProcessClasses(List<Class> Classes) int UniqueType = 0;
{
ProcessTypes(Classes);
foreach (var @class in Classes) void CleanupText(ref string debugText)
ProcessTypes(@class.Fields); {
} // Strip off newlines from the debug text.
if (String.IsNullOrWhiteSpace(debugText))
debugText = String.Empty;
void ProcessFunctions(List<Function> Functions) // TODO: Make this transformation in the output.
{ debugText = Regex.Replace(debugText, " ( )+", " ");
ProcessTypes(Functions); debugText = Regex.Replace(debugText, "\n", "");
}
foreach (var function in Functions) void ProcessType(Declaration type)
{ {
if (function.ReturnType == null) // If after all the transformations the type still does
{ // not have a name, then generate one.
// 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) );
}
ProcessTypes(function.Parameters); if (String.IsNullOrWhiteSpace(type.Name))
} type.Name = String.Format("UnnamedType{0}", UniqueType++);
}
void ProcessModules() CleanupText(ref type.DebugText);
{ }
if (String.IsNullOrEmpty(Library.Name))
Library.Name = "";
// Process everything in the global namespace for now. void ProcessTypes<T>(List<T> types) where T : Declaration
foreach (var module in Library.Modules)
{ {
ProcessNamespace(module); foreach (T type in types)
ProcessType(type);
} }
}
void ProcessNamespace(Namespace @namespace) void ProcessClasses(List<Class> Classes)
{ {
ProcessTypes(@namespace.Enums); ProcessTypes(Classes);
ProcessFunctions(@namespace.Functions);
ProcessClasses(@namespace.Classes);
}
void TransformModule() foreach (var @class in Classes)
{ ProcessTypes(@class.Fields);
if (String.IsNullOrEmpty(Library.Name)) }
Library.Name = "";
// Process everything in the global namespace for now. void ProcessFunctions(List<Function> Functions)
foreach (var module in Library.Modules)
{ {
foreach (Enumeration @enum in module.Enums) ProcessTypes(Functions);
TransformEnum(@enum);
foreach (Function function in module.Functions) foreach (var function in Functions)
TransformFunction(function); {
if (function.ReturnType == null)
{
// Ignore and warn about unknown types.
function.Ignore = true;
foreach (Class @class in module.Classes) var s = "Function '{0}' was ignored due to unknown return type...";
TransformClass(@class); Console.WriteLine(String.Format(s, function.Name));
}
ProcessTypes(function.Parameters);
}
} }
}
void TransformType(Declaration type) void ProcessModules()
{ {
foreach (var transform in Transformations) if (String.IsNullOrEmpty(Library.Name))
transform.ProcessDeclaration(type); Library.Name = "";
}
void TransformClass(Class @class) // Process everything in the global namespace for now.
{ foreach (var module in Library.Modules)
TransformType(@class); {
ProcessNamespace(module);
}
}
foreach (var field in @class.Fields) void ProcessNamespace(Namespace @namespace)
TransformType(field); {
} ProcessTypes(@namespace.Enums);
ProcessFunctions(@namespace.Functions);
ProcessClasses(@namespace.Classes);
}
void TransformFunction(Function function) void TransformModule()
{ {
TransformType(function); if (String.IsNullOrEmpty(Library.Name))
Library.Name = "";
foreach (var param in function.Parameters) // Process everything in the global namespace for now.
TransformType(param); 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) foreach (Class @class in module.Classes)
{ TransformClass(@class);
TransformType(@enum); }
}
foreach (var transform in Transformations) void TransformType(Declaration type)
{ {
foreach (var item in @enum.Items) foreach (var transform in Transformations)
transform.ProcessEnumItem(item); transform.ProcessDeclaration(type);
} }
// If the enumeration only has power of two values, assume it's void TransformClass(Class @class)
// a flags enum. {
TransformType(@class);
bool isFlags = true; foreach (var field in @class.Fields)
bool hasBigRange = false; TransformType(field);
}
foreach (var item in @enum.Items) void TransformFunction(Function function)
{ {
if (item.Name.Length >= 1 && Char.IsDigit(item.Name[0])) TransformType(function);
item.Name = String.Format("_{0}", item.Name);
long value = item.Value; foreach (var param in function.Parameters)
if (value >= 4) TransformType(param);
hasBigRange = true;
if (value <= 1 || value.IsPowerOfTwo())
continue;
isFlags = false;
} }
// 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 foreach (var transform in Transformations)
// based on the enum value names. {
foreach (var item in @enum.Items)
transform.ProcessEnumItem(item);
}
if (!String.IsNullOrWhiteSpace(@enum.Name)) // If the enumeration only has power of two values, assume it's
return; // a flags enum.
var names = new List<string>(); bool isFlags = true;
bool hasBigRange = false;
foreach (var item in @enum.Items)
names.Add(item.Name);
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. // Only apply this heuristic if there are enough values to have a
if (prefix.Length >= 3) // reasonable chance that it really is a bitfield.
{
prefix = prefix.Trim().Trim(new char[] { '_' }); if (isFlags && hasBigRange)
@enum.Name = prefix; {
@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() void GenerateModules()
{
// Process everything in the global namespace for now.
foreach (var module in Library.Modules)
{ {
if (module.Ignore || !module.HasDeclarations) // Process everything in the global namespace for now.
continue; foreach (var module in Library.Modules)
{
if (module.Ignore || !module.HasDeclarations)
continue;
// Generate the code from templates. // Generate the code from templates.
var template = new CSharpModule(); var template = new CSharpModule();
template.Library = Library; template.Library = Library;
template.Options = Options; template.Options = Options;
template.Module = module; template.Module = module;
if (!Directory.Exists(Options.OutputDir)) if (!Directory.Exists(Options.OutputDir))
Directory.CreateDirectory(Options.OutputDir); Directory.CreateDirectory(Options.OutputDir);
var file = Path.GetFileNameWithoutExtension(module.FileName) + ".cs"; var file = Path.GetFileNameWithoutExtension(module.FileName) + ".cs";
var path = Path.Combine(Options.OutputDir, file); var path = Path.Combine(Options.OutputDir, file);
// Normalize path. // Normalize path.
path = Path.GetFullPath(path); path = Path.GetFullPath(path);
string code = template.TransformText(); string code = template.TransformText();
Console.WriteLine(" Generated '" + file + "'."); Console.WriteLine(" Generated '" + file + "'.");
File.WriteAllText(path, code); File.WriteAllText(path, code);
}
} }
} }
} }

13
src/Generator/Program.cs

@ -69,14 +69,20 @@ class Program
Library library; Library library;
Options options; Options options;
public void GenerateCode() public void GenerateCode(LibraryTransform libTransform)
{ {
Console.WriteLine("Generating wrapper code..."); Console.WriteLine("Generating wrapper code...");
if (library.Modules.Count > 0) if (library.Modules.Count > 0)
{ {
var gen = new Generator(library, options); var gen = new Generator(library, options);
TransformSDL(gen);
libTransform.Preprocess(gen);
gen.Process();
libTransform.Postprocess(gen);
gen.Generate(); gen.Generate();
} }
} }
@ -126,7 +132,8 @@ class Program
library = new Library(options.OutputNamespace); library = new Library(options.OutputNamespace);
ParseCode(); ParseCode();
GenerateCode();
GenerateCode(new SDLTransforms());
} }
static void Main(String[] args) static void Main(String[] args)

7
src/Generator/SDL.cs

@ -6,7 +6,7 @@ namespace Cxxi
/// </summary> /// </summary>
class SDLTransforms : LibraryTransform class SDLTransforms : LibraryTransform
{ {
public override void Transform(Generator g) public void Preprocess(Generator g)
{ {
g.IgnoreEnumWithMatchingItem("SDL_FALSE"); g.IgnoreEnumWithMatchingItem("SDL_FALSE");
g.IgnoreEnumWithMatchingItem("DUMMY_ENUM_VALUE"); g.IgnoreEnumWithMatchingItem("DUMMY_ENUM_VALUE");
@ -40,9 +40,10 @@ namespace Cxxi
g.RemovePrefix("SDLK_"); g.RemovePrefix("SDLK_");
g.RemovePrefix("KMOD_"); g.RemovePrefix("KMOD_");
g.RemovePrefix("LOG_CATEGORY_"); g.RemovePrefix("LOG_CATEGORY_");
}
g.Process(); public void Postprocess(Generator g)
{
g.SetNameOfEnumWithName("PIXELTYPE", "PixelType"); g.SetNameOfEnumWithName("PIXELTYPE", "PixelType");
g.SetNameOfEnumWithName("BITMAPORDER", "BitmapOrder"); g.SetNameOfEnumWithName("BITMAPORDER", "BitmapOrder");
g.SetNameOfEnumWithName("PACKEDORDER", "PackedOrder"); g.SetNameOfEnumWithName("PACKEDORDER", "PackedOrder");

378
src/Generator/Transform.cs

@ -1,262 +1,272 @@
using Cxxi; using System;
using System;
using System.Globalization; using System.Globalization;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
/// <summary> namespace Cxxi
/// 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
{ {
/// <summary> /// <summary>
/// Processes a declaration. /// Used to massage the library types into something more .NET friendly.
/// </summary> /// </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> /// <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> /// </summary>
public virtual bool ProcessEnumItem(Enumeration.Item item) public abstract class ModuleTransform
{ {
return false; /// <summary>
} /// Processes a declaration.
} /// </summary>
public virtual bool ProcessDeclaration(Declaration declaration)
/// <summary> {
/// Renames a declaration based on a regular expression pattern. return false;
/// </summary> }
public class RenameTransform : ModuleTransform
{
public string Pattern;
public string Replacement;
public RenameTransform(string pattern, string replacement) /// <summary>
{ /// Processes an enum item.
Pattern = pattern; /// </summary>
Replacement = replacement; 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) public RenameTransform(string pattern, string replacement)
{ {
return Rename(ref item.Name); Pattern = pattern;
} Replacement = replacement;
}
bool Rename(ref string name) public override bool ProcessDeclaration(Declaration type)
{ {
string replace = Regex.Replace(name, Pattern, Replacement); return Rename(ref type.Name);
}
if (!name.Equals(replace)) public override bool ProcessEnumItem(Enumeration.Item item)
{ {
name = replace; return Rename(ref item.Name);
return true;
} }
return false; bool Rename(ref string name)
} {
} string replace = Regex.Replace(name, Pattern, Replacement);
public partial class Generator if (!name.Equals(replace))
{ {
#region Transform Operations name = replace;
return true;
public void RemovePrefix(string prefix) }
{
Transformations.Add(new RenameTransform(prefix, String.Empty)); return false;
}
} }
public void RemoveType(Declaration type) public partial class Generator
{ {
#region Transform Operations
} public void RemovePrefix(string prefix)
{
#endregion Transformations.Add(new RenameTransform(prefix, String.Empty));
}
#region Enum Helpers
public Enumeration FindEnum(string name) public void RemoveType(Declaration type)
{
foreach (var module in Library.Modules)
{ {
var @enum = module.FindEnum(name);
if (@enum != null)
return @enum;
} }
return null; #endregion
}
public void IgnoreEnumWithMatchingItem(string Pattern) #region Enum Helpers
{
Enumeration @enum = GetEnumWithMatchingItem(Pattern);
if (@enum != null)
@enum.Ignore = true;
}
public void SetNameOfEnumWithMatchingItem(string Pattern, string Name) public Enumeration FindEnum(string name)
{ {
Enumeration @enum = GetEnumWithMatchingItem(Pattern); foreach (var module in Library.Modules)
if (@enum != null) {
@enum.Name = Name; var @enum = module.FindEnum(name);
} if (@enum != null)
return @enum;
}
public void SetNameOfEnumWithName(string enumName, string name) return null;
{ }
Enumeration @enum = FindEnum(enumName);
if (@enum != null)
@enum.Name = name;
}
public Enumeration GetEnumWithMatchingItem(string Pattern) public void IgnoreEnumWithMatchingItem(string Pattern)
{
foreach (var module in Library.Modules)
{ {
Enumeration @enum = module.FindEnumWithItem(Pattern); Enumeration @enum = GetEnumWithMatchingItem(Pattern);
if (@enum == null) continue; if (@enum != null)
return @enum; @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) public void SetNameOfEnumWithName(string enumName, string name)
{ {
var item = new Enumeration.Item(); Enumeration @enum = FindEnum(enumName);
item.Name = macro.Name; if (@enum != null)
item.Expression = macro.Expression; @enum.Name = name;
item.Value = ParseMacroExpression(macro.Expression); }
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) return null;
{ }
Enumeration @enum = new Enumeration();
@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);
var pattern = String.Join("|", macros); return item;
var regex = new Regex(pattern); }
foreach (var module in Library.Modules) public Enumeration GenerateEnumFromMacros(string name, params string[] macros)
{ {
foreach (var macro in module.Macros) Enumeration @enum = new Enumeration();
{ @enum.Name = name;
var match = regex.Match(macro.Name);
if (!match.Success) continue;
var item = GenerateEnumItemFromMacro(macro); var pattern = String.Join("|", macros);
@enum.AddItem(item); var regex = new Regex(pattern);
}
if (@enum.Items.Count > 0) foreach (var module in Library.Modules)
{ {
module.Enums.Add(@enum); foreach (var macro in module.Macros)
break; {
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) return null;
{ }
foreach (var module in Library.Modules)
public void SetNameOfClassWithName(string className, string name)
{ {
var @class = module.FindClass(name); Class @class = FindClass(className);
if (@class != null) if (@class != null)
return @class; @class.Name = name;
} }
return null; #endregion
}
public void SetNameOfClassWithName(string className, string name) #region Function Helpers
{
Class @class = FindClass(className);
if (@class != null)
@class.Name = name;
}
#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) public void IgnoreFunctionWithName(string name)
{
foreach (var module in Library.Modules)
{ {
var function = module.FindFunction(name); Function function = FindFunction(name);
if (function != null) if (function != null)
return function; function.Ignore = true;
} }
return null; #endregion
}
public void IgnoreFunctionWithName(string name)
{
Function function = FindFunction(name);
if (function != null)
function.Ignore = true;
}
#endregion
#region Module Helpers #region Module Helpers
public Module IgnoreModuleWithName(string Pattern) public Module IgnoreModuleWithName(string Pattern)
{ {
Module module = Library.Modules.Find( Module module = Library.Modules.Find(
m => Regex.Match(m.FilePath, Pattern).Success); m => Regex.Match(m.FilePath, Pattern).Success);
if (module != null) if (module != null)
module.Ignore = true; module.Ignore = true;
return module; return module;
} }
#endregion #endregion
static bool ParseToNumber(string num, out long val) static bool ParseToNumber(string num, out long val)
{
if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase))
{ {
num = num.Substring(2); if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase))
{
num = num.Substring(2);
return long.TryParse(num, NumberStyles.HexNumber, return long.TryParse(num, NumberStyles.HexNumber,
CultureInfo.CurrentCulture, out val); 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