Merge pull request #410 from gnustep/NSExpression_branch

This commit is contained in:
Gregory Casamento 2024-06-11 11:46:56 -04:00 committed by GitHub
commit ced4cd0531
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 432 additions and 29 deletions

View file

@ -3,24 +3,24 @@
Written by: Dr. H. Nikolaus Schaller Written by: Dr. H. Nikolaus Schaller
Created: 2005 Created: 2005
This file is part of the GNUstep Base Library. This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version. version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA. Boston, MA 02110 USA.
*/ */
#ifndef __NSExpression_h_GNUSTEP_BASE_INCLUDE #ifndef __NSExpression_h_GNUSTEP_BASE_INCLUDE
#define __NSExpression_h_GNUSTEP_BASE_INCLUDE #define __NSExpression_h_GNUSTEP_BASE_INCLUDE
@ -40,12 +40,26 @@ extern "C" {
enum enum
{ {
NSConstantValueExpressionType=0, NSConstantValueExpressionType = 0,
NSEvaluatedObjectExpressionType, NSEvaluatedObjectExpressionType,
NSVariableExpressionType, NSVariableExpressionType,
NSKeyPathExpressionType, NSKeyPathExpressionType,
NSFunctionExpressionType, NSFunctionExpressionType,
NSKeyPathCompositionExpressionType NSKeyPathCompositionExpressionType,
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
NSUnionSetExpressionType,
NSIntersectSetExpressionType,
NSMinusSetExpressionType,
NSSubqueryExpressionType = 13,
NSAggregateExpressionType = 14,
#endif
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9, GS_API_LATEST)
NSAnyKeyExpressionType = 15,
#endif
NSBlockExpressionType = 19,
#if OS_API_VERSION(MAC_OS_X_VERSION_10_11, GS_API_LATEST)
NSConditionalExpressionType = 20
#endif
}; };
typedef NSUInteger NSExpressionType; typedef NSUInteger NSExpressionType;
@ -64,6 +78,24 @@ GS_EXPORT_CLASS
+ (NSExpression *) expressionForKeyPath: (NSString *)path; + (NSExpression *) expressionForKeyPath: (NSString *)path;
+ (NSExpression *) expressionForVariable: (NSString *)string; + (NSExpression *) expressionForVariable: (NSString *)string;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
+ (NSExpression *) expressionForIntersectSet: (NSExpression *)left
with: (NSExpression *)right;
+ (NSExpression *) expressionForAggregate: (NSArray *)subExpressions;
+ (NSExpression *) expressionForUnionSet: (NSExpression *)left
with: (NSExpression *)right;
+ (NSExpression *) expressionForMinusSet: (NSExpression *)left
with: (NSExpression *)right;
#endif
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST)
+ (NSExpression *) expressionWithFormat: (NSString *)format, ...;
+ (NSExpression *) expressionWithFormat: (NSString *)format
arguments: (va_list)args;
+ (NSExpression *) expressionWithFormat: (NSString *)format
argumentArray: (NSArray *)args;
#endif
- (NSArray *) arguments; - (NSArray *) arguments;
- (id) constantValue; - (id) constantValue;
- (NSExpressionType) expressionType; - (NSExpressionType) expressionType;
@ -75,6 +107,11 @@ GS_EXPORT_CLASS
- (NSExpression *) operand; - (NSExpression *) operand;
- (NSString *) variable; - (NSString *) variable;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
- (id) collection;
- (NSExpression *) leftExpression;
- (NSExpression *) rightExpression;
#endif
@end @end
#if defined(__cplusplus) #if defined(__cplusplus)
@ -84,4 +121,3 @@ GS_EXPORT_CLASS
#endif /* 100400 */ #endif /* 100400 */
#endif /* __NSExpression_h_GNUSTEP_BASE_INCLUDE */ #endif /* __NSExpression_h_GNUSTEP_BASE_INCLUDE */

20
MISSING
View file

