mirror of https://github.com/mono/CppSharp.git
3 changed files with 591 additions and 0 deletions
@ -0,0 +1,39 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,314 @@
@@ -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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,238 @@
@@ -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…
Reference in new issue