Browse Source

Added TypeReferenceCollector used for include and forward reference printing. TypeMaps are now able to add includes and forward references. Record system allows more complex situations where you need a declaration's origin type/declaration.

pull/13/head
marcos henrich 12 years ago
parent
commit
06ab4864e2
  1. 235
      src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs
  2. 41
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  3. 37
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  4. 1
      src/Generator/Generators/CLI/CLITextTemplate.cs
  5. 162
      src/Generator/Generators/CLI/CLITypeReferences.cs
  6. 3
      src/Generator/Types/TypeMap.cs

235
src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs

@ -1,235 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using CppSharp.AST;
using CppSharp.Types;
namespace CppSharp.Generators.CLI
{
public struct CLIForwardReference
{
public Declaration Declaration;
public Namespace Namespace;
public string Text;
}
public class CLIForwardReferencePrinter : IDeclVisitor<bool>
{
public readonly IList<string> Includes;
public readonly IList<CLIForwardReference> Refs;
private readonly TypeRefsVisitor TypeRefs;
public TypeReference CurrentTypeReference;
private readonly ITypeMapDatabase TypeMapDatabase;
public CLIForwardReferencePrinter(TypeRefsVisitor typeRefs, ITypeMapDatabase typeMapDatabase)
{
Includes = new List<string>();
Refs = new List<CLIForwardReference>();
TypeRefs = typeRefs;
TypeMapDatabase = typeMapDatabase;
}
public void Process()
{
foreach (var typeRef in TypeRefs.References)
{
CurrentTypeReference = typeRef;
typeRef.Declaration.Visit(this);
}
foreach (var baseClass in TypeRefs.Bases)
VisitBaseClass(baseClass);
}
public void VisitBaseClass(Class @class)
{
if (@class.IsIncomplete)
@class = @class.CompleteDeclaration as Class;
if (@class == null)
return;
Includes.Add(GetHeaderFromDecl(@class));
}
public bool VisitDeclaration(Declaration decl)
{
throw new NotImplementedException();
}
public bool VisitClassDecl(Class @class)
{
var completeDecl = @class.CompleteDeclaration as Class;
if (@class.IsIncomplete && completeDecl != null)
return VisitClassDecl(completeDecl);
if (@class.IsValueType)
{
Refs.Add(new CLIForwardReference()
{
Declaration = @class,
Namespace = CurrentTypeReference.Namespace,
Text = string.Format("value struct {0};", @class.Name)
});
return true;
}
Refs.Add(new CLIForwardReference()
{
Declaration = @class,
Namespace = CurrentTypeReference.Namespace,
Text = string.Format("ref class {0};", @class.Name)
});
return true;
}
public bool VisitFieldDecl(Field field)
{
Class @class;
if (field.Type.IsTagDecl(out @class))
{
if (@class.IsValueType)
Includes.Add(GetHeaderFromDecl(@class));
else
VisitClassDecl(@class);
return true;
}
Enumeration @enum;
if (field.Type.IsTagDecl(out @enum))
return VisitEnumDecl(@enum);
Includes.Add(GetHeaderFromDecl(field));
return true;
}
public bool VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public bool VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public bool VisitParameterDecl(Parameter parameter)
{
throw new NotImplementedException();
}
public string GetHeaderFromDecl(Declaration decl)
{
var @namespace = decl.Namespace;
var unit = @namespace.TranslationUnit;
if (unit.Ignore)
return string.Empty;
if (unit.IsSystemHeader)
return string.Empty;
return Path.GetFileNameWithoutExtension(unit.FileName);
}
public bool VisitTypedefDecl(TypedefDecl typedef)
{
FunctionType function;
if (typedef.Type.IsPointerTo<FunctionType>(out function))
{
Includes.Add(GetHeaderFromDecl(typedef));
return true;
}
throw new NotImplementedException();
}
public bool VisitEnumDecl(Enumeration @enum)
{
Includes.Add(GetHeaderFromDecl(@enum));
if (@enum.Type.IsPrimitiveType(PrimitiveType.Int32))
{
Refs.Add(new CLIForwardReference()
{
Declaration = @enum,
Namespace = CurrentTypeReference.Namespace,
Text = string.Format("enum struct {0};", @enum.Name)
});
return true;
}
Refs.Add(new CLIForwardReference()
{
Declaration = @enum,
Namespace = CurrentTypeReference.Namespace,
Text = string.Format("enum struct {0} : {1};", @enum.Name, @enum.Type)
});
return true;
}
public bool VisitVariableDecl(Variable variable)
{
throw new NotImplementedException();
}
public bool VisitClassTemplateDecl(ClassTemplate template)
{
var decl = template.TemplatedDecl;
TypeMap typeMap = null;
if (TypeMapDatabase.FindTypeMap(decl, out typeMap))
{
typeMap.Declaration = decl;
typeMap.CLIForwardReference(this);
return true;
}
if(decl.Ignore)
return true;
Includes.Add(GetHeaderFromDecl(template));
var @params = string.Empty;
for(var i = 0; i < template.Parameters.Count; i++)
@params = string.Format("{0}{1}typename {2}", @params, (i>0)? ", " : "", template.Parameters[i].Name);
Refs.Add(new CLIForwardReference()
{
Declaration = template,
Namespace = CurrentTypeReference.Namespace,
Text = string.Format("generic<{0}> ref class {1};", @params, template.TemplatedClass.QualifiedName)
});
return true;
}
public bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public bool VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
public bool VisitNamespace(Namespace @namespace)
{
throw new NotImplementedException();
}
public bool VisitEvent(Event @event)
{
throw new NotImplementedException();
}
public bool VisitProperty(Property property)
{
throw new NotImplementedException();
}
}
}