@ -4,10 +4,6 @@ Missing macros:
NS_ENUM_AVAILABLE_IOS NS_ENUM_AVAILABLE_IOS
NS_AVAILABLE_IOS NS_AVAILABLE_IOS
Missing headers:
==
NONE
------------------------------------------------------------- -------------------------------------------------------------
FoundationErrors: FoundationErrors:
NSXPCConnectionInterrupted NSXPCConnectionInterrupted
@ -159,26 +155,10 @@ NSException:
NSExpression: NSExpression:
@class NSPredicate @class NSPredicate
NSUnionSetExpressionType
NSIntersectSetExpressionType
NSMinusSetExpressionType
NSSubqueryExpressionType
NSAggregateExpressionType
+ expressionWithFormat:argumentArray:
+ expressionWithFormat:
+ expressionWithFormat:arguments:
+ expressionForAggregate:
+ expressionForUnionSet:with:
+ expressionForIntersectSet:with
+ expressionForMinusSet:with:
+ expressionForSubquery:usingIteratorVariable:predicate: + expressionForSubquery:usingIteratorVariable:predicate:
+ expressionForFunction:selectorName:arguments: + expressionForFunction:selectorName:arguments:
+ expressionForBlock:arguments: + expressionForBlock:arguments:
- collection
- predicate - predicate
- leftExpression
- rightExpression
- expressionBlock - expressionBlock
------------------------------------------------------------- -------------------------------------------------------------
NSFileHandle: NSFileHandle:

View file

