2023-12-23 01:44:50 +00:00
|
|
|
|
/** Interface for NSPredicate for GNUStep
|
2006-05-09 14:21:26 +00:00
|
|
|
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Written by: Dr. H. Nikolaus Schaller
|
|
|
|
|
Created: 2005
|
2007-05-23 13:11:55 +00:00
|
|
|
|
Modifications: Fred Kiefer <FredKiefer@gmx.de>
|
|
|
|
|
Date: May 2007
|
2007-06-21 05:48:09 +00:00
|
|
|
|
Modifications: Richard Frith-Macdoanld <rfm@gnu.org>
|
|
|
|
|
Date: June 2007
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2006-05-09 14:21:26 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2007-06-11 10:56:36 +00:00
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
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
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Lesser General Public License for more details.
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2006-05-09 14:21:26 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Boston, MA 02110 USA.
|
2006-05-09 14:21:26 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
|
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#define EXPOSE_NSComparisonPredicate_IVARS 1
|
|
|
|
|
#define EXPOSE_NSCompoundPredicate_IVARS 1
|
|
|
|
|
#define EXPOSE_NSExpression_IVARS 1
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "Foundation/NSComparisonPredicate.h"
|
|
|
|
|
#import "Foundation/NSCompoundPredicate.h"
|
|
|
|
|
#import "Foundation/NSExpression.h"
|
|
|
|
|
#import "Foundation/NSPredicate.h"
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "Foundation/NSArray.h"
|
2020-01-12 19:56:09 +00:00
|
|
|
|
#import "Foundation/NSDate.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
|
#import "Foundation/NSEnumerator.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
|
#import "Foundation/NSKeyValueCoding.h"
|
|
|
|
|
#import "Foundation/NSNull.h"
|
|
|
|
|
#import "Foundation/NSScanner.h"
|
|
|
|
|
#import "Foundation/NSValue.h"
|
|
|
|
|
|
|
|
|
|
#import "GSPrivate.h"
|
2024-05-28 19:03:26 +00:00
|
|
|
|
#import "GSFastEnumeration.h"
|
2007-04-15 09:50:48 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// For pow()
|
|
|
|
|
#include <math.h>
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2010-11-17 21:46:31 +00:00
|
|
|
|
#if defined(HAVE_UNICODE_UREGEX_H)
|
|
|
|
|
#include <unicode/uregex.h>
|
2021-08-06 07:29:11 +00:00
|
|
|
|
#elif defined(HAVE_ICU_H)
|
2021-07-16 12:31:38 +00:00
|
|
|
|
#include <icu.h>
|
|
|
|
|
#endif
|
2010-11-17 21:46:31 +00:00
|
|
|
|
|
2010-10-04 08:21:34 +00:00
|
|
|
|
/* Object to represent the expression beign evaluated.
|
|
|
|
|
*/
|
|
|
|
|
static NSExpression *evaluatedObjectExpression = nil;
|
|
|
|
|
|
2013-02-15 15:14:50 +00:00
|
|
|
|
extern void GSPropertyListMake(id,NSDictionary*,BOOL,BOOL,unsigned,id*);
|
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
@interface GSPredicateScanner : NSScanner
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *_args; // Not retained.
|
|
|
|
|
unsigned _retrieved;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithString: (NSString*)format
|
2006-08-06 05:18:41 +00:00
|
|
|
|
args: (NSArray*)args;
|
2007-06-21 05:46:13 +00:00
|
|
|
|
- (id) nextArg;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
- (BOOL) scanPredicateKeyword: (NSString *) key;
|
|
|
|
|
- (NSPredicate *) parse;
|
|
|
|
|
- (NSPredicate *) parsePredicate;
|
|
|
|
|
- (NSPredicate *) parseAnd;
|
|
|
|
|
- (NSPredicate *) parseNot;
|
|
|
|
|
- (NSPredicate *) parseOr;
|
|
|
|
|
- (NSPredicate *) parseComparison;
|
|
|
|
|
- (NSExpression *) parseExpression;
|
|
|
|
|
- (NSExpression *) parseFunctionalExpression;
|
|
|
|
|
- (NSExpression *) parsePowerExpression;
|
|
|
|
|
- (NSExpression *) parseMultiplicationExpression;
|
|
|
|
|
- (NSExpression *) parseAdditionExpression;
|
|
|
|
|
- (NSExpression *) parseBinaryExpression;
|
2007-06-11 10:56:36 +00:00
|
|
|
|
- (NSExpression *) parseSimpleExpression;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
@end
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
|
|
|
|
@interface GSTruePredicate : NSPredicate
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSFalsePredicate : NSPredicate
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSAndCompoundPredicate : NSCompoundPredicate
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSOrCompoundPredicate : NSCompoundPredicate
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSNotCompoundPredicate : NSCompoundPredicate
|
2007-05-23 13:11:55 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface NSExpression (Private)
|
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary *)variables;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSConstantValueExpression : NSExpression
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
id _obj;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSEvaluatedObjectExpression : NSExpression
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSVariableExpression : NSExpression
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSString *_variable;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSKeyPathExpression : NSExpression
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSString *_keyPath;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2022-02-12 13:06:23 +00:00
|
|
|
|
@interface GSKeyPathCompositionExpression : NSExpression
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSExpression *_left;
|
|
|
|
|
NSExpression *_right;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2024-05-26 12:39:44 +00:00
|
|
|
|
@interface GSUnionSetExpression : NSExpression
|
2024-05-26 13:11:21 +00:00
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSExpression *_left;
|
|
|
|
|
NSExpression *_right;
|
|
|
|
|
}
|
2024-05-26 12:39:44 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSIntersectSetExpression : NSExpression
|
2024-05-26 13:11:21 +00:00
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSExpression *_left;
|
|
|
|
|
NSExpression *_right;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSMinusSetExpression : NSExpression
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSExpression *_left;
|
|
|
|
|
NSExpression *_right;
|
|
|
|
|
}
|
2024-05-26 12:39:44 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSSubqueryExpression : NSExpression
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSAggregateExpression : NSExpression
|
2024-05-26 20:16:40 +00:00
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
id _collection;
|
|
|
|
|
}
|
2024-05-26 12:39:44 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@interface GSFunctionExpression : NSExpression
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSString *_function;
|
|
|
|
|
NSArray *_args;
|
|
|
|
|
unsigned int _argc;
|
2013-02-15 15:14:50 +00:00
|
|
|
|
SEL _selector;
|
|
|
|
|
NSString *_op; // Not retained;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2016-03-09 13:19:35 +00:00
|
|
|
|
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST)
|
|
|
|
|
@interface GSBlockPredicate : NSPredicate
|
|
|
|
|
{
|
|
|
|
|
GSBlockPredicateBlock _block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (instancetype) initWithBlock: (GSBlockPredicateBlock)block;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface GSBoundBlockPredicate : GSBlockPredicate
|
|
|
|
|
{
|
|
|
|
|
GS_GENERIC_CLASS(NSDictionary,NSString*,id)* _bindings;
|
|
|
|
|
}
|
|
|
|
|
- (instancetype) initWithBlock: (GSBlockPredicateBlock)block
|
|
|
|
|
bindings: (GS_GENERIC_CLASS(NSDictionary,NSString*,id)*)bindings;
|
|
|
|
|
@end
|
|
|
|
|
#endif
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSPredicate
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) predicateWithFormat: (NSString *) format, ...
|
|
|
|
|
{
|
|
|
|
|
NSPredicate *p;
|
|
|
|
|
va_list va;
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
va_start(va, format);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
p = [self predicateWithFormat: format arguments: va];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
va_end(va);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) predicateWithFormat: (NSString *)format
|
2007-05-23 13:11:55 +00:00
|
|
|
|
argumentArray: (NSArray *)args
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
GSPredicateScanner *s;
|
|
|
|
|
NSPredicate *p;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
s = [[GSPredicateScanner alloc] initWithString: format
|
2007-05-23 13:11:55 +00:00
|
|
|
|
args: args];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
p = [s parse];
|
|
|
|
|
RELEASE(s);
|
|
|
|
|
return p;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) predicateWithFormat: (NSString *)format
|
2007-05-23 13:11:55 +00:00
|
|
|
|
arguments: (va_list)args
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
GSPredicateScanner *s;
|
|
|
|
|
NSPredicate *p;
|
2007-06-21 05:46:13 +00:00
|
|
|
|
const char *ptr = [format UTF8String];
|
|
|
|
|
NSMutableArray *arr = [NSMutableArray arrayWithCapacity: 10];
|
|
|
|
|
|
|
|
|
|
while (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
char c = *ptr++;
|
|
|
|
|
|
|
|
|
|
if (c == '%')
|
|
|
|
|
{
|
|
|
|
|
c = *ptr;
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '%':
|
|
|
|
|
ptr++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'K':
|
|
|
|
|
case '@':
|
|
|
|
|
ptr++;
|
|
|
|
|
[arr addObject: va_arg(args, id)];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
|
ptr++;
|
|
|
|
|
[arr addObject: [NSNumber numberWithChar:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
(char)va_arg(args, NSInteger)]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'C':
|
|
|
|
|
ptr++;
|
|
|
|
|
[arr addObject: [NSNumber numberWithShort:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
(short)va_arg(args, NSInteger)]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'D':
|
|
|
|
|
case 'i':
|
|
|
|
|
ptr++;
|
|
|
|
|
[arr addObject: [NSNumber numberWithInt:
|
2015-01-16 15:25:50 +00:00
|
|
|
|
va_arg(args, int)]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'O':
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'U':
|
|
|
|
|
case 'x':
|
|
|
|
|
case 'X':
|
|
|
|
|
ptr++;
|
|
|
|
|
[arr addObject: [NSNumber numberWithUnsignedInt:
|
2015-01-16 15:25:50 +00:00
|
|
|
|
va_arg(args, unsigned)]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'E':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 'g':
|
|
|
|
|
case 'G':
|
|
|
|
|
ptr++;
|
|
|
|
|
[arr addObject: [NSNumber numberWithDouble:
|
|
|
|
|
va_arg(args, double)]];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
|
ptr++;
|
|
|
|
|
if (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
c = *ptr;
|
|
|
|
|
if (c == 'i')
|
|
|
|
|
{
|
|
|
|
|
[arr addObject: [NSNumber numberWithShort:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
(short)va_arg(args, NSInteger)]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
}
|
|
|
|
|
if (c == 'u')
|
|
|
|
|
{
|
|
|
|
|
[arr addObject: [NSNumber numberWithUnsignedShort:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
(unsigned short)va_arg(args, NSInteger)]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-06-21 05:46:13 +00:00
|
|
|
|
case 'q':
|
|
|
|
|
ptr++;
|
|
|
|
|
if (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
c = *ptr;
|
|
|
|
|
if (c == 'i')
|
|
|
|
|
{
|
|
|
|
|
[arr addObject: [NSNumber numberWithLongLong:
|
|
|
|
|
va_arg(args, long long)]];
|
|
|
|
|
}
|
|
|
|
|
if (c == 'u' || c == 'x' || c == 'X')
|
|
|
|
|
{
|
|
|
|
|
[arr addObject: [NSNumber numberWithUnsignedLongLong:
|
|
|
|
|
va_arg(args, unsigned long long)]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\'')
|
|
|
|
|
{
|
|
|
|
|
while (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
if (*ptr++ == '\'')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (c == '"')
|
|
|
|
|
{
|
|
|
|
|
while (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
if (*ptr++ == '"')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
s = [[GSPredicateScanner alloc] initWithString: format
|
2007-06-21 05:46:13 +00:00
|
|
|
|
args: arr];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
p = [s parse];
|
|
|
|
|
RELEASE(s);
|
|
|
|
|
return p;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) predicateWithValue: (BOOL)value
|
|
|
|
|
{
|
|
|
|
|
if (value)
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE([GSTruePredicate new]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([GSFalsePredicate new]);
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we don't ever instantiate NSPredicate
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone *)z
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return NSCopyObject(self, 0, z);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [self predicateFormat];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) predicateFormat
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) predicateWithSubstitutionVariables: (NSDictionary *)variables
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE([self copy]);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-09 15:38:32 +00:00
|
|
|
|
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
2017-04-09 12:45:18 +00:00
|
|
|
|
substitutionVariables: (GS_GENERIC_CLASS(NSDictionary, NSString*, id)*)variables
|
2016-03-09 15:38:32 +00:00
|
|
|
|
{
|
|
|
|
|
return [[self predicateWithSubstitutionVariables: variables]
|
2017-04-09 12:45:18 +00:00
|
|
|
|
evaluateWithObject: object];
|
2016-03-09 15:38:32 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
|
|
|
|
return [NSPredicate class];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 22:53:52 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder *) coder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
2006-05-09 14:21:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 22:53:52 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder *) coder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
2006-05-09 14:21:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-09 15:38:32 +00:00
|
|
|
|
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST)
|
2016-03-09 13:19:35 +00:00
|
|
|
|
+ (NSPredicate*)predicateWithBlock: (GSBlockPredicateBlock)block
|
|
|
|
|
{
|
|
|
|
|
return [[[GSBlockPredicate alloc] initWithBlock: block] autorelease];
|
|
|
|
|
}
|
2016-03-09 15:38:32 +00:00
|
|
|
|
#endif
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSTruePredicate
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone *)z
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return RETAIN(self);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) predicateFormat
|
|
|
|
|
{
|
|
|
|
|
return @"TRUEPREDICATE";
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSFalsePredicate
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone *)z
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return RETAIN(self);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) predicateFormat
|
|
|
|
|
{
|
|
|
|
|
return @"FALSEPREDICATE";
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSCompoundPredicate
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) andPredicateWithSubpredicates: (NSArray *)list
|
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
return AUTORELEASE([[GSAndCompoundPredicate alloc]
|
|
|
|
|
initWithType: NSAndPredicateType subpredicates: list]);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) notPredicateWithSubpredicate: (NSPredicate *)predicate
|
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSArray *list;
|
|
|
|
|
|
|
|
|
|
list = [NSArray arrayWithObject: predicate];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE([[GSNotCompoundPredicate alloc]
|
2013-10-18 07:25:32 +00:00
|
|
|
|
initWithType: NSNotPredicateType subpredicates: list]);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) orPredicateWithSubpredicates: (NSArray *)list
|
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
return AUTORELEASE([[GSOrCompoundPredicate alloc]
|
|
|
|
|
initWithType: NSOrPredicateType subpredicates: list]);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSCompoundPredicateType) compoundPredicateType
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return _type;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithType: (NSCompoundPredicateType)type
|
|
|
|
|
subpredicates: (NSArray *)list
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
if ((self = [super init]) != nil)
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
_type = type;
|
2013-10-18 07:25:32 +00:00
|
|
|
|
ASSIGNCOPY(_subs, list);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return self;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (void) dealloc
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
RELEASE(_subs);
|
|
|
|
|
[super dealloc];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone *)z
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [[[self class] alloc] initWithType: _type subpredicates: _subs];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (NSArray *) subpredicates
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return _subs;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (NSPredicate *) predicateWithSubstitutionVariables: (NSDictionary *)variables
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
unsigned int count = [_subs count];
|
|
|
|
|
NSMutableArray *esubs = [NSMutableArray arrayWithCapacity: count];
|
2013-10-18 07:25:32 +00:00
|
|
|
|
unsigned int i;
|
2015-05-26 13:24:26 +00:00
|
|
|
|
NSPredicate *p;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
[esubs addObject: [[_subs objectAtIndex: i]
|
|
|
|
|
predicateWithSubstitutionVariables: variables]];
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2015-05-26 13:24:26 +00:00
|
|
|
|
p = [[[self class] alloc] initWithType: _type subpredicates: esubs];
|
|
|
|
|
return AUTORELEASE(p);
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (Class) classForCoder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [NSCompoundPredicate class];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder *)coder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder *)coder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return self;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSAndCompoundPredicate
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
- (BOOL) evaluateWithObject: (id) object
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *e = [_subs objectEnumerator];
|
|
|
|
|
NSPredicate *p;
|
|
|
|
|
|
|
|
|
|
while ((p = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([p evaluateWithObject: object] == NO)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
return NO; // any NO returns NO
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
return YES; // all are true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) predicateFormat
|
|
|
|
|
{
|
|
|
|
|
NSString *fmt = @"";
|
|
|
|
|
NSEnumerator *e = [_subs objectEnumerator];
|
|
|
|
|
NSPredicate *sub;
|
|
|
|
|
unsigned cnt = 0;
|
|
|
|
|
|
|
|
|
|
while ((sub = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
// when to add ()? -> if sub is compound and of type "or"
|
|
|
|
|
if (cnt == 0)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
fmt = [sub predicateFormat]; // first
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
else
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
if (cnt == 1
|
2013-02-15 15:14:50 +00:00
|
|
|
|
&& [[_subs objectAtIndex: 0]
|
|
|
|
|
isKindOfClass: [NSCompoundPredicate class]]
|
|
|
|
|
&& [(NSCompoundPredicate *)[_subs objectAtIndex: 0]
|
|
|
|
|
compoundPredicateType] == NSOrPredicateType)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
// we need () around first OR on left side
|
|
|
|
|
fmt = [NSString stringWithFormat: @"(%@)", fmt];
|
|
|
|
|
}
|
|
|
|
|
if ([sub isKindOfClass: [NSCompoundPredicate class]]
|
|
|
|
|
&& [(NSCompoundPredicate *) sub compoundPredicateType]
|
|
|
|
|
== NSOrPredicateType)
|
|
|
|
|
{
|
|
|
|
|
// we need () around right OR
|
|
|
|
|
fmt = [NSString stringWithFormat: @"%@ AND (%@)",
|
|
|
|
|
fmt, [sub predicateFormat]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fmt = [NSString stringWithFormat: @"%@ AND %@",
|
|
|
|
|
fmt, [sub predicateFormat]];
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
cnt++;
|
|
|
|
|
}
|
|
|
|
|
return fmt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSOrCompoundPredicate
|
|
|
|
|
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *e = [_subs objectEnumerator];
|
|
|
|
|
NSPredicate *p;
|
|
|
|
|
|
|
|
|
|
while ((p = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([p evaluateWithObject: object] == YES)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
return YES; // any YES returns YES
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
return NO; // none is true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) predicateFormat
|
|
|
|
|
{
|
|
|
|
|
NSString *fmt = @"";
|
|
|
|
|
NSEnumerator *e = [_subs objectEnumerator];
|
|
|
|
|
NSPredicate *sub;
|
|
|
|
|
|
|
|
|
|
while ((sub = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([fmt length] > 0)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
fmt = [NSString stringWithFormat: @"%@ OR %@",
|
|
|
|
|
fmt, [sub predicateFormat]];
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
else
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
fmt = [sub predicateFormat]; // first
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
return fmt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSNotCompoundPredicate
|
|
|
|
|
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
NSPredicate *sub = [_subs objectAtIndex: 0];
|
|
|
|
|
|
|
|
|
|
return ![sub evaluateWithObject: object];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) predicateFormat
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
NSPredicate *sub = [_subs objectAtIndex: 0];
|
|
|
|
|
|
|
|
|
|
if ([sub isKindOfClass: [NSCompoundPredicate class]]
|
|
|
|
|
&& [(NSCompoundPredicate *)sub compoundPredicateType]
|
2006-05-09 14:21:26 +00:00
|
|
|
|
!= NSNotPredicateType)
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [NSString stringWithFormat: @"NOT(%@)", [sub predicateFormat]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [NSString stringWithFormat: @"NOT %@", [sub predicateFormat]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSComparisonPredicate
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) predicateWithLeftExpression: (NSExpression *)left
|
2007-05-23 13:11:55 +00:00
|
|
|
|
rightExpression: (NSExpression *)right
|
|
|
|
|
customSelector: (SEL) sel
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE([[self alloc] initWithLeftExpression: left
|
|
|
|
|
rightExpression: right
|
|
|
|
|
customSelector: sel]);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) predicateWithLeftExpression: (NSExpression *)left
|
2007-05-23 13:11:55 +00:00
|
|
|
|
rightExpression: (NSExpression *)right
|
|
|
|
|
modifier: (NSComparisonPredicateModifier)modifier
|
|
|
|
|
type: (NSPredicateOperatorType)type
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)opts
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE([[self alloc] initWithLeftExpression: left
|
|
|
|
|
rightExpression: right
|
|
|
|
|
modifier: modifier
|
|
|
|
|
type: type
|
|
|
|
|
options: opts]);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) initWithLeftExpression: (NSExpression *)left
|
2007-05-23 13:11:55 +00:00
|
|
|
|
rightExpression: (NSExpression *)right
|
|
|
|
|
customSelector: (SEL)sel
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
|
|
|
|
if ((self = [super init]) != nil)
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
ASSIGN(_left, left);
|
|
|
|
|
ASSIGN(_right, right);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
_selector = sel;
|
|
|
|
|
_type = NSCustomSelectorPredicateOperatorType;
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithLeftExpression: (NSExpression *)left
|
2007-05-23 13:11:55 +00:00
|
|
|
|
rightExpression: (NSExpression *)right
|
|
|
|
|
modifier: (NSComparisonPredicateModifier)modifier
|
|
|
|
|
type: (NSPredicateOperatorType)type
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)opts
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
|
|
|
|
if ((self = [super init]) != nil)
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
ASSIGN(_left, left);
|
|
|
|
|
ASSIGN(_right, right);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
_modifier = modifier;
|
|
|
|
|
_type = type;
|
|
|
|
|
_options = opts;
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc;
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
RELEASE(_left);
|
|
|
|
|
RELEASE(_right);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (NSComparisonPredicateModifier) comparisonPredicateModifier
|
|
|
|
|
{
|
|
|
|
|
return _modifier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (SEL) customSelector
|
|
|
|
|
{
|
|
|
|
|
return _selector;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
- (NSExpression *) leftExpression
|
|
|
|
|
{
|
|
|
|
|
return _left;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) options
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
|
|
|
|
return _options;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicateOperatorType) predicateOperatorType
|
|
|
|
|
{
|
|
|
|
|
return _type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) rightExpression
|
|
|
|
|
{
|
|
|
|
|
return _right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) predicateFormat
|
|
|
|
|
{
|
|
|
|
|
NSString *modi = @"";
|
|
|
|
|
NSString *comp = @"?comparison?";
|
|
|
|
|
NSString *opt = @"";
|
|
|
|
|
|
|
|
|
|
switch (_modifier)
|
|
|
|
|
{
|
|
|
|
|
case NSDirectPredicateModifier:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSAnyPredicateModifier:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
modi = @"ANY ";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSAllPredicateModifier:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
modi = @"ALL";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
default:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
modi = @"?modifier?";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
switch (_type)
|
|
|
|
|
{
|
|
|
|
|
case NSLessThanPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"<";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSLessThanOrEqualToPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"<=";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSGreaterThanPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @">=";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSGreaterThanOrEqualToPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @">";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSEqualToPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"=";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSNotEqualToPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"!=";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSMatchesPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"MATCHES";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSLikePredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"LIKE";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSBeginsWithPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"BEGINSWITH";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSEndsWithPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"ENDSWITH";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSInPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = @"IN";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSCustomSelectorPredicateOperatorType:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
comp = NSStringFromSelector(_selector);
|
|
|
|
|
break;
|
2008-10-31 23:43:44 +00:00
|
|
|
|
case NSContainsPredicateOperatorType:
|
|
|
|
|
comp = @"CONTAINS";
|
|
|
|
|
break;
|
|
|
|
|
case NSBetweenPredicateOperatorType:
|
|
|
|
|
comp = @"BETWEEN";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
switch (_options)
|
|
|
|
|
{
|
|
|
|
|
case NSCaseInsensitivePredicateOption:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
opt = @"[c]";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSDiacriticInsensitivePredicateOption:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
opt = @"[d]";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
case NSCaseInsensitivePredicateOption
|
2007-05-23 13:11:55 +00:00
|
|
|
|
| NSDiacriticInsensitivePredicateOption:
|
|
|
|
|
opt = @"[cd]";
|
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
default:
|
2013-01-22 08:31:40 +00:00
|
|
|
|
//opt = @"[?options?]";
|
2007-05-23 13:11:55 +00:00
|
|
|
|
break;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
return [NSString stringWithFormat: @"%@%@ %@%@ %@",
|
2007-05-23 13:11:55 +00:00
|
|
|
|
modi, _left, comp, opt, _right];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) predicateWithSubstitutionVariables: (NSDictionary *)variables
|
|
|
|
|
{
|
2013-02-15 15:14:50 +00:00
|
|
|
|
NSExpression *left;
|
|
|
|
|
NSExpression *right;
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2013-02-15 15:14:50 +00:00
|
|
|
|
left = [_left _expressionWithSubstitutionVariables: variables];
|
|
|
|
|
right = [_right _expressionWithSubstitutionVariables: variables];
|
|
|
|
|
if (_type == NSCustomSelectorPredicateOperatorType)
|
|
|
|
|
{
|
|
|
|
|
return [NSComparisonPredicate predicateWithLeftExpression: left
|
|
|
|
|
rightExpression: right
|
|
|
|
|
customSelector: _selector];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return [NSComparisonPredicate predicateWithLeftExpression: left
|
|
|
|
|
rightExpression: right
|
|
|
|
|
modifier: _modifier
|
|
|
|
|
type: _type
|
|
|
|
|
options: _options];
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-18 09:46:51 +00:00
|
|
|
|
#if GS_USE_ICU == 1
|
|
|
|
|
static BOOL
|
|
|
|
|
GSICUStringMatchesRegex(NSString *string, NSString *regex, NSStringCompareOptions opts)
|
2010-11-17 21:46:31 +00:00
|
|
|
|
{
|
|
|
|
|
BOOL result = NO;
|
|
|
|
|
UErrorCode error = 0;
|
|
|
|
|
uint32_t flags = 0;
|
|
|
|
|
NSUInteger stringLength = [string length];
|
|
|
|
|
NSUInteger regexLength = [regex length];
|
|
|
|
|
unichar *stringBuffer;
|
|
|
|
|
unichar *regexBuffer;
|
|
|
|
|
URegularExpression *icuregex = NULL;
|
|
|
|
|
|
|
|
|
|
stringBuffer = malloc(stringLength * sizeof(unichar));
|
|
|
|
|
if (NULL == stringBuffer) { return NO; }
|
|
|
|
|
regexBuffer = malloc(regexLength * sizeof(unichar));
|
|
|
|
|
if (NULL == regexBuffer) { free(stringBuffer); return NO; }
|
|
|
|
|
|
|
|
|
|
[string getCharacters: stringBuffer range: NSMakeRange(0, stringLength)];
|
|
|
|
|
[regex getCharacters: regexBuffer range: NSMakeRange(0, regexLength)];
|
|
|
|
|
|
|
|
|
|
flags |= UREGEX_DOTALL; // . is supposed to recognize newlines
|
|
|
|
|
if ((opts & NSCaseInsensitiveSearch) != 0) { flags |= UREGEX_CASE_INSENSITIVE; }
|
|
|
|
|
|
|
|
|
|
icuregex = uregex_open(regexBuffer, regexLength, flags, NULL, &error);
|
|
|
|
|
if (icuregex != NULL && U_SUCCESS(error))
|
|
|
|
|
{
|
|
|
|
|
uregex_setText(icuregex, stringBuffer, stringLength, &error);
|
|
|
|
|
result = uregex_matches(icuregex, 0, &error);
|
|
|
|
|
}
|
|
|
|
|
uregex_close(icuregex);
|
|
|
|
|
|
|
|
|
|
free(stringBuffer);
|
|
|
|
|
free(regexBuffer);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-10-04 14:44:54 +00:00
|
|
|
|
- (BOOL) _evaluateLeftValue: (id)leftResult
|
|
|
|
|
rightValue: (id)rightResult
|
|
|
|
|
object: (id)object
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2010-10-04 08:21:34 +00:00
|
|
|
|
unsigned compareOptions = 0;
|
|
|
|
|
BOOL leftIsNil;
|
|
|
|
|
BOOL rightIsNil;
|
2024-05-30 22:06:24 +00:00
|
|
|
|
Class constantValueClass;
|
|
|
|
|
|
2010-10-04 08:21:34 +00:00
|
|
|
|
|
|
|
|
|
leftIsNil = (leftResult == nil || [leftResult isEqual: [NSNull null]]);
|
|
|
|
|
rightIsNil = (rightResult == nil || [rightResult isEqual: [NSNull null]]);
|
|
|
|
|
if (leftIsNil || rightIsNil)
|
|
|
|
|
{
|
2013-10-27 08:47:03 +00:00
|
|
|
|
if (leftIsNil == rightIsNil)
|
|
|
|
|
{
|
|
|
|
|
/* Both of the values are nil.
|
|
|
|
|
* The result is YES if equality is requested.
|
|
|
|
|
*/
|
|
|
|
|
if (NSEqualToPredicateOperatorType == _type
|
|
|
|
|
|| NSLessThanOrEqualToPredicateOperatorType == _type
|
|
|
|
|
|| NSGreaterThanOrEqualToPredicateOperatorType == _type)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (NSNotEqualToPredicateOperatorType == _type)
|
|
|
|
|
{
|
|
|
|
|
/* One, but not both of the values are nil.
|
|
|
|
|
* The result is YES if inequality is requested.
|
|
|
|
|
*/
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
2010-10-04 08:21:34 +00:00
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2010-11-18 09:46:51 +00:00
|
|
|
|
// Change predicate options into string options.
|
|
|
|
|
if (!(_options & NSDiacriticInsensitivePredicateOption))
|
|
|
|
|
{
|
|
|
|
|
compareOptions |= NSLiteralSearch;
|
|
|
|
|
}
|
|
|
|
|
if (_options & NSCaseInsensitivePredicateOption)
|
|
|
|
|
{
|
|
|
|
|
compareOptions |= NSCaseInsensitiveSearch;
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2024-05-30 22:06:24 +00:00
|
|
|
|
/* If the left or right result is a constant value expression, we need to
|
|
|
|
|
* extract the constant value from it.
|
2010-11-18 09:46:51 +00:00
|
|
|
|
*/
|
2024-05-30 22:06:24 +00:00
|
|
|
|
constantValueClass = [GSConstantValueExpression class];
|
|
|
|
|
if ([leftResult isKindOfClass: constantValueClass])
|
2010-11-18 09:46:51 +00:00
|
|
|
|
{
|
2024-05-30 22:06:24 +00:00
|
|
|
|
leftResult = [(GSConstantValueExpression *)leftResult constantValue];
|
|
|
|
|
}
|
|
|
|
|
if ([rightResult isKindOfClass: constantValueClass])
|
|
|
|
|
{
|
|
|
|
|
rightResult = [(GSConstantValueExpression *)rightResult constantValue];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We are assuming that the API is stable and enumeration values
|
|
|
|
|
* won't change. This covers:
|
|
|
|
|
* - NSLessThanPredicateOperatorType = 0,
|
|
|
|
|
* - NSLessThanOrEqualToPredicateOperatorType = 1,
|
|
|
|
|
* - NSGreaterThanPredicateOperatorType = 2,
|
|
|
|
|
* - NSGreaterThanOrEqualToPredicateOperatorType = 3
|
|
|
|
|
*/
|
|
|
|
|
if (_type < NSEqualToPredicateOperatorType)
|
|
|
|
|
{
|
|
|
|
|
NSComparisonResult comparisonResult;
|
|
|
|
|
Class stringClass;
|
|
|
|
|
|
|
|
|
|
stringClass = [NSString class];
|
|
|
|
|
|
|
|
|
|
/* We first check if the left and right result are strings.
|
|
|
|
|
* If this is not the case, check if we can do a comparison with
|
|
|
|
|
* doubleValue: (Mainly useful as a shortcut for expressions like
|
|
|
|
|
* "abc" == 3
|
|
|
|
|
*/
|
|
|
|
|
if ([leftResult isKindOfClass:stringClass] &&
|
|
|
|
|
[rightResult isKindOfClass:stringClass])
|
2017-04-09 12:45:18 +00:00
|
|
|
|
{
|
2024-05-30 22:06:24 +00:00
|
|
|
|
comparisonResult = [leftResult compare:rightResult
|
|
|
|
|
options:compareOptions];
|
2017-04-09 12:45:18 +00:00
|
|
|
|
}
|
2024-05-30 22:06:24 +00:00
|
|
|
|
else if ([leftResult respondsToSelector:@selector(compare:)])
|
2017-04-09 12:45:18 +00:00
|
|
|
|
{
|
2024-05-30 22:06:24 +00:00
|
|
|
|
// Attempt a comparison
|
|
|
|
|
comparisonResult = [leftResult compare:rightResult];
|
2017-04-09 12:45:18 +00:00
|
|
|
|
}
|
2024-05-30 22:06:24 +00:00
|
|
|
|
else
|
2017-04-09 12:45:18 +00:00
|
|
|
|
{
|
2024-05-30 22:06:24 +00:00
|
|
|
|
// We can't compare these objects
|
|
|
|
|
[NSException raise:NSInvalidArgumentException
|
|
|
|
|
format:@"Cannot compare objects of type %@ and %@",
|
|
|
|
|
NSStringFromClass([leftResult class]),
|
|
|
|
|
NSStringFromClass([rightResult class])];
|
|
|
|
|
return NO;
|
2017-04-09 12:45:18 +00:00
|
|
|
|
}
|
2024-05-30 22:06:24 +00:00
|
|
|
|
|
|
|
|
|
switch (_type)
|
2017-04-09 12:45:18 +00:00
|
|
|
|
{
|
2024-05-30 22:06:24 +00:00
|
|
|
|
case NSLessThanPredicateOperatorType:
|
|
|
|
|
{
|
|
|
|
|
return (comparisonResult == NSOrderedAscending) ? YES : NO;
|
|
|
|
|
}
|
|
|
|
|
case NSLessThanOrEqualToPredicateOperatorType:
|
|
|
|
|
{
|
|
|
|
|
/* True if left value is less then (NSOrderedAscending) or equal
|
|
|
|
|
* (NSOrderedSame) */
|
|
|
|
|
return (comparisonResult != NSOrderedDescending) ? YES : NO;
|
|
|
|
|
}
|
|
|
|
|
case NSGreaterThanPredicateOperatorType:
|
|
|
|
|
{
|
|
|
|
|
return (comparisonResult == NSOrderedDescending) ? YES : NO;
|
|
|
|
|
}
|
|
|
|
|
case NSGreaterThanOrEqualToPredicateOperatorType:
|
|
|
|
|
{
|
|
|
|
|
return (comparisonResult != NSOrderedAscending) ? YES : NO;
|
|
|
|
|
}
|
|
|
|
|
default: // This should never happen
|
|
|
|
|
return NO;
|
2017-04-09 12:45:18 +00:00
|
|
|
|
}
|
2024-05-30 22:06:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Handle remaining cases */
|
|
|
|
|
switch (_type)
|
|
|
|
|
{
|
2010-11-18 09:46:51 +00:00
|
|
|
|
case NSEqualToPredicateOperatorType:
|
|
|
|
|
return [leftResult isEqual: rightResult];
|
|
|
|
|
case NSNotEqualToPredicateOperatorType:
|
|
|
|
|
return ![leftResult isEqual: rightResult];
|
|
|
|
|
case NSMatchesPredicateOperatorType:
|
|
|
|
|
#if GS_USE_ICU == 1
|
|
|
|
|
return GSICUStringMatchesRegex(leftResult, rightResult, compareOptions);
|
2010-11-17 21:46:31 +00:00
|
|
|
|
#else
|
2010-11-18 09:46:51 +00:00
|
|
|
|
return [leftResult compare: rightResult options: compareOptions]
|
2013-10-26 07:15:53 +00:00
|
|
|
|
== NSOrderedSame ? YES : NO;
|
2010-11-17 21:46:31 +00:00
|
|
|
|
#endif
|
2010-11-18 09:46:51 +00:00
|
|
|
|
case NSLikePredicateOperatorType:
|
|
|
|
|
#if GS_USE_ICU == 1
|
|
|
|
|
{
|
|
|
|
|
NSString *regex;
|
|
|
|
|
|
|
|
|
|
/* The right hand is a pattern with '?' meaning match one character,
|
|
|
|
|
* and '*' meaning match zero or more characters, so translate that
|
|
|
|
|
* into a regex.
|
|
|
|
|
*/
|
|
|
|
|
regex = [rightResult stringByReplacingOccurrencesOfString: @"*"
|
|
|
|
|
withString: @".*"];
|
|
|
|
|
regex = [regex stringByReplacingOccurrencesOfString: @"?"
|
|
|
|
|
withString: @".?"];
|
|
|
|
|
regex = [NSString stringWithFormat: @"^%@$", regex];
|
|
|
|
|
return GSICUStringMatchesRegex(leftResult, regex, compareOptions);
|
|
|
|
|
}
|
2010-11-17 21:46:31 +00:00
|
|
|
|
#else
|
2010-11-18 09:46:51 +00:00
|
|
|
|
return [leftResult compare: rightResult options: compareOptions]
|
2013-10-26 07:15:53 +00:00
|
|
|
|
== NSOrderedSame ? YES : NO;
|
2010-11-17 21:46:31 +00:00
|
|
|
|
#endif
|
2010-11-18 09:46:51 +00:00
|
|
|
|
case NSBeginsWithPredicateOperatorType:
|
|
|
|
|
{
|
2022-03-07 10:13:44 +00:00
|
|
|
|
NSRange range;
|
|
|
|
|
NSUInteger ll = [leftResult length];
|
|
|
|
|
NSUInteger rl = [rightResult length];
|
2014-02-13 15:45:06 +00:00
|
|
|
|
|
2022-03-07 10:13:44 +00:00
|
|
|
|
if (rl > ll)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
range = NSMakeRange(0, rl);
|
2010-11-18 09:46:51 +00:00
|
|
|
|
return ([leftResult compare: rightResult
|
|
|
|
|
options: compareOptions
|
2013-10-26 07:15:53 +00:00
|
|
|
|
range: range] == NSOrderedSame ? YES : NO);
|
2010-11-18 09:46:51 +00:00
|
|
|
|
}
|
|
|
|
|
case NSEndsWithPredicateOperatorType:
|
|
|
|
|
{
|
2022-03-07 10:13:44 +00:00
|
|
|
|
NSRange range;
|
2014-02-13 15:45:06 +00:00
|
|
|
|
NSUInteger ll = [leftResult length];
|
|
|
|
|
NSUInteger rl = [rightResult length];
|
2010-11-18 09:46:51 +00:00
|
|
|
|
|
2014-02-13 15:45:06 +00:00
|
|
|
|
if (ll < rl)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
range = NSMakeRange(ll - rl, rl);
|
2010-11-18 09:46:51 +00:00
|
|
|
|
return ([leftResult compare: rightResult
|
|
|
|
|
options: compareOptions
|
2013-10-26 07:15:53 +00:00
|
|
|
|
range: range] == NSOrderedSame ? YES : NO);
|
2010-11-18 09:46:51 +00:00
|
|
|
|
}
|
|
|
|
|
case NSInPredicateOperatorType:
|
|
|
|
|
/* Handle special case where rightResult is a collection
|
|
|
|
|
* and leftResult an element of it.
|
|
|
|
|
*/
|
|
|
|
|
if (![rightResult isKindOfClass: [NSString class]])
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *e;
|
|
|
|
|
id value;
|
|
|
|
|
|
|
|
|
|
if (![rightResult respondsToSelector: @selector(objectEnumerator)])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"The right hand side for an IN operator "
|
|
|
|
|
@"must be a collection"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e = [rightResult objectEnumerator];
|
|
|
|
|
while ((value = [e nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if ([value isEqual: leftResult])
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return ([rightResult rangeOfString: leftResult
|
|
|
|
|
options: compareOptions].location
|
2013-10-26 07:15:53 +00:00
|
|
|
|
!= NSNotFound ? YES : NO);
|
2010-11-18 09:46:51 +00:00
|
|
|
|
case NSCustomSelectorPredicateOperatorType:
|
|
|
|
|
{
|
2013-10-27 08:47:03 +00:00
|
|
|
|
BOOL (*function)(id,SEL,id)
|
|
|
|
|
= (BOOL (*)(id,SEL,id))[leftResult methodForSelector: _selector];
|
2010-11-18 09:46:51 +00:00
|
|
|
|
return function(leftResult, _selector, rightResult);
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
id leftValue = [_left expressionValueWithObject: object context: nil];
|
|
|
|
|
id rightValue = [_right expressionValueWithObject: object context: nil];
|
2010-10-04 08:21:34 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
if (_modifier == NSDirectPredicateModifier)
|
|
|
|
|
{
|
2010-10-04 14:44:54 +00:00
|
|
|
|
return [self _evaluateLeftValue: leftValue
|
|
|
|
|
rightValue: rightValue
|
|
|
|
|
object: object];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BOOL result = (_modifier == NSAllPredicateModifier);
|
|
|
|
|
NSEnumerator *e;
|
|
|
|
|
id value;
|
|
|
|
|
|
|
|
|
|
if (![leftValue respondsToSelector: @selector(objectEnumerator)])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"The left hand side for an ALL or ANY operator must be a collection"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e = [leftValue objectEnumerator];
|
|
|
|
|
while ((value = [e nextObject]))
|
|
|
|
|
{
|
2010-10-04 14:44:54 +00:00
|
|
|
|
BOOL eval = [self _evaluateLeftValue: value
|
|
|
|
|
rightValue: rightValue
|
|
|
|
|
object: object];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
if (eval != result)
|
|
|
|
|
return eval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone *)z
|
|
|
|
|
{
|
2007-06-21 05:46:13 +00:00
|
|
|
|
NSComparisonPredicate *copy;
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2007-06-21 05:46:13 +00:00
|
|
|
|
copy = (NSComparisonPredicate *)NSCopyObject(self, 0, z);
|
2007-05-23 13:11:55 +00:00
|
|
|
|
copy->_left = [_left copyWithZone: z];
|
|
|
|
|
copy->_right = [_right copyWithZone: z];
|
|
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
|
|
|
|
return [NSComparisonPredicate class];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder *)coder
|
|
|
|
|
{
|
|
|
|
|
// FIXME
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithCoder: (NSCoder *)coder
|
|
|
|
|
{
|
|
|
|
|
// FIXME
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return self;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@implementation NSExpression
|
|
|
|
|
|
2010-10-04 08:21:34 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSExpression class] && nil == evaluatedObjectExpression)
|
|
|
|
|
{
|
|
|
|
|
evaluatedObjectExpression = [GSEvaluatedObjectExpression new];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
+ (NSExpression *) expressionForConstantValue: (id)obj
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
GSConstantValueExpression *e;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
e = [[GSConstantValueExpression alloc]
|
|
|
|
|
initWithExpressionType: NSConstantValueExpressionType];
|
|
|
|
|
ASSIGN(e->_obj, obj);
|
|
|
|
|
return AUTORELEASE(e);
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
+ (NSExpression *) expressionForEvaluatedObject
|
|
|
|
|
{
|
2010-10-04 08:21:34 +00:00
|
|
|
|
return evaluatedObjectExpression;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
+ (NSExpression *) expressionForFunction: (NSString *)name
|
2007-05-23 13:11:55 +00:00
|
|
|
|
arguments: (NSArray *)args
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
GSFunctionExpression *e;
|
|
|
|
|
NSString *s;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2013-02-15 15:14:50 +00:00
|
|
|
|
e = [[GSFunctionExpression alloc]
|
|
|
|
|
initWithExpressionType: NSFunctionExpressionType];
|
2013-01-22 08:31:40 +00:00
|
|
|
|
s = [NSString stringWithFormat: @"_eval_%@:", name];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
e->_selector = NSSelectorFromString(s);
|
|
|
|
|
if (![e respondsToSelector: e->_selector])
|
2006-05-15 11:23:59 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2007-06-09 16:37:26 +00:00
|
|
|
|
format: @"Unknown function implementation: %@", name];
|
2006-05-15 11:23:59 +00:00
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
ASSIGN(e->_function, name);
|
2006-05-24 10:15:16 +00:00
|
|
|
|
e->_argc = [args count];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
ASSIGN(e->_args, args);
|
2013-02-15 15:14:50 +00:00
|
|
|
|
if ([name isEqualToString: @"_add"]) e->_op = @"+";
|
|
|
|
|
else if ([name isEqualToString: @"_sub"]) e->_op = @"-";
|
|
|
|
|
else if ([name isEqualToString: @"_mul"]) e->_op = @"*";
|
|
|
|
|
else if ([name isEqualToString: @"_div"]) e->_op = @"/";
|
|
|
|
|
else if ([name isEqualToString: @"_pow"]) e->_op = @"**";
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE(e);
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
+ (NSExpression *) expressionForKeyPath: (NSString *)path
|
|
|
|
|
{
|
|
|
|
|
GSKeyPathExpression *e;
|
2006-05-15 11:23:59 +00:00
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
if (![path isKindOfClass: [NSString class]])
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2006-05-24 10:15:16 +00:00
|
|
|
|
format: @"Keypath is not NSString: %@", path];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
e = [[GSKeyPathExpression alloc]
|
|
|
|
|
initWithExpressionType: NSKeyPathExpressionType];
|
|
|
|
|
ASSIGN(e->_keyPath, path);
|
|
|
|
|
return AUTORELEASE(e);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-12 13:06:23 +00:00
|
|
|
|
+ (NSExpression *) expressionForKeyPathCompositionWithLeft: (NSExpression*)left
|
|
|
|
|
right: (NSExpression*)right
|
|
|
|
|
{
|
|
|
|
|
GSKeyPathCompositionExpression *e;
|
|
|
|
|
|
|
|
|
|
e = [[GSKeyPathCompositionExpression alloc]
|
|
|
|
|
initWithExpressionType: NSKeyPathCompositionExpressionType];
|
|
|
|
|
ASSIGN(e->_left, left);
|
|
|
|
|
ASSIGN(e->_right, right);
|
|
|
|
|
return AUTORELEASE(e);
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
+ (NSExpression *) expressionForVariable: (NSString *)string
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
GSVariableExpression *e;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
e = [[GSVariableExpression alloc]
|
|
|
|
|
initWithExpressionType: NSVariableExpressionType];
|
|
|
|
|
ASSIGN(e->_variable, string);
|
|
|
|
|
return AUTORELEASE(e);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-24 20:55:16 +00:00
|
|
|
|
// 10.5 methods...
|
|
|
|
|
+ (NSExpression *) expressionForIntersectSet: (NSExpression *)left
|
|
|
|
|
with: (NSExpression *)right
|
|
|
|
|
{
|
2024-05-26 13:11:21 +00:00
|
|
|
|
GSIntersectSetExpression *e;
|
|
|
|
|
|
|
|
|
|
e = [[GSIntersectSetExpression alloc]
|
|
|
|
|
initWithExpressionType: NSIntersectSetExpressionType];
|
|
|
|
|
ASSIGN(e->_left, left);
|
|
|
|
|
ASSIGN(e->_right, right);
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE(e);
|
2024-05-24 20:55:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSExpression *) expressionForAggregate: (NSArray *)subExpressions
|
|
|
|
|
{
|
2024-05-26 20:16:40 +00:00
|
|
|
|
GSAggregateExpression *e;
|
|
|
|
|
|
|
|
|
|
e = [[GSAggregateExpression alloc]
|
|
|
|
|
initWithExpressionType: NSAggregateExpressionType];
|
2024-05-28 23:10:11 +00:00
|
|
|
|
ASSIGN(e->_collection, [NSSet setWithArray: subExpressions]);
|
2024-05-26 20:16:40 +00:00
|
|
|
|
|
|
|
|
|
return AUTORELEASE(e);
|
2024-05-24 20:55:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSExpression *) expressionForUnionSet: (NSExpression *)left
|
|
|
|
|
with: (NSExpression *)right
|
|
|
|
|
{
|
2024-05-26 13:11:21 +00:00
|
|
|
|
GSUnionSetExpression *e;
|
|
|
|
|
|
|
|
|
|
e = [[GSUnionSetExpression alloc]
|
|
|
|
|
initWithExpressionType: NSUnionSetExpressionType];
|
|
|
|
|
ASSIGN(e->_left, left);
|
|
|
|
|
ASSIGN(e->_right, right);
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE(e);
|
2024-05-24 20:55:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSExpression *) expressionForMinusSet: (NSExpression *)left
|
|
|
|
|
with: (NSExpression *)right
|
|
|
|
|
{
|
2024-05-26 13:11:21 +00:00
|
|
|
|
GSMinusSetExpression *e;
|
|
|
|
|
|
|
|
|
|
e = [[GSMinusSetExpression alloc]
|
|
|
|
|
initWithExpressionType: NSMinusSetExpressionType];
|
|
|
|
|
ASSIGN(e->_left, left);
|
|
|
|
|
ASSIGN(e->_right, right);
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE(e);
|
2024-05-24 20:55:16 +00:00
|
|
|
|
}
|
|
|
|
|
// end 10.5 methods
|
|
|
|
|
|
2024-05-24 18:28:04 +00:00
|
|
|
|
// 10.6 methods...
|
|
|
|
|
+ (NSExpression *) expressionWithFormat: (NSString *)format, ...
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
NSExpression *obj;
|
|
|
|
|
|
|
|
|
|
if (NULL == format)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[NSExpression+expressionWithFormat:]: NULL format"];
|
|
|
|
|
}
|
2024-05-24 18:37:24 +00:00
|
|
|
|
|
2024-05-24 18:28:04 +00:00
|
|
|
|
va_start(ap, format);
|
2024-05-25 04:39:34 +00:00
|
|
|
|
obj = [self expressionWithFormat: format
|
|
|
|
|
arguments: ap];
|
2024-05-24 18:28:04 +00:00
|
|
|
|
va_end(ap);
|
2024-05-24 18:37:24 +00:00
|
|
|
|
|
2024-05-24 18:28:04 +00:00
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSExpression *) expressionWithFormat: (NSString *)format
|
2024-05-24 18:37:24 +00:00
|
|
|
|
arguments: (va_list)args
|
2024-05-24 18:28:04 +00:00
|
|
|
|
{
|
|
|
|
|
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
|
2024-05-24 18:37:24 +00:00
|
|
|
|
argumentArray: (NSArray *)args
|
2024-05-24 18:28:04 +00:00
|
|
|
|
{
|
|
|
|
|
GSPredicateScanner *scanner = AUTORELEASE([[GSPredicateScanner alloc]
|
|
|
|
|
initWithString: format
|
|
|
|
|
args: args]);
|
|
|
|
|
return [scanner parseExpression];
|
|
|
|
|
}
|
|
|
|
|
// End 10.6 methods
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) initWithExpressionType: (NSExpressionType)type
|
|
|
|
|
{
|
|
|
|
|
if ((self = [super init]) != nil)
|
|
|
|
|
{
|
|
|
|
|
_type = type;
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone *)z
|
|
|
|
|
{
|
|
|
|
|
return NSCopyObject(self, 0, z);
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
- (NSArray *) arguments
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2006-05-15 11:23:59 +00:00
|
|
|
|
|
|
|
|
|
- (id) constantValue
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpressionType) expressionType
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return _type;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) expressionValueWithObject: (id)object
|
|
|
|
|
context: (NSMutableDictionary *)context
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) function
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) keyPath
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) operand
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) variable
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 12:39:44 +00:00
|
|
|
|
- (NSExpression *) leftExpression
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) rightExpression
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) collection
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (Class) classForCoder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [NSExpression class];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder *)coder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
2006-05-09 14:21:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder *)coder
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
2006-05-09 14:21:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return nil;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary *)variables
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSConstantValueExpression
|
|
|
|
|
|
|
|
|
|
- (id) constantValue
|
|
|
|
|
{
|
|
|
|
|
return _obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
2013-02-15 15:14:50 +00:00
|
|
|
|
if ([_obj isKindOfClass: [NSString class]])
|
|
|
|
|
{
|
|
|
|
|
NSMutableString *result = nil;
|
|
|
|
|
|
|
|
|
|
/* Quote the result string as necessary.
|
|
|
|
|
*/
|
|
|
|
|
GSPropertyListMake(_obj, nil, NO, YES, 2, &result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2020-01-12 19:56:09 +00:00
|
|
|
|
else if ([_obj isKindOfClass: [NSDate class]])
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"CAST(%15.6f, \"NSDate\")",
|
|
|
|
|
[(NSDate*)_obj timeIntervalSinceReferenceDate]];
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [_obj description];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) expressionValueWithObject: (id)object
|
|
|
|
|
context: (NSMutableDictionary *)context
|
|
|
|
|
{
|
2022-01-30 17:24:32 +00:00
|
|
|
|
if ([_obj isKindOfClass: [NSArray class]])
|
|
|
|
|
{
|
2022-01-31 12:18:24 +00:00
|
|
|
|
NSUInteger count = [(NSArray*)_obj count];
|
|
|
|
|
NSMutableArray *tmp = [NSMutableArray arrayWithCapacity: count];
|
|
|
|
|
NSUInteger index = 0;
|
2022-01-30 17:24:32 +00:00
|
|
|
|
|
2022-01-31 12:18:24 +00:00
|
|
|
|
while (index < count)
|
2022-01-30 17:24:32 +00:00
|
|
|
|
{
|
2022-08-24 16:01:30 +00:00
|
|
|
|
id e = [(NSArray*)_obj objectAtIndex: index++];
|
|
|
|
|
id o;
|
|
|
|
|
|
|
|
|
|
/* Array index is not always a NSExpression object
|
|
|
|
|
* (e.g. When specified as an argument instead of
|
|
|
|
|
* an inline expression).
|
|
|
|
|
*/
|
|
|
|
|
if ([e isKindOfClass: [NSExpression class]]) {
|
|
|
|
|
o = [e expressionValueWithObject: e context: context];
|
|
|
|
|
} else {
|
|
|
|
|
o = e;
|
|
|
|
|
}
|
2022-01-30 17:24:32 +00:00
|
|
|
|
|
2022-01-31 12:18:24 +00:00
|
|
|
|
[tmp addObject: o];
|
2022-01-30 17:24:32 +00:00
|
|
|
|
}
|
2022-01-31 12:18:24 +00:00
|
|
|
|
return tmp;
|
2022-01-30 17:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return _obj;
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (void) dealloc
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
RELEASE(_obj);
|
|
|
|
|
[super dealloc];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
GSConstantValueExpression *copy;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
copy = (GSConstantValueExpression *)[super copyWithZone: zone];
|
|
|
|
|
copy->_obj = [_obj copyWithZone: zone];
|
|
|
|
|
return copy;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary *)variables
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return self;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSEvaluatedObjectExpression
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return @"SELF";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) expressionValueWithObject: (id)object
|
|
|
|
|
context: (NSMutableDictionary *)context
|
|
|
|
|
{
|
2017-04-09 12:45:18 +00:00
|
|
|
|
return object;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary *)variables
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return self;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 12:45:18 +00:00
|
|
|
|
- (NSString *) keyPath
|
|
|
|
|
{
|
|
|
|
|
return @"SELF";
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSVariableExpression
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"$%@", _variable];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) expressionValueWithObject: (id)object
|
|
|
|
|
context: (NSMutableDictionary *)context
|
|
|
|
|
{
|
|
|
|
|
return [context objectForKey: _variable];
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (NSString *) variable
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return _variable;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (void) dealloc;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
RELEASE(_variable);
|
|
|
|
|
[super dealloc];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
GSVariableExpression *copy;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
copy = (GSVariableExpression *)[super copyWithZone: zone];
|
|
|
|
|
copy->_variable = [_variable copyWithZone: zone];
|
|
|
|
|
return copy;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary *)variables
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
id result = [variables objectForKey: _variable];
|
|
|
|
|
|
|
|
|
|
if (result != nil)
|
|
|
|
|
{
|
|
|
|
|
return [NSExpression expressionForConstantValue: result];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSKeyPathExpression
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return _keyPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) expressionValueWithObject: (id)object
|
|
|
|
|
context: (NSMutableDictionary *)context
|
|
|
|
|
{
|
|
|
|
|
return [object valueForKeyPath: _keyPath];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) keyPath
|
|
|
|
|
{
|
|
|
|
|
return _keyPath;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (void) dealloc;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
RELEASE(_keyPath);
|
|
|
|
|
[super dealloc];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
GSKeyPathExpression *copy;
|
|
|
|
|
|
|
|
|
|
copy = (GSKeyPathExpression *)[super copyWithZone: zone];
|
|
|
|
|
copy->_keyPath = [_keyPath copyWithZone: zone];
|
|
|
|
|
return copy;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary *)variables
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return self;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2022-02-12 13:06:23 +00:00
|
|
|
|
@implementation GSKeyPathCompositionExpression
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@.%@", _left, _right];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) expressionValueWithObject: (id)object
|
|
|
|
|
context: (NSMutableDictionary *)context
|
|
|
|
|
{
|
|
|
|
|
object = [_left expressionValueWithObject: object context: context];
|
|
|
|
|
return [_right expressionValueWithObject: object context: context];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) keyPath
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
RELEASE(_left);
|
|
|
|
|
RELEASE(_right);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
|
|
|
|
{
|
|
|
|
|
GSKeyPathCompositionExpression *copy;
|
|
|
|
|
|
|
|
|
|
copy = (GSKeyPathCompositionExpression *)[super copyWithZone: zone];
|
|
|
|
|
copy->_left = [_left copyWithZone: zone];
|
|
|
|
|
copy->_right = [_right copyWithZone: zone];
|
|
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary*)variables
|
|
|
|
|
{
|
|
|
|
|
NSExpression *left;
|
|
|
|
|
NSExpression *right;
|
|
|
|
|
|
|
|
|
|
left = [_left _expressionWithSubstitutionVariables: variables];
|
|
|
|
|
right = [_right _expressionWithSubstitutionVariables: variables];
|
|
|
|
|
return [NSExpression expressionForKeyPathCompositionWithLeft: left
|
|
|
|
|
right: right];
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 12:39:44 +00:00
|
|
|
|
- (NSExpression *) leftExpression
|
|
|
|
|
{
|
|
|
|
|
return _left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) rightExpression
|
|
|
|
|
{
|
|
|
|
|
return _right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2024-05-28 23:10:11 +00:00
|
|
|
|
// 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)
|
|
|
|
|
|
2024-05-26 12:39:44 +00:00
|
|
|
|
@implementation GSUnionSetExpression
|
2024-05-26 13:11:21 +00:00
|
|
|
|
|
2024-05-26 20:16:40 +00:00
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@.%@", _left, _right];
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 13:11:21 +00:00
|
|
|
|
- (NSExpression *) leftExpression
|
|
|
|
|
{
|
|
|
|
|
return _left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) rightExpression
|
|
|
|
|
{
|
|
|
|
|
return _right;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-28 23:10:11 +00:00
|
|
|
|
- (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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 12:39:44 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSIntersectSetExpression
|
2024-05-26 13:11:21 +00:00
|
|
|
|
|
2024-05-26 20:16:40 +00:00
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@.%@", _left, _right];
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 13:11:21 +00:00
|
|
|
|
- (NSExpression *) leftExpression
|
|
|
|
|
{
|
|
|
|
|
return _left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) rightExpression
|
|
|
|
|
{
|
|
|
|
|
return _right;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-28 23:10:11 +00:00
|
|
|
|
- (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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 13:11:21 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSMinusSetExpression
|
|
|
|
|
|
2024-05-26 20:16:40 +00:00
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@.%@", _left, _right];
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 13:11:21 +00:00
|
|
|
|
- (NSExpression *) leftExpression
|
|
|
|
|
{
|
|
|
|
|
return _left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) rightExpression
|
|
|
|
|
{
|
|
|
|
|
return _right;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-28 23:10:11 +00:00
|
|
|
|
- (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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-26 12:39:44 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSSubqueryExpression
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSAggregateExpression
|
2024-05-26 20:16:40 +00:00
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@", _collection];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) collection
|
|
|
|
|
{
|
|
|
|
|
return _collection;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-28 19:03:26 +00:00
|
|
|
|
- (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;
|
|
|
|
|
}
|
2022-02-12 13:06:23 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@implementation GSFunctionExpression
|
|
|
|
|
|
|
|
|
|
- (NSArray *) arguments
|
|
|
|
|
{
|
|
|
|
|
return _args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
2013-02-15 15:14:50 +00:00
|
|
|
|
if (nil != _op && 1 == [_args count])
|
|
|
|
|
{
|
|
|
|
|
GSFunctionExpression *a0 = [_args objectAtIndex: 0];
|
|
|
|
|
|
|
|
|
|
if (YES == [a0 isKindOfClass: [self class]] && nil != a0->_op)
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@(%@)", _op, a0];
|
|
|
|
|
}
|
|
|
|
|
return [NSString stringWithFormat: @"%@%@", _op, a0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nil != _op)
|
|
|
|
|
{
|
|
|
|
|
GSFunctionExpression *a0 = [_args objectAtIndex: 0];
|
|
|
|
|
GSFunctionExpression *a1 = [_args objectAtIndex: 1];
|
|
|
|
|
|
|
|
|
|
if (YES == [a0 isKindOfClass: [self class]] && nil != a0->_op)
|
|
|
|
|
{
|
|
|
|
|
if (YES == [a1 isKindOfClass: [self class]] && nil != a1->_op)
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"(%@) %@ (%@)", a0, _op, a1];
|
|
|
|
|
}
|
|
|
|
|
return [NSString stringWithFormat: @"(%@) %@ %@", a0, _op, a1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (YES == [a1 isKindOfClass: [self class]] && nil != a1->_op)
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@ %@ (%@)", a0, _op, a1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [NSString stringWithFormat: @"%@ %@ %@", a0, _op, a1];
|
|
|
|
|
}
|
|
|
|
|
return [NSString stringWithFormat: @"%@(%@)", [self function], _args];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (NSString *) function
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return _function;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-22 08:31:40 +00:00
|
|
|
|
- (NSString *) keyPath
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
- (id) expressionValueWithObject: (id)object
|
|
|
|
|
context: (NSMutableDictionary *)context
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
// temporary space
|
|
|
|
|
NSMutableArray *eargs = [NSMutableArray arrayWithCapacity: _argc];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < _argc; i++)
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[eargs addObject: [[_args objectAtIndex: i]
|
2007-06-21 05:46:13 +00:00
|
|
|
|
expressionValueWithObject: object context: context]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// apply method selector
|
2006-05-09 14:21:26 +00:00
|
|
|
|
return [self performSelector: _selector
|
2016-05-18 13:11:45 +00:00
|
|
|
|
withObject: eargs];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc;
|
|
|
|
|
{
|
|
|
|
|
RELEASE(_args);
|
|
|
|
|
RELEASE(_function);
|
|
|
|
|
[super dealloc];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
GSFunctionExpression *copy;
|
|
|
|
|
|
|
|
|
|
copy = (GSFunctionExpression *)[super copyWithZone: zone];
|
|
|
|
|
copy->_function = [_function copyWithZone: zone];
|
|
|
|
|
copy->_args = [_args copyWithZone: zone];
|
|
|
|
|
return copy;
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-18 13:11:45 +00:00
|
|
|
|
- (NSEnumerator*) _enum: (NSArray *)expressions
|
|
|
|
|
{
|
|
|
|
|
id o;
|
|
|
|
|
|
|
|
|
|
/* Check to see if this is aggregating over a collection.
|
|
|
|
|
*/
|
|
|
|
|
if (1 == _argc && [(o = [expressions lastObject])
|
|
|
|
|
respondsToSelector: @selector(objectEnumerator)])
|
|
|
|
|
{
|
|
|
|
|
return [o objectEnumerator];
|
|
|
|
|
}
|
|
|
|
|
return [expressions objectEnumerator];
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _expressionWithSubstitutionVariables: (NSDictionary *)variables
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
NSMutableArray *args = [NSMutableArray arrayWithCapacity: _argc];
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < _argc; i++)
|
|
|
|
|
{
|
|
|
|
|
[args addObject: [[_args objectAtIndex: i]
|
|
|
|
|
_expressionWithSubstitutionVariables: variables]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [NSExpression expressionForFunction: _function arguments: args];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__chs: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [NSNumber numberWithInt: -[[expressions objectAtIndex: 0] intValue]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__first: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [[expressions objectAtIndex: 0] objectAtIndex: 0];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__last: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [[expressions objectAtIndex: 0] lastObject];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__index: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
id left = [expressions objectAtIndex: 0];
|
|
|
|
|
id right = [expressions objectAtIndex: 1];
|
|
|
|
|
|
|
|
|
|
if ([left isKindOfClass: [NSDictionary class]])
|
|
|
|
|
{
|
|
|
|
|
return [left objectForKey: right];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// raises exception if invalid
|
|
|
|
|
return [left objectAtIndex: [right unsignedIntValue]];
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__pow: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
id left = [expressions objectAtIndex: 0];
|
|
|
|
|
id right = [expressions objectAtIndex: 1];
|
|
|
|
|
|
2016-05-18 13:11:45 +00:00
|
|
|
|
return [NSNumber numberWithDouble:
|
|
|
|
|
pow([left doubleValue], [right doubleValue])];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__mul: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
id left = [expressions objectAtIndex: 0];
|
|
|
|
|
id right = [expressions objectAtIndex: 1];
|
|
|
|
|
|
|
|
|
|
return [NSNumber numberWithDouble: [left doubleValue] * [right doubleValue]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__div: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
id left = [expressions objectAtIndex: 0];
|
|
|
|
|
id right = [expressions objectAtIndex: 1];
|
|
|
|
|
|
|
|
|
|
return [NSNumber numberWithDouble: [left doubleValue] / [right doubleValue]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval__add: (NSArray *)expressions
|
|
|
|
|
{
|
|
|
|
|
id left = [expressions objectAtIndex: 0];
|
|
|
|
|
id right = [expressions objectAtIndex: 1];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [NSNumber numberWithDouble: [left doubleValue] + [right doubleValue]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) _eval__sub: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
id left = [expressions objectAtIndex: 0];
|
|
|
|
|
id right = [expressions objectAtIndex: 1];
|
|
|
|
|
|
|
|
|
|
return [NSNumber numberWithDouble: [left doubleValue] - [right doubleValue]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval_count: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2010-01-10 14:38:16 +00:00
|
|
|
|
NSAssert(_argc == 1, NSInternalInconsistencyException);
|
|
|
|
|
return [NSNumber numberWithUnsignedInt:
|
|
|
|
|
[[expressions objectAtIndex: 0] count]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval_avg: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
NSEnumerator *e = [self _enum: expressions];
|
|
|
|
|
double sum = 0.0;
|
|
|
|
|
unsigned count = 0;
|
|
|
|
|
id o;
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2016-05-18 13:11:45 +00:00
|
|
|
|
while (nil != (o = [e nextObject]))
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
sum += [o doubleValue];
|
|
|
|
|
count++;
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2018-02-01 21:31:15 +00:00
|
|
|
|
if (count == 0)
|
|
|
|
|
{
|
|
|
|
|
return [NSNumber numberWithDouble: 0.0];
|
|
|
|
|
}
|
2016-05-18 13:11:45 +00:00
|
|
|
|
return [NSNumber numberWithDouble: sum / count];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-18 13:11:45 +00:00
|
|
|
|
- (id) _eval_max: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
NSEnumerator *e = [self _enum: expressions];
|
|
|
|
|
id o = [e nextObject];
|
|
|
|
|
double max = (nil == o) ? 0.0 : [o doubleValue];
|
|
|
|
|
double cur;
|
|
|
|
|
|
|
|
|
|
while (nil != (o = [e nextObject]))
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
cur = [o doubleValue];
|
|
|
|
|
if (max < cur)
|
|
|
|
|
{
|
|
|
|
|
max = cur;
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2016-05-18 13:11:45 +00:00
|
|
|
|
return [NSNumber numberWithDouble: max];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval_min: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
NSEnumerator *e = [self _enum: expressions];
|
|
|
|
|
id o = [e nextObject];
|
|
|
|
|
double min = (nil == o ? 0.0 : [o doubleValue]);
|
|
|
|
|
double cur;
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2016-05-18 13:11:45 +00:00
|
|
|
|
while (nil != (o = [e nextObject]))
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
cur = [o doubleValue];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
if (min > cur)
|
|
|
|
|
{
|
|
|
|
|
min = cur;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return [NSNumber numberWithDouble: min];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-18 13:11:45 +00:00
|
|
|
|
- (id) _eval_sum: (NSArray *)expressions
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
NSEnumerator *e = [self _enum: expressions];
|
|
|
|
|
double sum = 0.0;
|
|
|
|
|
id o;
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
2016-05-18 13:11:45 +00:00
|
|
|
|
while (nil != (o = [e nextObject]))
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2016-05-18 13:11:45 +00:00
|
|
|
|
sum += [o doubleValue];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2016-05-18 13:11:45 +00:00
|
|
|
|
return [NSNumber numberWithDouble: sum];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-12 19:56:09 +00:00
|
|
|
|
- (id) _eval_CAST: (NSArray *)expressions
|
|
|
|
|
{
|
|
|
|
|
id left = [expressions objectAtIndex: 0];
|
|
|
|
|
id right = [expressions objectAtIndex: 1];
|
|
|
|
|
|
|
|
|
|
if ([right isEqualToString: @"NSDate"])
|
|
|
|
|
{
|
2021-01-18 11:56:44 +00:00
|
|
|
|
return [NSDate dateWithTimeIntervalSinceReferenceDate:
|
|
|
|
|
[left doubleValue]];
|
2020-01-12 19:56:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSLog(@"Cast to unknown type %@", right);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// add arithmetic functions: average, median, mode, stddev, sqrt, log, ln, exp, floor, ceiling, abs, trunc, random, randomn, now
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@implementation NSArray (NSPredicate)
|
|
|
|
|
|
|
|
|
|
- (NSArray *) filteredArrayUsingPredicate: (NSPredicate *)predicate
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *result;
|
|
|
|
|
NSEnumerator *e = [self objectEnumerator];
|
|
|
|
|
id object;
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
result = [NSMutableArray arrayWithCapacity: [self count]];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
while ((object = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([predicate evaluateWithObject: object] == YES)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
[result addObject: object]; // passes filter
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
2016-03-10 16:50:41 +00:00
|
|
|
|
return GS_IMMUTABLE(result);
|
2007-04-15 09:50:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSMutableArray (NSPredicate)
|
|
|
|
|
|
|
|
|
|
- (void) filterUsingPredicate: (NSPredicate *)predicate
|
|
|
|
|
{
|
|
|
|
|
unsigned count = [self count];
|
|
|
|
|
|
|
|
|
|
while (count-- > 0)
|
|
|
|
|
{
|
|
|
|
|
id object = [self objectAtIndex: count];
|
|
|
|
|
|
|
|
|
|
if ([predicate evaluateWithObject: object] == NO)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
[self removeObjectAtIndex: count];
|
|
|
|
|
}
|
2007-04-15 09:50:48 +00:00
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2009-02-10 14:43:34 +00:00
|
|
|
|
@implementation NSSet (NSPredicate)
|
|
|
|
|
|
|
|
|
|
- (NSSet *) filteredSetUsingPredicate: (NSPredicate *)predicate
|
|
|
|
|
{
|
|
|
|
|
NSMutableSet *result;
|
|
|
|
|
NSEnumerator *e = [self objectEnumerator];
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
result = [NSMutableSet setWithCapacity: [self count]];
|
|
|
|
|
while ((object = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([predicate evaluateWithObject: object] == YES)
|
|
|
|
|
{
|
|
|
|
|
[result addObject: object]; // passes filter
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-10 16:50:41 +00:00
|
|
|
|
return GS_IMMUTABLE(result);
|
2009-02-10 14:43:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSMutableSet (NSPredicate)
|
|
|
|
|
|
|
|
|
|
- (void) filterUsingPredicate: (NSPredicate *)predicate
|
|
|
|
|
{
|
|
|
|
|
NSMutableSet *rejected;
|
|
|
|
|
NSEnumerator *e = [self objectEnumerator];
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
rejected = [NSMutableSet setWithCapacity: [self count]];
|
|
|
|
|
while ((object = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([predicate evaluateWithObject: object] == NO)
|
|
|
|
|
{
|
|
|
|
|
[rejected addObject: object];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[self minusSet: rejected];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
|
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
@implementation GSPredicateScanner
|
|
|
|
|
|
|
|
|
|
- (id) initWithString: (NSString*)format
|
2007-05-23 13:11:55 +00:00
|
|
|
|
args: (NSArray*)args
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
self = [super initWithString: format];
|
|
|
|
|
if (self != nil)
|
|
|
|
|
{
|
|
|
|
|
_args = [args objectEnumerator];
|
2006-08-06 05:18:41 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-21 05:46:13 +00:00
|
|
|
|
- (id) nextArg
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2007-06-21 05:46:13 +00:00
|
|
|
|
return [_args nextObject];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) scanPredicateKeyword: (NSString *)key
|
|
|
|
|
{
|
|
|
|
|
// save to back up
|
|
|
|
|
unsigned loc = [self scanLocation];
|
|
|
|
|
unichar c;
|
|
|
|
|
|
|
|
|
|
[self setCaseSensitive: NO];
|
|
|
|
|
if (![self scanString: key intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
// no match
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2007-06-09 16:37:26 +00:00
|
|
|
|
|
|
|
|
|
if ([self isAtEnd])
|
|
|
|
|
{
|
|
|
|
|
// ok
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Does the next character still belong to the token?
|
2006-05-24 10:15:16 +00:00
|
|
|
|
c = [[self string] characterAtIndex: [self scanLocation]];
|
|
|
|
|
if (![[NSCharacterSet alphanumericCharacterSet] characterIsMember: c])
|
|
|
|
|
{
|
|
|
|
|
// ok
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// back up
|
|
|
|
|
[self setScanLocation: loc];
|
|
|
|
|
// no match
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) parse
|
|
|
|
|
{
|
2008-11-17 13:45:32 +00:00
|
|
|
|
NSPredicate *r = nil;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2007-06-09 16:37:26 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
r = [self parsePredicate];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Parsing failed for %@ with %@", [self string], localException);
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
if (![self isAtEnd])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2006-05-24 10:27:47 +00:00
|
|
|
|
format: @"Format string contains extra characters: \"%@\"",
|
2006-05-24 10:15:16 +00:00
|
|
|
|
[self string]];
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) parsePredicate
|
|
|
|
|
{
|
|
|
|
|
return [self parseAnd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) parseAnd
|
|
|
|
|
{
|
2006-05-24 10:27:47 +00:00
|
|
|
|
NSPredicate *l = [self parseOr];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2007-06-20 08:03:51 +00:00
|
|
|
|
while ([self scanPredicateKeyword: @"AND"]
|
|
|
|
|
|| [self scanPredicateKeyword: @"&&"])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2006-05-24 10:27:47 +00:00
|
|
|
|
NSPredicate *r = [self parseOr];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2006-05-24 10:27:47 +00:00
|
|
|
|
if ([r isKindOfClass: [NSCompoundPredicate class]]
|
2007-06-20 08:03:51 +00:00
|
|
|
|
&& [(NSCompoundPredicate *)r compoundPredicateType]
|
|
|
|
|
== NSAndPredicateType)
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSCompoundPredicate *right = (NSCompoundPredicate*)r;
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// merge
|
2022-02-12 13:06:23 +00:00
|
|
|
|
if ([l isKindOfClass: [NSCompoundPredicate class]]
|
2007-06-20 08:03:51 +00:00
|
|
|
|
&& [(NSCompoundPredicate *)l compoundPredicateType]
|
|
|
|
|
== NSAndPredicateType)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSCompoundPredicate *left;
|
|
|
|
|
NSMutableArray *subs;
|
|
|
|
|
|
|
|
|
|
left = (NSCompoundPredicate*)l;
|
|
|
|
|
subs = [[left subpredicates] mutableCopy];
|
|
|
|
|
[subs addObjectsFromArray: [right subpredicates]];
|
|
|
|
|
l = [NSCompoundPredicate andPredicateWithSubpredicates: subs];
|
|
|
|
|
[subs release];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSMutableArray *subs;
|
|
|
|
|
|
|
|
|
|
subs = [[right subpredicates] mutableCopy];
|
|
|
|
|
[subs insertObject: l atIndex: 0];
|
|
|
|
|
l = [NSCompoundPredicate andPredicateWithSubpredicates: subs];
|
|
|
|
|
[subs release];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-05-24 10:27:47 +00:00
|
|
|
|
else if ([l isKindOfClass: [NSCompoundPredicate class]]
|
2007-06-20 08:03:51 +00:00
|
|
|
|
&& [(NSCompoundPredicate *)l compoundPredicateType]
|
|
|
|
|
== NSAndPredicateType)
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSCompoundPredicate *left;
|
|
|
|
|
NSMutableArray *subs;
|
|
|
|
|
|
|
|
|
|
left = (NSCompoundPredicate*)l;
|
|
|
|
|
subs = [[left subpredicates] mutableCopy];
|
|
|
|
|
[subs addObject: r];
|
|
|
|
|
l = [NSCompoundPredicate andPredicateWithSubpredicates: subs];
|
|
|
|
|
[subs release];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
l = [NSCompoundPredicate andPredicateWithSubpredicates:
|
2007-06-20 08:03:51 +00:00
|
|
|
|
[NSArray arrayWithObjects: l, r, nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) parseNot
|
|
|
|
|
{
|
|
|
|
|
if ([self scanString: @"(" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
NSPredicate *r = [self parsePredicate];
|
|
|
|
|
|
|
|
|
|
if (![self scanString: @")" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Missing ) in compound predicate"];
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-09 16:37:26 +00:00
|
|
|
|
if ([self scanPredicateKeyword: @"NOT"] || [self scanPredicateKeyword: @"!"])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
// -> NOT NOT x or NOT (y)
|
2006-05-24 10:27:47 +00:00
|
|
|
|
return [NSCompoundPredicate
|
2007-05-23 13:11:55 +00:00
|
|
|
|
notPredicateWithSubpredicate: [self parseNot]];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-03-30 03:39:18 +00:00
|
|
|
|
if ([self scanPredicateKeyword: @"TRUEPREDICATE"])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSPredicate predicateWithValue: YES];
|
|
|
|
|
}
|
2007-03-30 03:39:18 +00:00
|
|
|
|
if ([self scanPredicateKeyword: @"FALSEPREDICATE"])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSPredicate predicateWithValue: NO];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [self parseComparison];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) parseOr
|
|
|
|
|
{
|
2006-05-24 10:27:47 +00:00
|
|
|
|
NSPredicate *l = [self parseNot];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2007-06-20 04:36:31 +00:00
|
|
|
|
while ([self scanPredicateKeyword: @"OR"]
|
|
|
|
|
|| [self scanPredicateKeyword: @"||"])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2006-05-24 10:27:47 +00:00
|
|
|
|
NSPredicate *r = [self parseNot];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2006-05-24 10:27:47 +00:00
|
|
|
|
if ([r isKindOfClass: [NSCompoundPredicate class]]
|
2007-06-20 04:36:31 +00:00
|
|
|
|
&& [(NSCompoundPredicate *)r compoundPredicateType]
|
|
|
|
|
== NSOrPredicateType)
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSCompoundPredicate *right = (NSCompoundPredicate*)r;
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// merge
|
|
|
|
|
if ([l isKindOfClass: [NSCompoundPredicate class]]
|
2007-06-20 04:36:31 +00:00
|
|
|
|
&& [(NSCompoundPredicate *)l compoundPredicateType]
|
|
|
|
|
== NSOrPredicateType)
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSCompoundPredicate *left = (NSCompoundPredicate*)l;
|
|
|
|
|
NSMutableArray *subs;
|
|
|
|
|
|
|
|
|
|
subs = [[left subpredicates] mutableCopy];
|
|
|
|
|
[subs addObjectsFromArray: [right subpredicates]];
|
|
|
|
|
l = [NSCompoundPredicate orPredicateWithSubpredicates: subs];
|
|
|
|
|
[subs release];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSMutableArray *subs;
|
|
|
|
|
|
|
|
|
|
subs = [[right subpredicates] mutableCopy];
|
|
|
|
|
[subs insertObject: l atIndex: 0];
|
|
|
|
|
l = [NSCompoundPredicate orPredicateWithSubpredicates: subs];
|
|
|
|
|
[subs release];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-05-24 10:27:47 +00:00
|
|
|
|
else if ([l isKindOfClass: [NSCompoundPredicate class]]
|
2007-06-20 04:36:31 +00:00
|
|
|
|
&& [(NSCompoundPredicate *)l compoundPredicateType]
|
|
|
|
|
== NSOrPredicateType)
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2013-10-18 07:25:32 +00:00
|
|
|
|
NSCompoundPredicate *left = (NSCompoundPredicate*)l;
|
|
|
|
|
NSMutableArray *subs;
|
|
|
|
|
|
|
|
|
|
subs = [[left subpredicates] mutableCopy];
|
2022-02-12 13:06:23 +00:00
|
|
|
|
[subs addObject: r];
|
2013-10-18 07:25:32 +00:00
|
|
|
|
l = [NSCompoundPredicate orPredicateWithSubpredicates: subs];
|
|
|
|
|
[subs release];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
l = [NSCompoundPredicate orPredicateWithSubpredicates:
|
2007-06-20 04:36:31 +00:00
|
|
|
|
[NSArray arrayWithObjects: l, r, nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPredicate *) parseComparison
|
|
|
|
|
{
|
|
|
|
|
// there must always be a comparison
|
|
|
|
|
NSComparisonPredicateModifier modifier = NSDirectPredicateModifier;
|
|
|
|
|
NSPredicateOperatorType type = 0;
|
|
|
|
|
unsigned opts = 0;
|
|
|
|
|
NSExpression *left;
|
2007-06-14 05:20:17 +00:00
|
|
|
|
NSExpression *right;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
NSPredicate *p;
|
|
|
|
|
BOOL negate = NO;
|
2007-06-14 05:20:17 +00:00
|
|
|
|
BOOL swap = NO;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
if ([self scanPredicateKeyword: @"ANY"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
|
|
|
|
modifier = NSAnyPredicateModifier;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"ALL"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
|
|
|
|
modifier = NSAllPredicateModifier;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"NONE"])
|
|
|
|
|
{
|
|
|
|
|
modifier = NSAnyPredicateModifier;
|
|
|
|
|
negate = YES;
|
|
|
|
|
}
|
|
|
|
|
else if ([self scanPredicateKeyword: @"SOME"])
|
|
|
|
|
{
|
|
|
|
|
modifier = NSAllPredicateModifier;
|
|
|
|
|
negate = YES;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
left = [self parseExpression];
|
2007-06-20 04:36:31 +00:00
|
|
|
|
if ([self scanString: @"!=" intoString: NULL]
|
|
|
|
|
|| [self scanString: @"<>" intoString: NULL])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2007-06-20 04:36:31 +00:00
|
|
|
|
type = NSNotEqualToPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2007-06-14 05:20:17 +00:00
|
|
|
|
else if ([self scanString: @"<=" intoString: NULL]
|
|
|
|
|
|| [self scanString: @"=<" intoString: NULL])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSLessThanOrEqualToPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2007-06-14 05:20:17 +00:00
|
|
|
|
else if ([self scanString: @">=" intoString: NULL]
|
|
|
|
|
|| [self scanString: @"=>" intoString: NULL])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSGreaterThanOrEqualToPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2007-06-20 04:36:31 +00:00
|
|
|
|
else if ([self scanString: @"<" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
type = NSLessThanPredicateOperatorType;
|
|
|
|
|
}
|
|
|
|
|
else if ([self scanString: @">" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
type = NSGreaterThanPredicateOperatorType;
|
|
|
|
|
}
|
2007-06-14 05:20:17 +00:00
|
|
|
|
else if ([self scanString: @"==" intoString: NULL]
|
|
|
|
|
|| [self scanString: @"=" intoString: NULL])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSEqualToPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"MATCHES"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSMatchesPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"LIKE"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSLikePredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"BEGINSWITH"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSBeginsWithPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
|
|
|
|
else if ([self scanPredicateKeyword: @"ENDSWITH"])
|
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSEndsWithPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2007-06-14 05:20:17 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"IN"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
type = NSInPredicateOperatorType;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2007-06-14 05:20:17 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"CONTAINS"])
|
|
|
|
|
{
|
|
|
|
|
type = NSInPredicateOperatorType;
|
|
|
|
|
swap = YES;
|
|
|
|
|
}
|
2007-06-09 16:37:26 +00:00
|
|
|
|
else if ([self scanPredicateKeyword: @"BETWEEN"])
|
|
|
|
|
{
|
2007-06-11 10:56:36 +00:00
|
|
|
|
// Requires special handling to transfer into AND of
|
2007-06-09 16:37:26 +00:00
|
|
|
|
// two normal comparison predicates
|
2007-06-11 10:56:36 +00:00
|
|
|
|
NSExpression *exp = [self parseSimpleExpression];
|
|
|
|
|
NSArray *a = (NSArray *)[exp constantValue];
|
|
|
|
|
NSNumber *lower, *upper;
|
|
|
|
|
NSExpression *lexp, *uexp;
|
|
|
|
|
NSPredicate *lp, *up;
|
2007-06-09 16:37:26 +00:00
|
|
|
|
|
2007-06-11 10:56:36 +00:00
|
|
|
|
if (![a isKindOfClass: [NSArray class]])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"BETWEEN operator requires array argument"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lower = [a objectAtIndex: 0];
|
|
|
|
|
upper = [a objectAtIndex: 1];
|
|
|
|
|
lexp = [NSExpression expressionForConstantValue: lower];
|
|
|
|
|
uexp = [NSExpression expressionForConstantValue: upper];
|
|
|
|
|
lp = [NSComparisonPredicate predicateWithLeftExpression: left
|
|
|
|
|
rightExpression: lexp
|
|
|
|
|
modifier: modifier
|
2024-05-30 22:06:24 +00:00
|
|
|
|
type: NSGreaterThanOrEqualToPredicateOperatorType
|
2007-06-11 10:56:36 +00:00
|
|
|
|
options: opts];
|
|
|
|
|
up = [NSComparisonPredicate predicateWithLeftExpression: left
|
|
|
|
|
rightExpression: uexp
|
|
|
|
|
modifier: modifier
|
2024-05-30 22:06:24 +00:00
|
|
|
|
type: NSLessThanOrEqualToPredicateOperatorType
|
2007-06-11 10:56:36 +00:00
|
|
|
|
options: opts];
|
|
|
|
|
return [NSCompoundPredicate andPredicateWithSubpredicates:
|
|
|
|
|
[NSArray arrayWithObjects: lp, up, nil]];
|
2007-06-09 16:37:26 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2007-06-09 16:37:26 +00:00
|
|
|
|
format: @"Invalid comparison predicate: %@",
|
2006-05-24 10:15:16 +00:00
|
|
|
|
[[self string] substringFromIndex: [self scanLocation]]];
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
if ([self scanString: @"[cd]" intoString: NULL])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
|
|
|
|
opts = NSCaseInsensitivePredicateOption
|
2007-06-14 05:20:17 +00:00
|
|
|
|
| NSDiacriticInsensitivePredicateOption;
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanString: @"[c]" intoString: NULL])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
|
|
|
|
opts = NSCaseInsensitivePredicateOption;
|
|
|
|
|
}
|
|
|
|
|
else if ([self scanString: @"[d]" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
opts = NSDiacriticInsensitivePredicateOption;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2007-06-14 05:20:17 +00:00
|
|
|
|
right = [self parseExpression];
|
|
|
|
|
if (swap == YES)
|
|
|
|
|
{
|
|
|
|
|
NSExpression *tmp = left;
|
|
|
|
|
|
|
|
|
|
left = right;
|
|
|
|
|
right = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-24 10:15:16 +00:00
|
|
|
|
p = [NSComparisonPredicate predicateWithLeftExpression: left
|
2007-06-14 05:20:17 +00:00
|
|
|
|
rightExpression: right
|
2007-05-23 13:11:55 +00:00
|
|
|
|
modifier: modifier
|
|
|
|
|
type: type
|
|
|
|
|
options: opts];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
return negate ? [NSCompoundPredicate notPredicateWithSubpredicate: p] : p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parseExpression
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [self parseBinaryExpression];
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-22 08:31:40 +00:00
|
|
|
|
- (NSExpression *) parseIdentifierExpression
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
2007-06-20 08:03:51 +00:00
|
|
|
|
static NSCharacterSet *_identifier;
|
|
|
|
|
NSString *ident;
|
2013-01-22 08:31:40 +00:00
|
|
|
|
|
2018-02-06 12:26:32 +00:00
|
|
|
|
// skip # as prefix if present (reserved words)
|
|
|
|
|
(void)[self scanString: @"#" intoString: NULL];
|
2013-01-22 08:31:40 +00:00
|
|
|
|
if (!_identifier)
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_identifier, [NSCharacterSet characterSetWithCharactersInString:
|
|
|
|
|
@"_$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (![self scanCharactersFromSet: _identifier intoString: &ident])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Missing identifier: %@",
|
|
|
|
|
[[self string] substringFromIndex: [self scanLocation]]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [NSExpression expressionForKeyPath: ident];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parseSimpleExpression
|
|
|
|
|
{
|
|
|
|
|
unsigned location;
|
2007-06-20 08:03:51 +00:00
|
|
|
|
double dbl;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
if ([self scanDouble: &dbl])
|
|
|
|
|
{
|
|
|
|
|
return [NSExpression expressionForConstantValue:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[NSNumber numberWithDouble: dbl]];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: handle integer, hex constants, 0x 0o 0b
|
|
|
|
|
if ([self scanString: @"-" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
return [NSExpression expressionForFunction: @"_chs"
|
2006-05-24 10:27:47 +00:00
|
|
|
|
arguments: [NSArray arrayWithObject: [self parseExpression]]];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-05-24 10:27:47 +00:00
|
|
|
|
if ([self scanString: @"(" intoString: NULL])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
NSExpression *arg = [self parseExpression];
|
|
|
|
|
|
|
|
|
|
if (![self scanString: @")" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Missing ) in expression"];
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"{" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *a = [NSMutableArray arrayWithCapacity: 10];
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"}" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// empty
|
2007-06-11 10:56:36 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue: a];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
// first element
|
|
|
|
|
[a addObject: [self parseExpression]];
|
|
|
|
|
while ([self scanString: @"," intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// more elements
|
|
|
|
|
[a addObject: [self parseExpression]];
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2006-05-24 10:27:47 +00:00
|
|
|
|
if (![self scanString: @"}" intoString: NULL])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Missing } in aggregate"];
|
|
|
|
|
}
|
2007-06-11 10:56:36 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue: a];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-06-20 08:03:51 +00:00
|
|
|
|
if ([self scanPredicateKeyword: @"NULL"]
|
|
|
|
|
|| [self scanPredicateKeyword: @"NIL"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue: [NSNull null]];
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2007-06-20 08:03:51 +00:00
|
|
|
|
if ([self scanPredicateKeyword: @"TRUE"]
|
|
|
|
|
|| [self scanPredicateKeyword: @"YES"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue:
|
2007-06-20 08:03:51 +00:00
|
|
|
|
[NSNumber numberWithBool: YES]];
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2007-06-20 08:03:51 +00:00
|
|
|
|
if ([self scanPredicateKeyword: @"FALSE"]
|
|
|
|
|
|| [self scanPredicateKeyword: @"NO"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue:
|
2007-06-20 08:03:51 +00:00
|
|
|
|
[NSNumber numberWithBool: NO]];
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
if ([self scanPredicateKeyword: @"SELF"])
|
2006-05-24 10:27:47 +00:00
|
|
|
|
{
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return [NSExpression expressionForEvaluatedObject];
|
2006-05-24 10:27:47 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
if ([self scanString: @"$" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
// variable
|
2013-01-22 08:31:40 +00:00
|
|
|
|
NSExpression *var = [self parseIdentifierExpression];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
if (![var keyPath])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Invalid variable identifier: %@", var];
|
|
|
|
|
}
|
|
|
|
|
return [NSExpression expressionForVariable: [var keyPath]];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-06-20 08:03:51 +00:00
|
|
|
|
location = [self scanLocation];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2007-06-20 08:03:51 +00:00
|
|
|
|
if ([self scanString: @"%" intoString: NULL])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2007-06-20 08:03:51 +00:00
|
|
|
|
if ([self isAtEnd] == NO)
|
|
|
|
|
{
|
|
|
|
|
unichar c = [[self string] characterAtIndex: [self scanLocation]];
|
|
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '%': // '%%' is treated as '%'
|
|
|
|
|
location = [self scanLocation];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'K':
|
|
|
|
|
[self setScanLocation: [self scanLocation] + 1];
|
|
|
|
|
return [NSExpression expressionForKeyPath:
|
2007-06-21 05:46:13 +00:00
|
|
|
|
[self nextArg]];
|
2007-06-20 08:03:51 +00:00
|
|
|
|
|
|
|
|
|
case '@':
|
|
|
|
|
case 'c':
|
|
|
|
|
case 'C':
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'D':
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'O':
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'U':
|
|
|
|
|
case 'x':
|
|
|
|
|
case 'X':
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'E':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 'g':
|
|
|
|
|
case 'G':
|
|
|
|
|
[self setScanLocation: [self scanLocation] + 1];
|
|
|
|
|
return [NSExpression expressionForConstantValue:
|
2007-06-21 05:46:13 +00:00
|
|
|
|
[self nextArg]];
|
2007-06-20 08:03:51 +00:00
|
|
|
|
|
|
|
|
|
case 'h':
|
2018-02-08 06:10:47 +00:00
|
|
|
|
(void)[self scanString: @"h" intoString: NULL];
|
2007-06-20 08:03:51 +00:00
|
|
|
|
if ([self isAtEnd] == NO)
|
|
|
|
|
{
|
|
|
|
|
c = [[self string] characterAtIndex: [self scanLocation]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
if (c == 'i' || c == 'u')
|
2007-06-20 08:03:51 +00:00
|
|
|
|
{
|
|
|
|
|
[self setScanLocation: [self scanLocation] + 1];
|
|
|
|
|
return [NSExpression expressionForConstantValue:
|
2007-06-21 05:46:13 +00:00
|
|
|
|
[self nextArg]];
|
2007-06-20 08:03:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'q':
|
2018-02-08 06:10:47 +00:00
|
|
|
|
(void)[self scanString: @"q" intoString: NULL];
|
2007-06-20 08:03:51 +00:00
|
|
|
|
if ([self isAtEnd] == NO)
|
|
|
|
|
{
|
|
|
|
|
c = [[self string] characterAtIndex: [self scanLocation]];
|
2007-06-21 05:46:13 +00:00
|
|
|
|
if (c == 'i' || c == 'u' || c == 'x' || c == 'X')
|
2007-06-20 08:03:51 +00:00
|
|
|
|
{
|
|
|
|
|
[self setScanLocation: [self scanLocation] + 1];
|
|
|
|
|
return [NSExpression expressionForConstantValue:
|
2007-06-21 05:46:13 +00:00
|
|
|
|
[self nextArg]];
|
2007-06-20 08:03:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[self setScanLocation: location];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"\"" intoString: NULL])
|
|
|
|
|
{
|
2008-10-31 23:43:44 +00:00
|
|
|
|
NSCharacterSet *skip = [self charactersToBeSkipped];
|
|
|
|
|
NSString *str = nil;
|
|
|
|
|
|
|
|
|
|
[self setCharactersToBeSkipped: nil];
|
|
|
|
|
if ([self scanUpToString: @"\"" intoString: &str] == NO)
|
|
|
|
|
{
|
|
|
|
|
[self setCharactersToBeSkipped: skip];
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Invalid double quoted literal at %u", location];
|
|
|
|
|
}
|
|
|
|
|
[self setCharactersToBeSkipped: skip];
|
2018-02-06 18:05:28 +00:00
|
|
|
|
if (NO == [self scanString: @"\"" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Unterminated double quoted literal at %u", location];
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue: str];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"'" intoString: NULL])
|
|
|
|
|
{
|
2008-10-31 23:43:44 +00:00
|
|
|
|
NSCharacterSet *skip = [self charactersToBeSkipped];
|
|
|
|
|
NSString *str = nil;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2008-10-31 23:43:44 +00:00
|
|
|
|
[self setCharactersToBeSkipped: nil];
|
|
|
|
|
if ([self scanUpToString: @"'" intoString: &str] == NO)
|
|
|
|
|
{
|
|
|
|
|
[self setCharactersToBeSkipped: skip];
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Invalid single quoted literal at %u", location];
|
|
|
|
|
}
|
|
|
|
|
[self setCharactersToBeSkipped: skip];
|
2018-02-06 18:05:28 +00:00
|
|
|
|
if (NO == [self scanString: @"'" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Unterminated single quoted literal at %u", location];
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue: str];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"@" intoString: NULL])
|
|
|
|
|
{
|
2013-01-22 08:31:40 +00:00
|
|
|
|
NSExpression *e = [self parseIdentifierExpression];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
if (![e keyPath])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Invalid keypath identifier: %@", e];
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
// prefix with keypath
|
|
|
|
|
return [NSExpression expressionForKeyPath:
|
2007-06-20 08:03:51 +00:00
|
|
|
|
[NSString stringWithFormat: @"@%@", [e keyPath]]];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-22 08:31:40 +00:00
|
|
|
|
return [self parseIdentifierExpression];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parseFunctionalExpression
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
NSExpression *left = [self parseSimpleExpression];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
|
|
|
|
while (YES)
|
|
|
|
|
{
|
|
|
|
|
if ([self scanString: @"(" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
// function - this parser allows for (max)(a, b, c) to be properly
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// recognized and even (%K)(a, b, c) if %K evaluates to "max"
|
|
|
|
|
NSMutableArray *args = [NSMutableArray arrayWithCapacity: 5];
|
|
|
|
|
|
|
|
|
|
if (![left keyPath])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Invalid function identifier: %@", left];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (![self scanString: @")" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
// any arguments
|
|
|
|
|
// first argument
|
|
|
|
|
[args addObject: [self parseExpression]];
|
|
|
|
|
while ([self scanString: @"," intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
// more arguments
|
|
|
|
|
[args addObject: [self parseExpression]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (![self scanString: @")" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Missing ) in function arguments"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
left = [NSExpression expressionForFunction: [left keyPath]
|
|
|
|
|
arguments: args];
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanString: @"[" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// index expression
|
|
|
|
|
if ([self scanPredicateKeyword: @"FIRST"])
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression expressionForFunction: @"_first"
|
2023-10-08 12:48:33 +00:00
|
|
|
|
arguments: [NSArray arrayWithObject: left]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else if ([self scanPredicateKeyword: @"LAST"])
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression expressionForFunction: @"_last"
|
2023-10-08 12:48:33 +00:00
|
|
|
|
arguments: [NSArray arrayWithObject: left]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else if ([self scanPredicateKeyword: @"SIZE"])
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression expressionForFunction: @"count"
|
2023-10-08 12:48:33 +00:00
|
|
|
|
arguments: [NSArray arrayWithObject: left]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression expressionForFunction: @"_index"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObjects: left,
|
|
|
|
|
[self parseExpression], nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
if (![self scanString: @"]" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Missing ] in index argument"];
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanString: @"." intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// keypath - this parser allows for (a).(b.c)
|
|
|
|
|
// to be properly recognized
|
|
|
|
|
// and even %K.((%K)) if the first %K evaluates to "a" and the
|
|
|
|
|
// second %K to "b.c"
|
|
|
|
|
NSExpression *right;
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
right = [self parseExpression];
|
|
|
|
|
|
2017-04-09 12:45:18 +00:00
|
|
|
|
if (evaluatedObjectExpression != left)
|
|
|
|
|
{
|
2022-02-12 13:06:23 +00:00
|
|
|
|
// if both are simple key expressions (identifiers)
|
|
|
|
|
if ([left keyPath] && [right keyPath])
|
|
|
|
|
{
|
|
|
|
|
// concatenate
|
|
|
|
|
left = [NSExpression expressionForKeyPath:
|
|
|
|
|
[NSString stringWithFormat: @"%@.%@",
|
|
|
|
|
[left keyPath], [right keyPath]]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression
|
|
|
|
|
expressionForKeyPathCompositionWithLeft: left
|
|
|
|
|
right: right];
|
|
|
|
|
}
|
2017-04-09 12:45:18 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression expressionForKeyPath: [right keyPath]];
|
|
|
|
|
}
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// done with suffixes
|
|
|
|
|
return left;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parsePowerExpression
|
|
|
|
|
{
|
|
|
|
|
NSExpression *left = [self parseFunctionalExpression];
|
|
|
|
|
|
2006-05-24 10:27:47 +00:00
|
|
|
|
while (YES)
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
NSExpression *right;
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"**" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
right = [self parseFunctionalExpression];
|
|
|
|
|
left = [NSExpression expressionForFunction: @"_pow"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObjects: left, right, nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return left;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parseMultiplicationExpression
|
|
|
|
|
{
|
|
|
|
|
NSExpression *left = [self parsePowerExpression];
|
|
|
|
|
|
|
|
|
|
while (YES)
|
|
|
|
|
{
|
|
|
|
|
NSExpression *right;
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"*" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
right = [self parsePowerExpression];
|
|
|
|
|
left = [NSExpression expressionForFunction: @"_mul"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObjects: left, right, nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanString: @"/" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
right = [self parsePowerExpression];
|
|
|
|
|
left = [NSExpression expressionForFunction: @"_div"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObjects: left, right, nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return left;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parseAdditionExpression
|
|
|
|
|
{
|
|
|
|
|
NSExpression *left = [self parseMultiplicationExpression];
|
|
|
|
|
|
2006-05-24 10:27:47 +00:00
|
|
|
|
while (YES)
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
|
|
|
|
NSExpression *right;
|
|
|
|
|
|
2006-05-24 10:27:47 +00:00
|
|
|
|
if ([self scanString: @"+" intoString: NULL])
|
2006-05-24 10:15:16 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
right = [self parseMultiplicationExpression];
|
2013-02-15 15:14:50 +00:00
|
|
|
|
left = [NSExpression expressionForFunction: @"_add"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObjects: left, right, nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else if ([self scanString: @"-" intoString: NULL])
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
right = [self parseMultiplicationExpression];
|
2013-02-15 15:14:50 +00:00
|
|
|
|
left = [NSExpression expressionForFunction: @"_sub"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObjects: left, right, nil]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return left;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parseBinaryExpression
|
|
|
|
|
{
|
|
|
|
|
NSExpression *left = [self parseAdditionExpression];
|
|
|
|
|
|
|
|
|
|
while (YES)
|
|
|
|
|
{
|
|
|
|
|
NSExpression *right;
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @":=" intoString: NULL]) // assignment
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// check left to be a variable?
|
|
|
|
|
right = [self parseAdditionExpression];
|
|
|
|
|
// FIXME
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
else
|
2007-05-23 13:11:55 +00:00
|
|
|
|
{
|
|
|
|
|
return left;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-09 13:19:35 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSBlockPredicate
|
|
|
|
|
|
|
|
|
|
- (instancetype) initWithBlock: (GSBlockPredicateBlock)block
|
|
|
|
|
{
|
|
|
|
|
if (nil == (self = [super init]))
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
_block = (GSBlockPredicateBlock)[(id)block retain];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (instancetype) predicateWithSubstitutionVariables:
|
|
|
|
|
(GS_GENERIC_CLASS(NSDictionary,NSString*,id)*)variables
|
|
|
|
|
{
|
|
|
|
|
return [[[GSBoundBlockPredicate alloc] initWithBlock: _block
|
|
|
|
|
bindings: variables] autorelease];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
substitutionVariables: (GS_GENERIC_CLASS(NSDictionary,
|
|
|
|
|
NSString*,id)*)variables
|
|
|
|
|
{
|
2021-11-17 13:35:49 +00:00
|
|
|
|
return CALL_NON_NULL_BLOCK(_block, object, variables);
|
2016-03-09 13:19:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
return [self evaluateWithObject: object
|
|
|
|
|
substitutionVariables: nil];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
[(id)_block release];
|
|
|
|
|
_block = NULL;
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) predicateFormat
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"BLOCKPREDICATE(%p)", (void*)_block];
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation GSBoundBlockPredicate
|
|
|
|
|
|
|
|
|
|
- (instancetype) initWithBlock: (GSBlockPredicateBlock)block
|
|
|
|
|
bindings: (GS_GENERIC_CLASS(NSDictionary,
|
|
|
|
|
NSString*,id)*)bindings
|
|
|
|
|
{
|
|
|
|
|
if (nil == (self = [super initWithBlock: block]))
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
ASSIGN(_bindings, bindings);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2006-05-24 10:15:16 +00:00
|
|
|
|
|
2016-03-09 13:19:35 +00:00
|
|
|
|
- (BOOL) evaluateWithObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
return [self evaluateWithObject: object
|
|
|
|
|
substitutionVariables: _bindings];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
DESTROY(_bindings);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|
2016-03-09 13:19:35 +00:00
|
|
|
|
|
|
|
|
|
#endif
|