Browse Source

Added the new C# backend (still a work-in-progress).

pull/1/head
triton 13 years ago
parent
commit
014a084039
  1. 39
      src/Generator/Generators/CSharp/CSharpGenerator.cs
  2. 314
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  3. 238
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs

39
src/Generator/Generators/CSharp/CSharpGenerator.cs

@ -0,0 +1,39 @@
using System;
using System.IO;
using Cxxi.Types;
namespace Cxxi.Generators.CSharp
{
public class CSharpGenerator : Generator
{
private readonly ITypePrinter typePrinter;
public CSharpGenerator(Driver driver) : base(driver)
{
typePrinter = new CSharpTypePrinter(driver.TypeDatabase, driver.Library);
Type.TypePrinter = typePrinter;
}
void WriteTemplate(TextTemplate template)
{
var file = Path.GetFileNameWithoutExtension(template.unit.FileName)
+ Driver.Options.WrapperSuffix + "."
+ template.FileExtension;
var path = Path.Combine(Driver.Options.OutputDir, file);
template.Generate();
Console.WriteLine(" Generated '" + file + "'.");
File.WriteAllText(Path.GetFullPath(path), template.ToString());
}
public override bool Generate(TranslationUnit unit)
{
var template = new CSharpTextTemplate(Driver, unit);
WriteTemplate(template);
return true;
}
}
}

