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
Created: 2005
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
*/
#ifndef __NSExpression_h_GNUSTEP_BASE_INCLUDE
#define __NSExpression_h_GNUSTEP_BASE_INCLUDE
@ -40,12 +40,26 @@ extern "C" {
enum
{
NSConstantValueExpressionType=0,
NSConstantValueExpressionType = 0,
NSEvaluatedObjectExpressionType,
NSVariableExpressionType,
NSKeyPathExpressionType,
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;
@ -64,6 +78,24 @@ GS_EXPORT_CLASS
+ (NSExpression *) expressionForKeyPath: (NSString *)path;
+ (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;
- (id) constantValue;
- (NSExpressionType) expressionType;
@ -75,6 +107,11 @@ GS_EXPORT_CLASS
- (NSExpression *) operand;
- (NSString *) variable;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
- (id) collection;
- (NSExpression *) leftExpression;
- (NSExpression *) rightExpression;
#endif
@end
#if defined(__cplusplus)
@ -84,4 +121,3 @@ GS_EXPORT_CLASS
#endif /* 100400 */
#endif /* __NSExpression_h_GNUSTEP_BASE_INCLUDE */

20
MISSING
View file

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

View file

@ -48,6 +48,7 @@
#import "Foundation/NSValue.h"
#import "GSPrivate.h"
#import "GSFastEnumeration.h"
// For pow()
#include <math.h>
@ -141,6 +142,40 @@ extern void GSPropertyListMake(id,NSDictionary*,BOOL,BOOL,unsigned,id*);
}
@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
{
@public
@ -1285,6 +1320,99 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
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
{
if ((self = [super init]) != nil)
@ -1353,6 +1481,24 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
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
{
return [NSExpression class];
@ -1621,6 +1767,179 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
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
@implementation GSFunctionExpression
@ -2383,7 +2702,6 @@ GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOption
- (NSExpression *) parseExpression
{
// return [self parseAdditionExpression];
return [self parseBinaryExpression];
}

View file

@ -175,6 +175,74 @@ void testArray(void)
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()
{
NSArray *filtered;
@ -310,7 +378,8 @@ int main()
"predicate created with format can filter an array")
testArray();
testExpressions();
END_SET("basic")
return 0;