Make type swapping generic and get rid of config files (fixes #3) #13
Merged
Letterus
merged 29 commits from generic-type-swapping
into main
6 months ago
20 changed files with 1322 additions and 1030 deletions
@ -1,40 +0,0 @@
|
||||
{ |
||||
"OGTKMenuButton": [ |
||||
"\"OGTKMenu.h\"" |
||||
], |
||||
"OGTKTextMark": [ |
||||
], |
||||
"GtkBuilder": [ |
||||
"\"OGTKWidget.h\"" |
||||
], |
||||
"OGTKStyleContext": [ |
||||
], |
||||
"OGTKClipboard": [ |
||||
"\"OGTKTextBuffer.h\"" |
||||
], |
||||
"OGTKContainer": [ |
||||
"\"OGTKAdjustment.h\"" |
||||
], |
||||
"OGTKTextBuffer": [ |
||||
"\"OGTKTextChildAnchor.h\"", |
||||
"\"OGTKTextTag.h\"", |
||||
"\"OGTKTextTagTable.h\"", |
||||
"\"OGTKTextMark.h\"" |
||||
], |
||||
"OGTKWindow": [ |
||||
"\"OGTKWindowGroup.h\"" |
||||
], |
||||
"OGTKApplication": [ |
||||
"\"OGTKWindow.h\"" |
||||
], |
||||
"OGTKWidget": [ |
||||
"\"OGTKAccelGroup.h\"", |
||||
"\"OGTKClipboard.h\"", |
||||
"\"OGTKRcStyle.h\"", |
||||
"\"OGTKSettings.h\"", |
||||
"\"OGTKStyle.h\"", |
||||
"\"OGTKStyleContext.h\"" |
||||
], |
||||
"OGTKSettings": [ |
||||
] |
||||
} |
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* OGTKMapper.h |
||||
* This file is part of ObjGTKGen |
||||
* |
||||
* Copyright (C) 2021 - Johannes Brakensiek |
||||
* |
||||
* This library is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU Lesser General Public |
||||
* License as published by the Free Software Foundation; either |
||||
* version 2.1 of the License, or (at your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
* Lesser General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public |
||||
* License along with this library; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/*
|
||||
* Modified by the ObjGTK Team, 2021. See the AUTHORS file for a |
||||
* list of people on the ObjGTK Team. |
||||
* See the ChangeLog files for a list of changes. |
||||
*/ |
||||
|
||||
#import <ObjFW/ObjFW.h> |
||||
|
||||
@class OGTKClass; |
||||
|
||||
@interface OGTKMapper : OFObject { |
||||
OFMutableDictionary OF_GENERIC(OFString*, OGTKClass*) |
||||
* _gobjTypeToClassMapping; |
||||
OFMutableDictionary OF_GENERIC(OFString*, OGTKClass*) |
||||
* _girNameToClassMapping; |
||||
OFMutableDictionary OF_GENERIC(OFString*, OGTKClass*) |
||||
* _objcTypeToClassMapping; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Dictionary that maps Gobj type names to class information (OGTKClass) |
||||
*/ |
||||
@property (readonly, nonatomic) OFMutableDictionary OF_GENERIC( |
||||
OFString*, OGTKClass*) |
||||
* gobjTypeToClassMapping; |
||||
|
||||
/**
|
||||
* @brief Dictionary that maps general type names that are specified in the .gir |
||||
* file to class information (OGTKClass) |
||||
*/ |
||||
@property (readonly, nonatomic) OFMutableDictionary OF_GENERIC( |
||||
OFString*, OGTKClass*) |
||||
* girNameToClassMapping; |
||||
|
||||
/**
|
||||
* @brief Dictionary that maps ObjC type names to class information (OGTKClass) |
||||
*/ |
||||
@property (readonly, nonatomic) OFMutableDictionary OF_GENERIC( |
||||
OFString*, OGTKClass*) |
||||
* objcTypeToClassMapping; |
||||
|
||||
/**
|
||||
* @brief Singleton |
||||
* @return instancetype One unique instance of OGTKMapper |
||||
*/ |
||||
+ (instancetype)sharedMapper; |
||||
|
||||
/**
|
||||
* @brief Adds a class to the mapping dictionaries |
||||
* @param classInfo The object describing the class |
||||
*/ |
||||
- (void)addClass:(OGTKClass*)classInfo; |
||||
|
||||
/**
|
||||
* @brief Iterates through all the class information objects retained in the |
||||
* dict and looks for class dependencies |
||||
* @details Dependencies are stored as Gobj types as well and should be |
||||
* mapped/swapped using this class when actually written out to ObjC files. |
||||
* |
||||
* For this method to work all the class information objects need to be filled |
||||
* with correct data. |
||||
*/ |
||||
- (void)determineDependencies; |
||||
|
||||
/**
|
||||
* @brief Iterates through all the dependencies of all the class information |
||||
* objects retained in the dict |
||||
* @details This will only work if ```determineDependencies``` is called before |
||||
* @see -determineDependencies |
||||
*/ |
||||
- (void)detectAndMarkCircularDependencies; |
||||
|
||||
/**
|
||||
* @brief Returns if a given type string is listed as Gobj class type |
||||
* @return True if the given string is a listed Gobj class type |
||||
*/ |
||||
- (bool)isGobjType:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Returns if a given type string is listed as ObjC class type |
||||
* @return True if the given string is a listed ObjC class type |
||||
*/ |
||||
- (bool)isObjcType:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Tries to swap Gobj data types with ObjC data types and vice versa. |
||||
* Returns the input if it can't. |
||||
* @details In addition to the class information provided via |
||||
* ```addClass:```before this method will also swap basic data types like gchar* |
||||
* and gboolean. |
||||
* |
||||
* Class types of basic (runtime) libraries which Gtk depends on, f.e. Glib, are |
||||
* always mapped to OGTKObject because we do not want to wrap and use those but |
||||
* use ObjFW classes instead. |
||||
* |
||||
* Pointers to pointer (**) currently are not swapped because conversion of |
||||
* these types is not yet implemented by ```convertType:withName:toType```. |
||||
* @see -convertType:withName:toType |
||||
* |
||||
*/ |
||||
- (OFString*)swapTypes:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Tests if the given type is swappable by ```swapTypes:``` |
||||
* @param type The Gobj or ObjC type name |
||||
* @return True if the given type is swappable by ```swapTypes:``` |
||||
*/ |
||||
- (bool)isTypeSwappable:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Provides the string holding the source code snipped to convert |
||||
* ```fromType``` to ```toType``` holding ```name``` as variable name |
||||
* @details This method is the corresponding part to ```swapTypes:```. While |
||||
* that swaps type names this is meant to provide the code snipped string needed |
||||
* to transfor one type to the other. |
||||
* @param fromType The Gobj or ObjC type name to provide conversion code for. |
||||
* @param name The name of the variable in the source code, defined by fromType. |
||||
* @param toType The ObjC or Gobj type name which the returned code should |
||||
* convert to. |
||||
* @return The source code needed to convert ```fromType``` to |
||||
* ```toType``` holding ```name``` as variable name |
||||
* |
||||
*/ |
||||
- (OFString*)convertType:(OFString*)fromType |
||||
withName:(OFString*)name |
||||
toType:(OFString*)toType; |
||||
|
||||
/**
|
||||
* @brief Returns the appropriate self referencing method call for the type |
||||
* (i.e. -(type)[self TYPE] or GTK_TYPE([self GOBJECT]) to unwrap the Gobj |
||||
* object instance |
||||
* @param type The Gobj or ObjC class name for which the method call should be |
||||
* generated. |
||||
* @return The code snipped holding the method call snipped to unwrap the Gobj |
||||
* object instance. |
||||
* |
||||
*/ |
||||
- (OFString*)selfTypeMethodCall:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Returns the cType (Gobj type) for a name provided by a gir file |
||||
* @details In some cases the gir files do not provide cTypes (Gobj/Glib type |
||||
* names). Then this method may be used to retrieve the correct cType for gir |
||||
* class (name) definition. |
||||
* |
||||
* This only works if the necessary class information has been provided using |
||||
* ```addClass:``` before. |
||||
* @see -addClass: |
||||
* |
||||
*/ |
||||
- (OFString*)getCTypeFromName:(OFString*)name; |
||||
|
||||
/**
|
||||
* @brief Return is ```type``` is known by the Gobj type dict |
||||
* |
||||
*/ |
||||
+ (bool)isGobjType:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Return is ```type``` is known by the ObjC type dict |
||||
* |
||||
*/ |
||||
+ (bool)isObjcType:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Tries to swap Gobj data types with ObjC data types and vice versa. |
||||
* Returns the input if it can't. Singleton access shortcut. |
||||
* @see -swapTypes: |
||||
*/ |
||||
+ (OFString*)swapTypes:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Tests if the given type is swappable by ```swapTypes:``` Singleton |
||||
* access shortcut. |
||||
* @see -isTypeSwappable: |
||||
*/ |
||||
+ (bool)isTypeSwappable:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Provides the string holding the source code snipped to convert |
||||
* ```fromType``` to ```toType``` holding ```name``` as variable name. Singleton |
||||
* access shortcut. |
||||
* @see -convertType:withName:toType: |
||||
*/ |
||||
+ (OFString*)convertType:(OFString*)fromType |
||||
withName:(OFString*)name |
||||
toType:(OFString*)toType; |
||||
|
||||
/**
|
||||
* @brief Returns the appropriate self referencing method call for the type |
||||
* (i.e. -(type)[self TYPE] or GTK_TYPE([self GOBJECT]) to unwrap the Gobj |
||||
* object instance. Singleton access shortcut. |
||||
* @see -selfTypeMethodCall: |
||||
*/ |
||||
+ (OFString*)selfTypeMethodCall:(OFString*)type; |
||||
|
||||
/**
|
||||
* @brief Returns the appropriate self referencing method call for the type |
||||
* (i.e. -(type)[self TYPE] or GTK_TYPE([self GOBJECT]) to unwrap the Gobj |
||||
* object instance. Singleton access shortcut. |
||||
* @see -getCTypeFromName: |
||||
*/ |
||||
+ (OFString*)getCTypeFromName:(OFString*)name; |
||||
|
||||
@end |
@ -0,0 +1,445 @@
|
||||
/* |
||||
* OGTKMapper.m |
||||
* This file is part of ObjGTKGen |
||||
* |
||||
* Copyright (C) 2021 - Johannes Brakensiek |
||||
* |
||||
* This library is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU Lesser General Public |
||||
* License as published by the Free Software Foundation; either |
||||
* version 2.1 of the License, or (at your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
* Lesser General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public |
||||
* License along with this library; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/* |
||||
* Modified by the ObjGTK Team, 2021. See the AUTHORS file for a |
||||
* list of people on the ObjGTK Team. |
||||
* See the ChangeLog files for a list of changes. |
||||
*/ |
||||
|
||||
#import "OGTKMapper.h" |
||||
#import "OGTKClass.h" |
||||
#import "OGTKParameter.h" |
||||
|
||||
static OGTKMapper* sharedMyMapper = nil; |
||||
|
||||
@implementation OGTKMapper |
||||
|
||||
@synthesize gobjTypeToClassMapping = _gobjTypeToClassMapping, |
||||
girNameToClassMapping = _girNameToClassMapping, |
||||
objcTypeToClassMapping = _objcTypeToClassMapping; |
||||
|
||||
#pragma mark - Object lifecycle |
||||
|
||||
- (instancetype)init |
||||
{ |
||||
self = [super init]; |
||||
|
||||
@try { |
||||
_gobjTypeToClassMapping = [[OFMutableDictionary alloc] init]; |
||||
_girNameToClassMapping = [[OFMutableDictionary alloc] init]; |
||||
_objcTypeToClassMapping = [[OFMutableDictionary alloc] init]; |
||||
} @catch (id e) { |
||||
[self release]; |
||||
@throw e; |
||||
} |
||||
|
||||
return self; |
||||
} |
||||
|
||||
- (void)dealloc |
||||
{ |
||||
[_gobjTypeToClassMapping release]; |
||||
[_girNameToClassMapping release]; |
||||
[_objcTypeToClassMapping release]; |
||||
|
||||
[super dealloc]; |
||||
} |
||||
|
||||
+ (instancetype)sharedMapper |
||||
{ |
||||
@synchronized(self) { |
||||
if (sharedMyMapper == nil) |
||||
sharedMyMapper = [[self alloc] init]; |
||||
} |
||||
return sharedMyMapper; |
||||
} |
||||
|
||||
#pragma mark - Public methods - domain logic |
||||
|
||||
- (void)addClass:(OGTKClass*)classInfo |
||||
{ |
||||
[_gobjTypeToClassMapping setObject:classInfo forKey:classInfo.cType]; |
||||
|
||||
[_girNameToClassMapping setObject:classInfo forKey:classInfo.cName]; |
||||
|
||||
[_objcTypeToClassMapping setObject:classInfo forKey:classInfo.type]; |
||||
} |
||||
|
||||
- (bool)isGobjType:(OFString*)type |
||||
{ |
||||
return ([_gobjTypeToClassMapping objectForKey:[self stripAsterisks:type]] |
||||
!= nil); |
||||
} |
||||
|
||||
- (bool)isObjcType:(OFString*)type |
||||
{ |
||||
return ([_objcTypeToClassMapping objectForKey:[self stripAsterisks:type]] |
||||
!= nil); |
||||
} |
||||
|
||||
- (void)determineDependencies |
||||
{ |
||||
for (OFString* className in _objcTypeToClassMapping) { |
||||
OGTKClass* classInfo = [_objcTypeToClassMapping objectForKey:className]; |
||||
|
||||
if (classInfo.cParentType != nil) |
||||
[classInfo addDependency:classInfo.cParentType]; |
||||
|
||||
for (OGTKMethod* constructor in classInfo.constructors) |
||||
[self addDependenciesFromMethod:constructor to:classInfo]; |
||||
|
||||
for (OGTKMethod* function in classInfo.functions) |
||||
[self addDependenciesFromMethod:function to:classInfo]; |
||||
|
||||
for (OGTKMethod* method in classInfo.methods) |
||||
[self addDependenciesFromMethod:method to:classInfo]; |
||||
} |
||||
} |
||||
|
||||
- (void)detectAndMarkCircularDependencies |
||||
{ |
||||
for (OFString* className in _objcTypeToClassMapping) { |
||||
OGTKClass* classInfo = [_objcTypeToClassMapping objectForKey:className]; |
||||
|
||||
OFMutableDictionary* stack = [[OFMutableDictionary alloc] init]; |
||||
|
||||
[stack setObject:@"1" forKey:classInfo.cType]; |
||||
|
||||
[self walkDependencyTreeFrom:classInfo usingStack:stack]; |
||||
|
||||
[stack release]; |
||||
} |
||||
} |
||||
|
||||
- (OFString*)swapTypes:(OFString*)type |
||||
{ |
||||
// Convert basic types by hardcoding |
||||
if ([type isEqual:@"AtkObject"] || [type isEqual:@"GApplication"] || |
||||
[type isEqual:@"GInitiallyUnowned"] || [type isEqual:@"GObject"] || |
||||
[type isEqual:@"GMountOperation"]) |
||||
return @"OGTKObject"; |
||||
else if ([type isEqual:@"const gchar*"] || [type isEqual:@"gchar*"]) |
||||
return @"OFString*"; |
||||
else if ([type isEqual:@"Gtk"]) |
||||
return @"OGTK"; |
||||
else if ([type isEqual:@"OFString*"]) |
||||
return @"const gchar*"; |
||||
|
||||
// Different naming, same type |
||||
else if ([type isEqual:@"gboolean"]) |
||||
return @"bool"; |
||||
else if ([type isEqual:@"bool"]) |
||||
return @"gboolean"; |
||||
|
||||
// Get the number of '*' - currently we only swap simple pointers (*) |
||||
size_t numberOfAsterisks = [self numberOfAsterisksIn:type]; |
||||
if (numberOfAsterisks > 1) |
||||
return type; |
||||
|
||||
OFString* strippedType = [self stripAsterisks:type]; |
||||
|
||||
// Gobj -> ObjC type swapping |
||||
OGTKClass* objcClassInfo = |
||||
[_gobjTypeToClassMapping objectForKey:strippedType]; |
||||
|
||||
if (objcClassInfo != nil) { |
||||
if ([strippedType isEqual:type]) |
||||
return objcClassInfo.type; |
||||
else |
||||
return [OFString stringWithFormat:@"%@*", objcClassInfo.type]; |
||||
} |
||||
|
||||
// ObjC -> Gobj type swapping |
||||
OGTKClass* gobjClassInfo = |
||||
[_objcTypeToClassMapping objectForKey:strippedType]; |
||||
|
||||
if (gobjClassInfo != nil) { |
||||
if ([strippedType isEqual:type]) |
||||
return gobjClassInfo.cType; |
||||
else |
||||
return [OFString stringWithFormat:@"%@*", gobjClassInfo.cType]; |
||||
} |
||||
|
||||
return type; |
||||
} |
||||
|
||||
- (bool)isTypeSwappable:(OFString*)type |
||||
{ |
||||
return [type isEqual:@"gchar*"] || [type isEqual:@"const gchar*"] || |
||||
[type isEqual:@"OFString*"] || [type isEqual:@"OFArray*"] || |
||||
[self isGobjType:type] || [self isObjcType:type]; |
||||
} |
||||
|
||||
- (OFString*)convertType:(OFString*)fromType |
||||
withName:(OFString*)name |
||||
toType:(OFString*)toType |
||||
{ |
||||
// Try to return conversion for string types first |
||||
if (([fromType isEqual:@"gchar*"] || [fromType isEqual:@"const gchar*"]) && |
||||
[toType isEqual:@"OFString*"]) { |
||||
return [OFString |
||||
stringWithFormat:@"[OFString stringWithUTF8String:%@]", name]; |
||||
} else if ([fromType isEqual:@"OFString*"] |
||||
&& ([toType isEqual:@"gchar*"] || [toType isEqual:@"const gchar*"])) { |
||||
return [OFString stringWithFormat:@"[%@ UTF8String]", name]; |
||||
} |
||||
|
||||
// Then try to return generic Gobj type conversion |
||||
if ([self isGobjType:fromType] && [self isObjcType:toType]) { |
||||
// Converting from Gobjc -> Objc |
||||
|
||||
return [OFString |
||||
stringWithFormat:@"[[%@ alloc] initWithGObject:(GObject*)%@]", |
||||
[self stripAsterisks:toType], name]; |
||||
|
||||
} else if ([self isObjcType:fromType] && [self isGobjType:toType]) { |
||||
// Converting from Objc -> Gobj |
||||
|
||||
OGTKClass* toClass = [_objcTypeToClassMapping |
||||
objectForKey:[self stripAsterisks:fromType]]; |
||||
|
||||
return [OFString |
||||
stringWithFormat:@"[%@ %@]", name, [toClass.cName uppercaseString]]; |
||||
} |
||||
|
||||
// Otherwise don't do any conversion (including bool types, as ObjFW uses |
||||
// the stdc bool type) |
||||
return name; |
||||
} |
||||
|
||||
- (OFString*)selfTypeMethodCall:(OFString*)type; |
||||
{ |
||||
// Convert OGTKFooBar into [self FOOBAR] |
||||
if ([self isObjcType:type]) { |
||||
OGTKClass* toClass = |
||||
[_objcTypeToClassMapping objectForKey:[self stripAsterisks:type]]; |
||||
|
||||
return [OFString |
||||
stringWithFormat:@"[self %@]", [toClass.cName uppercaseString]]; |
||||
} |
||||
|
||||
// Convert GtkFooBar into GTK_FOO_BAR([self GOBJECT]) |
||||
if ([self isGobjType:type]) { |
||||
OGTKClass* classInfo = |
||||
[_gobjTypeToClassMapping objectForKey:[self stripAsterisks:type]]; |
||||
|
||||
OFString* functionMacroName = |
||||
[[OFString stringWithFormat:@"%@_%@", classInfo.cNSSymbolPrefix, |
||||
classInfo.cSymbolPrefix] uppercaseString]; |
||||
|
||||
return [OFString |
||||
stringWithFormat:@"%@%@", functionMacroName, @"([self GOBJECT])"]; |
||||
} |
||||
|
||||
return type; |
||||
} |
||||
|
||||
- (OFString*)getCTypeFromName:(OFString*)name |
||||
{ |
||||
// Some shortcut definitions from libraries we do not want to add as |
||||
// dependencies |
||||
if ([name isEqual:@"Atk.Object"]) |
||||
return @"AtkObject"; |
||||
else if ([name isEqual:@"Gio.Application"]) |
||||
return @"GApplication"; |
||||
else if ([name isEqual:@"GObject.InitiallyUnowned"]) |
||||
return @"GInitiallyUnowned"; |
||||
else if ([name isEqual:@"GObject.Object"]) |
||||
return @"GObject"; |
||||
|
||||
// Case: Name has a namespace prefix |
||||
if ([name containsString:@"."]) { |
||||
OFArray* nameParts = [name componentsSeparatedByString:@"."]; |
||||
|
||||
OGTKClass* classInfo = |
||||
[_girNameToClassMapping objectForKey:[nameParts objectAtIndex:1]]; |
||||
|
||||
if (classInfo != nil && |
||||
[classInfo.cNSIdentifierPrefix isEqual:[nameParts objectAtIndex:0]]) |
||||
return classInfo.cType; |
||||
} |
||||
|
||||
// Case: Simple name without prefix |
||||
OGTKClass* classInfo = [_girNameToClassMapping objectForKey:name]; |
||||
if (classInfo != nil) |
||||
return classInfo.cType; |
||||
|
||||
// Case: We did not find any c type |
||||
@throw [OFInvalidArgumentException exception]; |
||||
} |
||||
|
||||
#pragma mark - Private methods - domain logic |
||||
|
||||
- (OFString*)stripAsterisks:(OFString*)identifier |
||||
{ |
||||
OFCharacterSet* charSet = |
||||
[OFCharacterSet characterSetWithCharactersInString:@"*"]; |
||||
size_t index = [identifier indexOfCharacterFromSet:charSet]; |
||||
|
||||
if (index == OFNotFound) |
||||
return identifier; |
||||
|
||||
return [identifier substringToIndex:index]; |
||||
} |
||||
|
||||
- (size_t)numberOfAsterisksIn:(OFString*)identifier |
||||
{ |
||||
OFCharacterSet* charSet = |
||||
[OFCharacterSet characterSetWithCharactersInString:@"*"]; |
||||
size_t index = [identifier indexOfCharacterFromSet:charSet]; |
||||
|
||||
if (index == OFNotFound) |
||||
return 0; |
||||
|
||||
return identifier.length - index; |
||||
} |
||||
|
||||
- (void)addDependenciesFromMethod:(OGTKMethod*)method to:(OGTKClass*)classInfo |
||||
{ |
||||
OFString* strippedReturnType = [self stripAsterisks:method.cReturnType]; |
||||
|
||||
if ([self isTypeSwappable:strippedReturnType] |
||||
&& ![strippedReturnType isEqual:classInfo.cType]) |
||||
[classInfo addDependency:strippedReturnType]; |
||||
|
||||
for (OGTKParameter* parameter in method.parameters) { |
||||
OFString* strippedParameterCType = |
||||
[self stripAsterisks:parameter.cType]; |
||||
|
||||
if ([self isTypeSwappable:strippedParameterCType] |
||||
&& ![strippedParameterCType isEqual:classInfo.cType]) |
||||
[classInfo addDependency:strippedParameterCType]; |
||||
} |
||||
} |
||||
|
||||
- (void)walkDependencyTreeFrom:(OGTKClass*)classInfo |
||||
usingStack:(OFMutableDictionary*)stack |
||||
{ |
||||
if (classInfo.visited) { |
||||
// OFLog(@"Class %@ aleady visited. Skipping…", classInfo.cType); |
||||
return; |
||||
} |
||||
|
||||
// OFLog(@"Visiting class: %@.", classInfo.cType); |
||||
classInfo.visited = true; |
||||
|
||||
// First follow parent classes - traverse to the topmost tree element |
||||
OGTKClass* parentClassInfo = nil; |
||||
|
||||
if (classInfo.cParentType != nil) |
||||
parentClassInfo = |
||||
[_gobjTypeToClassMapping objectForKey:classInfo.cParentType]; |
||||
|
||||
if (parentClassInfo != nil && |
||||
[stack objectForKey:classInfo.cParentType] == nil) { |
||||
|
||||
[stack setObject:@"1" forKey:classInfo.cParentType]; |
||||
[self walkDependencyTreeFrom:parentClassInfo usingStack:stack]; |
||||
} |
||||
|
||||
// OFLog(@"Checking dependencies of %@.", classInfo.cType); |
||||
// Then start to follow dependencies - leave out parent classes this time |
||||
for (OFString* dependencyGobjName in classInfo.dependsOnClasses) { |
||||
|
||||
// Add a forward declaration if the dependency is within the stack - |
||||
// we're inside a circular dependency structure then |
||||
if ([stack objectForKey:dependencyGobjName] != nil |
||||
&& ![classInfo.cParentType isEqual:dependencyGobjName]) { |
||||
|
||||
// OFLog( |
||||
// @"Detected circular dependency %@, adding forward declaration.", |
||||
// dependencyGobjName); |
||||
[classInfo addForwardDeclarationForClass:dependencyGobjName]; |
||||
|
||||
continue; |
||||
} |
||||
|
||||
OGTKClass* dependencyClassInfo = |
||||
[_gobjTypeToClassMapping objectForKey:dependencyGobjName]; |
||||
|
||||
if (dependencyClassInfo == nil) |
||||
continue; |
||||
|
||||
// We got a dependency to follow, so we are eady to visit that |
||||
// dependency and follow its dependencies |
||||
[stack setObject:@"1" forKey:dependencyGobjName]; |
||||
|
||||
[self walkDependencyTreeFrom:dependencyClassInfo usingStack:stack]; |
||||
} |
||||
|
||||
[classInfo removeForwardDeclarationsFromDependencies]; |
||||
} |
||||
|
||||
#pragma mark - Shortcuts for singleton access |
||||
|
||||
+ (OFString*)swapTypes:(OFString*)type |
||||
{ |
||||
OGTKMapper* sharedMapper = [OGTKMapper sharedMapper]; |
||||
|
||||
return [sharedMapper swapTypes:type]; |
||||
} |
||||
|
||||
+ (bool)isTypeSwappable:(OFString*)type |
||||
{ |
||||
OGTKMapper* sharedMapper = [OGTKMapper sharedMapper]; |
||||
|
||||
return [sharedMapper isTypeSwappable:type]; |
||||
} |
||||
|
||||
+ (bool)isGobjType:(OFString*)type |
||||
{ |
||||
OGTKMapper* sharedMapper = [OGTKMapper sharedMapper]; |
||||
|
||||
return [sharedMapper isGobjType:type]; |
||||
} |
||||
|
||||
+ (bool)isObjcType:(OFString*)type |
||||
{ |
||||
OGTKMapper* sharedMapper = [OGTKMapper sharedMapper]; |
||||
|
||||
return [sharedMapper isObjcType:type]; |
||||
} |
||||
|
||||
+ (OFString*)convertType:(OFString*)fromType |
||||
withName:(OFString*)name |
||||
toType:(OFString*)toType |
||||
{ |
||||
OGTKMapper* sharedMapper = [OGTKMapper sharedMapper]; |
||||
|
||||
return [sharedMapper convertType:fromType withName:name toType:toType]; |
||||
} |
||||
|
||||
+ (OFString*)selfTypeMethodCall:(OFString*)type |
||||
{ |
||||
OGTKMapper* sharedMapper = [OGTKMapper sharedMapper]; |
||||
|
||||
return [sharedMapper selfTypeMethodCall:type]; |
||||
} |
||||
|
||||
+ (OFString*)getCTypeFromName:(OFString*)name |
||||
{ |
||||
OGTKMapper* sharedMapper = [OGTKMapper sharedMapper]; |
||||
|
||||
return [sharedMapper getCTypeFromName:name]; |
||||
} |
||||
|
||||
@end |