Skip to content

Commit

Permalink
Wrap return value of instance methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jacob-carlborg committed May 10, 2024
1 parent 08741e1 commit d955b51
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 5 deletions.
6 changes: 6 additions & 0 deletions clang/Cursor.d
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ struct Cursor
return clang_isTranslationUnit(kind) != 0;
}

bool isRecord() const
{
with (CXCursorKind)
return kind == structDecl || kind == unionDecl;
}

File includedFile()
{
return File(clang_getIncludedFile(cx));
Expand Down
64 changes: 60 additions & 4 deletions dstep/translator/ApiNotesTranslator.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ module dstep.translator.ApiNotesTranslator;
import std.algorithm;
import std.format;
import std.functional;
import std.range;

import clang.c.Index;
import clang.Cursor;
import clang.SourceRange;
import clang.Type;

import dstep.core.Core;
import dstep.core.Optional;
Expand All @@ -34,11 +36,39 @@ struct ApiNotesTranslator
private Set!string declarationsNeedingWrapping;
private ApiNotes apiNotes;

/**
* This maps a context name from an API Notes file to a the cursor that
* corresponds to the type that the raw value in the wrapper struct should
* be of.
*
* Examples:
*
* ```yaml
* - Name: CGColorCreateGenericGray
* SwiftName: CGColor.init(gray:alpha:) # "CGColor" will be store as the key
* ```
*
* ```c
* typedef struct CGColor* CGColorRef;
* // The cursor of this return type will be stored as a value.
* CGColorRef CGColorCreateGenericGray(double gray, double alpha);
* ```
*
* ```
* struct CGColor
* {
* private CGColorRef rawValue;
* }
* ```
*/
private Optional!Cursor[string] rawValueMappings;

this(Context context, ApiNotes apiNotes)
{
this.context = context;
this.apiNotes = apiNotes;
collectDeclarationsNeedingWrapping();
collectContextNames();
}

void addDeclaration(StructData structData)
Expand Down Expand Up @@ -81,7 +111,13 @@ struct ApiNotesTranslator
}

output.subscopeStrong(wrapperResult.extent, wrapperResult.makeString) in {
output.singleLine("return %s(%-(%s, %));", originalName, parameterNames);
if (wrapper(of: cursor.func.resultType).isPresent)
{
output.singleLine("typeof(this) __result = { %s(%-(%s, %)) };", originalName, parameterNames);
output.singleLine("return __result;");
}
else
output.singleLine("return %s(%-(%s, %));", originalName, parameterNames);
};

addOriginalFunction(cursor, output, originalName);
Expand All @@ -107,7 +143,7 @@ struct ApiNotesTranslator
throw new DStepException(message);
}

setCursor(cursor, for_: func.context.or(""));
setCursor(cursor, forContext: func.context.or(""));

auto member = (Output output) {
auto wrapperFunction = dstep.translator.Translator.Function(
Expand Down Expand Up @@ -175,6 +211,14 @@ struct ApiNotesTranslator
}
}

Optional!string wrapper(Type of) =>
declarations
.byValue
.filter!(ad => !ad.cursor.func.resultType.declaration.isRecord.or(false))
.find!(ad => ad.cursor.func.resultType.isEqualTo(of).or(false))
.map!(ad => ad.name.some)
.or(none!string);

private:

auto declarationsNeedingSynthesizing() =>
Expand Down Expand Up @@ -203,9 +247,9 @@ private:
.addMember(member);
}

void setCursor(Cursor cursor, string for_)
void setCursor(Cursor cursor, string forContext)
{
auto name = for_;
auto name = forContext;
declarations.require(name, new AnnotatedDeclaration(name))
.cursor = cursor;
}
Expand Down Expand Up @@ -234,4 +278,16 @@ private:
.filter!(spelling => spelling in apiNotes.contextsWithConstructors)
.each!(spelling => declarationsNeedingWrapping.put(spelling));
}

void collectContextNames()
{
auto contexts = apiNotes
.functions
.save
.filter!(func => func.isConstructor)
.map!(func => func.context.or(""));

foreach (context; contexts)
declarations.require(context, new AnnotatedDeclaration(context));
}
}
18 changes: 17 additions & 1 deletion dstep/translator/Translator.d
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,23 @@ SourceNode translateFunction (

auto returnType = func.canonicalizeReturnType ?
func.cursor.resultType.canonical : func.cursor.resultType;
auto resultType = translateType(context, func.cursor, returnType);

SourceNode resultType;

auto translateReturnType() => translateType(context, func.cursor, returnType);

if (func.apiNotesFunction.isInstanceMethod.or(false))
{
const wrapper = context
.translator
.apiNotesTranslator
.wrapper(of: func.cursor.resultType);

resultType = wrapper.map!(w => makeSourceNode(w)).or(translateReturnType());
}
else
resultType = translateReturnType();

auto multiline = func.cursor.extent.isMultiline &&
!context.options.singleLineFunctionSignatures;
auto spacer = context.options.spaceAfterFunctionName ? " " : "";
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/ApiNotes.d
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,16 @@ q"YAML
Functions:
- Name: CGPathCreateMutable
DName: CGMutablePathRef.init()
- Name: CGPathCreateCopy
SwiftName: CGMutablePathRef.copy(self:)
YAML"
);

assertTranslatesAnnotated(
q"C
typedef struct CGPath *CGMutablePathRef;
CGMutablePathRef CGPathCreateMutable(void);
CGMutablePathRef CGPathCreateCopy(CGMutablePathRef path);
C",
q"D
struct CGMutablePathRef
Expand All @@ -426,6 +429,15 @@ struct CGMutablePathRef
extern (C) private static pragma(mangle, "CGPathCreateMutable")
CGPath* CGPathCreateMutable ();
CGMutablePathRef copy ()
{
typeof(this) __result = { __copy(this) };
return __result;
}
extern (C) private static pragma(mangle, "CGPathCreateCopy")
CGPath* __copy (CGMutablePathRef path);
}
D", options, annotatedFile: "CGMutablePathRef.d");
}

0 comments on commit d955b51

Please sign in to comment.