Merge branch 'master' of git://github.com/280north/cappuccino

This commit is contained in:
Daniel Stolzenberg committed 2010-10-28 09:20:52 +02:00
commit 24fbecb2e6
26 files changed
+642 -1086

No files matched your search

+3 -3
View File
@@ -28,7 +28,7 @@
- (id)mutableArrayValueForKey:(id)aKey
{
return [[_CPKVCArray alloc] initWithKey:aKey forProxyObject:self];
return [[_CPKVCArray alloc] initWithKey:aKey forProxyObject:self];
}
- (id)mutableArrayValueForKeyPath:(id)aKeyPath
@@ -430,7 +430,7 @@ kvoOperators["avg"] = function avgOperator(self, _cmd, param)
{
var objects = [self valueForKeyPath:param],
length = [objects count],
index = length;
index = length,
average = 0.0;
if (!length)
@@ -525,7 +525,7 @@ kvoOperators["sum"] = function sumOperator(self, _cmd, param)
[super addObserver:observer forKeyPath:aKeyPath options:options context:context];
}
-(void)removeObserver:(id)observer forKeyPath:(CPString)aKeyPath
- (void)removeObserver:(id)observer forKeyPath:(CPString)aKeyPath
{
if ([isa instanceMethodForSelector:_cmd] === [CPArray instanceMethodForSelector:_cmd])
[CPException raise:CPInvalidArgumentException reason:"Unsupported method on CPArray"];
+22 -22
View File
@@ -405,7 +405,7 @@ CPEnumerationReverse = 1 << 1;
@param predicate The function to apply to elements of the array. The function receives two arguments:
object The element in the array.
index The index of the element in the array.
The predicate function should either return a Boolean value that indicates whether the object passed the test,
The predicate function should either return a Boolean value that indicates whether the object passed the test,
or nil to stop the search, which will return CPNotFound to the sender.
@return The index of the first matching object, or \c CPNotFound if there is no matching object.
*/
@@ -420,7 +420,7 @@ CPEnumerationReverse = 1 << 1;
object The element in the array.
index The index of the element in the array.
context The object passed to the receiver in the aContext parameter.
The predicate function should either return a Boolean value that indicates whether the object passed the test,
The predicate function should either return a Boolean value that indicates whether the object passed the test,
or nil to stop the search, which will return CPNotFound to the sender.
@param context An object that contains context information you want passed to the predicate function.
@return The index of the first matching object, or \c CPNotFound if there is no matching object.
@@ -432,29 +432,29 @@ CPEnumerationReverse = 1 << 1;
/*!
Returns the index of the first object in the receiver that passes a test in a given Javascript function.
@param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards
@param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards
or CPEnumerationReverse to search in reverse.
@param predicate The function to apply to elements of the array. The function receives two arguments:
object The element in the array.
index The index of the element in the array.
The predicate function should either return a Boolean value that indicates whether the object passed the test,
The predicate function should either return a Boolean value that indicates whether the object passed the test,
or nil to stop the search, which will return CPNotFound to the sender.
@return The index of the first matching object, or \c CPNotFound if there is no matching object.
*/
- (unsigned)indexOfObjectWithOptions:(CPEnumerationOptions)opts passingTest:(Function)predicate
{
return [self indexOfObjectWithOptions:opts passingTest:predicate context:undefined];
}
}
/*!
Returns the index of the first object in the receiver that passes a test in a given Javascript function.
@param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards
@param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards
or CPEnumerationReverse to search in reverse.
@param predicate The function to apply to elements of the array. The function receives two arguments:
object The element in the array.
index The index of the element in the array.
context The object passed to the receiver in the aContext parameter.
The predicate function should either return a Boolean value that indicates whether the object passed the test,
The predicate function should either return a Boolean value that indicates whether the object passed the test,
or nil to stop the search, which will return CPNotFound to the sender.
@param context An object that contains context information you want passed to the predicate function.
@return The index of the first matching object, or \c CPNotFound if there is no matching object.
@@ -463,9 +463,9 @@ CPEnumerationReverse = 1 << 1;
{
// We don't use an enumerator because they return nil to indicate end of enumeration,
// but nil may actually be the value we are looking for, so we have to loop over the array.
var start, stop, increment;
if (opts & CPEnumerationReverse)
{
start = [self count] - 1;
@@ -478,17 +478,17 @@ CPEnumerationReverse = 1 << 1;
stop = [self count];
increment = 1;
}
for (var i = start; i != stop; i += increment)
{
var result = predicate([self objectAtIndex:i], i, aContext);
if (typeof result === 'boolean' && result)
return i;
else if (typeof result === 'object' && result == nil)
return CPNotFound;
}
return CPNotFound;
}
@@ -615,7 +615,7 @@ CPEnumerationReverse = 1 << 1;
result = CPOrderedSame;
while (i < count)
if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
return result;
return result;
@@ -1071,7 +1071,7 @@ CPEnumerationReverse = 1 << 1;
result = CPOrderedSame;
while (i < count)
if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
return result;
return result;
@@ -1296,7 +1296,7 @@ CPEnumerationReverse = 1 << 1;
{
var h, i, j, k, l, m, n = [self count], o;
var A, B = [];
for (h = 1; h < n; h += h)
{
for (m = n - 1 - h; m >= 0; m -= h + h)
@@ -1304,10 +1304,10 @@ CPEnumerationReverse = 1 << 1;
l = m - h + 1;
if (l < 0)
l = 0;
for (i = 0, j = l; j <= m; i++, j++)
B[i] = self[j];
for (i = 0, k = l; k < j && j <= m + h; k++)
{
A = self[j];
@@ -1320,7 +1320,7 @@ CPEnumerationReverse = 1 << 1;
j++;
}
}
while (k < j)
self[k++] = B[i++];
}
@@ -1345,14 +1345,14 @@ var selectorCompare = function selectorCompare(object1, object2, selector)
// sort using sort descriptors
var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs, rhs, descriptors)
{
{
var result = CPOrderedSame,
i = 0,
i = 0,
n = [descriptors count];
while (i < n && result === CPOrderedSame)
result = [descriptors[i++] compareObject:lhs withObject:rhs];
return result;
}
+11 -11
View File
@@ -390,11 +390,11 @@
*/
- (BOOL)isEqualToAttributedString:(CPAttributedString)aString
{
if (!aString)
return NO;
if (!aString)
return NO;
if (_string != [aString string])
return NO;
if (_string != [aString string])
return NO;
var myRange = CPMakeRange(),
comparisonRange = CPMakeRange(),
@@ -424,13 +424,13 @@
*/
- (BOOL)isEqual:(id)anObject
{
if (anObject == self)
return YES;
if (anObject == self)
return YES;
if ([anObject isKindOfClass:[self class]])
return [self isEqualToAttributedString:anObject];
if ([anObject isKindOfClass:[self class]])
return [self isEqualToAttributedString:anObject];
return NO;
return NO;
}
//Extracting a Substring
@@ -530,8 +530,8 @@
endingIndex = startingIndex + 1;
while(endingIndex < _rangeEntries.length)
_rangeEntries[endingIndex++].range.location+=additionalLength;
while (endingIndex < _rangeEntries.length)
_rangeEntries[endingIndex++].range.location += additionalLength;
}
/*!
+32 -32
View File
@@ -128,17 +128,17 @@ var _builtInCharacterSets = {};
+ (id)_sharedCharacterSetWithName:(id)csname
{
var cs = _builtInCharacterSets[csname];
if(cs == nil)
if (cs == nil)
{
var i,
ranges = [CPArray array],
rangeArray = eval(csname);
for(i = 0; i < rangeArray.length; i+= 2)
for (i = 0; i < rangeArray.length; i+= 2)
{
var loc = rangeArray[i];
var length = rangeArray[i+1];
var range = CPMakeRange(loc,length);
var loc = rangeArray[i],
length = rangeArray[i + 1],
range = CPMakeRange(loc,length);
[ranges addObject:range];
}
cs = [[_CPRangeCharacterSet alloc] initWithRanges:ranges];
@@ -196,13 +196,13 @@ var _builtInCharacterSets = {};
- (BOOL)characterIsMember:(CPString)aCharacter
{
c = aCharacter.charCodeAt(0);
var enu = [_ranges objectEnumerator];
var range;
var enu = [_ranges objectEnumerator],
range;
while (range = [enu nextObject])
{
if (CPLocationInRange(c, range))
return !_inverted;
return !_inverted;
}
return _inverted;
@@ -226,10 +226,10 @@ var _builtInCharacterSets = {};
{
var i;
for(i = 0; i < aString.length; i++)
for (i = 0; i < aString.length; i++)
{
var code = aString.charCodeAt(i);
var range = CPMakeRange(code,1);
var code = aString.charCodeAt(i),
range = CPMakeRange(code,1);
[_ranges addObject:range];
}
@@ -262,7 +262,7 @@ var _builtInCharacterSets = {};
return set;
}
-(id)invertedSet
- (id)invertedSet
{
var set = [[_CPStringContentCharacterSet alloc] initWithString:_string];
[set invert];
@@ -294,7 +294,7 @@ var _builtInCharacterSets = {};
- (void)addCharactersInRange:(CPRange)aRange // Needs _inverted support
{
var i;
for(i = aRange.location; i < aRange.location + aRange.length; i++)
for (i = aRange.location; i < aRange.location + aRange.length; i++)
{
var s = String.fromCharCode(i);
@@ -307,7 +307,7 @@ var _builtInCharacterSets = {};
{
var i;
for(i = 0; i < aString.length; i++)
for (i = 0; i < aString.length; i++)
{
var s = aString.charAt(i);
@@ -330,34 +330,34 @@ _CPCharacterSetTrimAtEnd = 1 << 2;
and the set is [CPCharacterSet whitespaceCharacterSet]
the returned array would contain:
<pre> ["Baku", "baku", "to", "jest", "", "skład."] </pre>
Adjacent occurences of the separator characters produce empty strings in the result.
@author Arkadiusz Młynarczyk <arek@tupux.com>
Adjacent occurences of the separator characters produce empty strings in the result.
@author Arkadiusz Młynarczyk <arek@tupux.com>
@param A character set containing the characters to use to split the receiver. Must not be nil.
@return An CPArray object containing substrings from the receiver that have been divided by characters in separator.
*/
- (CPArray)componentsSeparatedByCharactersInSet:(CPCharacterSet)separator
{
if (!separator)
[CPException raise:CPInvalidArgumentException
if (!separator)
[CPException raise:CPInvalidArgumentException
reason:"componentsSeparatedByCharactersInSet: the separator can't be 'nil'"];
var components = [CPMutableArray array],
componentRange = CPMakeRange(0, 0);
var components = [CPMutableArray array],
componentRange = CPMakeRange(0, 0);
for (var i=0; i < self.length; i++)
{
if ([separator characterIsMember:self.charAt(i)])
{
componentRange.length = i - componentRange.location;
[components addObject:[self substringWithRange:componentRange]];
componentRange.location += componentRange.length + 1;
}
}
for (var i = 0; i < self.length; i++)
{
if ([separator characterIsMember:self.charAt(i)])
{
componentRange.length = i - componentRange.location;
[components addObject:[self substringWithRange:componentRange]];
componentRange.location += componentRange.length + 1;
}
}
componentRange.length = self.length - componentRange.location;
[components addObject:[self substringWithRange:componentRange]];
componentRange.length = self.length - componentRange.location;
[components addObject:[self substringWithRange:componentRange]];
return components;
return components;
}
// As per the Cocoa method.
+1 -1
View File
@@ -364,7 +364,7 @@
}
return matchingKeys;
}
}
/*!
Returns an enumerator that enumerates over all the dictionary's keys.
+33 -33
View File
@@ -23,13 +23,13 @@
/*!
@class CPFormatter
@ingroup foundation
@brief CPFormatter is an abstract class that declares an interface for objects that create, interpret,
and validate the textual representation of cell contents. The Foundation framework provides two
@brief CPFormatter is an abstract class that declares an interface for objects that create, interpret,
and validate the textual representation of cell contents. The Foundation framework provides two
concrete subclasses of CPFormatter to generate these objects: CPNumberFormatter and CPDateFormatter.
CPFormatter is intended for subclassing. A custom formatter can restrict the input and enhance the
display of data in novel ways. For example, you could have a custom formatter that ensures that serial
numbers entered by a user conform to predefined formats. Before you decide to create a custom formatter,
CPFormatter is intended for subclassing. A custom formatter can restrict the input and enhance the
display of data in novel ways. For example, you could have a custom formatter that ensures that serial
numbers entered by a user conform to predefined formats. Before you decide to create a custom formatter,
make sure that you cannot configure the public subclasses CPDateFormatter and CPNumberFormatter to satisfy your requirements.
*/
@@ -40,10 +40,10 @@
/*!
The default implementation of this method raises an exception.
When implementing a subclass, return the CPString object that textually represents
the view's object for display and if editingStringForObjectValue: is unimplemented for editing.
First test the passed-in object to see if it's of the correct class. If it isn't, return nil;
but if it is of the right class, return a properly formatted and, if necessary, localized string.
When implementing a subclass, return the CPString object that textually represents
the view's object for display and if editingStringForObjectValue: is unimplemented for editing.
First test the passed-in object to see if it's of the correct class. If it isn't, return nil;
but if it is of the right class, return a properly formatted and, if necessary, localized string.
(See the specification of the CPString class for formatting and localizing details.)
@param anObject The object for which a textual representation is returned
@@ -65,9 +65,9 @@
/*!
The default implementation of this method invokes stringForObjectValue:.
When implementing a subclass, override this method only when the string that users see and the string
that they edit are different. In your implementation, return an CPString object that is used for editing,
following the logic recommended for implementing stringForObjectValue:. As an example, you would implement
When implementing a subclass, override this method only when the string that users see and the string
that they edit are different. In your implementation, return an CPString object that is used for editing,
following the logic recommended for implementing stringForObjectValue:. As an example, you would implement
this method if you want the dollar signs in displayed strings removed for editing.
@param anObject the object for which to return an editing string
@@ -82,11 +82,11 @@
/*!
The default implementation of this method raises an exception.
When implementing a subclass, return by reference the object anObject after creating it from string.
Return YES if the conversion is successful. If you return NO, also return by indirection (in error)
a localized user-presentable CPString object that explains the reason why the conversion failed; the delegate
(if any) of the CPControl object managing the cell can then respond to the failure in
control:didFailToFormatString:errorDescription:. However, if error is nil, the sender is not interested in
When implementing a subclass, return by reference the object anObject after creating it from string.
Return YES if the conversion is successful. If you return NO, also return by indirection (in error)
a localized user-presentable CPString object that explains the reason why the conversion failed; the delegate
(if any) of the CPControl object managing the cell can then respond to the failure in
control:didFailToFormatString:errorDescription:. However, if error is nil, the sender is not interested in
the error description, and you should not attempt to assign one.
@param anObject if conversion is successful, upon return contains the object created from the string
@@ -104,18 +104,18 @@
/*!
Returns a Boolean value that indicates whether a partial string is valid.
This method is invoked each time the user presses a key while the cell has the keyboard focus it lets you verify and
This method is invoked each time the user presses a key while the cell has the keyboard focus it lets you verify and
edit the cell text as the user types it.
In a subclass implementation, evaluate partialString according to the context, edit the text if necessary, and return
by reference any edited string in newString. Return YES if partialString is acceptable and NO if partialString is unacceptable.
If you return NO and newString is nil, the cell displays partialString minus the last character typed. If you return NO, you can
also return by indirection an CPString object (in error) that explains the reason why the validation failed; the delegate (if any)
of the CPControl object managing the cell can then respond to the failure in control:didFailToValidatePartialString:errorDescription:.
In a subclass implementation, evaluate partialString according to the context, edit the text if necessary, and return
by reference any edited string in newString. Return YES if partialString is acceptable and NO if partialString is unacceptable.
If you return NO and newString is nil, the cell displays partialString minus the last character typed. If you return NO, you can
also return by indirection an CPString object (in error) that explains the reason why the validation failed; the delegate (if any)
of the CPControl object managing the cell can then respond to the failure in control:didFailToValidatePartialString:errorDescription:.
The selection range will always be set to the end of the text if replacement occurs.
This method is a compatibility method. If a subclass overrides this method and does not override
isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:, this method will be called as before
This method is a compatibility method. If a subclass overrides this method and does not override
isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:, this method will be called as before
(isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription: just calls this one by default).
@param aPartialString the text currently in the view.
@@ -130,20 +130,20 @@
}
/*!
This method should be implemented in subclasses that want to validate user changes to a string in a field, where the user changes are
not necessarily at the end of the string, and preserve the selection (or set a different one, such as selecting the erroneous part of
This method should be implemented in subclasses that want to validate user changes to a string in a field, where the user changes are
not necessarily at the end of the string, and preserve the selection (or set a different one, such as selecting the erroneous part of
the string the user has typed).
In a subclass implementation, evaluate partialString according to the context. Return YES if partialStringPtr is acceptable and NO if partialStringPtr
is unacceptable. Assign a new string to partialStringPtr and a new range to proposedSelRangePtr and return NO if you want to replace the string and
change the selection range. If you return NO, you can also return by indirection an CPString object (in error) that explains the reason why the
validation failed; the delegate (if any) of the CPControl object managing the cell can then respond to the failure in
In a subclass implementation, evaluate partialString according to the context. Return YES if partialStringPtr is acceptable and NO if partialStringPtr
is unacceptable. Assign a new string to partialStringPtr and a new range to proposedSelRangePtr and return NO if you want to replace the string and
change the selection range. If you return NO, you can also return by indirection an CPString object (in error) that explains the reason why the
validation failed; the delegate (if any) of the CPControl object managing the cell can then respond to the failure in
control:didFailToValidatePartialString:errorDescription:.
@param aPartialString The new string to validate.
@param aProposedSelectedRange The selection range that will be used if the string is accepted or replaced.
@param originalString The original string, before the proposed change.
@param originalSelectedRange The selection range over which the change is to take place.
@param originalSelectedRange The selection range over which the change is to take place.
@param error If non-nil, if validation fails contains an CPString object that descibes the problem.
@return YES if aPartialString is acceptable, otherwise NO.
@@ -161,7 +161,7 @@
- (void)encodeWithCoder:(CPCoder)aCoder
{
}
@end
+1 -1
View File
@@ -134,7 +134,7 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
{
var head = document.getElementsByTagName("head").item(0);
if(_scriptTag && _scriptTag.parentNode == head)
if (_scriptTag && _scriptTag.parentNode == head)
head.removeChild(_scriptTag);
CPJSONPConnectionCallbacks["callback" + [self UID]] = nil;
+15 -43
View File
@@ -4,7 +4,6 @@
@import "CPEnumerator.j"
@import "CPPredicate.j"
@import "CPExpression.j"
@import "CPExpression_operator.j"
/*!
A predicate to compare directly the left and right hand sides.
@@ -136,8 +135,8 @@ CPContainsPredicateOperatorType = 99;
*/
CPBetweenPredicateOperatorType = 100;
var CPComparisonPredicateModifier;
var CPPredicateOperatorType;
var CPComparisonPredicateModifier,
CPPredicateOperatorType;
/*!
@ingroup foundation
@@ -426,8 +425,8 @@ var CPPredicateOperatorType;
lhs = lhs.stripDiacritics();
rhs = rhs.stripDiacritics();
}
var commut = (_options & CPCaseInsensitivePredicateOption) ? "gi":"g";
var reg = new RegExp(rhs.escapeForRegExp(),commut);
var commut = (_options & CPCaseInsensitivePredicateOption) ? "gi":"g",
reg = new RegExp(rhs.escapeForRegExp(),commut);
return reg.test(lhs);
case CPBeginsWithPredicateOperatorType:
var range = CPMakeRange(0,[rhs length]);
@@ -441,43 +440,19 @@ var CPPredicateOperatorType;
if (_options & CPDiacriticInsensitivePredicateOption) string_compare_options |= CPDiacriticInsensitiveSearch;
return ([lhs compare:rhs options:string_compare_options range:range] == CPOrderedSame);
case CPInPredicateOperatorType:
// Handle special case where rhs is a collection and lhs an element of it.
if (![rhs isKindOfClass: [CPString class]])
{
if (![rhs respondsToSelector: @selector(objectEnumerator)])
[CPException raise:CPInvalidArgumentException reason:@"The right hand side for an IN operator must be a collection"];
var e = [rhs objectEnumerator],
value;
while (value = [e nextObject])
if ([value isEqual:lhs])
return YES;
return NO;
}
if (_options & CPCaseInsensitivePredicateOption)
string_compare_options |= CPCaseInsensitiveSearch;
if (_options & CPDiacriticInsensitivePredicateOption)
string_compare_options |= CPDiacriticInsensitiveSearch;
return ([rhs rangeOfString:lhs options:string_compare_options].location != CPNotFound);
case CPCustomSelectorPredicateOperatorType:
return [lhs performSelector:_customSelector withObject:rhs];
case CPInPredicateOperatorType:
var a = lhs; // swap
lhs = rhs;
rhs = a;
case CPContainsPredicateOperatorType:
if (![lhs isKindOfClass: [CPString class]])
if (![lhs isKindOfClass:[CPString class]])
{
if (![lhs respondsToSelector: @selector(objectEnumerator)])
[CPException raise:CPInvalidArgumentException reason:@"The left hand side for a CONTAINS operator must be a collection or a string"];
[CPException raise:CPInvalidArgumentException reason:@"The left/right hand side for a CONTAINS/IN operator must be a collection or a string"];
var e = [lhs objectEnumerator],
value;
while (value = [e nextObject])
if ([value isEqual:rhs])
return YES;
return NO;
return [lhs containsObject:rhs];
}
if (_options & CPCaseInsensitivePredicateOption)
@@ -487,13 +462,10 @@ var CPPredicateOperatorType;
return ([lhs rangeOfString:rhs options:string_compare_options].location != CPNotFound);
case CPBetweenPredicateOperatorType:
if ([lhs count] < 2)
if ([rhs count] < 2)
[CPException raise:CPInvalidArgumentException reason:@"The right hand side for a BETWEEN operator must contain 2 objects"];
var lower = [rhs objectAtIndex:0],
upper = [rhs objectAtIndex:1];
return ([lhs compare:lower] == CPOrderedDescending && [lhs compare:upper] == CPOrderedAscending);
return ([lhs compare:rhs[0]] == CPOrderedDescending && [lhs compare:rhs[1]] == CPOrderedAscending);
default:
return NO;
}
@@ -572,8 +544,8 @@ var CPPredicateOperatorType;
@end
var source = ['*','?','(',')','{','}','.','+','|','/','$','^'];
var dest = ['.*','.?','\\(','\\)','\\{','\\}','\\.','\\+','\\|','\\/','\\$','\\^'];
var source = ['*','?','(',')','{','}','.','+','|','/','$','^'],
dest = ['.*','.?','\\(','\\)','\\{','\\}','\\.','\\+','\\|','\\/','\\$','\\^'];
String.prototype.escapeForRegExp = function()
{
+1 -1
View File
@@ -126,7 +126,7 @@ var CPCompoundPredicateType;
i;
if (count == 0)
return @"TRUPREDICATE";
return @"TRUPREDICATE";
for (i = 0; i < count; i++)
{
+4 -6
View File
@@ -132,7 +132,7 @@ CPMinusSetExpressionType = 9;
*/
+ (CPExpression)expressionForUnionSet:(CPExpression)left with:(CPExpression)right
{
return [[CPExpression_unionset alloc] initWithLeft:left right:right];
return [[CPExpression_set alloc] initWithType:CPUnionSetExpressionType left:left right:right];
}
/*!
@@ -143,7 +143,7 @@ CPMinusSetExpressionType = 9;
*/
+ (CPExpression)expressionForIntersectSet:(CPExpression)left with:(CPExpression)right
{
return [[CPExpression_intersectset alloc] initWithLeft:left right:right];
return [[CPExpression_set alloc] initWithType:CPIntersectSetExpressionType left:left right:right];
}
/*!
@@ -154,7 +154,7 @@ CPMinusSetExpressionType = 9;
*/
+ (CPExpression)expressionForMinusSet:(CPExpression)left with:(CPExpression)right
{
return [[CPExpression_minusset alloc] initWithLeft:left right:right];
return [[CPExpression_set alloc] initWithType:CPMinusSetExpressionType left:left right:right];
}
// Creating an Expression for a Function
@@ -319,6 +319,4 @@ CPMinusSetExpressionType = 9;
@import "CPExpression_keypath.j"
@import "CPExpression_function.j"
@import "CPExpression_aggregate.j"
@import "CPExpression_unionset.j"
@import "CPExpression_intersectset.j"
@import "CPExpression_minusset.j"
@import "CPExpression_set.j"
+26 -41
View File
@@ -15,30 +15,14 @@
return self;
}
+ (CPExpression)expressionForAggregate:(CPArray)collection
{
return [[self alloc] initWithAggregate:collection];
}
- (id)initWithCoder:(CPCoder)coder
{
var aggregate = [coder decodeObjectForKey:@"CPExpressionAggregate"];
return [self initWithAggregate:aggregate];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_aggregate forKey:@"CPExpressionAggregate"]; // subexpressions must be CPCoding compliant.
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object collection] isEqual:[self collection]])
return NO;
return YES;
}
@@ -47,32 +31,16 @@
return _aggregate;
}
- (CPExpression)rightExpression
{
if ([_aggregate count] > 0)
return [_aggregate lastObject];
return nil;
}
- (CPExpression)leftExpression
{
if ([_aggregate count] > 0)
return [_aggregate objectAtIndex:0];
return nil;
}
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
{
var eval_array = [CPArray array],
collection = [_aggregate objectEnumerator],
exp;
while (exp = [collection nextObject])
{
var eval = [exp expressionValueWithObject:object context:context];
if (eval != nil)[eval_array addObject:eval];
[eval_array addObject:eval];
}
return eval_array;
@@ -81,14 +49,14 @@
- (CPString)description
{
var i,
count = [_aggregate count],
count = [_aggregate count],
result = "{";
for (i = 0; i < count; i++)
result = result + [CPString stringWithFormat:@"%s%s", [[_aggregate objectAtIndex:i] description], (i + 1 < count) ? @", " : @""];
result = result + "}";
return result;
}
@@ -97,7 +65,7 @@
var subst_array = [CPArray array],
count = [_aggregate count],
i;
for (i = 0; i < count; i++)
[subst_array addObject:[[_aggregate objectAtIndex:i] _expressionWithSubstitutionVariables:variables]];
@@ -105,3 +73,20 @@
}
@end
var CPCollectionKey = @"CPCollection";
@implementation CPExpression_aggregate (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
var collection = [coder decodeObjectForKey:CPCollectionKey];
return [self initWithAggregate:collection];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_aggregate forKey:CPCollectionKey];
}
@end
@@ -1,92 +0,0 @@
@import "CPExpression.j"
@import "CPExpression_variable.j"
@import <Foundation/CPString.j>
@implementation CPExpression_assignment: CPExpression
{
CPExpression_variable _assignmentVariable;
CPExpression _subexpression;
}
- (id)initWithAssignmentVariable:(CPString)variable expression:(CPExpression)expression
{
_assignmentVariable = [CPExpression expressionForVariable:variable];
_subexpression = expression;
return self;
}
- (id)initWithAssignmentExpression:(CPExpression)variableExpression expression:(CPExpression)expression
{
_assignmentVariable = variableExpression;
_subexpression = expression;
return self;
}
- (id)initWithCoder:(CPCoder)coder
{
var variable = [coder decodeObjectForKey:@"CPExpressionAssignmentVariable"];
var expression = [coder decodeObjectForKey:@"CPExpressionAssignmentExpression"];
return [self initWithAssignmentVariable:variable expression:expression];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_assignmentVariable forKey:@"CPExpressionAssignmentVariable"];
[coder encodeObject:_subexpression forKey:@"CPExpressionAssignmentExpression"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object subexpression] isEqual:[self subexpression]] || ![[object variable] isEqualToString:[self variable]])
return NO;
return YES;
}
- (CPExpression)assignmentVariable
{
return _assignmentVariable;
}
- (CPExpression)subexpression
{
return _subexpression;
}
- (CPString)variable
{
return [_assignmentVariable variable];
}
- (CPString)description
{
var pretty = [_expression description];
if ([_subexpression isKindOfClass:[CPExpression_operator class]])
pretty = [CPString stringWithFormat:@"(%@)", pretty];
return [CPString stringWithFormat:@"%@ := %@", [self variable], pretty];
}
- (id)expressionValueWithObject:(id)object context:(id)context
{
// UNIMPLEMENTED
return nil;
}
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
{
// UNIMPLEMENTED
return nil;
}
@end
+19 -15
View File
@@ -11,30 +11,18 @@
{
[super initWithExpressionType:CPConstantValueExpressionType];
_value = value;
return self;
}
- (id)initWithCoder:(CPCoder)coder
{
var value = [coder decodeObjectForKey:@"CPExpressionConstantValue"];
return [self initWithValue:value];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_value forKey:@"CPExpressionConstantValue"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object constantValue] isEqual:[self constantValue]])
return NO;
return YES;
}
@@ -63,3 +51,19 @@
@end
var CPConstantValueKey = @"CPConstantValue";
@implementation CPExpression_constant (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
var value = [coder decodeObjectForKey:CPConstantValueKey];
return [self initWithValue:value];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_value forKey:CPConstantValueKey];
}
@end
+123 -235
View File
@@ -12,59 +12,38 @@
int _argc;
}
- (id)initWithSelector:(SEL)aselector arguments:(CPArray)parameters
- (id)initWithSelector:(SEL)aSelector arguments:(CPArray)parameters
{
[super initWithExpressionType:CPFunctionExpressionType];
if (![self respondsToSelector:aselector])
[CPException raise: CPInvalidArgumentException reason:@"Unknown function implementation: " + aselector];
_selector = aselector;
_operand = nil;
_arguments = parameters;
_argc = [parameters count];
return self;
var target = [CPPredicateUtilities class];
if (![target respondsToSelector:aSelector])
[CPException raise:CPInvalidArgumentException reason:@"Unknown function implementation: " + aSelector];
var operand = [CPExpression expressionForConstantValue:target];
return [self initWithTarget:operand selector:aSelector arguments:parameters];
}
- (id)initWithTarget:(CPExpression)targetExpression selector:(SEL)aselector arguments:(CPArray)parameters
- (id)initWithTarget:(CPExpression)targetExpression selector:aSelector arguments:parameters
{
[super initWithExpressionType:CPFunctionExpressionType];
var target = [targetExpression expressionValueWithObject:object context:context];
if (![target respondsToSelector:aselector])
[CPException raise: CPInvalidArgumentException reason:@"Unknown function implementation: " + aselector];
_selector = aselector;
[super initWithExpressionType:CPFunctionExpressionType];
// Cocoa doc: "This method throws an exception immediately if the selector is unknown"
// but targetExpression's value (selector's target) may be resolved only at runtime.
_selector = aSelector;
_operand = targetExpression;
_arguments = parameters;
_argc = [parameters count];
return self;
}
- (id)initWithCoder:(CPCoder)coder
{
var selector = CPSelectorFromString([coder decodeObjectForKey:@"CPExpressionFunctionName"]);
var arguments = [coder decodeObjectForKey:@"CPExpressionFunctionArguments"];
return [self initWithSelector:selector arguments:arguments];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:[self _function] forKey:@"CPExpressionFunctionName"];
[coder encodeObject:_arguments forKey:@"CPExpressionArguments"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object _function] isEqualToString:[self _function]] || ![[object operand] isEqual:[self operand]] || ![[object arguments] isEqualToArray:[self arguments]])
return NO;
return YES;
}
@@ -90,284 +69,193 @@
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
{
var eval_args = [CPArray array],
var target = [_operand expressionValueWithObject:object context:context],
objj_args = [target, _selector],
i;
for (i = 0; i < _argc; i++)
{
var arg = [[_arguments objectAtIndex:i] expressionValueWithObject:object context:context];
if (arg != nil)
[eval_args addObject:arg];
var arg = [_arguments[i] expressionValueWithObject:object context:context];
objj_args.push(arg);
}
var target = (_operand == nil) ? self : [_operand expressionValueWithObject:object context:context];
return [target performSelector:_selector withObject:eval_args];
return objj_msgSend.apply(this, objj_args);
}
- (CPString)description
{
var result = [CPString stringWithFormat:@"%@ %s(", [_operand description], [self _function]],
i;
for (i = 0; i < _argc; i++)
result = result + [_arguments objectAtIndex:i] + (i+1<_argc) ? ", " : "";
{
var result = _operand + [self _function] + "(";
for (var i = 0; i < _argc; i++)
result = result + [_arguments[i] description] + ((i + 1 < _argc) ? ", " : "");
result = result + ")";
return result ;
}
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
{
var array = [CPArray array],
i;
for (i = 0; i < _argc; i++)
[array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]];
return [CPExpression expressionForFunction:[self operand] selectorName:[self _function] arguments:array];
}
- (CPNumber)sum:(CPArray)parameters
@end
var CPSelectorNameKey = @"CPSelectorName",
CPArgumentsKey = @"CPArguments",
CPOperandKey = @"CPOperand";
@implementation CPExpression_function (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
if (_argc < 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var i,
sum = 0.0;
for (i = 0; i < _argc; i++)
sum += [[parameters objectAtIndex:i] doubleValue];
return [CPNumber numberWithDouble: sum];
var target = [coder decodeObjectForKey:CPOperandKey],
selector = CPSelectorFromString([coder decodeObjectForKey:CPSelectorNameKey]),
arguments = [coder decodeObjectForKey:CPArgumentsKey];
return [self initWithTarget:target selector:selector arguments:arguments];
}
- (CPNumber)count:(CPArray)parameters
- (void)encodeWithCoder:(CPCoder)coder
{
if (_argc < 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
return [CPNumber numberWithUnsignedInt: [[parameters objectAtIndex:0] count]];
[coder encodeObject:[self _function] forKey:CPSelectorNameKey];
[coder encodeObject:_arguments forKey:CPArgumentsKey];
[coder encodeObject:_operand forKey:CPOperandKey];
}
- (CPNumber)min:(CPArray)parameters
@end
// Built-in functions
@implementation CPPredicateUtilities : CPObject
{
if (_argc < 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
return MIN([parameters objectAtIndex:0],[parameters objectAtIndex:1]);
}
- (CPNumber)max:(CPArray)parameters
+ (float)sum:(CPArray)parameters
{
if (_argc < 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
return MAX([parameters objectAtIndex:0],[parameters objectAtIndex:1]);
var sum = 0,
count = parameters.length;
while (count--)
sum += parameters[count];
return sum;
}
- (CPNumber)average:(CPArray)parameters
+ (float)count:(CPArray)parameters
{
if (_argc < 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var i,
sum = 0.0;
for (i = 0; i < _argc; i++)
sum += [[parameters objectAtIndex:i] doubleValue];
return [CPNumber numberWithDouble: sum / _argc];
return [parameters count];
}
- (CPNumber)add:to:(CPArray)parameters
+ (float)min:(CPArray)parameters
{
if (_argc != 2)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var left = [parameters objectAtIndex:0],
right = [parameters objectAtIndex:1];
return [CPNumber numberWithDouble: [left doubleValue] + [right doubleValue]];
return parameters.sort()[0];
}
- (CPNumber)from:subtract:(CPArray)parameters
+ (float)max:(CPArray)parameters
{
if (_argc != 2)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var left = [parameters objectAtIndex:0],
right = [parameters objectAtIndex:1];
return [CPNumber numberWithDouble: [left doubleValue] - [right doubleValue]];
return parameters.sort()[parameters.length - 1];
}
- (CPNumber)multiply:by:(CPArray)parameters
+ (float)average:(CPArray)parameters
{
if (_argc != 2)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var left = [parameters objectAtIndex:0],
right = [parameters objectAtIndex:1];
return [CPNumber numberWithDouble: [left doubleValue] * [right doubleValue]];
return [self sum:parameters] / parameters.length;
}
- (CPNumber)divide:by:(CPArray)parameters
+ (id)first:(CPArray)parameters
{
if (_argc != 2)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var left = [parameters objectAtIndex:0],
right = [parameters objectAtIndex:1];
return [CPNumber numberWithDouble: [left doubleValue] / [right doubleValue]];
return parameters[0];
}
- (CPNumber)sqrt:(CPArray)parameters
+ (id)last:(CPArray)parameters
{
if (_argc != 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var num = [[parameters objectAtIndex:0] doubleValue];
return [CPNumber numberWithDouble: SQRT(num)];
return parameters[parameters.length - 1];
}
- (CPNumber)raise:to:(CPArray)parameters
+ (id)fromObject:(id)object index:(id)anIndex
{
if (_argc < 2)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var num = [[parameters objectAtIndex:0] doubleValue],
power = [[parameters objectAtIndex:1] doubleValue];
return [CPNumber numberWithDouble: POW(num,power)];
if ([object isKindOfClass:[CPDictionary class]])
return [object objectForKey:anIndex];
else ([object isKindOfClass:[CPArray class]])
return [object objectAtIndex:anIndex];
[CPException raise:CPInvalidArgumentException reason:@"object[#] requires a CPDictionary or CPArray"];
}
- (CPNumber)abs:(CPArray)parameters
+ (float)add:(int)n to:(int)m
{
if (_argc != 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var num = [[parameters objectAtIndex:0] doubleValue];
return [CPNumber numberWithDouble:ABS(num)];
return n + m;
}
- (CPDate)now
+ (float)from:(int)n substract:(int)m
{
return n - m;
}
+ (float)multiply:(float)n by:(int)m
{
return n * m;
}
+ (float)divide:(float)n by:(float)m
{
return n / m;
}
+ (float)sqrt:(float)n
{
return SQRT(n);
}
+ (float)raise:(float)num to:(int)power
{
return POW(num, power);
}
+ (float)abs:(float)num
{
return ABS(num);
}
+ (CPDate)now
{
return [CPDate date];
}
- (CPNumber)ln:(CPArray)parameters
+ (float)ln:(float)num
{
if (_argc != 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var num = [[parameters objectAtIndex:0] doubleValue];
return [CPNumber numberWithDouble:Math.log(num)];
return LN10(num);
}
- (CPNumber)exp:(CPArray)parameters
+ (float)exp:(float)num
{
if (_argc != 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var num = [[parameters objectAtIndex:0] doubleValue];
return [CPNumber numberWithDouble:EXP(num)];
return EXP(num);
}
- (CPNumber)ceiling:(CPArray)parameters
+ (float)ceiling:(float)num
{
if (_argc != 1)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var num = [[parameters objectAtIndex:0] doubleValue];
return [CPNumber numberWithDouble:CEIL(num)];
return CEIL(num);
}
- (CPNumber)random
+ (int)random:(int)num
{
return [CPNumber numberWithDouble:RAND()];
return ROUND(RAND() * num);
}
- (CPNumber)modulus:by:(CPArray)parameters
+ (int)modulus:(int)n by:(int)n
{
if (_argc != 2)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var left = [parameters objectAtIndex:0],
right = [parameters objectAtIndex:1];
return [CPNumber numberWithInt:([left intValue] % [right intValue])];
return n % m;
}
- (id)first:(CPArray)parameters
+ (float)chs:(int)num
{
if (_argc == 0)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
return [[parameters objectAtIndex:0] objectAtIndex:0];
return -num;
}
- (id)last:(CPArray)parameters
{
if (_argc == 0)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
return [[parameters objectAtIndex:0] lastObject];
}
- (CPNumber)chs:(CPArray)parameters
{
if (_argc == 0)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
return [CPNumber numberWithInt: - [[parameters objectAtIndex:0] intValue]];
}
- (id)index:(CPArray)parameters
{
if (_argc < 2)
[CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"];
var left = [parameters objectAtIndex:0],
right = [parameters objectAtIndex:1];
if ([left isKindOfClass: [CPDictionary class]])
return [left objectForKey:right];
else
return [left objectAtIndex: [right intValue]];
}
/*
- (CPNumber)median:(CPArray)parameters
{
}
- (CPNumber)mode:(CPArray)parameters
{
}
- (CPNumber)stddev:(CPArray)parameters
{
}
- (CPNumber)log:(CPArray)parameters
{
}
- (CPNumber)raise:to:(CPArray)parameters
{
}
- (CPNumber)trunc:(CPArray)parameters
{
}
// These functions are used when parsing
*/
@end
@@ -1,86 +0,0 @@
@import "CPExpression.j"
@implementation CPExpression_intersectset : CPExpression
{
CPExpression _left;
CPExpression _right;
}
- (id)initWithLeft:(CPExpression)left right:(CPExpression)right
{
[super initWithExpressionType:CPIntersectSetExpressionType];
_left = left ;
_right = right;
return self;
}
- (id)initWithCoder:(CPCoder)coder
{
var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"];
var right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"];
return [self initWithLeft:left right:right];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_left forKey:@"CPExpressionUnionSetLeftExpression"];
[coder encodeObject:_right forKey:@"CPExpressionUnionSetRightExpression"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]])
return NO;
return YES;
}
- (id)expressionValueWithObject:object context:(CPDictionary)context
{
var right = [_right expressionValueWithObject:object context:context];
if (![right respondsToSelector: @selector(objectEnumerator)])
[CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"];
var left = [_left expressionValueWithObject:object context:context];
if (![left isKindOfClass:[CPSet set]])
[CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"];
var set = [CPSet setWithSet:left],
e = [right objectEnumerator],
item;
while (item = [e nextObject])
if ([left containsObject:item])
[set addObject:item];
return [CPExpression expressionForConstantValue:set];
}
- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables
{
return self;
}
- (CPExpression)leftExpression
{
return _left;
}
- (CPExpression)rightExpression
{
return _right;
}
- (CPString )description
{
return [_left description] +" INTERSECT "+ [_right description];
}
@end
+15 -37
View File
@@ -2,61 +2,39 @@
@import "CPExpression.j"
@import <Foundation/CPString.j>
@import <Foundation/CPKeyValueCoding.j>
@import "CPExpression_function.j"
@implementation CPExpression_keypath : CPExpression
@implementation CPExpression_keypath : CPExpression_function
{
CPString _keyPath;
}
- (id)initWithKeyPath:(CPString)keyPath
{
[super initWithExpressionType:CPKeyPathExpressionType];
_keyPath = keyPath ;
return [self initWithOperand:[CPExpression expressionForEvaluatedObject] andKeyPath:keyPath];
}
- (id)initWithOperand:(CPExpression)operand andKeyPath:(CPString)keyPath
{
var arg = [CPExpression expressionForConstantValue:keyPath];
// Cocoa: if it's a direct path selector is valueForKey:
self = [super initWithTarget:operand selector:@selector(valueForKeyPath:) arguments:[arg]];
return self;
}
- (id)initWithCoder:(CPCoder)coder
- (CPExpression)pathExpression
{
var keyPath = [coder decodeObjectForKey:@"CPExpressionKeyPath"];
return [self initWithKeyPath:keyPath];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_keyPath forKey:@"CPExpressionKeyPath"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object keyPath] isEqualToString:[self keyPath]])
return NO;
return YES;
return [[self arguments] objectAtIndex:0];
}
- (CPString)keyPath
{
return _keyPath;
}
- (id)expressionValueWithObject:object context:(CPDictionary)context
{
return [object valueForKeyPath:_keyPath];
}
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
{
return self;
return [[self pathExpression] constantValue];
}
- (CPString)description
{
return _keyPath;
return [self keyPath];
}
@end
@@ -1,81 +0,0 @@
@import "CPExpression.j"
@implementation CPExpression_minusset : CPExpression
- (id)initWithLeft:(CPExpression)left right:(CPExpression)right
{
[super initWithExpressionType:CPMinusSetExpressionType];
_left = left ;
_right = right;
return self;
}
- (id)initWithCoder:(CPCoder)coder
{
var left = [coder decodeObjectForKey:@"CPExpressionMinusSetLeftExpression"];
var right = [coder decodeObjectForKey:@"CPExpressionMinusSetRightExpression"];
return [self initWithLeft:left right:right];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_left forKey:@"CPExpressionMinusSetLeftExpression"];
[coder encodeObject:_right forKey:@"CPExpressionMinusSetRightExpression"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]])
return NO;
return YES;
}
- (id)expressionValueWithObject:object context:(CPDictionary)context
{
var right = [_right expressionValueWithObject:object context:context];
if (![right respondsToSelector: @selector(objectEnumerator)])
[CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"];
var left = [_left expressionValueWithObject:object context:context];
if (![left isKindOfClass:[CPSet set]])
[CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"];
var set = [CPSet setWithSet:left],
e = [right objectEnumerator],
item;
while (item = [e nextObject])
[set removeObject:item];
return [CPExpression expressionForConstantValue:set];
}
- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables
{
return self;
}
- (CPExpression)leftExpression
{
return _left;
}
- (CPExpression)rightExpression
{
return _right;
}
- (CPString )description
{
return [_left description] +" MINUS "+ [_right description];
}
@end
@@ -1,117 +0,0 @@
@import "CPExpression.j"
@import <Foundation/CPArray.j>
@import <Foundation/CPString.j>
@import <Foundation/CPDictionary.j>
var CPExpressionOperatorNegate = "CPExpressionOperatorNegate";
var CPExpressionOperatorAdd = "CPExpressionOperatorAdd";
var CPExpressionOperatorSubtract = "CPExpressionOperatorSubtract";
var CPExpressionOperatorMultiply = "CPExpressionOperatorMultiply";
var CPExpressionOperatorDivide = "CPExpressionOperatorDivide";
var CPExpressionOperatorExp = "CPExpressionOperatorExp";
var CPExpressionOperatorAssign = "CPExpressionOperatorAssign";
var CPExpressionOperatorKeypath = "CPExpressionOperatorKeypath";
var CPExpressionOperatorIndex = "CPExpressionOperatorIndex";
var CPExpressionOperatorIndexFirst = "CPExpressionOperatorIndexFirst";
var CPExpressionOperatorIndexLast = "CPExpressionOperatorIndexLast";
var CPExpressionOperatorIndexSize = "CPExpressionOperatorIndexSize";
@implementation CPExpression_operator : CPExpression
{
int _operator;
CPArray _arguments;
}
- (id)initWithOperator:(int)operator arguments:(CPArray)arguments
{
_operator = operator;
_arguments = arguments;
return self;
}
+ (CPExpression)expressionForOperator:(CPExpressionOperator)operator arguments:(CPArray)arguments
{
return [self initWithOperator:operator arguments:arguments];
}
- (CPArray)arguments
{
return _arguments;
}
- (CPString)description
{
var result = [CPString string],
args = [CPArray array],
count = [_arguments count],
i;
for (i = 0; i < count; i++)
{
var check = [_arguments objectAtIndex:i],
precedence = [check description];
if ([check isKindOfClass:[CPExpression_operator class]])
precedence = [CPString stringWithFormat:@"(%@)", precedence];
[args addObject:precedence];
}
switch (_operator)
{
case CPExpressionOperatorNegate :
result = result + [CPString stringWithFormat:@"-%@", [args objectAtIndex:0]];
break;
case CPExpressionOperatorAdd :
result = result + [CPString stringWithFormat:@"%@ + %@", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorSubtract :
result = result + [CPString stringWithFormat:@"%@ - %@", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorMultiply :
result = result + [CPString stringWithFormat:@"%@ * %@", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorDivide :
result = result + [CPString stringWithFormat:@"%@ / %@", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorExp :
result = result + [CPString stringWithFormat:@"%@ ** %@", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorAssign :
result = result + [CPString stringWithFormat:@"%@ := %@", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorKeypath :
result = result + [CPString stringWithFormat:@"%@.%@", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorIndex :
result = result + [CPString stringWithFormat:@"%@[%@]", [args objectAtIndex:0], [args objectAtIndex:1]];
break;
case CPExpressionOperatorIndexFirst :
result = result + [CPString stringWithFormat:@"%@[FIRST]", [args objectAtIndex:0]];
break;
case CPExpressionOperatorIndexLast :
result = result + [CPString stringWithFormat:@"%@[LAST]", [args objectAtIndex:0]];
break;
case CPExpressionOperatorIndexSize :
result = result + [CPString stringWithFormat:@"%@[SIZE]", [args objectAtIndex:0]];
break;
}
return result;
}
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
{
var array = [CPArray array],
count = [_arguments count],
i;
for (i = 0; i < count; i++)
[array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]];
return [CPExpression_operator expressionForOperator:_operator arguments:array];
}
@end
+12 -5
View File
@@ -4,13 +4,20 @@
@import <Foundation/CPDictionary.j>
@import <Foundation/CPCoder.j>
@implementation CPExpression_self : CPExpression{}
var defaultInstance = nil;
@implementation CPExpression_self : CPExpression
{
}
- (id)init
{
[super initWithExpressionType:CPEvaluatedObjectExpressionType];
if (defaultInstance == nil)
{
[super initWithExpressionType:CPEvaluatedObjectExpressionType];
defaultInstance = self;
}
return self;
return defaultInstance;
}
- (id)initWithCoder:(CPCoder)coder
@@ -24,10 +31,10 @@
- (BOOL)isEqual:(id)object
{
return (object == self);
return (object === self);
}
- (id)expressionValueWithObject:object context:(CPDictionary)context
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
{
return object;
}
+115
View File
@@ -0,0 +1,115 @@
@import "CPExpression.j"
@implementation CPExpression_set : CPExpression
{
CPExpression _left;
CPExpression _right;
}
- (id)initWithType:(int)type left:(CPExpression)left right:(CPExpression)right
{
[super initWithExpressionType:type];
_left = left;
_right = right;
return self;
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]])
return NO;
return YES;
}
- (id)expressionValueWithObject:object context:(CPDictionary)context
{
var right = [_right expressionValueWithObject:object context:context];
if ([right isKindOfClass:[CPArray class]]) // Or we could do [[right objectEnumerator] allObjects]
right = [CPSet setWithArray:right];
else if ([right isKindOfClass:[CPDictionary class]])
right = [CPSet setWithArray:[right allValues]];
else if (![right isKindOfClass:[CPSet class]])
[CPException raise:CPInvalidArgumentException reason:@"The right expression for a CP*SetExpressionType expression must evaluate to a CPArray, CPDictionary or CPSet"];
var left = [_left expressionValueWithObject:object context:context];
if (![left isKindOfClass:[CPSet class]])
[CPException raise:CPInvalidArgumentException reason:@"The left expression for a CP*SetExpressionType expression must evaluate to a CPSet"];
var result = [left copy];
switch (_type)
{
case CPIntersectSetExpressionType : [result intersectSet:right];
break;
case CPUnionSetExpressionType : [result unionSet:right];
break;
case CPMinusSetExpressionType : [result minusSet:right];
break;
default:
}
return [CPExpression expressionForConstantValue:result];
}
- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables
{
return self;
}
- (CPExpression)leftExpression
{
return _left;
}
- (CPExpression)rightExpression
{
return _right;
}
- (CPString)description
{
var desc;
switch (_type)
{
case CPIntersectSetExpressionType : desc = @" INTERSECT ";
break;
case CPUnionSetExpressionType : desc = @" UNION ";
break;
case CPMinusSetExpressionType : desc = @" MINUS ";
break;
default:
}
return [_left description] + desc + [_right description];
}
@end
var CPLeftExpressionKey = @"CPLeftExpression",
CPRightExpressionKey = @"CPRightExpression",
CPExpressionType = @"CPExpressionType";
@implementation CPExpression_set (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
var left = [coder decodeObjectForKey:CPLeftExpressionKey],
right = [coder decodeObjectForKey:CPRightExpressionKey],
type = [coder decodeIntForKey:CPExpressionType];
return [self initWithType:type left:left right:right];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_left forKey:CPLeftExpressionKey];
[coder encodeObject:_right forKey:CPRightExpressionKey];
[coder encodeInt:_type forKey:CPExpressionType];
}
@end
@@ -1,84 +0,0 @@
@import "CPExpression.j"
@implementation CPExpression_unionset : CPExpression
- (id)initWithLeft:(CPExpression)left right:(CPExpression)right
{
[super initWithExpressionType:CPUnionSetExpressionType];
_left = left;
_right = right;
return self;
}
- (id)initWithCoder:(CPCoder)coder
{
var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"],
right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"];
return [self initWithLeft:left right:right];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_left forKey:@"CPExpressionUnionSetLeftExpression"];
[coder encodeObject:_right forKey:@"CPExpressionUnionSetRightExpression"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
return YES;
if (object.isa != self.isa
|| [object expressionType] != [self expressionType]
|| ![[object leftExpression] isEqual:[self leftExpression]]
|| ![[object rightExpression] isEqual:[self rightExpression]])
return NO;
return YES;
}
- (id)expressionValueWithObject:object context:(CPDictionary )context
{
var right = [_right expressionValueWithObject:object context:context];
if (![right respondsToSelector: @selector(objectEnumerator)])
[CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"];
var left = [_left expressionValueWithObject:object context:context];
if (![left isKindOfClass:[CPSet set]])
[CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"];
var unionset = [CPSet setWithSet:left],
e = [right objectEnumerator],
item;
while (item = [e nextObject])
[unionset addObject:item];
return [CPExpression expressionForConstantValue:unionset];
}
- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables
{
return self;
}
- (CPExpression)leftExpression
{
return _left;
}
- (CPExpression)rightExpression
{
return _right;
}
- (CPString )description
{
return [_left description] +" UNION "+ [_right description];
}
@end
+16 -11
View File
@@ -16,17 +16,6 @@
return self;
}
- (id)initWithCoder:(CPCoder)coder
{
var variable = [coder decodeObjectForKey:@"CPExpressionVariable"];
return [self initWithVariable:variable];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_variable forKey:@"CPExpressionVariable"];
}
- (BOOL)isEqual:(id)object
{
if (self == object)
@@ -63,6 +52,22 @@
return self;
}
@end
var CPVariableKey = @"CPVariable";
@implementation CPExpression_variable (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
var variable = [coder decodeObjectForKey:CPVariableKey];
return [self initWithVariable:variable];
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_variable forKey:CPVariableKey];
}
@end
+63 -93
View File
@@ -37,7 +37,7 @@
@param … A comma-separated list of arguments to substitute into format.
@return A new predicate formed by creating a new string with format and parsing the result.
*/
+ (CPPredicate)predicateWithFormat:(CPString) format, ...
+ (CPPredicate)predicateWithFormat:(CPString)format, ...
{
if (!format)
[CPException raise:CPInvalidArgumentException reason:_cmd + " the format can't be 'nil'"];
@@ -238,7 +238,7 @@ function(newValue)\
unsigned _retrieved;
}
- (id) initWithString:(CPString)format args:(CPArray)args
- (id)initWithString:(CPString)format args:(CPArray)args
{
self = [super initWithString:format];
if (self != nil)
@@ -248,15 +248,15 @@ function(newValue)\
return self;
}
- (id) nextArg
- (id)nextArg
{
return [_args nextObject];
}
- (BOOL)scanPredicateKeyword:(CPString)key
{
var loc = [self scanLocation];
var c;
var loc = [self scanLocation],
c;
[self setCaseSensitive:NO];
if (![self scanString:key intoString:NULL])
@@ -274,7 +274,7 @@ function(newValue)\
return NO;
}
- (CPPredicate) parse
- (CPPredicate)parse
{
var r = nil;
@@ -296,12 +296,12 @@ function(newValue)\
return r;
}
- (CPPredicate) parsePredicate
- (CPPredicate)parsePredicate
{
return [self parseAnd];
}
- (CPPredicate) parseAnd
- (CPPredicate)parseAnd
{
var l = [self parseOr];
@@ -333,7 +333,7 @@ function(newValue)\
return l;
}
- (CPPredicate) parseNot
- (CPPredicate)parseNot
{
if ([self scanString:@"(" intoString:NULL])
{
@@ -361,7 +361,7 @@ function(newValue)\
return [self parseComparison];
}
- (CPPredicate) parseOr
- (CPPredicate)parseOr
{
var l = [self parseNot];
while ([self scanPredicateKeyword:@"OR"] || [self scanPredicateKeyword:@"||"])
@@ -392,7 +392,7 @@ function(newValue)\
return l;
}
- (CPPredicate) parseComparison
- (CPPredicate)parseComparison
{
var modifier = CPDirectPredicateModifier,
type = 0,
@@ -400,8 +400,7 @@ function(newValue)\
left,
right,
p,
negate = NO,
swap = NO;
negate = NO;
if ([self scanPredicateKeyword:@"ANY"])
{
@@ -469,36 +468,11 @@ function(newValue)\
}
else if ([self scanPredicateKeyword:@"CONTAINS"])
{
type = CPInPredicateOperatorType;
swap = YES;
type = CPContainsPredicateOperatorType;
}
else if ([self scanPredicateKeyword:@"BETWEEN"])
{
var exp = [self parseSimpleExpression],
a = [exp constantValue],
lower, upper,
lexp, uexp,
lp, up;
if (![a isKindOfClass:[CPArray class]])
[CPException raise:CPInvalidArgumentException reason:@"BETWEEN operator requires array argument"];
lower = [a objectAtIndex:0];
upper = [a objectAtIndex:1];
lexp = [CPExpression expressionForConstantValue:lower];
uexp = [CPExpression expressionForConstantValue:upper];
lp = [CPComparisonPredicate predicateWithLeftExpression:left
rightExpression:lexp
modifier:modifier
type:CPGreaterThanPredicateOperatorType
options:opts];
up = [CPComparisonPredicate predicateWithLeftExpression:left
rightExpression:uexp
modifier:modifier
type:CPLessThanPredicateOperatorType
options:opts];
return [CPCompoundPredicate andPredicateWithSubpredicates:
[CPArray arrayWithObjects:lp, up]];
type = CPBetweenPredicateOperatorType;
}
else
[CPException raise:CPInvalidArgumentException reason:@"Invalid comparison predicate: "+ [[self string] substringFromIndex: [self scanLocation]]];
@@ -518,14 +492,6 @@ function(newValue)\
right = [self parseExpression];
if (swap == YES)
{
var tmp = left;
left = right;
right = tmp;
}
p = [CPComparisonPredicate predicateWithLeftExpression:left
rightExpression:right
modifier:modifier
@@ -535,12 +501,12 @@ function(newValue)\
return negate ? [CPCompoundPredicate notPredicateWithSubpredicate:p]:p;
}
- (CPExpression) parseExpression
- (CPExpression)parseExpression
{
return [self parseBinaryExpression];
}
- (CPExpression) parseSimpleExpression
- (CPExpression)parseSimpleExpression
{
var identifier,
location,
@@ -548,11 +514,11 @@ function(newValue)\
dbl;
if ([self scanDouble:REFERENCE(dbl)])
return [CPExpression expressionForConstantValue:[CPNumber numberWithDouble:dbl]];
return [CPExpression expressionForConstantValue:dbl];
// FIXME: handle integer, hex constants, 0x 0o 0b
if ([self scanString:@"-" intoString:NULL])
return [CPExpression expressionForFunction:@"chs" arguments:[CPArray arrayWithObject:[self parseExpression]]];
return [CPExpression expressionForFunction:@"chs:" arguments:[CPArray arrayWithObject:[self parseExpression]]];
if ([self scanString:@"(" intoString:NULL])
{
@@ -578,7 +544,7 @@ function(newValue)\
if (![self scanString:@"}" intoString:NULL])
[CPException raise:CPInvalidArgumentException reason:@"Missing } in aggregate"];
return [CPExpression expressionForConstantValue:a];
return [CPExpression expressionForAggregate:a];
}
if ([self scanPredicateKeyword:@"NULL"] || [self scanPredicateKeyword:@"NIL"])
@@ -676,33 +642,36 @@ function(newValue)\
if ([self scanString:@"\"" intoString:NULL])
{
var skip = [self charactersToBeSkipped],
str;
str = @"";
[self setCharactersToBeSkipped:nil];
if ([self scanUpToString:@"\"" intoString:REFERENCE(str)] == NO)
[self scanUpToString:@"\"" intoString:REFERENCE(str)];
if ([self scanString:@"\"" intoString:NULL] == NO)
{
[self setCharactersToBeSkipped:skip];
[CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at "+location];
}
[self scanString:@"\"" intoString:NULL];
[self setCharactersToBeSkipped:skip];
return [CPExpression expressionForConstantValue:str];
}
if ([self scanString:@"'" intoString:NULL])
{
var skip = [self charactersToBeSkipped],
str;
str = @"";
[self setCharactersToBeSkipped:nil];
if ([self scanUpToString:@"'" intoString:REFERENCE(str)] == NO)
[self scanUpToString:@"'" intoString:REFERENCE(str)];
if ([self scanString:@"'" intoString:NULL] == NO)
{
[self setCharactersToBeSkipped:skip];
[CPException raise:CPInvalidArgumentException reason:@"Invalid single quoted literal at "+location];
[CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at " + location];
}
[self scanString:@"'" intoString:NULL];
[self setCharactersToBeSkipped:skip];
return [CPExpression expressionForConstantValue:str];
@@ -713,9 +682,9 @@ function(newValue)\
var e = [self parseExpression];
if (![e keyPath])
[CPException raise:CPInvalidArgumentException reason:@"Invalid keypath identifier: "+e];
[CPException raise:CPInvalidArgumentException reason:@"Invalid keypath identifier: " + e];
return [CPExpression expressionForKeyPath:[e keyPath]+"@"];
return [CPExpression expressionForKeyPath:[e keyPath] + "@"];
}
[self scanString:@"#" intoString:NULL];
@@ -759,28 +728,6 @@ function(newValue)\
}
left = [CPExpression expressionForFunction:[left keyPath] arguments:args];
}
else if ([self scanString:@"[" intoString:NULL])
{
// index expression
if ([self scanPredicateKeyword:@"FIRST"])
{
left = [CPExpression expressionForFunction:@"first" arguments:[CPArray arrayWithObject:[self parseExpression]]];
}
else if ([self scanPredicateKeyword:@"LAST"])
{
left = [CPExpression expressionForFunction:@"last" arguments:[CPArray arrayWithObject:[self parseExpression]]];
}
else if ([self scanPredicateKeyword:@"SIZE"])
{
left = [CPExpression expressionForFunction:@"count" arguments:[CPArray arrayWithObject:[self parseExpression]]];
}
else
{
left = [CPExpression expressionForFunction:@"index" arguments:[CPArray arrayWithObjects:left, [self parseExpression]]];
}
if (![self scanString:@"]" intoString:NULL])
[CPException raise:CPInvalidArgumentException reason:@"Missing ] in index argument"];
}
else if ([self scanString:@"." intoString:NULL])
{
// keypath - this parser allows for (a).(b.c)
@@ -791,12 +738,38 @@ function(newValue)\
if (![left keyPath])
[CPException raise:CPInvalidArgumentException reason:@"Invalid left keypath:" + left];
var right = [self parseExpression];
var right = [self parseSimpleExpression];
if (![right keyPath])
[CPException raise:CPInvalidArgumentException reason:@"Invalid right keypath:" + right];
// concatenate
left = [CPExpression expressionForKeyPath:[left keyPath]+ "." + [right keyPath]];
}
else if ([self scanString:@"[" intoString:NULL])
{
// index expression
if ([self scanPredicateKeyword:@"FIRST"])
{
left = [CPExpression expressionForFunction:@"first:" arguments:[CPArray arrayWithObject:left]];
}
else if ([self scanPredicateKeyword:@"LAST"])
{
left = [CPExpression expressionForFunction:@"last:" arguments:[CPArray arrayWithObject:left]];
}
else if ([self scanPredicateKeyword:@"SIZE"])
{
left = [CPExpression expressionForFunction:@"count:" arguments:[CPArray arrayWithObject:left]];
}
else
{
var integer;
if ([self scanInt:REFERENCE(integer)])
left = [CPExpression expressionForFunction:@"fromObject:index:" arguments:[CPArray arrayWithObjects:left, [CPExpression expressionForConstantValue:integer]]];
}
if (![self scanString:@"]" intoString:NULL])
[CPException raise:CPInvalidArgumentException reason:@"Missing ] in index argument"];
}
else
{
@@ -817,7 +790,7 @@ function(newValue)\
if ([self scanString:@"**" intoString:NULL])
{
right = [self parseFunctionalExpression];
left = [CPExpression expressionForFunction:@"pow" arguments:[CPArray arrayWithObjects:left, right]];
left = [CPExpression expressionForFunction:@"raise:to:" arguments:[CPArray arrayWithObjects:left, right]];
}
else
{
@@ -837,12 +810,12 @@ function(newValue)\
if ([self scanString:@"*" intoString:NULL])
{
right = [self parsePowerExpression];
left = [CPExpression expressionForFunction:@"_mul" arguments:[CPArray arrayWithObjects:left, right]];
left = [CPExpression expressionForFunction:@"multiply:by:" arguments:[CPArray arrayWithObjects:left, right]];
}
else if ([self scanString:@"/" intoString:NULL])
{
right = [self parsePowerExpression];
left = [CPExpression expressionForFunction:@"_div" arguments:[CPArray arrayWithObjects:left, right]];
left = [CPExpression expressionForFunction:@"divide:by:" arguments:[CPArray arrayWithObjects:left, right]];
}
else
{
@@ -862,12 +835,12 @@ function(newValue)\
if ([self scanString:@"+" intoString:NULL])
{
right = [self parseMultiplicationExpression];
left = [CPExpression expressionForFunction:@"_add" arguments:[CPArray arrayWithObjects:left, right]];
left = [CPExpression expressionForFunction:@"add:to:" arguments:[CPArray arrayWithObjects:left, right]];
}
else if ([self scanString:@"-" intoString:NULL])
{
right = [self parseMultiplicationExpression];
left = [CPExpression expressionForFunction:@"_sub" arguments:[CPArray arrayWithObjects:left, right]];
left = [CPExpression expressionForFunction:@"from:substract:" arguments:[CPArray arrayWithObjects:left, right]];
}
else
{
@@ -903,6 +876,3 @@ function(newValue)\
@import "CPComparisonPredicate.j"
@import "CPExpression.j"
@import "CPExpression_operator.j"
@import "CPExpression_aggregate.j"
@import "CPExpression_assignment.j"
+16 -11
View File
@@ -22,8 +22,8 @@
// sprintf:
var formatRegex = new RegExp("([^%]+|%[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cbBdieEfgGosuxXpn%@])", "g");
var tagRegex = new RegExp("(%)([\\+\\-\\ \\#0]*)([0-9\\*]*)((.[0-9\\*]+)?)([hlL]?)([cbBdieEfgGosuxXpn%@])");
var formatRegex = new RegExp("([^%]+|%(?:\\d+\\$)?[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cbBdieEfgGosuxXpn%@])", "g");
var tagRegex = new RegExp("(%)(?:(\\d+)\\$)?([\\+\\-\\ \\#0]*)([0-9\\*]*)((?:.[0-9\\*]+)?)([hlL]?)([cbBdieEfgGosuxXpn%@])");
exports.sprintf = function(format)
{
@@ -55,21 +55,27 @@ exports.sprintf = function(format)
}
var percentSign = subtokens[1],
flags = subtokens[2],
widthString = subtokens[3],
precisionString = subtokens[4],
argIndex = subtokens[2],
flags = subtokens[3],
widthString = subtokens[4],
precisionString = subtokens[5],
length = subtokens[6],
specifier = subtokens[7];
if (argIndex === undefined || argIndex === null || argIndex === "")
argIndex = arg++;
else
argIndex = Number(argIndex);
var width = null;
if (widthString == "*")
width = arguments[arg++];
width = arguments[argIndex];
else if (widthString != "")
width = Number(widthString);
var precision = null;
if (precisionString == ".*")
precision = arguments[arg++];
precision = arguments[argIndex];
else if (precisionString != "")
precision = Number(precisionString.substring(1));
@@ -80,7 +86,7 @@ exports.sprintf = function(format)
if (RegExp("[bBdiufeExXo]").test(specifier))
{
var num = Number(arguments[arg++]);
var num = Number(arguments[argIndex]);
var sign = "";
if (num < 0)
@@ -154,12 +160,11 @@ exports.sprintf = function(format)
if (specifier == "%")
subresult = "%";
else if (specifier == "c")
subresult = String(arguments[arg++]).charAt(0);
subresult = String(arguments[argIndex]).charAt(0);
else if (specifier == "s" || specifier == "@")
subresult = String(arguments[arg++]);
subresult = String(arguments[argIndex]);
else if (specifier == "p" || specifier == "n")
{
arg++;
subresult = "";
}
+84 -12
View File
@@ -14,7 +14,7 @@
objects;
dict = [[CPDictionary alloc] init];
[dict setObject: @"A Title" forKey:@"title"];
[dict setObject: @"Title" forKey:@"title"];
var keys = [CPArray arrayWithObjects:@"Name",@"Age",@"Children"];
objects = [CPArray arrayWithObjects:@"John",[CPNumber numberWithInt:34],[CPArray arrayWithObjects:@"Kid1", @"Kid2"]];
@@ -35,7 +35,8 @@
{
var expression_keypath = [CPExpression expressionForKeyPath:@"name"];
[self assertNotNull:expression_keypath message:"KeyPath Expression should not be nil"];
[self assertTrue:[expression_keypath keyPath] == @"name" message:"-keyPath should not be \"name\""];
var expression_str = [CPExpression expressionForConstantValue:@"j[a-z]an"];
[self assertNotNull:expression_str message:"ConstantValue Expression should not be nil"];
@@ -51,17 +52,20 @@
var expression_function = [CPExpression expressionForFunction:@"sum:" arguments:[CPArray arrayWithObjects:expression_num,expression_num]];
[self assertNotNull:expression_function message:"Function Expression should not be nil"];
var expression_self = [CPExpression expressionForEvaluatedObject];
[self assertNotNull:expression_self message:"Function Expression should not be nil"];
expression_function = [CPExpression expressionForFunction:expression_num selectorName:@"isEqual:" arguments:[CPArray arrayWithObjects:expression_num]];
[self assertNotNull:expression_function message:"Function Expression with target and selector should not be nil"];
var expression_aggregate = [CPExpression expressionForAggregate:[CPArray arrayWithObjects:expression_str,expression_num,expression_function]];
var expression_self = [CPExpression expressionForEvaluatedObject];
[self assertNotNull:expression_self message:"Self Expression should not be nil"];
var expression_aggregate = [CPExpression expressionForAggregate:[CPArray arrayWithObjects:expression_str,expression_num]];
[self assertNotNull:expression_aggregate message:"Aggregate Expression should not be nil"];
var expression_subquery = [CPExpression expressionForSubquery:expression_collection usingIteratorVariable:@"self" predicate:[CPPredicate predicateWithValue:YES]];
// [self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"];
var set = [CPSet setWithObjects:@"a",@"b",@"d"];
var array = [CPArray arrayWithObjects:@"a",@"b",@"d"];
var set = [CPExpression expressionForConstantValue:[CPSet setWithObjects:@"a",@"b",@"c"]];
var array = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d"]];
var expression_intersect = [CPExpression expressionForIntersectSet:set with:array];
[self assertNotNull:expression_intersect message:"IntersectSet Expression should not be nil"];
@@ -73,16 +77,40 @@
[self assertNotNull:expression_minusset message:"MinusSet Expression should not be nil"];
}
- (void)testFunctionExpression
- (void)testSetExpressionEvaluation
{
var function_exp = [CPExpression expressionForFunction:"sum:" arguments:[CPArray arrayWithObjects:[CPExpression expressionForConstantValue:1],[CPExpression expressionForConstantValue:2],[CPExpression expressionForConstantValue:3]]];
var left = [CPExpression expressionForConstantValue:[CPSet setWithObjects:@"a",@"b",@"c"]];
var right = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d"]];
var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:3] modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0];
var expression = [CPExpression expressionForIntersectSet:left with:right];
var eval = [[expression expressionValueWithObject:nil context:nil] constantValue];
[self assertTrue:[eval isEqualToSet:[CPSet setWithObjects:@"a",@"b"]] message:"Result should be {(a, b)}, is " + eval];
expression = [CPExpression expressionForUnionSet:left with:right];
eval = [[expression expressionValueWithObject:nil context:nil] constantValue];
[self assertTrue:[eval isEqualToSet:[CPSet setWithObjects:@"a",@"b",@"c",@"d"]] message:"Result should be {(a, b, c, d)}, is " + eval];
expression = [CPExpression expressionForMinusSet:left with:right];
eval = [[expression expressionValueWithObject:nil context:nil] constantValue];
[self assertTrue:[eval isEqualToSet:[CPSet setWithObjects:@"c"]] message:"Result should be {(c)}, is " + eval];
}
- (void)testFunctionExpressionEvaluation
{
var expression = [CPExpression expressionForConstantValue:[1,2,3]];
var function_exp = [CPExpression expressionForFunction:"sum:" arguments:[expression]];
var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:6] modifier:CPDirectPredicateModifier type:CPEqualToPredicateOperatorType options:0];
[self assertTrue:[pred evaluateWithObject:nil] message:[pred description] + " should be true"];
var operand = [CPExpression expressionForConstantValue:@"text"];
var arg = [CPExpression expressionForConstantValue:2];
function_exp = [CPExpression expressionForFunction:operand selectorName:@"substringFromIndex:" arguments:[arg]];
pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:@"xt"] modifier:CPDirectPredicateModifier type:CPEqualToPredicateOperatorType options:0];
[self assertTrue:[pred evaluateWithObject:nil] message:[pred description] + " should be true"];
}
- (void)testVariableExpression
- (void)testVariableExpressionEvaluation
{
var variable_exp = [CPExpression expressionForVariable:@"variable"];
var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:variable_exp modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0];
@@ -205,12 +233,56 @@
predicate = [CPPredicate predicateWithFormat: @"%f > %K", 40.5, @"Record1.Age"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
// TEST Aggregate
// TEST KeyPath
predicate = [CPPredicate predicateWithFormat: @"%@ IN %K", @"Kid1", @"Record1.Children"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat: @"%K CONTAINS %@", @"Record1.Children", @"Kid1"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat: @"ANY %K == %@", @"Record2.Children", @"Girl1"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
// Test Aggregate
predicate = [CPPredicate predicateWithFormat:@"{Record1 .Name, Record1.Age} = {'John',34}"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
// Test Symbolic token
predicate = [CPPredicate predicateWithFormat:@"Record1.Children[FIRST] = 'Kid1'"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat:@"Record1.Children[1] = 'Kid2'"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
// Test arithm
var n = 2;
predicate = [CPPredicate predicateWithFormat:@"SELF +1 = 3"];
[self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat:@"SELF- 1 = 1"];
[self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat:@"SELF / 2 = 1"];
[self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat:@"SELF / 2 = 1"];
[self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat:@"SELF* 2 = 4"];
[self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat:@"SELF** 3 = 8"];
[self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"];
// TEST Operator type
predicate = [CPPredicate predicateWithFormat: @"a CONTAINS[c] \"b\""];
[self assertTrue:([predicate predicateOperatorType] == CPContainsPredicateOperatorType) message:[predicate description] + " operator should be a CPContainsPredicateOperatorType"];
predicate = [CPPredicate predicateWithFormat: @"a BETWEEN {%f,%f}", 20, 40];
[self assertTrue:([predicate predicateOperatorType] == CPBetweenPredicateOperatorType) message:[predicate description] + " operator should be a CPBetweenPredicateOperatorType"];
predicate = [CPPredicate predicateWithFormat: @"a CONTAINS \"\""];
[self assertNotNull:predicate message:[predicate description] + " should not be nil"];
}
@end
+30 -13
View File
@@ -1,20 +1,37 @@
// TODO: add many many more of these...
var sprintfTestCases = [
[["[%@]", "hello world"], "[hello world]"],
[["[%d]", 123], "[123]"],
[["[%f]", 123.1234], "[123.1234]"],
[["[%d]", 123.1234], "[123]"]
];
var sprintf = ObjectiveJ.sprintf;
@implementation sprintfTest : OJTestCase
- (void)test_sprintf
// TODO: add many many more of these...
- (void)testObjectWithPrefixAndSuffix
{
for (var i = 0; i < sprintfTestCases.length; i++)
{
[self assert:ObjectiveJ.sprintf.apply(null, sprintfTestCases[i][0]) equals:sprintfTestCases[i][1]];
}
[self assert:@"[hello world]" equals:sprintf(@"[%@]", @"hello world")];
}
- (void)testDecimalWithPrefixAndSuffix
{
[self assert:@"[123]" equals:sprintf(@"[%d]", 123)];
}
- (void)testFloatWithPrefixAndSuffix
{
[self assert:@"[123.1234]" equals:sprintf(@"[%f]", 123.1234)];
}
- (void)testZeroPaddingWithWidthAndPercentEscaping
{
[self assert:@"099%" equals:sprintf(@"%03d%%", 99)];
}
- (void)testOutOfOrderExplicitFormatParameterIndexes
{
[self assert:@"2 > 1" equals:sprintf(@"%2$d > %1$d", 1, 2)];
}
- (void)testMixingImplicitAndExplicitFormatParameterIndexes
{
[self assert:@"a < b && b > a" equals:sprintf(@"%@ < %2$@ && %@ > %1$@", @"a", @"b")];
}
@end