Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 105 additions & 25 deletions lib/objc/DNObjectiveCContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class DNArgumentContext extends DNContext {
super(internal)
this.name = name
this.type = type
this.anonDef = null
this.anonDef = null //user for block arguement
this.isNullable = false
}
}

Expand All @@ -89,6 +90,7 @@ class DNMethodContext extends DNContext {
this.names = []
this.args = []
this.returnType = null
this.retValIsObj = false
this.isClassMethod = false
}

Expand All @@ -99,10 +101,15 @@ class DNMethodContext extends DNContext {
return this.parseForOptionalSingleArg()
}

var result = ' ' + (this.isClassMethod ? 'static ' : '') + this.convertMutableTypeIfNeed(this.returnType) + ' ' + this.methodDeclaration() + '(' + this.methodArgs() + ')' + ' {\n'
result += this.preHandleMutableArgsIfNeed() + ' ' + this.methodImpl()
result += ' }'
return result
var isInstanceConstr = (this.returnType == this.parent.name) && !this.isClassMethod
if(isInstanceConstr){
return this.constructorImpl()
}else{
var result = ' ' + (this.isClassMethod ? 'static ' : '') + this.convertMutableTypeIfNeed(this.returnType) + ' ' + this.methodDeclaration() + this.methodArgs() + ' {\n'
result += this.preHandleMutableArgsIfNeed() + ' ' + this.methodImpl()
result += ' }'
return result
}
}