314
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -0,0 +1,314 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Cxxi.Types;
namespace Cxxi.Generators.CSharp
{
public class CSharpTextTemplate : TextTemplate
{
public ITypePrinter TypePrinter { get; set; }
public CSharpTextTemplate(Driver driver, TranslationUnit unit)
: base(driver, unit)
{
TypePrinter = new CSharpTypePrinter(driver.TypeDatabase, driver.Library);
}
// from https://github.com/mono/mono/blob/master/mcs/class/System/Microsoft.CSharp/CSharpCodeGenerator.cs
private static string[] keywords = new string[]
{
"abstract", "event", "new", "struct", "as", "explicit", "null", "switch", "base", "extern",
"this", "false", "operator", "throw", "break", "finally", "out", "true",
"fixed", "override", "try", "case", "params", "typeof", "catch", "for",
"private", "foreach", "protected", "checked", "goto", "public",
"unchecked", "class", "if", "readonly", "unsafe", "const", "implicit", "ref",
"continue", "in", "return", "using", "virtual", "default",
"interface", "sealed", "volatile", "delegate", "internal", "do", "is",
"sizeof", "while", "lock", "stackalloc", "else", "static", "enum",
"namespace",
"object", "bool", "byte", "float", "uint", "char", "ulong", "ushort",
"decimal", "int", "sbyte", "short", "double", "long", "string", "void",
"partial", "yield", "where"
};
public static string SafeIdentifier(string proposedName)
{
proposedName =
new string(((IEnumerable<char>) proposedName).Select(c => char.IsLetterOrDigit(c) ? c : '_').ToArray());
return keywords.Contains(proposedName) ? "@" + proposedName : proposedName;
}
public override string FileExtension
{
get { return "cs"; }
}
public override void Generate()
{
GenerateStart();
WriteLine("using System;");
WriteLine("using System.Runtime.InteropServices;");
NewLine();
WriteLine("namespace {0}", SafeIdentifier(Driver.Options.LibraryName));
WriteStartBraceIndent();
GenerateDeclarations();
WriteCloseBraceIndent();
}
public void GenerateStart()
{
if (Transform != null)
{
Transform.GenerateStart(this);
return;
}
WriteLine("//----------------------------------------------------------------------------");
WriteLine("// This is autogenerated code by Cxxi.");
WriteLine("// Do not edit this file or all your changes will be lost after re-generation.");
WriteLine("//----------------------------------------------------------------------------");
}
public void GenerateDeclarations()
{
// Generate all the enum declarations for the module.
foreach (var @enum in unit.Enums)
{
if (@enum.Ignore || @enum.IsIncomplete)
continue;
GenerateEnum(@enum);
NewLine();
}
// Generate all the typedef declarations for the module.
foreach (var typedef in unit.Typedefs)
{
if (typedef.Ignore) continue;
if (!GenerateTypedef(typedef))
continue;
NewLine();
}
// Generate all the struct/class declarations for the module.
foreach (var @class in unit.Classes)
{
if (@class.Ignore) continue;
GenerateClass(@class);
NewLine();
}
if (unit.HasFunctions)
{
WriteLine("public partial class " + SafeIdentifier(Options.LibraryName));
WriteStartBraceIndent();
// Generate all the function declarations for the module.
foreach (var function in unit.Functions)
GenerateFunction(function);
WriteCloseBraceIndent();
}
}
public void GenerateDeclarationCommon(Declaration T)
{
GenerateSummary(T.BriefComment);
GenerateDebug(T);
}
#region Classes
public void GenerateClass(Class @class)
{
if (@class.Ignore) return;
GenerateDeclarationCommon(@class);
GenerateClassProlog(@class);
NewLine();
WriteStartBraceIndent();
if (!@class.IsOpaque)
GenerateClassFields(@class);
WriteCloseBraceIndent();
}
public void GenerateClassProlog(Class @class)
{
if (@class.IsUnion)
WriteLine("[StructLayout(LayoutKind.Explicit)]");
Write("public unsafe ");
if (@class.IsAbstract)
Write("abstract ");
Write("class {0}", SafeIdentifier(@class.Name));
if (@class.HasBase)
Write(" : {0}", SafeIdentifier(@class.Bases[0].Class.Name));
}
public void GenerateClassFields(Class @class)
{
foreach (var field in @class.Fields)
{
if (field.Ignore) continue;
GenerateDeclarationCommon(field);
if (@class.IsUnion)
WriteLine("[FieldOffset({0})]", field.Offset);
WriteLine("public {0} {1};", field.Type, SafeIdentifier(field.Name));
}
}
#endregion
public bool GenerateTypedef(TypedefDecl typedef)
{
if (typedef.Ignore)
return false;
GenerateDeclarationCommon(typedef);
FunctionType func;
TagType tag;
if (typedef.Type.IsPointerToPrimitiveType(PrimitiveType.Void)
|| typedef.Type.IsPointerTo<TagType>(out tag))
{
WriteLine("public class " + SafeIdentifier(typedef.Name) + @" { }");
}
else if (typedef.Type.IsPointerTo<FunctionType>(out func))
{
//WriteLine("public {0};",
// string.Format(func.ToDelegateString(), SafeIdentifier(T.Name)));
}
else if (typedef.Type.IsEnumType())
{
// Already handled in the parser.
return false;
}
else
{
Console.WriteLine("Unhandled typedef type: {0}", typedef);
return false;
}
return true;
}
public void GenerateEnum(Enumeration @enum)
{
if (@enum.Ignore) return;
GenerateDeclarationCommon(@enum);
if (@enum.IsFlags)
WriteLine("[Flags]");
Write("public enum {0}", SafeIdentifier(@enum.Name));
var typeName = TypePrinter.VisitPrimitiveType(@enum.BuiltinType.Type,
new TypeQualifiers());
if (@enum.BuiltinType.Type != PrimitiveType.Int32)
Write(" : {0}", typeName);
NewLine();
WriteStartBraceIndent();
for (var i = 0; i < @enum.Items.Count; ++i)
{
var item = @enum.Items[i];
GenerateInlineSummary(item.Comment);
Write(item.ExplicitValue
? string.Format("{0} = {1}", SafeIdentifier(item.Name), item.Value)
: string.Format("{0}", SafeIdentifier(item.Name)));
if (i < @enum.Items.Count - 1)
Write(",");
NewLine();
}
WriteCloseBraceIndent();
}
public void GenerateFunction(Function function)
{
if(function.Ignore) return;
GenerateDeclarationCommon(function);
Write("[DllImport(\"{0}.dll\", ", SafeIdentifier(Library.SharedLibrary));
Write("CallingConvention = CallingConvention.{0}, ", ToCSharpCallConv(function.CallingConvention));
WriteLine("EntryPoint=\"{0}\")]", function.Mangled);
Write("public unsafe static extern {0} {1}(", function.ReturnType,
SafeIdentifier(function.Name));
for(var i = 0; i < function.Parameters.Count; ++i)
{
var param = function.Parameters[i];
Write("{0} {1}", param.Type, SafeIdentifier(param.Name));
if (i < function.Parameters.Count - 1)
Write(", ");
}
WriteLine(");");
}
public static string ToCSharpCallConv(CallingConvention convention)
{
switch (convention)
{
case CallingConvention.Default:
return "Winapi";
case CallingConvention.C:
return "Cdecl";
case CallingConvention.StdCall:
return "StdCall";
case CallingConvention.ThisCall:
return "ThisCall";
case CallingConvention.FastCall:
return "FastCall";
}
return "Winapi";
}
public void GenerateDebug(Declaration decl)
{
if(Options.OutputDebug && !String.IsNullOrWhiteSpace(decl.DebugText))
WriteLine("// DEBUG: " + decl.DebugText);
}
public void GenerateSummary(string comment)
{
if(String.IsNullOrWhiteSpace(comment))
return;
WriteLine("/// <summary>");
WriteLine("/// {0}", comment);
WriteLine("/// </summary>");
}
public void GenerateInlineSummary(string comment)
{
if(String.IsNullOrWhiteSpace(comment))
return;
WriteLine("/// <summary>{0}</summary>", comment);
}
}
}

