68 var args = Array.prototype.slice.call(arguments, 3);
127 - (BOOL)evaluateWithObject:(
id)object
138 - (BOOL)evaluateWithObject:(
id)object substitutionVariables:(
CPDictionary)variables
165 - (id)initWithBool:(BOOL)value
173 if (
self === anObject)
176 if (
self.
isa !== anObject.isa || _value !== [anObject evaluateObject:nil])
182 - (BOOL)evaluateObject:(
id)object
189 return (_value) ?
@"TRUEPREDICATE" :
@"FALSEPREDICATE";
199 var count = [
self count],
203 for (; i < count; i++)
206 if ([predicate evaluateWithObject:
object])
215 var count = [
self count];
219 if (![predicate evaluateWithObject:[
self objectAtIndex:count]])
230 var count = [
self count],
234 for (; i < count; i++)
236 var
object = [
self objectAtIndex:i];
238 if ([predicate evaluateWithObject:
object])
239 [result addObject:object];
247 var count = [
self count];
251 var
object = [
self objectAtIndex:count];
253 if (![predicate evaluateWithObject:
object])
254 [
self removeObjectAtIndex:count];
260 #define REFERENCE(variable) \
263 var oldValue = variable;\
264 if (typeof newValue != 'undefined')\
265 variable = newValue;\
277 self = [
super initWithString:format]
288 return [_args nextObject];
291 - (BOOL)scanPredicateKeyword:(
CPString)key
293 var loc = [
self scanLocation];
295 [
self setCaseSensitive:NO];
296 if (![
self scanString:key intoString:NULL])
302 var c = [[
self string] characterAtIndex:[
self scanLocation]];
306 [
self setScanLocation:loc];
318 r = [
self parsePredicate];
322 CPLogConsole(
@"Unable to parse predicate '" + [
self string] +
"' with " + error);
328 var pstr = [
self string],
329 loc = [
self scanLocation];
330 CPLogConsole(
@"Format string contains extra characters: '" + [pstr substringToIndex:loc] +
"**" + [pstr substringFromIndex:loc] +
"**'");
339 return [
self parseAnd];
344 var l = [
self parseOr];
346 while ([
self scanPredicateKeyword:
@"AND"] || [
self scanPredicateKeyword:
@"&&"])
348 var r = [
self parseOr];
354 [[l subpredicates] addObjectsFromArray:[r subpredicates]];
358 [[r subpredicates] insertObject:l atIndex:0];
364 [[l subpredicates] addObject:r];
376 if ([
self scanString:
@"(" intoString:NULL])
378 var r = [
self parsePredicate];
380 if (![
self scanString:
@")" intoString:NULL])
381 CPRaiseParseError(
self,
@"predicate");
386 if ([
self scanPredicateKeyword:
@"NOT"] || [
self scanPredicateKeyword:
@"!"])
390 if ([
self scanPredicateKeyword:
@"TRUEPREDICATE"])
394 if ([
self scanPredicateKeyword:
@"FALSEPREDICATE"])
399 return [
self parseComparison];
404 var l = [
self parseNot];
405 while ([
self scanPredicateKeyword:
@"OR"] || [
self scanPredicateKeyword:
@"||"])
407 var r = [
self parseNot];
413 [[l subpredicates] addObjectsFromArray:[r subpredicates]];
417 [[r subpredicates] insertObject:l atIndex:0];
423 [[l subpredicates] addObject:r];
443 if ([
self scanPredicateKeyword:
@"ANY"])
447 else if ([
self scanPredicateKeyword:
@"ALL"])
451 else if ([
self scanPredicateKeyword:
@"NONE"])
456 else if ([
self scanPredicateKeyword:
@"SOME"])
462 left = [
self parseExpression];
463 if ([
self scanString:
@"!=" intoString:NULL] || [
self scanString:
@"<>" intoString:NULL])
467 else if ([
self scanString:
@"<=" intoString:NULL] || [
self scanString:
@"=<" intoString:NULL])
471 else if ([
self scanString:
@">=" intoString:NULL] || [
self scanString:
@"=>" intoString:NULL])
475 else if ([
self scanString:
@"<" intoString:NULL])
479 else if ([
self scanString:
@">" intoString:NULL])
483 else if ([
self scanString:
@"==" intoString:NULL] || [
self scanString:
@"=" intoString:NULL])
487 else if ([
self scanPredicateKeyword:
@"MATCHES"])
491 else if ([
self scanPredicateKeyword:
@"LIKE"])
495 else if ([
self scanPredicateKeyword:
@"BEGINSWITH"])
499 else if ([
self scanPredicateKeyword:
@"ENDSWITH"])
503 else if ([
self scanPredicateKeyword:
@"IN"])
507 else if ([
self scanPredicateKeyword:
@"CONTAINS"])
511 else if ([
self scanPredicateKeyword:
@"BETWEEN"])
516 CPRaiseParseError(
self,
@"comparison predicate");
518 if ([
self scanString:
@"[cd]" intoString:NULL])
522 else if ([
self scanString:
@"[c]" intoString:NULL])
526 else if ([
self scanString:
@"[d]" intoString:NULL])
531 right = [
self parseExpression];
544 return [
self parseBinaryExpression];
558 if ([
self scanString:
@"-" intoString:NULL])
561 if ([
self scanString:
@"(" intoString:NULL])
563 var arg = [
self parseExpression];
565 if (![
self scanString:
@")" intoString:NULL])
566 CPRaiseParseError(
self,
@"expression");
571 if ([
self scanString:
@"{" intoString:NULL])
573 if ([
self scanString:
@"}" intoString:NULL])
578 [a addObject:[
self parseExpression]];
580 while ([
self scanString:
@"," intoString:NULL])
581 [a addObject:[
self parseExpression]];
583 if (![
self scanString:
@"}" intoString:NULL])
584 CPRaiseParseError(
self,
@"expression");
589 if ([
self scanPredicateKeyword:
@"NULL"] || [
self scanPredicateKeyword:
@"NIL"])
593 if ([
self scanPredicateKeyword:
@"TRUE"] || [
self scanPredicateKeyword:
@"YES"])
597 if ([
self scanPredicateKeyword:
@"FALSE"] || [
self scanPredicateKeyword:
@"NO"])
601 if ([
self scanPredicateKeyword:
@"SELF"])
606 if ([
self scanString:
@"$" intoString:NULL])
608 var variable = [
self parseSimpleExpression];
610 if (![variable keyPath])
611 CPRaiseParseError(
self,
@"expression");
616 location = [
self scanLocation];
618 if ([
self scanString:
@"%" intoString:NULL])
620 if ([
self isAtEnd] == NO)
622 var c = [[
self string] characterAtIndex:[
self scanLocation]];
627 location = [
self scanLocation];
630 [
self setScanLocation:[
self scanLocation] + 1];
649 [
self setScanLocation:[
self scanLocation] + 1];
652 [
self scanString:@"h" intoString:NULL];
653 if ([
self isAtEnd] == NO)
655 c = [[
self string] characterAtIndex:[
self scanLocation]];
656 if (c ==
'i' || c ==
'u')
658 [
self setScanLocation:[
self scanLocation] + 1];
664 [
self scanString:@"q" intoString:NULL];
665 if ([
self isAtEnd] == NO)
667 c = [[
self string] characterAtIndex:[
self scanLocation]];
668 if (c ==
'i' || c ==
'u' || c ==
'x' || c ==
'X')
670 [
self setScanLocation:[
self scanLocation] + 1];
678 [
self setScanLocation:location];
681 if ([
self scanString:
@"\"" intoString:NULL])
683 var skip = [self charactersToBeSkipped],
686 [self setCharactersToBeSkipped:nil];
687 [self scanUpToString:@"\
"" intoString:
REFERENCE(str)];
689 if ([
self scanString:
@"\"" intoString:NULL] == NO)
690 CPRaiseParseError(self, @"expression
");
692 [self setCharactersToBeSkipped:skip];
694 return [CPExpression expressionForConstantValue:str];
697 if ([self scanString:@"'" intoString:NULL])
699 var skip = [self charactersToBeSkipped],
702 [self setCharactersToBeSkipped:nil];
703 [self scanUpToString:@"'" intoString:REFERENCE(str)];
705 if ([self scanString:@"'" intoString:NULL] == NO)
706 CPRaiseParseError(self, @"expression");
708 [self setCharactersToBeSkipped:skip];
710 return [CPExpression expressionForConstantValue:str];
713 if ([self scanString:@"@" intoString:NULL])
715 var e = [self parseExpression];
718 CPRaiseParseError(self, @"expression");
720 return [CPExpression expressionForKeyPath:[e keyPath] + "@"];
723 if ([self scanString:@"SUBQUERY" intoString:NULL])
725 if (![self scanString:@"(" intoString:NULL])
726 CPRaiseParseError(self, @"expression");
728 var collection = [self parseExpression],
732 if (![self scanString:@"," intoString:NULL])
733 CPRaiseParseError(self, @"expression");
734 variableExpression = [self parseExpression];
736 if (![self scanString:@"," intoString:NULL])
737 CPRaiseParseError(self, @"expression");
738 subpredicate = [self parsePredicate];
740 if (![self scanString:@")" intoString:NULL])
741 CPRaiseParseError(self, @"expression");
743 return [[_CPSubqueryExpression alloc] initWithExpression:collection usingIteratorExpression:variableExpression predicate:subpredicate];
746 if ([self scanString:@"FUNCTION" intoString:NULL])
748 if (![self scanString:@"(" intoString:NULL])
749 CPRaiseParseError(self, @"expression");
751 var args = [CPArray arrayWithObject:[self parseExpression]];
752 while ([self scanString:@"," intoString:NULL])
753 [args addObject:[self parseExpression]];
755 if (![self scanString:@")" intoString:NULL] || [args count] < 2 || [args[1] expressionType] != CPConstantValueExpressionType)
756 CPRaiseParseError(self, @"expression");
758 return [CPExpression expressionForFunction:args[0] selectorName:[args[1] constantValue] arguments:args.slice(2)];
761 [self scanString:@"#" intoString:NULL];
763 identifier = [CPCharacterSet characterSetWithCharactersInString:@"_$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"];
765 if (![self scanCharactersFromSet:identifier intoString:REFERENCE(ident)])
766 CPRaiseParseError(self, @"expression");
768 return [CPExpression expressionForKeyPath:ident];
771 - (CPExpression)parseFunctionalExpression
773 var left = [self parseSimpleExpression];
777 if ([self scanString:@"." intoString:NULL])
779 var right = [self parseSimpleExpression],
780 expressionType = [right expressionType];
782 if (expressionType == CPKeyPathExpressionType)
783 left = [[_CPKeyPathExpression alloc] initWithOperand:left andKeyPath:[right keyPath]];
784 else if (expressionType == CPVariableExpressionType)
785 left = [CPExpression expressionForFunction:left selectorName:@"valueForKey:" arguments:[right]];
787 CPRaiseParseError(self, @"expression");
789 else if ([self scanString:@"[" intoString:NULL])
792 if ([self scanPredicateKeyword:@"FIRST"])
794 left = [CPExpression expressionForFunction:@"first:" arguments:[CPArray arrayWithObject:left]];
796 else if ([self scanPredicateKeyword:@"LAST"])
798 left = [CPExpression expressionForFunction:@"last:" arguments:[CPArray arrayWithObject:left]];
800 else if ([self scanPredicateKeyword:@"SIZE"])
802 left = [CPExpression expressionForFunction:@"count:" arguments:[CPArray arrayWithObject:left]];
806 var index = [self parseExpression];
807 left = [CPExpression expressionForFunction:@"fromObject:index:" arguments:[CPArray arrayWithObjects:left, index]];
810 if (![self scanString:@"]" intoString:NULL])
811 CPRaiseParseError(self, @"expression");
813 else if ([self scanString:@":" intoString:NULL])
815 // function - this parser allows for (max)(a, b, c) to be properly
816 // recognized and even (%K)(a, b, c) if %K evaluates to "max"
819 CPRaiseParseError(self, @"expression");
821 var selector = [left keyPath] + @":",
824 if (![self scanString:@"(" intoString:NULL])
827 [self scanCharactersFromSet:[CPCharacterSet lowercaseLetterCharacterSet] intoString:REFERENCE(str)];
829 if (![self scanString:@":(" intoString:NULL])
830 CPRaiseParseError(self, @"expression");
832 selector += str + @":";
835 if (![self scanString:@")" intoString:NULL])
837 [args addObject:[self parseExpression]];
838 while ([self scanString:@"," intoString:NULL])
839 [args addObject:[self parseExpression]];
841 if (![self scanString:@")" intoString:NULL])
842 CPRaiseParseError(self, @"expression");
845 left = [CPExpression expressionForFunction:selector arguments:args];
847 else if ([self scanString:@"UNION" intoString:NULL])
849 left = [CPExpression expressionForUnionSet:left with:[self parseExpression]];
851 else if ([self scanString:@"INTERSECT" intoString:NULL])
853 left = [CPExpression expressionForIntersectSet:left with:[self parseExpression]];
855 else if ([self scanString:@"MINUS" intoString:NULL])
857 left = [CPExpression expressionForMinusSet:left with:[self parseExpression]];
861 // done with suffixes
867 - (CPExpression)parsePowerExpression
869 var left = [self parseFunctionalExpression];
875 if ([self scanString:@"**" intoString:NULL])
877 right = [self parseFunctionalExpression];
878 left = [CPExpression expressionForFunction:@"raise:to:" arguments:[CPArray arrayWithObjects:left, right]];
887 - (CPExpression)parseMultiplicationExpression
889 var left = [self parsePowerExpression];
895 if ([self scanString:@"*" intoString:NULL])
897 right = [self parsePowerExpression];
898 left = [CPExpression expressionForFunction:@"multiply:by:" arguments:[CPArray arrayWithObjects:left, right]];
900 else if ([self scanString:@"/" intoString:NULL])
902 right = [self parsePowerExpression];
903 left = [CPExpression expressionForFunction:@"divide:by:" arguments:[CPArray arrayWithObjects:left, right]];
912 - (CPExpression)parseAdditionExpression
914 var left = [self parseMultiplicationExpression];
920 if ([self scanString:@"+" intoString:NULL])
922 right = [self parseMultiplicationExpression];
923 left = [CPExpression expressionForFunction:@"add:to:" arguments:[CPArray arrayWithObjects:left, right]];
925 else if ([self scanString:@"-" intoString:NULL])
927 right = [self parseMultiplicationExpression];
928 left = [CPExpression expressionForFunction:@"from:substract:" arguments:[CPArray arrayWithObjects:left, right]];
937 - (CPExpression)parseBinaryExpression
939 var left = [self parseAdditionExpression];
945 if ([self scanString:@":=" intoString:NULL]) // assignment
947 // check left to be a variable?
948 right = [self parseAdditionExpression];
960 var CPRaiseParseError = function CPRaiseParseError(aScanner, target)
962 [CPException raise:CPInvalidArgumentException reason:@"unable to parse " + target + " at index " + [aScanner scanLocation]];