diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index 4f5739aaa13..a5676529fc9 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -61,6 +61,7 @@ + (void)installFunctions { INSTALL_METHOD(mgl_interpolate:withCurveType:parameters:stops:); INSTALL_METHOD(mgl_step:from:stops:); INSTALL_METHOD(mgl_coalesce:); + INSTALL_METHOD(mgl_hasProperty:properties:); // Install functions that resemble control structures, taking arbitrary // numbers of arguments. Vararg aftermarket functions need to be declared @@ -109,6 +110,15 @@ - (id)mgl_coalesce:(NSArray *)elements { return nil; } +/** + A placeholder for a method that evaluates a coalesce expression. + */ +- (id)mgl_hasProperty:(id)element properties:(id)properties { + [NSException raise:NSInvalidArgumentException + format:@"Has expressions lack underlying Objective-C implementations."]; + return nil; +} + /** A placeholder for a method that evaluates an expression based on an arbitrary number of variable names and assigned expressions. @@ -586,7 +596,8 @@ + (instancetype)mgl_expressionWithJSONObject:(id)object { NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects); NSExpression *operand = argumentObjects.count > 1 ? subexpressions[1] : [NSExpression expressionWithFormat:@"self"]; NSExpression *property = subexpressions.firstObject; - return [NSExpression expressionWithFormat:@"FUNCTION(%@, 'mgl_has:', %@)", operand, property]; + + return [NSExpression expressionForFunction:@"mgl_hasProperty:properties:" arguments:@[property, operand]]; } else if ([op isEqualToString:@"interpolate"]) { NSArray *interpolationOptions = argumentObjects.firstObject; NSString *curveType = interpolationOptions.firstObject; @@ -837,12 +848,9 @@ - (id)mgl_jsonExpressionObject { return @[@"to-string", self.operand.mgl_jsonExpressionObject]; } else if ([function isEqualToString:@"noindex:"]) { return self.arguments.firstObject.mgl_jsonExpressionObject; - } else if ([function isEqualToString:@"mgl_has:"]) { - NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"has", self.arguments[0].mgl_jsonExpressionObject, nil]; - if (self.operand.expressionType != NSEvaluatedObjectExpressionType) { - [expressionObject addObject:self.operand.mgl_jsonExpressionObject]; - } - return expressionObject; + } else if ([function isEqualToString:@"mgl_hasProperty:properties:"] || + [function isEqualToString:@"mgl_has:"]) { + return self.mgl_jsonHasExpressionObject; } else if ([function isEqualToString:@"mgl_interpolate:withCurveType:parameters:stops:"] || [function isEqualToString:@"mgl_interpolateWithCurveType:parameters:stops:"]) { return self.mgl_jsonInterpolationExpressionObject; @@ -1066,4 +1074,17 @@ - (id)mgl_jsonCoalesceExpressionObject { return expressionObject; } +- (id)mgl_jsonHasExpressionObject { + BOOL isAftermarketFunction = [self.function isEqualToString:@"mgl_hasProperty:properties:"]; + NSExpression *operand = isAftermarketFunction ? self.arguments[1] : self.operand; + + NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"has", self.arguments[0].mgl_jsonExpressionObject, nil]; + if (operand.expressionType != NSEvaluatedObjectExpressionType) { + [expressionObject addObject:operand.mgl_jsonExpressionObject]; + } + return expressionObject; + + return expressionObject; +} + @end diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index 20209f305e4..9c6a4549436 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -718,19 +718,24 @@ - (void)testLookupExpressionObject { XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); } { - NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(self, 'mgl_has:', 'x')"]; + NSExpression *expression = [NSExpression expressionForFunction:@"mgl_hasProperty:properties:" arguments:@[[NSExpression expressionForConstantValue:@"x"], + [NSExpression expressionForEvaluatedObject]]]; + NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(self, 'mgl_has:', 'x')"]; NSArray *jsonExpression = @[@"has", @"x"]; XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression); XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); } { - NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(%@, 'mgl_has:', 'x')", [NSExpression expressionForConstantValue:@{@"x": MGLConstantExpression(@0)}]]; + NSExpression *expression = [NSExpression expressionForFunction:@"mgl_hasProperty:properties:" arguments:@[[NSExpression expressionForConstantValue:@"x"], + [NSExpression expressionForConstantValue:@{@"x": MGLConstantExpression(@0)}]]]; NSArray *jsonExpression = @[@"has", @"x", @[@"literal", @{@"x": @0}]]; XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); } { - NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION($mgl_featureProperties, 'mgl_has:', 'x')"]; + NSExpression *expression = [NSExpression expressionForFunction:@"mgl_hasProperty:properties:" arguments:@[[NSExpression expressionForConstantValue:@"x"], + [NSExpression expressionForVariable:@"mgl_featureProperties"]]]; NSArray *jsonExpression = @[@"has", @"x", @[@"properties"]]; XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);