2006-05-09 14:21:26 +00:00
|
|
|
|
/* Interface for NSPredicate for GNUStep
|
|
|
|
|
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
|
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
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,
|
|
|
|
|
Boston, MA 02111 USA.
|
|
|
|
|
*/
|
|
|
|
|
|
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"
|
|
|
|
|
#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"
|
|
|
|
|
#import "GNUstepBase/NSObject+GNUstepBase.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>
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-10-04 08:21:34 +00:00
|
|
|
|
/* Object to represent the expression beign evaluated.
|
|
|
|
|
*/
|
|
|
|
|
static NSExpression *evaluatedObjectExpression = nil;
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
@interface GSFunctionExpression : NSExpression
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSString *_function;
|
|
|
|
|
NSArray *_args;
|
|
|
|
|
unsigned int _argc;
|
|
|
|
|
SEL _selector;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
va_arg(args, NSInteger)]];
|
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:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
va_arg(args, NSUInteger)]];
|
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]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
|
|
|
|
return [NSPredicate class];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder *) coder;
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
2006-05-09 14:21:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithCoder: (NSCoder *) coder;
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME
|
2006-05-09 14:21:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE([[GSAndCompoundPredicate alloc] initWithType: NSAndPredicateType
|
|
|
|
|
subpredicates: list]);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) notPredicateWithSubpredicate: (NSPredicate *)predicate
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return AUTORELEASE([[GSNotCompoundPredicate alloc]
|
|
|
|
|
initWithType: NSNotPredicateType
|
|
|
|
|
subpredicates: [NSArray arrayWithObject: predicate]]);
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSPredicate *) orPredicateWithSubpredicates: (NSArray *)list
|
|
|
|
|
{
|
2007-05-23 13:11:55 +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;
|
|
|
|
|
ASSIGN(_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];
|
|
|
|
|
unsigned int i;
|
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
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
return [[[self class] alloc] initWithType: _type subpredicates: esubs];
|
|
|
|
|
}
|
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
|
|
|
|
|
&& [[_subs objectAtIndex: 0]
|
|
|
|
|
isKindOfClass: [NSCompoundPredicate class]]
|
|
|
|
|
&& [(NSCompoundPredicate *)[_subs objectAtIndex: 0]
|
|
|
|
|
compoundPredicateType] == NSOrPredicateType)
|
|
|
|
|
{
|
|
|
|
|
// 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:
|
2007-05-23 13:11:55 +00:00
|
|
|
|
opt = @"[?options?]";
|
|
|
|
|
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
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
NSExpression *left = [_left _expressionWithSubstitutionVariables: variables];
|
|
|
|
|
NSExpression *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];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
2010-10-04 14:44:54 +00:00
|
|
|
|
if (leftResult == evaluatedObjectExpression)
|
|
|
|
|
{
|
|
|
|
|
leftResult = object;
|
|
|
|
|
}
|
|
|
|
|
if (rightResult == evaluatedObjectExpression)
|
|
|
|
|
{
|
|
|
|
|
rightResult = object;
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
/* One of the values is nil. The result is YES,
|
|
|
|
|
* if both are nil and equality is requested.
|
|
|
|
|
*/
|
|
|
|
|
return ((leftIsNil == rightIsNil)
|
|
|
|
|
&& ((_type == NSEqualToPredicateOperatorType)
|
|
|
|
|
|| (_type == NSLessThanOrEqualToPredicateOperatorType)
|
|
|
|
|
|| (_type == NSGreaterThanOrEqualToPredicateOperatorType)));
|
|
|
|
|
}
|
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
|
|
|
|
|
2010-11-18 09:46:51 +00:00
|
|
|
|
/* This is a very optimistic implementation,
|
|
|
|
|
* hoping that the values are of the right type.
|
|
|
|
|
*/
|
|
|
|
|
switch (_type)
|
|
|
|
|
{
|
|
|
|
|
case NSLessThanPredicateOperatorType:
|
|
|
|
|
return ([leftResult compare: rightResult] == NSOrderedAscending);
|
|
|
|
|
case NSLessThanOrEqualToPredicateOperatorType:
|
|
|
|
|
return ([leftResult compare: rightResult] != NSOrderedDescending);
|
|
|
|
|
case NSGreaterThanPredicateOperatorType:
|
|
|
|
|
return ([leftResult compare: rightResult] == NSOrderedDescending);
|
|
|
|
|
case NSGreaterThanOrEqualToPredicateOperatorType:
|
|
|
|
|
return ([leftResult compare: rightResult] != NSOrderedAscending);
|
|
|
|
|
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]
|
|
|
|
|
== NSOrderedSame;
|
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]
|
|
|
|
|
== NSOrderedSame;
|
2010-11-17 21:46:31 +00:00
|
|
|
|
#endif
|
2010-11-18 09:46:51 +00:00
|
|
|
|
case NSBeginsWithPredicateOperatorType:
|
|
|
|
|
{
|
|
|
|
|
NSRange range = NSMakeRange(0, [rightResult length]);
|
|
|
|
|
return ([leftResult compare: rightResult
|
|
|
|
|
options: compareOptions
|
|
|
|
|
range: range] == NSOrderedSame);
|
|
|
|
|
}
|
|
|
|
|
case NSEndsWithPredicateOperatorType:
|
|
|
|
|
{
|
|
|
|
|
NSRange range;
|
|
|
|
|
|
|
|
|
|
range = NSMakeRange([leftResult length] - [rightResult length],
|
|
|
|
|
[rightResult length]);
|
|
|
|
|
return ([leftResult compare: rightResult
|
|
|
|
|
options: compareOptions
|
|
|
|
|
range: range] == NSOrderedSame);
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
!= NSNotFound);
|
|
|
|
|
case NSCustomSelectorPredicateOperatorType:
|
|
|
|
|
{
|
|
|
|
|
BOOL (*function)(id,SEL,id) = (BOOL (*)(id,SEL,id))[leftResult methodForSelector: _selector];
|
|
|
|
|
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;
|
|
|
|
|
|
2010-10-04 14:44:54 +00:00
|
|
|
|
if (leftValue == evaluatedObjectExpression)
|
|
|
|
|
{
|
|
|
|
|
leftValue = object;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
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
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
e = [[GSFunctionExpression alloc] initWithExpressionType: NSFunctionExpressionType];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
s = [NSString stringWithFormat: @"_eval_%@: context: ", name];
|
|
|
|
|
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);
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (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;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
{
|
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
|
|
|
|
|
{
|
|
|
|
|
return _obj;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
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 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
|
|
|
|
|
|
|
|
|
|
@implementation GSFunctionExpression
|
|
|
|
|
|
|
|
|
|
- (NSArray *) arguments
|
|
|
|
|
{
|
|
|
|
|
return _args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// FIXME: here we should recognize binary and unary operators
|
2006-05-09 14:21:26 +00:00
|
|
|
|
// and convert back to standard format
|
|
|
|
|
// and add parentheses if required
|
|
|
|
|
return [NSString stringWithFormat: @"%@(%@)",
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (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
|
2007-05-23 13:11:55 +00:00
|
|
|
|
withObject: eargs];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (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
|
|
|
|
}
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
unsigned int i;
|
|
|
|
|
double sum = 0.0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < _argc; i++)
|
|
|
|
|
{
|
|
|
|
|
sum += [[expressions objectAtIndex: i] doubleValue];
|
|
|
|
|
}
|
|
|
|
|
return [NSNumber numberWithDouble: sum / _argc];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval_sum: (NSArray *)expressions
|
2006-05-09 14:21:26 +00:00
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
unsigned int i;
|
|
|
|
|
double sum = 0.0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < _argc; i++)
|
|
|
|
|
{
|
|
|
|
|
sum += [[expressions objectAtIndex: i] doubleValue];
|
|
|
|
|
}
|
|
|
|
|
return [NSNumber numberWithDouble: sum];
|
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
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
unsigned int i;
|
|
|
|
|
double min = 0.0;
|
|
|
|
|
double cur;
|
|
|
|
|
|
|
|
|
|
if (_argc > 0)
|
|
|
|
|
{
|
|
|
|
|
min = [[expressions objectAtIndex: 0] doubleValue];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < _argc; i++)
|
|
|
|
|
{
|
|
|
|
|
cur = [[expressions objectAtIndex: i] doubleValue];
|
|
|
|
|
if (min > cur)
|
|
|
|
|
{
|
|
|
|
|
min = cur;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return [NSNumber numberWithDouble: min];
|
2006-05-09 14:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-23 13:11:55 +00:00
|
|
|
|
- (id) _eval_max: (NSArray *)expressions
|
|
|
|
|
{
|
|
|
|
|
unsigned int i;
|
|
|
|
|
double max = 0.0;
|
|
|
|
|
double cur;
|
|
|
|
|
|
|
|
|
|
if (_argc > 0)
|
|
|
|
|
{
|
|
|
|
|
max = [[expressions objectAtIndex: 0] doubleValue];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < _argc; i++)
|
|
|
|
|
{
|
|
|
|
|
cur = [[expressions objectAtIndex: i] doubleValue];
|
|
|
|
|
if (max < cur)
|
|
|
|
|
{
|
|
|
|
|
max = cur;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return [NSNumber numberWithDouble: max];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2007-04-15 09:50:48 +00:00
|
|
|
|
return [result makeImmutableCopyOnFail: NO];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return [result makeImmutableCopyOnFail: NO];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// merge
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
[(NSMutableArray *)[(NSCompoundPredicate *)l subpredicates]
|
2007-06-20 08:03:51 +00:00
|
|
|
|
addObjectsFromArray: [(NSCompoundPredicate *)r subpredicates]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[(NSMutableArray *)[(NSCompoundPredicate *)r subpredicates]
|
2007-06-20 08:03:51 +00:00
|
|
|
|
insertObject: l atIndex: 0];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
l = r;
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
// add to l
|
|
|
|
|
[(NSMutableArray *)[(NSCompoundPredicate *)l subpredicates]
|
2007-06-20 08:03:51 +00:00
|
|
|
|
addObject: r];
|
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
|
|
|
|
{
|
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
|
|
|
|
{
|
|
|
|
|
[(NSMutableArray *)[(NSCompoundPredicate *)l subpredicates]
|
2007-06-20 04:36:31 +00:00
|
|
|
|
addObjectsFromArray: [(NSCompoundPredicate *)r subpredicates]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[(NSMutableArray *)[(NSCompoundPredicate *)r subpredicates]
|
2007-06-20 04:36:31 +00:00
|
|
|
|
insertObject: l atIndex: 0];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
l = r;
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
[(NSMutableArray *) [(NSCompoundPredicate *) l subpredicates]
|
2007-06-20 04:36:31 +00:00
|
|
|
|
addObject:r];
|
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
|
|
|
|
|
type: NSGreaterThanPredicateOperatorType
|
|
|
|
|
options: opts];
|
|
|
|
|
up = [NSComparisonPredicate predicateWithLeftExpression: left
|
|
|
|
|
rightExpression: uexp
|
|
|
|
|
modifier: modifier
|
|
|
|
|
type: NSLessThanPredicateOperatorType
|
|
|
|
|
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 parseAdditionExpression];
|
|
|
|
|
return [self parseBinaryExpression];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSExpression *) parseSimpleExpression
|
|
|
|
|
{
|
2007-06-20 08:03:51 +00:00
|
|
|
|
static NSCharacterSet *_identifier;
|
|
|
|
|
unsigned location;
|
|
|
|
|
NSString *ident;
|
|
|
|
|
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
|
|
|
|
|
NSExpression *var = [self parseExpression];
|
|
|
|
|
|
|
|
|
|
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':
|
|
|
|
|
[self scanString: @"h" intoString: NULL];
|
|
|
|
|
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':
|
|
|
|
|
[self scanString: @"q" intoString: NULL];
|
|
|
|
|
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];
|
|
|
|
|
[self scanString: @"\"" intoString: NULL];
|
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];
|
|
|
|
|
[self scanString: @"'" intoString: NULL];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
return [NSExpression expressionForConstantValue: str];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([self scanString: @"@" intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
NSExpression *e = [self parseExpression];
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// skip # as prefix (reserved words)
|
|
|
|
|
[self scanString: @"#" intoString: NULL];
|
|
|
|
|
if (!_identifier)
|
|
|
|
|
{
|
2007-05-23 13:11:55 +00:00
|
|
|
|
ASSIGN(_identifier, [NSCharacterSet characterSetWithCharactersInString:
|
|
|
|
|
@"_$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"]);
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (![self scanCharactersFromSet: _identifier intoString: &ident])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2007-05-23 13:11:55 +00:00
|
|
|
|
format: @"Missing identifier: %@",
|
|
|
|
|
[[self string] substringFromIndex: [self scanLocation]]];
|
2006-05-24 10:15:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [NSExpression expressionForKeyPath: ident];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (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"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObject: [self parseExpression]]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else if ([self scanPredicateKeyword: @"LAST"])
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression expressionForFunction: @"_last"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObject: [self parseExpression]]];
|
2007-05-23 13:11:55 +00:00
|
|
|
|
}
|
|
|
|
|
else if ([self scanPredicateKeyword: @"SIZE"])
|
|
|
|
|
{
|
|
|
|
|
left = [NSExpression expressionForFunction: @"count"
|
2007-06-20 08:03:51 +00:00
|
|
|
|
arguments: [NSArray arrayWithObject: [self parseExpression]]];
|
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
|
|
|
|
if (![left keyPath])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Invalid left keypath: %@", left];
|
|
|
|
|
}
|
|
|
|
|
right = [self parseExpression];
|
|
|
|
|
if (![right keyPath])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Invalid right keypath: %@", left];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// concatenate
|
|
|
|
|
left = [NSExpression expressionForKeyPath:
|
|
|
|
|
[NSString stringWithFormat: @"%@.%@",
|
|
|
|
|
[left keyPath], [right keyPath]]];
|
|
|
|
|
}
|
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];
|
|
|
|
|
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];
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-09 14:21:26 +00:00
|
|
|
|
@end
|