238
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -0,0 +1,238 @@
using System;
using Cxxi.Types;
namespace Cxxi.Generators.CSharp
{
public class CSharpTypePrinter : ITypePrinter, IDeclVisitor<string>
{
public Library Library { get; set; }
private readonly ITypeMapDatabase TypeMapDatabase;
public CSharpTypePrinter(ITypeMapDatabase database, Library library)
{
TypeMapDatabase = database;
Library = library;
}
public string VisitTagType(TagType tag, TypeQualifiers quals)
{
if (tag.Declaration == null)
return string.Empty;
return VisitDeclaration(tag.Declaration, quals);
}
public string VisitArrayType(ArrayType array, TypeQualifiers quals)
{
return string.Format("{0}[]", array.Type.Visit(this));
// C# only supports fixed arrays in unsafe sections
// and they are constrained to a set of built-in types.
}
public string VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var arguments = function.Arguments;
var returnType = function.ReturnType;
var args = string.Empty;
if (arguments.Count > 0)
args = GetArgumentsString(function, hasNames: false);
if (returnType.IsPrimitiveType(PrimitiveType.Void))
{
if (!string.IsNullOrEmpty(args))
args = string.Format("<{0}>", args);
return string.Format("Action{0}", args);
}
if (!string.IsNullOrEmpty(args))
args = string.Format(", {0}", args);
return string.Format("Func<{0}{1}>", returnType.Visit(this), args);
}
public string VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
var pointee = pointer.Pointee;
if (pointee is FunctionType)
{
var function = pointee as FunctionType;
return string.Format("{0}", function.Visit(this, quals));
}
if (pointee.IsPrimitiveType(PrimitiveType.Void, walkTypedefs: true) ||
pointee.IsPrimitiveType(PrimitiveType.UInt8, walkTypedefs: true))
{
return "IntPtr";
}
if (pointee.IsPrimitiveType(PrimitiveType.Char) && quals.IsConst)
{
return "string";
}
return pointee.Visit(this, quals);
}
public string VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type, quals);
}
public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
TypeMap typeMap = null;
if (TypeMapDatabase.FindTypeMap(decl, out typeMap))
{
return typeMap.Signature();
}
FunctionType func;
if (decl.Type.IsPointerTo<FunctionType>(out func))
{
// TODO: Use SafeIdentifier()
return string.Format("{0}", VisitDeclaration(decl));
}
return decl.Type.Visit(this);
}
public string VisitTemplateSpecializationType(TemplateSpecializationType template, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers quals)
{
switch (primitive)
{
case PrimitiveType.Bool: return "bool";
case PrimitiveType.Void: return "void";
case PrimitiveType.WideChar: return "char";
case PrimitiveType.Int8: return "sbyte";
case PrimitiveType.UInt8: return "byte";
case PrimitiveType.Int16: return "short";
case PrimitiveType.UInt16: return "ushort";
case PrimitiveType.Int32: return "int";
case PrimitiveType.UInt32: return "uint";
case PrimitiveType.Int64: return "long";
case PrimitiveType.UInt64: return "ulong";
case PrimitiveType.Float: return "float";
case PrimitiveType.Double: return "double";
}
throw new NotSupportedException();
}
public string VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
return VisitDeclaration(decl);
}
public string VisitDeclaration(Declaration decl)
{
var name = decl.Visit(this);
return string.Format("{0}", name);
}
public string VisitClassDecl(Class @class)
{
return @class.Name;
}
public string VisitFieldDecl(Field field)
{
throw new NotImplementedException();
}
public string VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public string VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public string VisitParameterDecl(Parameter parameter)
{
throw new NotImplementedException();
}
public string VisitTypedefDecl(TypedefDecl typedef)
{
return typedef.Name;
}
public string VisitEnumDecl(Enumeration @enum)
{
return @enum.Name;
}
public string VisitClassTemplateDecl(ClassTemplate template)
{
throw new NotImplementedException();
}
public string VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public string VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
public string VisitNamespace(Namespace @namespace)
{
throw new NotImplementedException();
}
public string GetArgumentsString(FunctionType function, bool hasNames)
{
var arguments = function.Arguments;
var s = string.Empty;
for (var i = 0; i < arguments.Count; ++i)
{
s += GetArgumentString(arguments[i], hasNames);
if (i < arguments.Count - 1)
s += ", ";
}
return s;
}
public string GetArgumentString(Parameter arg, bool hasName)
{
var quals = new TypeQualifiers { IsConst = arg.IsConst };
var type = arg.Type.Visit(this, quals);
var name = arg.Name;
if (hasName && !string.IsNullOrEmpty(name))
return string.Format("{0} {1}", type, name);
return type;
}
public string ToDelegateString(FunctionType function)
{
return string.Format("delegate {0} {{0}}({1})",
function.ReturnType.Visit(this),
GetArgumentsString(function, hasNames: true));
}
}
}
Loading…
Cancel
Save