Permalink
Browse files

Support to call methods on nil

  • Loading branch information...
bang590 committed Jul 1, 2015
1 parent f610135 commit cb7688ee74c3bbc88f0a80c72b1864a93e918f66
View
@@ -85,6 +85,7 @@ @implementation JPEngine
static NSString *_replaceStr = @".__c(\"$1\")(";
static NSRegularExpression* _regex;
static NSObject *_nullObj;
static NSObject *_nilObj;
static NSMutableArray *_extensions;
static NSMutableArray *_structExtensions;
@@ -159,6 +160,7 @@ + (void)startEngine
};
_nullObj = [[NSObject alloc] init];
_nilObj = [[NSObject alloc] init];
context[@"_OC_null"] = formatOCToJS(_nullObj);
__weak JSContext *weakCtx = context;
@@ -392,7 +394,8 @@ static _type JPMETHOD_IMPLEMENTATION_NAME(_typeString) (id slf, SEL selector) {
#define JPMETHOD_RET_ID \
id obj = formatJSToOC(ret); \
if ([obj isKindOfClass:[NSNull class]]) return nil; \
if (obj == _nilObj || \
([obj isKindOfClass:[NSNumber class]] && strcmp([obj objCType], "c") == 0 && ![obj boolValue])) return nil; \
return obj;
#define JPMETHOD_RET_STRUCT(_methodName) \
@@ -500,9 +503,9 @@ static void JPForwardInvocation(id slf, SEL selector, NSInvocation *invocation)
[invocation getArgument:&arg atIndex:i];
static const char *blockType = @encode(typeof(^{}));
if (!strcmp(argumentType, blockType)) {
[argList addObject:(arg ? [arg copy]: [NSNull null])];
[argList addObject:(arg ? [arg copy]: _nilObj)];
} else {
[argList addObject:(arg ? arg: [NSNull null])];
[argList addObject:(arg ? arg: _nilObj)];
}
break;
}
@@ -540,7 +543,7 @@ static void JPForwardInvocation(id slf, SEL selector, NSInvocation *invocation)
SEL selector;
[invocation getArgument:&selector atIndex:i];
NSString *selectorName = NSStringFromSelector(selector);
[argList addObject:(selectorName ? selectorName: [NSNull null])];
[argList addObject:(selectorName ? selectorName: _nilObj)];
break;
}
case '^':
@@ -767,7 +770,7 @@ static id callSelector(NSString *className, NSString *selectorName, JSValue *arg
case ':': {
SEL value = nil;
if (![valObj isEqual:[NSNull null]]) {
if (valObj == _nilObj) {
value = NSSelectorFromString(valObj);
}
[invocation setArgument:&value atIndex:i];
@@ -821,7 +824,8 @@ static id callSelector(NSString *className, NSString *selectorName, JSValue *arg
[invocation setArgument:&valObj atIndex:i];
break;
}
if ([valObj isEqual:[NSNull null]]) {
if (valObj == _nilObj ||
([valObj isKindOfClass:[NSNumber class]] && strcmp([valObj objCType], "c") == 0 && ![valObj boolValue])) {
valObj = nil;
[invocation setArgument:&valObj atIndex:i];
break;
@@ -1055,7 +1059,8 @@ id formatOCToJS(id obj)
id formatJSToOC(JSValue *jsval)
{
id obj = [jsval toObject];
if (!obj) return [NSNull null];
if (!obj || [obj isKindOfClass:[NSNull class]]) return _nilObj;
if ([obj isKindOfClass:[JPBoxing class]]) return [obj unbox];
if ([obj isKindOfClass:[NSArray class]]) {
NSMutableArray *newArr = [[NSMutableArray alloc] init];
@@ -1091,7 +1096,7 @@ static id _formatOCToJSList(NSArray *list)
static NSDictionary *_wrapObj(id obj)
{
if (!obj || [obj isKindOfClass:[NSNull class]]) {
if (!obj || obj == _nilObj) {
return @{@"__isNull": @(YES)};
}
return @{@"__clsName": NSStringFromClass([obj class]), @"__obj": obj};
View
@@ -14,10 +14,10 @@ var global = this
}
var _formatOCToJS = function(obj) {
if (obj === undefined || obj === null) return null
if (obj === undefined || obj === null) return false
if (typeof obj == "object") {
if (obj.__obj) return obj
if (obj.__isNull) return null
if (obj.__isNull) return false
}
if (obj instanceof Array) {
var ret = []
@@ -57,6 +57,12 @@ var global = this
}
Object.prototype.__c = function(methodName) {
if (this instanceof Boolean) {
return function() {
return false
}
}
if (!this.__obj && !this.__clsName) {
return this[methodName].bind(this);
}
@@ -18,8 +18,12 @@
@property (nonatomic, assign) BOOL funcWithIntPassed;
@property (nonatomic, assign) BOOL funcWithNilPassed;
@property (nonatomic, assign) BOOL funcReturnNilPassed;
@property (nonatomic, assign) BOOL funcWithNilAndOthersPassed;
@property (nonatomic, assign) BOOL funcWithNullPassed;
@property (nonatomic, assign) BOOL funcTestBoolPassed;
@property (nonatomic, assign) BOOL funcTestNSNumberPassed;
@property (nonatomic, assign) BOOL funcWithDictAndDoublePassed;
@@ -60,6 +60,21 @@ - (void)funcWithNil:(NSObject *)nilObj
self.funcWithNilPassed = nilObj == nil;
}
- (id)funcReturnNil
{
return nil;
}
- (BOOL)funcTestBool:(BOOL)b
{
return b;
}
- (NSNumber *)funcTestNSNumber:(NSNumber *)num
{
return num;
}
- (void)funcWithNil:(NSObject *)nilObj dict:(NSDictionary *)dict str:(NSString *)str num:(double)num
{
self.funcWithNilAndOthersPassed = nilObj == nil && [dict[@"k"] isEqualToString:@"JSPatch"] && [str isEqualToString:@"JSPatch"] && num - 4.2 < 0.001;
@@ -54,8 +54,11 @@ - (void)testEngine {
XCTAssert(obj.funcWithIntPassed, @"funcWithIntPassed");
XCTAssert(obj.funcWithNilPassed, @"funcWithNilPassed");
XCTAssert(obj.funcReturnNilPassed, @"funcReturnNilPassed");
XCTAssert(obj.funcWithNilAndOthersPassed, @"funcWithNilAndOthersPassed");
XCTAssert(obj.funcWithNullPassed, @"funcWithNullPassed");
XCTAssert(obj.funcTestBoolPassed, @"funcTestBoolPassed");
XCTAssert(obj.funcTestNSNumberPassed, @"funcTestNSNumberPassed");
XCTAssert(obj.funcWithDictAndDoublePassed, @"funcWithDictAndDoublePassed");
@@ -109,9 +109,23 @@ var global = this;
obj.funcWithInt(42);
obj.funcWithDict_andDouble({test: "test"}, 4.2)
//////nil / NSNull
obj.funcWithNil_dict_str_num(null, {k: "JSPatch"}, "JSPatch", 4.2)
obj.funcWithNil(null)
obj.funcWithNull(nsnull)
var o = obj.funcReturnNil()
obj.funcWithNil(o)
obj.setFuncReturnNilPassed(!o)
o.callAnyMethod().willNotCrash()
var bTrue = obj.funcTestBool(true)
var bFalse = obj.funcTestBool(false)
var bFalseNum = obj.funcTestBool(0)
obj.setFuncTestBoolPassed(bTrue && !bFalse && !bFalseNum)
var num0 = obj.funcTestNSNumber(0)
var num1 = obj.funcTestNSNumber(1)
obj.setFuncTestNSNumberPassed(num0 === 0 && num1 === 1)
///////UIView/NSObject
var view = obj.funcReturnViewWithFrame({

0 comments on commit cb7688e

Please sign in to comment.