preHandleMutableArgsIfNeed(){
Expand Down Expand Up @@ -139,31 +146,74 @@ class DNMethodContext extends DNContext {
}

methodImpl(noArg){
var funcName = ''
this.args.forEach((_element, index) => {
funcName += this.names[index] + (this.args.length >= 1 ? ':' : '')
})
funcName = funcName ? funcName : this.methodName
var callerPrefix = (this.isClassMethod ? ' Class(\'' + this.parent.name + '\').' : ' ')
var args = noArg ? '' : ', args: [' + this.args.map(arg => arg.name) + ']'
var impl = callerPrefix + 'perform(\'' + funcName + '\'.toSEL()' + args + ');\n'

var rawRetType = this.rawGenericType(this.returnType)
if(DNObjectiveCTypeConverter.SupportMutableTypes.indexOf(rawRetType) > -1){
// TO-DO:Need to consider duplicate names
var newImpl = 'NSObject _result = ' + impl
newImpl += ' return ' + rawRetType + '.fromPointer(_result.pointer).value;\n'
return newImpl
var impl = callerPrefix + 'perform(\'' + this.ocMethodName() + '\'.toSEL()' + args + ');\n'

var rawRetType = this.rawGenericType(this.returnType) //remove <> symbol
var isMutableRetType = DNObjectiveCTypeConverter.SupportMutableTypes.indexOf(rawRetType) > -1

if(!isMutableRetType && !this.retValIsObj){
return (this.returnType == 'void' ? '' : 'return') + impl
}

var newImpl = 'Pointer<Void> result = ' + impl.replace(');\n','') + ' ,decodeRetVal: false);\n'
if(isMutableRetType){
newImpl += ' return ' + rawRetType + '.fromPointer(result).raw;\n'
}
if(this.retValIsObj){
var supportType = DNObjectiveCTypeConverter.DNDartToOCMap[rawRetType]
if(supportType) {
newImpl += ' return ' + supportType + '.fromPointer(result).raw;\n'
}else {
newImpl += ' return ' + rawRetType + '.fromPointer(result);\n'
}
}
return (this.returnType == 'void' ? '' : 'return') + impl
return newImpl
}

methodArgs(){
var argList = ''
constructorImpl(){
var result = ''
if(this.isSingleInstanceConstr){
// such as NSError(arg x)
result += ' ' + this.parent.name + this.methodArgs() + '\n'
}else{
// such as NSError.initWithxxxx(arg x)
result += ' ' + this.parent.name + '.' + this.methodDeclaration() + this.methodArgs() + '\n'
}
result += ' : super.fromPointer(_' + this.methodDeclaration() + '(' +this.args.map(arg => arg.name) + '));\n'
result += '\n';
result += ' static Pointer<Void> _' + this.methodDeclaration() + this.methodArgs() + ' {\n'
result += this.preHandleMutableArgsIfNeed()
result +=' Pointer<Void> target = alloc(Class(\'' + this.parent.name + '\'));\n'
result += ' SEL sel = \'' + this.ocMethodName() + '\'.toSEL();\n'
result += ' return msgSend(target, sel, ' + 'args: [' + this.args.map(arg => arg.name) + ']' + ', decodeRetVal: false);\n'
result += ' }\n'
return result
}

methodArgs(optional){
//convert as follows: int a, String b, {int c, String d}
var argList = optional ? '([' : '('
var nullableArgs = []
this.args.forEach((element, index) => {
var arg = element.anonDef ? element.anonDef : this.convertMutableTypeIfNeed(element.type) + ' ' + element.name
argList += arg + (index == this.args.length - 1 ? '' : ', ')
if(element.isNullable){
nullableArgs.push(element)
}else{
var arg = element.anonDef ? element.anonDef : this.convertMutableTypeIfNeed(element.type) + ' ' + element.name
argList += arg + (index == this.args.length - 1 && nullableArgs.length == 0 ? '' : ', ')
}
})

if(nullableArgs.length > 0){
argList += '{'
nullableArgs.forEach((element, index) => {
var arg = element.anonDef ? element.anonDef : this.convertMutableTypeIfNeed(element.type) + ' ' + element.name
argList += arg + (index == nullableArgs.length - 1 ? '' : ', ')
})
argList += '}'
}
argList += optional ? '])' : ')'
return argList
}

Expand Down Expand Up @@ -192,6 +242,15 @@ class DNMethodContext extends DNContext {
var rawType = isGeneric ? type.substring(0,type.indexOf('<')) : type
return rawType
}

ocMethodName(){
var funcName = ''
this.args.forEach((_element, index) => {
funcName += this.names[index] + (this.args.length >= 1 ? ':' : '')
})
funcName = funcName ? funcName : this.methodName
return funcName
}
}
class DNMethodDeclarationContext extends DNMethodContext{
constructor(internal) {
Expand All @@ -202,9 +261,9 @@ class DNMethodDeclarationContext extends DNMethodContext{
if(this.args.length == 0 && this.hasSameMethodDeclaration()){
return ''
}else if(this.args.length == 1 && this.hasSameMethodDeclaration()){
return ' ' + (this.isClassMethod ? 'static ' : '') + this.returnType + ' ' + this.methodDeclaration() + '([' + this.methodArgs() + ']);'
return ' ' + (this.isClassMethod ? 'static ' : '') + this.returnType + ' ' + this.methodDeclaration() + this.methodArgs(true) +';'
}
return ' ' + (this.isClassMethod ? 'static ' : '') + this.returnType + ' ' + this.methodDeclaration() + '(' + this.methodArgs() + ');'
return ' ' + (this.isClassMethod ? 'static ' : '') + this.returnType + ' ' + this.methodDeclaration() + this.methodArgs() + ';'
}
}

Expand Down Expand Up @@ -264,6 +323,7 @@ class DNClassContext extends DNContext {
}

parse() {
this.preMarkConstructMethods()
var result = '@native\nclass ' + this.name + ' extends ' + this.superClass
if (typeof this.protocols !== 'undefined' && this.protocols.length > 0) {
result += ' with ' + this.protocols.join(',')
Expand All @@ -281,6 +341,26 @@ class DNClassContext extends DNContext {
result += '\n}'
return result
}

// mark the method if the class has only one instance construction
preMarkConstructMethods(){
var markMethod
var hasOneInstanceConstr = false
for(var i = 0 ; i < this.methods.length; i++){
var method = this.methods[i]
var isInstanceConstr = (method.returnType == this.name) && !method.isClassMethod
if(isInstanceConstr){
if(hasOneInstanceConstr){
markMethod.isSingleInstanceConstr = false
break
}else{
hasOneInstanceConstr = true
method.isSingleInstanceConstr = true
markMethod = method
}
}
}
}
}

class DNCategoryContext extends DNContext {
Expand Down
9 changes: 8 additions & 1 deletion lib/objc/DNObjectiveCParserListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ class DNObjectiveCParserListener extends ObjectiveCParserListener {
}
// Exit a parse tree produced by ObjectiveCParser#typeVariableDeclaratorOrName.
exitTypeVariableDeclaratorOrName(ctx) {
if (this.currentContext instanceof DNArgumentContext) {
if (this.currentContext.parent instanceof DNBlockDefContext) {
this.currentContext = this.currentContext.parent
}
}
Expand Down Expand Up @@ -837,8 +837,15 @@ class DNObjectiveCParserListener extends ObjectiveCParserListener {
enterTypeName(ctx) {
if (this.currentContext instanceof DNMethodContext) {
this.currentContext.returnType = TC.convert(ctx.start.text == 'instancetype' ? this.currentContext.parent.name : ctx.start.text,true)
this.currentContext.retValIsObj = ctx.stop.text == '*'
} else if (this.currentContext instanceof DNArgumentContext) {
this.currentContext.type = TC.convert(ctx.start.text,true)
if(ctx.start.text == 'nullable'){
this.currentContext.isNullable = true
this.currentContext.type = TC.convert(ctx.children[0].stop.text,true) //correct arg type
}else if(ctx.stop.text == '_Nullable' || ctx.stop.text == '__nullable'){
this.currentContext.isNullable = true
}
}
}
// Exit a parse tree produced by ObjectiveCParser#typeName.
Expand Down
14 changes: 11 additions & 3 deletions lib/objc/DNObjectiveCTypeConverter.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ class DNObjectiveCTypeConverter {
}

convert(objcType,isMethodArg){
var convertRet = DNObjectiveCTypeConverter.DNObjectiveCTypeMap[objcType]
var convertRet = DNObjectiveCTypeConverter.DNOCToDartMap[objcType]
convertRet = (!convertRet && !isMethodArg) ? DNObjectiveCTypeConverter.SupportMutableTypesMap[objcType] : convertRet
// convertRet = (!convertRet && !isMethodArg) ? '123123' : 'asd'
return convertRet ? convertRet : objcType
}
}

//Not yet confirmed what type need to convert
DNObjectiveCTypeConverter.DNObjectiveCTypeMap = {
DNObjectiveCTypeConverter.DNOCToDartMap = {
// objc type || dart type
'int8_t' : 'int',
'int16_t' : 'int',
Expand All @@ -32,12 +32,20 @@ DNObjectiveCTypeConverter.DNObjectiveCTypeMap = {
'void *' : 'Pointer<Void>',
'char *' : 'String',
'NSString' : 'String',
'NSMutableString' : 'String',
'NSArray' : 'List',
'NSDictionary' : 'Map',
'NSSet' : 'Set',
}

//ignore mutable type
DNObjectiveCTypeConverter.DNDartToOCMap = {
// dart type || objc type
'String' : 'NSString',
'List' : 'NSArray',
'Map' : 'NSDictionary',
'Set' : 'NSSet',
}

// dart-native support mutable types
DNObjectiveCTypeConverter.SupportMutableTypes = [
'NUMutableString',
Expand Down
1 change: 1 addition & 0 deletions test/objc/RuntimeStub.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
- (void)fooBOOLAnonFunc:(BOOL)a block:(int(^)(BOOL a, NSString *b))block;
- (NSMutableSet<NSString *> *)fooMutable:(BOOL)a bar:(NSMutableArray<NSMutableArray *> *)b c:(NSMutableArray *)c;
- (void)fooEnum:(RuntimeStubEnum)aEnum;
- (void)foolNullable:(nullable NSString *)a b:(int _Nullable)b c:(NSString * __nullable)c d:(int)d;
@end

@interface RuntimeStub(Foo)
Expand Down