mirror of https://github.com/mono/CppSharp.git
5 changed files with 265 additions and 30 deletions
@ -0,0 +1,248 @@ |
|||||||
|
using CppSharp.AST; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.C |
||||||
|
{ |
||||||
|
public struct CInclude |
||||||
|
{ |
||||||
|
public enum IncludeKind |
||||||
|
{ |
||||||
|
Angled, |
||||||
|
Quoted |
||||||
|
} |
||||||
|
|
||||||
|
public string File; |
||||||
|
public TranslationUnit TranslationUnit; |
||||||
|
|
||||||
|
public IncludeKind Kind; |
||||||
|
public bool InHeader; |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return string.Format(Kind == IncludeKind.Angled ? |
||||||
|
"#include <{0}>" : "#include \"{0}\"", File); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public abstract class CCodeGenerator : CodeGenerator |
||||||
|
{ |
||||||
|
public CCodeGenerator(BindingContext context) |
||||||
|
: base(context) |
||||||
|
{ |
||||||
|
VisitOptions.VisitPropertyAccessors = true; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual string QualifiedName(Declaration decl) |
||||||
|
{ |
||||||
|
if (Options.GeneratorKind == GeneratorKind.CPlusPlus) |
||||||
|
return decl.Name; |
||||||
|
|
||||||
|
return decl.QualifiedName; |
||||||
|
} |
||||||
|
|
||||||
|
public override string GeneratedIdentifier(string id) |
||||||
|
{ |
||||||
|
return "__" + id.Replace('-', '_'); |
||||||
|
} |
||||||
|
|
||||||
|
private CppTypePrinter typePrinter = new CppTypePrinter(); |
||||||
|
public virtual CppTypePrinter CTypePrinter => typePrinter; |
||||||
|
|
||||||
|
public virtual void WriteHeaders() { } |
||||||
|
|
||||||
|
public virtual void WriteInclude(CInclude include) |
||||||
|
{ |
||||||
|
WriteLine(include.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitDeclaration(Declaration decl) |
||||||
|
{ |
||||||
|
return decl.IsGenerated && !AlreadyVisited(decl); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual string GetMethodIdentifier(Method method) => method.Name; |
||||||
|
|
||||||
|
public override void GenerateMethodSpecifier(Method method, Class @class) |
||||||
|
{ |
||||||
|
var retType = method.ReturnType.Visit(CTypePrinter); |
||||||
|
Write($"{retType} {GetMethodIdentifier(method)}("); |
||||||
|
Write(CTypePrinter.VisitParameters(method.Parameters)); |
||||||
|
Write(")"); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefDecl(TypedefDecl typedef) |
||||||
|
{ |
||||||
|
if (!VisitDeclaration(typedef)) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(); |
||||||
|
|
||||||
|
var typeName = typedef.Type.Visit(CTypePrinter); |
||||||
|
WriteLine($"typedef {typeName} {typedef};"); |
||||||
|
|
||||||
|
var newlineKind = NewLineKind.BeforeNextBlock; |
||||||
|
|
||||||
|
var declarations = typedef.Namespace.Declarations.ToList(); |
||||||
|
var newIndex = declarations.FindIndex(d => d == typedef) + 1; |
||||||
|
if (newIndex < declarations.Count) |
||||||
|
{ |
||||||
|
if (declarations[newIndex] is TypedefDecl) |
||||||
|
newlineKind = NewLineKind.Never; |
||||||
|
} |
||||||
|
|
||||||
|
PopBlock(newlineKind); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEnumDecl(Enumeration @enum) |
||||||
|
{ |
||||||
|
if (!VisitDeclaration(@enum)) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(); |
||||||
|
|
||||||
|
var useTypedefEnum = Options.GeneratorKind == GeneratorKind.C; |
||||||
|
var enumName = Options.GeneratorKind != GeneratorKind.CPlusPlus ? |
||||||
|
QualifiedName(@enum) : @enum.Name; |
||||||
|
|
||||||
|
var enumKind = @enum.IsScoped ? "enum class" : "enum"; |
||||||
|
|
||||||
|
if (useTypedefEnum) |
||||||
|
Write($"typedef {enumKind} {enumName}"); |
||||||
|
else |
||||||
|
Write($"{enumKind} {enumName}"); |
||||||
|
|
||||||
|
if (Options.GeneratorKind == GeneratorKind.CPlusPlus) |
||||||
|
{ |
||||||
|
var typeName = CTypePrinter.VisitPrimitiveType( |
||||||
|
@enum.BuiltinType.Type, new TypeQualifiers()); |
||||||
|
|
||||||
|
if (@enum.BuiltinType.Type != PrimitiveType.Int) |
||||||
|
Write($" : {typeName}"); |
||||||
|
} |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
foreach (var item in @enum.Items) |
||||||
|
{ |
||||||
|
var enumItemName = Options.GeneratorKind != GeneratorKind.CPlusPlus ? |
||||||
|
$"{@enum.QualifiedName}_{item.Name}" : item.Name; |
||||||
|
|
||||||
|
Write(enumItemName); |
||||||
|
|
||||||
|
if (item.ExplicitValue) |
||||||
|
Write($" = {@enum.GetItemValueAsString(item)}"); |
||||||
|
|
||||||
|
if (item != @enum.Items.Last()) |
||||||
|
WriteLine(","); |
||||||
|
} |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
Unindent(); |
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(enumName) && useTypedefEnum) |
||||||
|
WriteLine($"}} {enumName};"); |
||||||
|
else |
||||||
|
WriteLine($"}};"); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetAccess(AccessSpecifier accessSpecifier) |
||||||
|
{ |
||||||
|
switch (accessSpecifier) |
||||||
|
{ |
||||||
|
case AccessSpecifier.Private: |
||||||
|
return "private"; |
||||||
|
case AccessSpecifier.Internal: |
||||||
|
return string.Empty; |
||||||
|
case AccessSpecifier.Protected: |
||||||
|
return "protected"; |
||||||
|
default: |
||||||
|
return "public"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void GenerateClassSpecifier(Class @class) |
||||||
|
{ |
||||||
|
var keywords = new List<string>(); |
||||||
|
|
||||||
|
if (Options.GeneratorKind == GeneratorKind.CLI) |
||||||
|
{ |
||||||
|
keywords.Add(AccessIdentifier(@class.Access)); |
||||||
|
|
||||||
|
if (@class.IsAbstract) |
||||||
|
keywords.Add("abstract"); |
||||||
|
} |
||||||
|
|
||||||
|
if (@class.IsFinal) |
||||||
|
keywords.Add("final"); |
||||||
|
|
||||||
|
if (@class.IsStatic) |
||||||
|
keywords.Add("static"); |
||||||
|
|
||||||
|
if (Options.GeneratorKind == GeneratorKind.CLI) |
||||||
|
keywords.Add(@class.IsInterface ? "interface" : "class"); |
||||||
|
else |
||||||
|
keywords.Add("class"); |
||||||
|
|
||||||
|
keywords.Add(@class.Name); |
||||||
|
|
||||||
|
keywords = keywords.Where(s => !string.IsNullOrWhiteSpace(s)).ToList(); |
||||||
|
if (keywords.Count != 0) |
||||||
|
Write("{0}", string.Join(" ", keywords)); |
||||||
|
|
||||||
|
var bases = @class.Bases.Where(@base => @base.IsGenerated && |
||||||
|
@base.IsClass && @base.Class.IsGenerated).ToList(); |
||||||
|
|
||||||
|
if (bases.Count > 0 && !@class.IsStatic) |
||||||
|
{ |
||||||
|
var classes = bases.Select(@base => |
||||||
|
$"{GetAccess(@base.Access)} {@base.Class.Visit(CTypePrinter)}"); |
||||||
|
if (classes.Count() > 0) |
||||||
|
Write(" : {0}", string.Join(", ", classes)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (!VisitDeclaration(@class)) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(); |
||||||
|
|
||||||
|
GenerateClassSpecifier(@class); |
||||||
|
NewLine(); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
VisitDeclContext(@class); |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
WriteLine("};"); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefNameDecl(TypedefNameDecl typedef) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitVariableDecl(Variable variable) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue