Merge pull request #537 from tritao/swift-improvements

[swift] Swift backend implementation improvements
This commit is contained in:
João Matos 2017-11-07 12:28:46 +00:00 коммит произвёл GitHub
Родитель c491dd33cc 4a3d186528
Коммит 36e32c87bf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 204 добавлений и 156 удалений

Просмотреть файл

@ -178,7 +178,8 @@ namespace Embeddinator
}
//NOTE: Choosing Java generator, needs to imply the C generator
if (Generators.Contains(GeneratorKind.Java) && !Generators.Contains(GeneratorKind.C))
if ((Generators.Contains(GeneratorKind.Java) || Generators.Contains(GeneratorKind.Swift)) &&
!Generators.Contains(GeneratorKind.C))
{
Generators.Insert(0, GeneratorKind.C);
}

Просмотреть файл

@ -95,19 +95,35 @@ namespace Embeddinator
"Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs");
var sdk = Directory.EnumerateDirectories(sdkPath).First();
var args = new List<string> {
"-emit-module",
$"-emit-module-path {Options.OutputDir}",
$"-module-name {moduleName}",
$"-swift-version {swiftVersion}",
$"-sdk {sdk}",
string.Join(" ", files.ToList())
};
bool compileSuccess = true;
var invocation = string.Join(" ", args);
var output = Invoke(swiftcBin, invocation);
foreach (var file in files)
{
var args = new List<string>
{
"-emit-module",
$"-emit-module-path {Options.OutputDir}",
$"-module-name {moduleName}",
$"-swift-version {swiftVersion}",
$"-sdk {sdk}",
$"-I \"{MonoSdkPath}/include/mono-2.0\"",
};
return output.ExitCode == 0;
var bridgingHeader = Directory.EnumerateFiles(Options.OutputDir, "*.h")
.SingleOrDefault(header => Path.GetFileNameWithoutExtension(header) ==
Path.GetFileNameWithoutExtension(file));
args.Add($"-import-objc-header {bridgingHeader}");
args.Add(file);
var invocation = string.Join(" ", args);
var output = Invoke(swiftcBin, invocation);
compileSuccess &= output.ExitCode == 0;
}
return compileSuccess;
}
bool CompileJava(IEnumerable<string> files)

Просмотреть файл

