mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-05 22:20:59 +00:00
Merge pull request #410 from gnustep/NSExpression_branch
This commit is contained in:
commit
ced4cd0531
4 changed files with 432 additions and 29 deletions
|
@ -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
20
MISSING
|
@ -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:
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue