From 2aaa038ef182cbba3095fa7636c15ab376f87b84 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Wed, 28 Mar 2018 18:09:17 -0400 Subject: [PATCH] [ios, macos] Add lookup and feature operators. (#11528) * [ios, macos] Add Expressions 'at' operator. * [ios, macos] Implement 'has' operator. * [ios, macos] Implement expressions feature operators. * [ios, macos] Refactor expressions variable name and 'mgl_has' implementation. * [ios, macos] Refactor expresssion variable names. * [ios, macos] Update 'mgl_has' to support non-self operands. --- .../darwin/src/NSExpression+MGLAdditions.mm | 45 +++++++++++++++ .../src/NSExpression+MGLPrivateAdditions.h | 4 ++ platform/darwin/test/MGLExpressionTests.mm | 57 +++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index 9797709b7bd..a193b85caaf 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -277,6 +277,12 @@ - (id)mgl_jsonExpressionObject { return expressionObject; } +- (id)mgl_has:(id)element { + [NSException raise:NSInvalidArgumentException + format:@"Has expressions lack underlying Objective-C implementations."]; + return nil; +} + @end @implementation NSExpression (MGLExpressionAdditions) @@ -287,6 +293,12 @@ - (NSExpression *)mgl_expressionWithContext:(NSDictionary 1 ? subexpressions[1] : [NSExpression expressionWithFormat:@"self"]; + NSExpression *property = subexpressions.firstObject; + return [NSExpression expressionWithFormat:@"FUNCTION(%@, 'mgl_has:', %@)", operand, property]; } else if ([op isEqualToString:@"interpolate"]) { NSArray *interpolationOptions = argumentObjects.firstObject; NSString *curveType = interpolationOptions.firstObject; @@ -456,6 +478,12 @@ + (instancetype)mgl_expressionWithJSONObject:(id)object { return [NSExpression expressionForVariable:@"zoomLevel"]; } else if ([op isEqualToString:@"heatmap-density"]) { return [NSExpression expressionForVariable:@"heatmapDensity"]; + } else if ([op isEqualToString:@"geometry-type"]) { + return [NSExpression expressionForVariable:@"mgl_geometryType"]; + } else if ([op isEqualToString:@"id"]) { + return [NSExpression expressionForVariable:@"mgl_featureIdentifier"]; + } else if ([op isEqualToString:@"properties"]) { + return [NSExpression expressionForVariable:@"mgl_featureProperties"]; } else if ([op isEqualToString:@"let"]) { NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.lastObject]; NSArray *bindingObjects = [argumentObjects subarrayWithRange:NSMakeRange(0, argumentObjects.count - 1)]; @@ -544,6 +572,15 @@ - (id)mgl_jsonExpressionObject { if ([self.variable isEqualToString:@"zoomLevel"]) { return @[@"zoom"]; } + if ([self.variable isEqualToString:@"mgl_geometryType"]) { + return @[@"geometry-type"]; + } + if ([self.variable isEqualToString:@"mgl_featureIdentifier"]) { + return @[@"id"]; + } + if ([self.variable isEqualToString:@"mgl_featureProperties"]) { + return @[@"properties"]; + } return @[@"var", self.variable]; } @@ -639,6 +676,8 @@ - (id)mgl_jsonExpressionObject { } else if ([function isEqualToString:@"stringByAppendingString:"]) { NSArray *arguments = self.arguments.mgl_jsonExpressionObject; return [@[@"concat", self.operand.mgl_jsonExpressionObject] arrayByAddingObjectsFromArray:arguments]; + } else if ([function isEqualToString:@"objectFrom:withIndex:"]) { + return @[@"at", self.arguments[1].mgl_jsonExpressionObject, self.arguments[0].mgl_jsonExpressionObject]; } else if ([function isEqualToString:@"boolValue"]) { return @[@"to-boolean", self.operand.mgl_jsonExpressionObject]; } else if ([function isEqualToString:@"mgl_numberWithFallbackValues:"] || @@ -651,6 +690,12 @@ - (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_interpolateWithCurveType:parameters:stops:"]) { if (self.arguments.count < 3) { [NSException raise:NSInvalidArgumentException format: diff --git a/platform/darwin/src/NSExpression+MGLPrivateAdditions.h b/platform/darwin/src/NSExpression+MGLPrivateAdditions.h index b16e2625a05..f726dd3e712 100644 --- a/platform/darwin/src/NSExpression+MGLPrivateAdditions.h +++ b/platform/darwin/src/NSExpression+MGLPrivateAdditions.h @@ -62,6 +62,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) id mgl_jsonExpressionObject; +- (id)mgl_has:(id)element; + @end @interface MGLColor (MGLExpressionAdditions) @@ -74,6 +76,8 @@ NS_ASSUME_NONNULL_BEGIN - (NSExpression *)mgl_expressionWithContext:(NSDictionary *)context; +- (id)mgl_has:(id)element; + @end extern NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects); diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index ea5a1cd41ce..d189b41cd77 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -170,6 +170,24 @@ - (void)testVariableExpressionObject { NSMutableDictionary *context = [@{@"heatmapDensity": @1} mutableCopy]; XCTAssertEqualObjects([expression expressionValueWithObject:nil context:context], @1); } + { + NSExpression *expression = [NSExpression expressionForVariable:@"mgl_geometryType"]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"geometry-type"]); + XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$mgl_geometryType"].mgl_jsonExpressionObject, @[@"geometry-type"]); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:@[@"geometry-type"]], expression); + } + { + NSExpression *expression = [NSExpression expressionForVariable:@"mgl_featureIdentifier"]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"id"]); + XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$mgl_featureIdentifier"].mgl_jsonExpressionObject, @[@"id"]); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:@[@"id"]], expression); + } + { + NSExpression *expression = [NSExpression expressionForVariable:@"mgl_featureProperties"]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"properties"]); + XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$mgl_featureProperties"].mgl_jsonExpressionObject, @[@"properties"]); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:@[@"properties"]], expression); + } { NSExpression *expression = [NSExpression expressionForVariable:@"loremIpsum"]; NSArray *jsonExpression = @[@"var", @"loremIpsum"]; @@ -629,4 +647,43 @@ - (void)testConditionalExpressionObject { } +- (void)testLookupExpressionObject { + { + NSExpression *array = [NSExpression expressionForAggregate:@[MGLConstantExpression(@9), + MGLConstantExpression(@8), + MGLConstantExpression(@7)]]; + NSExpression *expression = [NSExpression expressionForFunction:@"objectFrom:withIndex:" arguments:@[array, MGLConstantExpression(@1)]]; + NSArray *jsonExpression = @[@"at", @1, @[ @"literal", @[@9, @8, @7]]]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); + } + { + NSExpression *array = [NSExpression expressionForAggregate:@[MGLConstantExpression(@9), + MGLConstantExpression(@8), + MGLConstantExpression(@7)]]; + NSExpression *expression = [NSExpression expressionForFunction:@"objectFrom:withIndex:" arguments:@[array, [NSExpression expressionForKeyPath:@"x"]]]; + NSArray *jsonExpression = @[@"at", @[@"get", @"x"], @[ @"literal", @[@9, @8, @7]]]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); + } + { + NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(self, 'mgl_has:', 'x')"]; + NSArray *jsonExpression = @[@"has", @"x"]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); + } + { + NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(%@, 'mgl_has:', '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')"]; + NSArray *jsonExpression = @[@"has", @"x", @[@"properties"]]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); + } +} + @end