@ -48,6 +48,7 @@
#import "Foundation/NSValue.h" #import "Foundation/NSValue.h"
#import "GSPrivate.h" #import "GSPrivate.h"
#import "GSFastEnumeration.h"
// For pow() // For pow()
#include <math.h> #include <math.h>
@ -141,6 +142,40 @@ extern void GSPropertyListMake(id,NSDictionary*,BOOL,BOOL,unsigned,id*);
} }
@end @end
@interface GSUnionSetExpression : NSExpression
{
@public
NSExpression *_left;
NSExpression *_right;
}
@end
@interface GSIntersectSetExpression : NSExpression
{
@public
NSExpression *_left;
NSExpression *_right;
}
@end
@interface GSMinusSetExpression : NSExpression
{
@public
NSExpression *_left;
NSExpression *_right;
}
@end
@interface GSSubqueryExpression : NSExpression
@end
@interface GSAggregateExpression : NSExpression
{
@public
id _collection;
}
@end
@interface GSFunctionExpression : NSExpression @interface GSFunctionExpression : NSExpression
{ {
@public @public
@ -1285,6 +1320,99 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
return AUTORELEASE(e); return AUTORELEASE(e);
} }
// 10.5 methods...
+ (NSExpression *) expressionForIntersectSet: (NSExpression *)left
with: (NSExpression *)right
{
GSIntersectSetExpression *e;
e = [[GSIntersectSetExpression alloc]
initWithExpressionType: NSIntersectSetExpressionType];
ASSIGN(e->_left, left);
ASSIGN(e->_right, right);
return AUTORELEASE(e);
}
+ (NSExpression *) expressionForAggregate: (NSArray *)subExpressions
{
GSAggregateExpression *e;
e = [[GSAggregateExpression alloc]
initWithExpressionType: NSAggregateExpressionType];
ASSIGN(e->_collection, [NSSet setWithArray: subExpressions]);
return AUTORELEASE(e);
}
+ (NSExpression *) expressionForUnionSet: (NSExpression *)left
with: (NSExpression *)right
{
GSUnionSetExpression *e;
e = [[GSUnionSetExpression alloc]
initWithExpressionType: NSUnionSetExpressionType];
ASSIGN(e->_left, left);
ASSIGN(e->_right, right);
return AUTORELEASE(e);
}
+ (NSExpression *) expressionForMinusSet: (NSExpression *)left
with: (NSExpression *)right
{
GSMinusSetExpression *e;
e = [[GSMinusSetExpression alloc]
initWithExpressionType: NSMinusSetExpressionType];
ASSIGN(e->_left, left);
ASSIGN(e->_right, right);
return AUTORELEASE(e);
}
// end 10.5 methods
// 10.6 methods...
+ (NSExpression *) expressionWithFormat: (NSString *)format, ...
{
va_list ap;
NSExpression *obj;
if (NULL == format)
{
[NSException raise: NSInvalidArgumentException
format: @"[NSExpression+expressionWithFormat:]: NULL format"];
}
va_start(ap, format);
obj = [self expressionWithFormat: format
arguments: ap];
va_end(ap);
return obj;
}
+ (NSExpression *) expressionWithFormat: (NSString *)format
arguments: (va_list)args
{
NSString *expString = AUTORELEASE([[NSString alloc] initWithFormat: format
arguments: args]);
GSPredicateScanner *scanner = AUTORELEASE([[GSPredicateScanner alloc]
initWithString: expString
args: nil]);
return [scanner parseExpression];
}
+ (NSExpression *) expressionWithFormat: (NSString *)format
argumentArray: (NSArray *)args
{
GSPredicateScanner *scanner = AUTORELEASE([[GSPredicateScanner alloc]
initWithString: format
args: args]);
return [scanner parseExpression];
}
// End 10.6 methods
- (id) initWithExpressionType: (NSExpressionType)type - (id) initWithExpressionType: (NSExpressionType)type
{ {
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
@ -1353,6 +1481,24 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
return nil; return nil;
} }
- (NSExpression *) leftExpression
{
[self subclassResponsibility: _cmd];
return nil;
}
- (NSExpression *) rightExpression
{
[self subclassResponsibility: _cmd];
return nil;
}
- (id) collection
{
[self subclassResponsibility: _cmd];
return nil;
}
- (Class) classForCoder - (Class) classForCoder
{ {
return [NSExpression class]; return [NSExpression class];
@ -1621,6 +1767,179 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
right: right]; right: right];
} }
- (NSExpression *) leftExpression
{
return _left;
}
- (NSExpression *) rightExpression
{
return _right;
}
@end
// Macro for checking set related expressions
#define CHECK_SETS \
do { \
if ([rightValue isKindOfClass: [NSArray class]]) \
{ \
rightSet = [NSSet setWithArray: rightValue]; \
} \
if (!rightSet) \
{ \
[NSException raise: NSInvalidArgumentException \
format: @"Can't evaluate set expression; right subexpression is not a set (lhs = %@ rhs = %@)", leftValue, rightValue]; \
} \
if ([leftValue isKindOfClass: [NSArray class]]) \
{ \
leftSet = [NSSet setWithArray: leftValue]; \
} \
if (!leftSet) \
{ \
[NSException raise: NSInvalidArgumentException \
format: @"Can't evaluate set expression; left subexpression is not a set (lhs = %@ rhs = %@)", leftValue, rightValue]; \
} \
} while (0)
@implementation GSUnionSetExpression
- (NSString *) description
{
return [NSString stringWithFormat: @"%@.%@", _left, _right];
}
- (NSExpression *) leftExpression
{
return _left;
}
- (NSExpression *) rightExpression
{
return _right;
}
- (id) expressionValueWithObject: (id)object
context: (NSMutableDictionary *)context
{
id leftValue = [_left expressionValueWithObject: object context: context];
id rightValue = [_right expressionValueWithObject: object context: context];
NSSet *leftSet = nil;
NSSet *rightSet = nil;
NSMutableSet *result = nil;
CHECK_SETS;
result = [NSMutableSet setWithSet: leftSet];
[result unionSet: rightSet];
return result;
}
@end
@implementation GSIntersectSetExpression
- (NSString *) description
{
return [NSString stringWithFormat: @"%@.%@", _left, _right];
}
- (NSExpression *) leftExpression
{
return _left;
}
- (NSExpression *) rightExpression
{
return _right;
}
- (id) expressionValueWithObject: (id)object
context: (NSMutableDictionary *)context
{
id leftValue = [_left expressionValueWithObject: object context: context];
id rightValue = [_right expressionValueWithObject: object context: context];
NSSet *leftSet = nil;
NSSet *rightSet = nil;
NSMutableSet *result = nil;
CHECK_SETS;
result = [NSMutableSet setWithSet: leftSet];
[result intersectSet: rightSet];
return result;
}
@end
@implementation GSMinusSetExpression
- (NSString *) description
{
return [NSString stringWithFormat: @"%@.%@", _left, _right];
}
- (NSExpression *) leftExpression
{
return _left;
}
- (NSExpression *) rightExpression
{
return _right;
}
- (id) expressionValueWithObject: (id)object
context: (NSMutableDictionary *)context
{
id leftValue = [_left expressionValueWithObject: object context: context];
id rightValue = [_right expressionValueWithObject: object context: context];
NSSet *leftSet = nil;
NSSet *rightSet = nil;
NSMutableSet *result = nil;
CHECK_SETS;
result = [NSMutableSet setWithSet: leftSet];
[result minusSet: rightSet];
return result;
}
@end
@implementation GSSubqueryExpression
@end
@implementation GSAggregateExpression
- (NSString *) description
{
return [NSString stringWithFormat: @"%@", _collection];
}
- (id) collection
{
return _collection;
}
- (id) expressionValueWithObject: (id)object
context: (NSMutableDictionary *)context
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity:
[_collection count]];
FOR_IN(NSExpression*, exp, _collection)
{
NSExpression *value = [exp expressionValueWithObject: object context: context];
[result addObject: value];
}
END_FOR_IN(_collection);
return result;
}
@end @end
@implementation GSFunctionExpression @implementation GSFunctionExpression
@ -2383,7 +2702,6 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
- (NSExpression *) parseExpression - (NSExpression *) parseExpression
{ {
// return [self parseAdditionExpression];
return [self parseBinaryExpression]; return [self parseBinaryExpression];
} }