41
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -46,47 +46,38 @@ namespace CppSharp.Generators.CLI
public void GenerateIncludeForwardRefs() public void GenerateIncludeForwardRefs()
{ {
var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor; var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase);
typeReferenceCollector.Process(TranslationUnit);
var forwardRefsPrinter = new CLIForwardReferencePrinter(typeRefs, Driver.TypeDatabase);
forwardRefsPrinter.Process();
var includes = new SortedSet<string>(StringComparer.InvariantCulture); var includes = new SortedSet<string>(StringComparer.InvariantCulture);
foreach (var include in forwardRefsPrinter.Includes) foreach (var typeRef in typeReferenceCollector.TypeReferences)
{ {
if (string.IsNullOrWhiteSpace(include)) if (typeRef.Include.File == TranslationUnit.FileName)
continue;
if (include == Path.GetFileNameWithoutExtension(TranslationUnit.FileName))
continue; continue;
includes.Add(string.Format("#include \"{0}.h\"", include)); var include = typeRef.Include;
if(!string.IsNullOrEmpty(include.File) && include.InHeader)
includes.Add(include.ToString());
} }
foreach (var include in Includes)
includes.Add(include.ToString());
foreach (var include in includes) foreach (var include in includes)
WriteLine(include); WriteLine(include);
} }
public void GenerateForwardRefs(Namespace @namespace) public void GenerateForwardRefs(Namespace @namespace)
{ {
var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor; var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase);
typeReferenceCollector.Process(@namespace);
var forwardRefsPrinter = new CLIForwardReferencePrinter(typeRefs, Driver.TypeDatabase);
forwardRefsPrinter.Process();
// Use a set to remove duplicate entries. // Use a set to remove duplicate entries.
var forwardRefs = new SortedSet<string>(StringComparer.InvariantCulture); var forwardRefs = new SortedSet<string>(StringComparer.InvariantCulture);
foreach (var forwardRef in forwardRefsPrinter.Refs) foreach (var typeRef in typeReferenceCollector.TypeReferences)
{ {
if (forwardRef.Namespace != @namespace) var @ref = typeRef.FowardReference;
continue; if(!string.IsNullOrEmpty(@ref) && !typeRef.Include.InHeader)
forwardRefs.Add(@ref);
forwardRefs.Add(forwardRef.Text);
} }
foreach (var forwardRef in forwardRefs) foreach (var forwardRef in forwardRefs)
@ -259,8 +250,8 @@ namespace CppSharp.Generators.CLI
PushIndent(); PushIndent();
WriteLine("property System::IntPtr Instance"); WriteLine("property System::IntPtr Instance");
WriteStartBraceIndent(); WriteStartBraceIndent();
WriteLine("virtual System::IntPtr get();"); WriteLine("virtual System::IntPtr get() override;");
WriteLine("virtual void set(System::IntPtr instance);"); WriteLine("virtual void set(System::IntPtr instance) override;");
WriteCloseBraceIndent(); WriteCloseBraceIndent();
NewLine(); NewLine();

37
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -52,38 +52,22 @@ namespace CppSharp.Generators.CLI
public void GenerateForwardReferenceHeaders() public void GenerateForwardReferenceHeaders()
{ {
PushBlock(CLIBlockKind.IncludesForwardReferences); PushBlock(CLIBlockKind.IncludesForwardReferences);
var includes = new SortedSet<string>(StringComparer.InvariantCulture);
var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor;
// Generate the forward references.
foreach (var forwardRef in typeRefs.References)
{
var decl = forwardRef.Declaration;
if (decl.IsIncomplete && decl.CompleteDeclaration != null)
decl = decl.CompleteDeclaration;
var @namespace = decl.Namespace; var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase);
var translationUnit = @namespace.TranslationUnit; typeReferenceCollector.Process(TranslationUnit);
if (translationUnit.Ignore) var includes = new SortedSet<string>(StringComparer.InvariantCulture);
continue;
if (translationUnit.IsSystemHeader)
continue;
var includeName = Path.GetFileNameWithoutExtension(translationUnit.FileName);
if (includeName == Path.GetFileNameWithoutExtension(TranslationUnit.FileName)) foreach (var typeRef in typeReferenceCollector.TypeReferences)
{
if (typeRef.Include.File == TranslationUnit.FileName)
continue; continue;
includes.Add(string.Format("#include \"{0}.h\"", includeName.Replace('\\', '/'))); var include = typeRef.Include;
if(!string.IsNullOrEmpty(include.File) && !include.InHeader)
includes.Add(include.ToString());
} }
foreach (var include in Includes)
includes.Add(include.ToString());
foreach (var include in includes) foreach (var include in includes)
WriteLine(include); WriteLine(include);
@ -726,8 +710,7 @@ namespace CppSharp.Generators.CLI
if (IsNativeFunctionOrStaticMethod(function)) if (IsNativeFunctionOrStaticMethod(function))
{ {
Write("::"); Write("::{0}(", function.QualifiedOriginalName);
Write("{0}(", function.QualifiedOriginalName);
} }
else else
{ {

1
src/Generator/Generators/CLI/CLITextTemplate.cs

@ -15,6 +15,7 @@ namespace CppSharp.Generators.CLI
public string File; public string File;
public IncludeKind Kind; public IncludeKind Kind;
public bool InHeader;
public override string ToString() public override string ToString()
{ {

162
src/Generator/Generators/CLI/CLITypeReferences.cs

@ -0,0 +1,162 @@
using System.Collections.Generic;
using CppSharp.AST;
using CppSharp.Generators.AST;
using CppSharp.Types;
namespace CppSharp.Generators.CLI
{
public class CLITypeReference
{
public Include Include;
public string FowardReference;
}
public class CLITypeReferenceCollector : AstVisitor
{
private Dictionary<Declaration, CLITypeReference> typeReferences;
private readonly ITypeMapDatabase TypeMapDatabase;
private TranslationUnit TranslationUnit;
public IEnumerable<CLITypeReference> TypeReferences
{
get { return typeReferences.Values; }
}
public CLITypeReferenceCollector(ITypeMapDatabase typeMapDatabase)
{
TypeMapDatabase = typeMapDatabase;
typeReferences = new Dictionary<Declaration,CLITypeReference>();
}
public CLITypeReference GetTypeReference(Declaration decl)
{
if(typeReferences.ContainsKey(decl))
return typeReferences[decl];
var @ref = new CLITypeReference();
typeReferences.Add(decl, @ref);
return @ref;
}
public void Process(Namespace @namespace)
{
var collector = new RecordCollector(@namespace.TranslationUnit);
@namespace.Visit(collector);
TranslationUnit = @namespace.TranslationUnit;
foreach (var record in collector.Declarations)
{
record.Value.Visit(this);
GenerateInclude(record);
ProcessTypeMap(record);
}
}
private void ProcessTypeMap(ASTRecord<Declaration> record)
{
TypeMap typeMap;
if (!TypeMapDatabase.FindTypeMap(record.Value, out typeMap)) return;
// Typemap must explicitly set the include file when one is required.
GetTypeReference(record.Value).Include.File = "";
typeMap.Declaration = record.Value;
typeMap.CLITypeReference(this, record);
}
private void GenerateInclude(ASTRecord<Declaration> record)
{
var decl = record.Value;
if(decl.Namespace == null)
return;
var declFile = decl.Namespace.TranslationUnit.FileName;
if(decl.Namespace.TranslationUnit.IsSystemHeader)
return;
if(decl.Ignore)
return;
if(IsBuiltinTypedef(decl))
return;
if (declFile.Contains("String"))
return;
GetTypeReference(decl).Include = new Include()
{
File = declFile,
Kind = Include.IncludeKind.Quoted,
InHeader = IsIncludeInHeader(record)
};
}
private bool IsBuiltinTypedef(Declaration decl)
{
var typedefDecl = decl as TypedefDecl;
if(typedefDecl == null) return false;
if(typedefDecl.Type is BuiltinType) return true;
var typedefType = typedefDecl.Type as TypedefType;
if(typedefType == null) return false;
if(typedefType.Declaration == null) return false;
return typedefType.Declaration.Type is BuiltinType;
}
private bool IsIncludeInHeader(ASTRecord<Declaration> record)
{
return record.IsBaseClass() || record.IsFieldValueType();
}
public override bool VisitDeclaration(Declaration decl)
{
return ShouldVisitDecl(decl);
}
public override bool VisitClassDecl(Class @class)
{
if(!ShouldVisitDecl(@class))
return false;
if (@class.IsIncomplete && @class.CompleteDeclaration != null)
@class = (Class) @class.CompleteDeclaration;
var keywords = @class.IsValueType? "value struct" : "ref class";
var @ref = string.Format("{0} {1};", keywords, @class.Name);
GetTypeReference(@class).FowardReference = @ref;
return false;
}
public override bool VisitEnumDecl(Enumeration @enum)
{
if(!ShouldVisitDecl(@enum))
return false;
var @base = "";
if(!@enum.Type.IsPrimitiveType(PrimitiveType.Int32))
@base = string.Format(" : {0}", @enum.Type);
var @ref = string.Format("enum struct {0}{1};", @enum.Name, @base);
GetTypeReference(@enum).FowardReference = @ref;
return false;
}
private bool ShouldVisitDecl(Declaration decl)
{
if(decl.Namespace != null && decl.Namespace.TranslationUnit.IsSystemHeader)
return false;
if (decl.Ignore)
return false;
return true;
}
}
}

3
src/Generator/Types/TypeMap.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.Generators; using CppSharp.Generators;
using CppSharp.Generators.AST;
using CppSharp.Generators.CLI; using CppSharp.Generators.CLI;
using CppSharp.Generators.CSharp; using CppSharp.Generators.CSharp;
using Type = CppSharp.AST.Type; using Type = CppSharp.AST.Type;
@ -65,7 +66,7 @@ namespace CppSharp.Types
throw new NotImplementedException(); throw new NotImplementedException();
} }
public virtual void CLIForwardReference(CLIForwardReferencePrinter ctx) public virtual void CLITypeReference(CLITypeReferenceCollector collector, ASTRecord<Declaration> loc)
{ {
} }

Loading…
Cancel
Save