@ -426,7 +426,7 @@ namespace Embeddinator.Generators
}
else if (managedType.IsArray)
{
if (Options.GeneratorKind == GeneratorKind.Java)
if (Options.GeneratorKind == GeneratorKind.Java || Options.GeneratorKind == GeneratorKind.Swift)
return new QualifiedType(new UnsupportedType { Description = managedType.FullName });
var array = new ArrayType

Просмотреть файл

@ -152,9 +152,6 @@ namespace Embeddinator.Generators
case PrimitiveType.ULong: return "UnsignedLong";
case PrimitiveType.LongLong: return "LongLong";
case PrimitiveType.ULongLong: return "UnsignedLongLong";
case PrimitiveType.Int128: return "__int128";
case PrimitiveType.UInt128: return "__uint128_t";
case PrimitiveType.Half: return "__fp16";
case PrimitiveType.Float: return useReferencePrimitiveTypes ? "Float" : "float";
case PrimitiveType.Double: return useReferencePrimitiveTypes ? "Double" : "double";
case PrimitiveType.IntPtr:

Просмотреть файл

@ -1,9 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using CppSharp;
using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.Passes;
namespace Embeddinator.Generators
{
@ -11,17 +9,12 @@ namespace Embeddinator.Generators
{
public SwiftTypePrinter TypePrinter { get; internal set; }
public static string IntPtrType = "UnsafePointer<Void>";
PassBuilder<TranslationUnitPass> Passes;
public static string IntPtrType = "UnsafeRawPointer";
public SwiftGenerator(BindingContext context)
: base(context)
{
TypePrinter = new SwiftTypePrinter(Context);
Passes = new PassBuilder<TranslationUnitPass>(Context);
CGenerator.SetupPasses(Passes);
}
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
@ -29,16 +22,7 @@ namespace Embeddinator.Generators
var unit = units.First();
var sources = new SwiftSources(Context, unit);
// Also generate a separate file with equivalent of P/Invoke declarations.
var nativeSources = GenerateNativeDeclarations(unit);
return new List<CodeGenerator> { sources, nativeSources };
}
public CodeGenerator GenerateNativeDeclarations(TranslationUnit unit)
{
CGenerator.RunPasses(Context, Passes);
return new SwiftNative(Context, unit);
return new List<CodeGenerator> { sources };
}
public override bool SetupPasses()

Просмотреть файл

@ -1,5 +1,4 @@
using CppSharp.AST;
using CppSharp.AST.Extensions;
namespace Embeddinator.Generators
{
@ -36,24 +35,74 @@ namespace Embeddinator.Generators
public override bool VisitClassDecl(Class @class)
{
Context.Return.Write($"{Context.ArgName}");
var objectRef = @class.IsInterface ? "__getObject()" : "__object!";
Context.Return.Write($"{Context.ArgName}.{objectRef}");
return true;
}
public void HandleRefOutPrimitiveType(PrimitiveType type, Enumeration @enum = null)
{
Context.Return.Write(Context.ArgName);
}
public override bool VisitEnumDecl(Enumeration @enum)
{
Context.Return.Write(Context.ArgName);
return true;
}
void HandleDecimalType()
{
var decimalId = SwiftGenerator.GeneratedIdentifier($"{Context.Parameter.Name}_decimal");
var @var = IsByRefParameter ? "var" : "let";
Context.SupportBefore.WriteLine($"{@var} {decimalId} : MonoDecimal = mono_embeddinator_string_to_decimal(\"\")");
var pointerId = "pointer";
if (IsByRefParameter)
{
Context.SupportBefore.WriteLine($"withUnsafeMutablePointer(to: &{decimalId}) {{ ({pointerId}) in");
Context.SupportAfter.WriteLine("}");
}
Context.Return.Write(IsByRefParameter ? pointerId : decimalId);
}
public void HandleRefOutPrimitiveType(PrimitiveType type)
{
if (type == PrimitiveType.String)
{
var gstringId = $"{Context.ReturnVarName}_gstring";
Context.SupportBefore.WriteLine($"let {gstringId} : UnsafeMutablePointer<GString> = g_string_new(\"\")");
Context.SupportBefore.WriteLine($"g_string_free({gstringId}, 1)");
Context.Return.Write(gstringId);
return;
}
else if (type == PrimitiveType.Decimal)
{
HandleDecimalType();
return;
}
Context.Return.Write($"&{Context.ArgName}");
}
public override bool VisitPrimitiveType(PrimitiveType type,
TypeQualifiers quals)
{
if (IsByRefParameter)
{
HandleRefOutPrimitiveType(type);
return true;
}
if (type == PrimitiveType.Char)
{
Context.Return.Write($"gunichar2({Context.ArgName}.unicodeScalars.first!.value)");
return true;
}
else if (type == PrimitiveType.Decimal)
{
HandleDecimalType();
return true;
}
Context.Return.Write(Context.ArgName);
return true;
}
@ -82,7 +131,15 @@ namespace Embeddinator.Generators
public override bool VisitClassDecl(Class @class)
{
Context.Return.Write(Context.ReturnVarName);
var typePrinter = new SwiftTypePrinter(Context.Context);
var typeName = @class.Visit(typePrinter);
//if (@class.IsInterface || @class.IsAbstract)
//typeName = $"{typeName}Impl";
Context.Return.Write($"{typeName}()");
//Context.Return.Write(Context.ReturnVarName);
return true;
}
@ -95,8 +152,41 @@ namespace Embeddinator.Generators
public override bool VisitPrimitiveType(PrimitiveType type,
TypeQualifiers quals)
{
if (type == PrimitiveType.Char)
{
Context.Return.Write($"Character(Unicode.Scalar({Context.ReturnVarName})!)");
return true;
}
else if (type == PrimitiveType.String)
{
Context.Return.Write($"String(cString: {Context.ReturnVarName})");
return true;
}
else if (type == PrimitiveType.Decimal)
{
HandleDecimalType();
return true;
}
Context.Return.Write(Context.ReturnVarName);
return true;
}
void HandleDecimalType()
{
var gstringId = $"{Context.ReturnVarName}_gstring";
Context.SupportBefore.Write($"let {gstringId} : UnsafeMutablePointer<GString> = ");
Context.SupportBefore.WriteLine($"mono_embeddinator_decimal_to_gstring({Context.ReturnVarName})");
var stringId = $"{Context.ReturnVarName}_string";
Context.SupportBefore.WriteLine($"let {stringId} : String = String(cString: {gstringId}.pointee.str)");
var decimalId = $"{Context.ReturnVarName}_decimal";
Context.SupportBefore.WriteLine($"let {decimalId} : Decimal = Decimal(string: {stringId})!");
Context.SupportBefore.WriteLine($"g_string_free({gstringId}, 1)");
Context.Return.Write(decimalId);
}
}
}

Просмотреть файл

@ -1,96 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using CppSharp;
using CppSharp.AST;
using CppSharp.Generators;
namespace Embeddinator.Generators
{
/// <summary>
/// This class is responsible for generating JNA-compatible method and class
/// Java code for a given managed library represented as a translation unit.
/// </summary>
[DebuggerDisplay("Unit = {TranslationUnit}")]
public class SwiftNative : SwiftSources
{
public SwiftNative(BindingContext context, TranslationUnit unit)
: base(context, unit)
{
}
public static string GetNativeLibClassName(TranslationUnit unit) =>
GetNativeLibClassName(unit.FileName);
public static string GetNativeLibClassName(string fileName) =>
$"Native_{JavaGenerator.FileNameAsIdentifier(fileName)}";
public string ClassName => GetNativeLibClassName(TranslationUnit);
public override string FilePath => $"{ClassName}.{FileExtension}";
public override void Process()
{
GenerateFilePreamble(CommentKind.JavaDoc, "Embeddinator-4000");
GenerateImports();
TranslationUnit.Visit(this);
}
public override bool VisitTranslationUnit(TranslationUnit unit)
{
Write($"public class {ClassName} ");
WriteStartBraceIndent();
var ret = base.VisitTranslationUnit(unit);
WriteCloseBraceIndent();
return ret;
}
public static IEnumerable<Declaration> GetOverloadedDeclarations(Declaration decl)
{
var @class = decl.Namespace as Class;
return @class.Declarations.Where(d => d.OriginalName == decl.OriginalName);
}
public override bool VisitMethodDecl(Method method)
{
if (!VisitDeclaration(method))
return false;
if (method.IsImplicit)
return false;
PushBlock(BlockKind.Method, method);
TypePrinter.PushContext(TypePrinterContextKind.Native);
var returnTypeName = method.ReturnType.Visit(TypePrinter);
Write($"public static func {JavaNative.GetCMethodIdentifier(method)}(");
Write(TypePrinter.VisitParameters(method.Parameters, hasNames: true).ToString());
Write($") -> {returnTypeName};");
TypePrinter.PopContext();
PopBlock(NewLineKind.Never);
return true;
}
public override bool VisitClassDecl(Class @class)
{
if (!VisitDeclaration(@class))
return false;
VisitDeclContext(@class);
return true;
}
public override bool VisitEnumDecl(Enumeration @enum)
{
return VisitDeclaration(@enum);
}
}
}

Просмотреть файл

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using CppSharp;
@ -172,6 +173,21 @@ namespace Embeddinator.Generators
Write(" ");
WriteStartBraceIndent();
var hasNonInterfaceBase = @class.HasBaseClass && @class.BaseClass.IsGenerated
&& !@class.BaseClass.IsInterface;
var objectIdent = SwiftGenerator.GeneratedIdentifier("object");
if (!@class.IsStatic && !@class.IsInterface && !hasNonInterfaceBase)
{
TypePrinter.PushContext(TypePrinterContextKind.Native);
var typeName = @class.Visit(TypePrinter);
TypePrinter.PopContext();
WriteLine($"public var {objectIdent} : {typeName}");
NewLine();
}
VisitDeclContext(@class);
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
@ -277,6 +293,47 @@ namespace Embeddinator.Generators
@params.Add(marshal.Context.Return);
}
var hasReturn = !method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void) &&
!(method.IsConstructor || method.IsDestructor);
if (hasReturn)
{
TypePrinter.PushContext(TypePrinterContextKind.Native);
var typeName = method.ReturnType.Visit(TypePrinter);
TypePrinter.PopContext();
Write($"let __ret : {typeName.Type} = ");
}
var effectiveMethod = method.CompleteDeclaration as Method ?? method;
var nativeMethodId = JavaNative.GetCMethodIdentifier(effectiveMethod);
WriteLine($"{nativeMethodId}({string.Join(", ", @params)})");
foreach (var marshal in contexts)
{
if (!string.IsNullOrWhiteSpace(marshal.SupportAfter))
Write(marshal.SupportAfter);
}
if (hasReturn)
{
var ctx = new MarshalContext(Context)
{
ReturnType = method.ReturnType,
ReturnVarName = "__ret"
};
var marshal = new SwiftMarshalNativeToManaged(ctx);
method.ReturnType.Visit(marshal);
if (marshal.Context.Return.ToString().Length == 0)
throw new NotSupportedException($"Cannot marshal return type {method.ReturnType}");
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
WriteLine($"return {marshal.Context.Return}");
}
}
public override bool VisitTypedefDecl(TypedefDecl typedef)