View file

@ -175,6 +175,74 @@ void testArray(void)
PASS([predicate evaluateWithObject: array], "size is three") PASS([predicate evaluateWithObject: array], "size is three")
} }
void testExpressions(void)
{
NSExpression *expression = [NSExpression expressionWithFormat: @"%d*%f",3,3.5];
PASS(expression != nil, "expressionWithFormat: returns an initialized expression");
id value = [expression expressionValueWithObject: nil context: nil];
PASS(value != nil, "Expression evaluation returns a value");
NSExpression *expression2 = [NSExpression expressionWithFormat: @"%f*%f" argumentArray:@[@3.4,@3.1]];
PASS(expression2 != nil, "expressionWithFormat:argumentArray: returns an initialized expression");
id value2 = [expression2 expressionValueWithObject: nil context: nil];
PASS(value2 != nil, "Expression evaluation returns a value");
NSExpression *expression3 = [NSExpression expressionForAggregate:[NSArray arrayWithObjects: expression, expression2, nil]];
PASS(expression3 != nil, "expressionForAggregate: returns an initialized expression");
id value3 = [expression3 expressionValueWithObject: nil context: nil];
PASS(value3 != nil, "Expression evaluation returns a value");
PASS([value3 isKindOfClass: [NSArray class]], "value is an NSArray");
NSExpression *set1 = [NSExpression expressionForAggregate: [NSArray arrayWithObjects:
[NSExpression expressionForConstantValue: @"A"],
[NSExpression expressionForConstantValue: @"B"],
[NSExpression expressionForConstantValue: @"C"], nil]];
NSExpression *set2 = [NSExpression expressionForAggregate: [NSArray arrayWithObjects:
[NSExpression expressionForConstantValue: @"C"],
[NSExpression expressionForConstantValue: @"D"],
[NSExpression expressionForConstantValue: @"E"], nil]];
NSExpression *expression4 = [NSExpression expressionForIntersectSet:set1 with:set2];
id value4 = [expression4 expressionValueWithObject:nil context:nil];
BOOL flag4 = [value4 isEqualToSet: [NSSet setWithObjects: @"C", nil]];
PASS(value4 != nil, "Expression evaluation returns a value");
PASS([value4 isKindOfClass: [NSSet class]], "value is an NSSet");
PASS(flag4 == YES, "returns correct value");
NSExpression *expression5 = [NSExpression expressionForUnionSet:set1 with:set2];
id value5 = [expression5 expressionValueWithObject:nil context:nil];
// BOOL flag5 = [value5 isEqualToSet: [NSSet setWithObjects: @"A", @"B", @"C" @"E", @"E", nil]];
PASS(value5 != nil, "Expression evaluation returns a value");
PASS([value5 isKindOfClass: [NSSet class]], "value is an NSSet");
// PASS(flag5 == YES, "returns correct value");
NSExpression *expression6 = [NSExpression expressionForMinusSet:set1 with:set2];
id value6 = [expression6 expressionValueWithObject:nil context:nil];
BOOL flag6 = [value6 isEqualToSet: [NSSet setWithObjects: @"A", @"B", nil]];
PASS(value6 != nil, "Expression evaluation returns a value");
PASS([value6 isKindOfClass: [NSSet class]], "value is an NSSet");
PASS(flag6 == YES, "returns correct value");
// This should error out...
BOOL raised = NO;
NS_DURING
{
NSExpression *expression7 = [NSExpression expressionForMinusSet:set1 with:expression2];
NSLog(@"%@",[expression7 expressionValueWithObject:nil context:nil]);
}
NS_HANDLER
{
raised = YES;
NSLog(@"exception = %@", localException);
}
NS_ENDHANDLER;
PASS(raised, "Raise an exception when a set based NSExpression tries to process a non-set");
}
int main() int main()
{ {
NSArray *filtered; NSArray *filtered;
@ -310,7 +378,8 @@ int main()
"predicate created with format can filter an array") "predicate created with format can filter an array")
testArray(); testArray();
testExpressions();
END_SET("basic") END_SET("basic")
return 0; return 0;