summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2018-03-26 10:19:41 -0700
committerFabian Guerra <fabian.guerra@mapbox.com>2018-03-28 19:37:12 -0400
commit1dcc93d9213a7aee2f049ec3cb52b04d7a244373 (patch)
tree73d8f9663a59b944ccf0870a6a0c4fa3bc8d58d1
parent66648e5ac25f86a0c643d2837163b143bc63b2e0 (diff)
downloadqtlocation-mapboxgl-1dcc93d9213a7aee2f049ec3cb52b04d7a244373.tar.gz
[ios, macos] Aftermarket let expressions
-rw-r--r--platform/darwin/docs/guides/Predicates and Expressions.md17
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm29
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm13
3 files changed, 31 insertions, 28 deletions
diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md
index 97834b4f71..5e6af06dc4 100644
--- a/platform/darwin/docs/guides/Predicates and Expressions.md
+++ b/platform/darwin/docs/guides/Predicates and Expressions.md
@@ -193,6 +193,7 @@ string syntax:
Initializer parameter | Format string syntax | Arguments | Returns
----------------------|----------------------|-----------|--------
`mgl_join:` | `mgl_join({'Old', 'MacDonald'})` | An aggregate expression or `NSArray` constant value expression containing one or more `NSExpression`s, each evaluating to a string. | An `NSString` object (the result of concatenating together all the elements of an array in order).
+`MGL_LET` | `MGL_LET('age', uppercase('old'), 'name', uppercase('MacDonald'), mgl_join({$age, $name}))` | Any number of variable names interspersed with their assigned `NSExpression` values, followed by an `NSExpression` that may contain references to those variables.
The following custom functions are also available with the
`+[NSExpression expressionForFunction:selectorName:arguments:]` method or the
@@ -215,22 +216,6 @@ The following custom functions are also available with the
</td>
</tr>
<tr>
- <td><code>mgl_expressionWithContext:</code></td>
- <td>
- An `NSExpression` that may contain references to the variables defined in
- the context dictionary.
- </td>
- <td>
- An `NSDictionary` with `NSString`s as keys and `NSExpression`s as values.
- Each key is a variable name and each value is the variable’s value within
- the target expression.
- </td>
- <td>
- The target expression with variable subexpressions replaced with the
- values defined in the context dictionary.
- </td>
-</tr>
-<tr>
<td><code>mgl_interpolateWithCurveType:parameters:stops:</code></td>
<td>
An `NSExpression` that evaluates to a number and contains a variable or
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index 43661a5502..16c1656fb8 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -24,6 +24,16 @@ NSString *MGLJoinComponents(Class self, SEL _cmd, NSArray<NSString *> *component
}
/**
+ A placeholder for a method that evaluates an expression based on an arbitrary
+ number of variable names and assigned expressions.
+ */
+id MGLEvaluateWithContext(Class self, SEL _cmd, NSString *firstVariableName, ...) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Assignment expressions lack underlying Objective-C implementations."];
+ return nil;
+};
+
+/**
Adds to NSExpression’s built-in repertoire of functions.
*/
void MGLInstallAftermarketExpressionFunctions() {
@@ -38,6 +48,10 @@ void MGLInstallAftermarketExpressionFunctions() {
#pragma clang push
#pragma clang diagnostic ignored "-Wundeclared-selector"
class_addMethod(NSPredicateUtilities, @selector(mgl_join:), (IMP)MGLJoinComponents, "@@:@");
+
+ // Vararg aftermarket expressions need to be declared with an explicit and implicit first argument.
+ class_addMethod(NSPredicateUtilities, @selector(MGL_LET), (IMP)MGLEvaluateWithContext, "@@:@");
+ class_addMethod(NSPredicateUtilities, @selector(MGL_LET:), (IMP)MGLEvaluateWithContext, "@@:@");
#pragma clang pop
}
@@ -369,6 +383,7 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
@"^": @"raise:toPower:",
@"upcase": @"uppercase:",
@"downcase": @"lowercase:",
+ @"let": @"MGL_LET",
};
});
@@ -530,17 +545,6 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
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)];
- NSMutableDictionary *context = [NSMutableDictionary dictionaryWithCapacity:bindingObjects.count / 2];
- NSEnumerator *bindingEnumerator = bindingObjects.objectEnumerator;
- while (NSString *key = bindingEnumerator.nextObject) {
- context[key] = [NSExpression mgl_expressionWithJSONObject:bindingEnumerator.nextObject];
- }
- return [NSExpression expressionForFunction:operand
- selectorName:@"mgl_expressionWithContext:"
- arguments:@[[NSExpression expressionForConstantValue:context]]];
} else if ([op isEqualToString:@"var"]) {
return [NSExpression expressionForVariable:argumentObjects.firstObject];
} else if ([op isEqualToString:@"case"]) {
@@ -608,6 +612,9 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
@"uppercase:": @"upcase",
@"lowercase:": @"downcase",
@"length:": @"length",
+ // Vararg aftermarket expressions need to be declared with an explicit and implicit first argument.
+ @"MGL_LET": @"let",
+ @"MGL_LET:": @"let",
};
});
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 5451174e24..94c9410892 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -199,9 +199,11 @@ using namespace std::string_literals;
}
{
NSDictionary *context = @{@"loremIpsum": MGLConstantExpression(@"Lorem ipsum dolor sit amet")};
- NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(uppercase($loremIpsum), 'mgl_expressionWithContext:', %@)", context];
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_LET('loremIpsum', 'Lorem ipsum dolor sit amet', uppercase($loremIpsum))", context];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(uppercase($loremIpsum), 'mgl_expressionWithContext:', %@)", context];
NSArray *jsonExpression = @[@"let", @"loremIpsum", @"Lorem ipsum dolor sit amet", @[@"upcase", @[@"var", @"loremIpsum"]]];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
}
}
@@ -353,6 +355,15 @@ using namespace std::string_literals;
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
}
{
+ NSArray *arguments = @[MGLConstantExpression(@1), MGLConstantExpression(@1), MGLConstantExpression(@1)];
+ NSExpression *expression = [NSExpression expressionForFunction:@"add:to:" arguments:arguments];
+ NSArray *jsonExpression = @[@"+", @1, @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ jsonExpression = @[@"+", @[@"+", @1, @1], @1];
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 + 1 + 1"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], [NSExpression expressionWithFormat:@"1 + 1 + 1"]);
+ }
+ {
NSExpression *expression = [NSExpression expressionForFunction:@"from:subtract:" arguments:arguments];
NSArray *jsonExpression = @[@"-", @1, @1];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);