Просмотреть файл

@ -29,7 +29,7 @@ namespace Embeddinator.Generators
public override TypePrinterResult VisitClassDecl(Class @class)
{
if (ContextKind == TypePrinterContextKind.Native)
return VisitPrimitiveType(PrimitiveType.IntPtr);
return $"UnsafeMutablePointer<{CGenerator.QualifiedName(@class)}>!";
return VisitDeclaration(@class);
}
@ -37,11 +37,13 @@ namespace Embeddinator.Generators
public override TypePrinterResult VisitParameter(Parameter param, bool hasName)
{
Parameter = param;
var type = param.QualifiedType.Visit(this);
var name = hasName ? $"{param.Name}" : string.Empty;
var inout = IsByRefParameter ? "inout " : string.Empty;
var type = param.QualifiedType.Visit(this);
Parameter = null;
var inout = IsByRefParameter ? "inout " : string.Empty;
return $"{name} : {inout}{type}";
}
@ -57,6 +59,9 @@ namespace Embeddinator.Generators
{
var isNative = ContextKind == TypePrinterContextKind.Native;
if (isNative && IsByRefParameter && primitive == PrimitiveType.String)
return "GString";
switch (primitive)
{
case PrimitiveType.Bool: return isNative ? "CBool" : "Bool";
@ -64,27 +69,24 @@ namespace Embeddinator.Generators
case PrimitiveType.Char16: return "CChar16";
case PrimitiveType.Char32: return "CChar32";
case PrimitiveType.WideChar: return "CWideChar";
case PrimitiveType.Char: return "Character";
case PrimitiveType.Char: return isNative ? "gunichar2" : "Character";
case PrimitiveType.SChar: return isNative ? "CChar" : "Int8";
case PrimitiveType.UChar: return isNative ? "CUnsignedChar" : "UInt8";
case PrimitiveType.Short: return isNative ? "CShort" : "Int16";
case PrimitiveType.UShort: return isNative ? "CUnsignedShort" : "UInt16";
case PrimitiveType.Int: return isNative ? "CInt" : "Int32";
case PrimitiveType.UInt: return isNative ? "CUnsignedInt" : "UInt32";
case PrimitiveType.Long: return isNative ? "CLong" : "Int64";
case PrimitiveType.ULong: return isNative ? "CUnsignedLong" : "UInt64";
case PrimitiveType.Long: return isNative ? "CLongLong" : "Int64";
case PrimitiveType.ULong: return isNative ? "CUnsignedLongLong" : "UInt64";
case PrimitiveType.LongLong: return isNative ? "CLongLong" : "LongLong";
case PrimitiveType.ULongLong: return isNative ? "CUnsignedLongLong" : "UnsignedLongLong";
case PrimitiveType.Int128: return "__int128";
case PrimitiveType.UInt128: return "__uint128_t";
case PrimitiveType.Half: return "__fp16";
case PrimitiveType.Float: return isNative ? "CFloat" : "Float";
case PrimitiveType.Double: return isNative ? "CDouble" : "Double";
case PrimitiveType.IntPtr:
case PrimitiveType.UIntPtr:
case PrimitiveType.Null: return SwiftGenerator.IntPtrType;
case PrimitiveType.String: return "String";
case PrimitiveType.Decimal: return "Decimal";
case PrimitiveType.String: return isNative ? "UnsafePointer<CChar>" : "String";
case PrimitiveType.Decimal: return isNative ? "MonoDecimal" : "Decimal";
}
throw new NotSupportedException();

Просмотреть файл

@ -123,6 +123,9 @@
<Compile Include="../../binder/Generators/Swift/SwiftGenerator.cs">
<Link>binder/Generators/Swift/SwiftGenerator.cs</Link>
</Compile>
<Compile Include="../../binder/Generators/Swift/SwiftMarshal.cs">
<Link>binder/Generators/Swift/SwiftMarshal.cs</Link>
</Compile>
<Compile Include="../../binder/Generators/Swift/SwiftSources.cs">
<Link>binder/Generators/Swift/SwiftSources.cs</Link>
</Compile>
@ -193,12 +196,6 @@
<Link>binder/Utils/XamarinAndroidBuild.cs</Link>
</Compile>
<None Include="packages.config" />
<Compile Include="..\..\binder\Generators\Swift\SwiftMarshal.cs">
<Link>binder\Generators\Swift\SwiftMarshal.cs</Link>
</Compile>
<Compile Include="..\..\binder\Generators\Swift\SwiftNative.cs">
<Link>binder\Generators\Swift\SwiftNative.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="IKVM.Reflection.csproj">