![]() |
API 0.9.5
|
00001 /* 00002 * CPExpression_function.j 00003 * 00004 * Created by cacaodev. 00005 * Copyright 2010. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 00023 @implementation CPExpression_function : CPExpression 00024 { 00025 CPExpression _operand; 00026 SEL _selector; 00027 CPArray _arguments; 00028 int _argc; 00029 int _maxargs; 00030 } 00031 00032 - (id)initWithSelector:(SEL)aSelector arguments:(CPArray)parameters 00033 { 00034 var target = [CPPredicateUtilities class]; 00035 if (![target respondsToSelector:aSelector]) 00036 [CPException raise:CPInvalidArgumentException reason:@"Unknown function implementation: " + aSelector]; 00037 00038 var operand = [CPExpression expressionForConstantValue:target]; 00039 return [self initWithTarget:operand selector:aSelector arguments:parameters]; 00040 } 00041 00042 - (id)initWithTarget:(CPExpression)operand selector:(SEL)aSelector arguments:(CPArray)parameters 00043 { 00044 return [self initWithTarget:operand selector:aSelector arguments:parameters type:CPFunctionExpressionType]; 00045 } 00046 00047 - (id)initWithTarget:(CPExpression)operand selector:(SEL)aSelector arguments:(CPArray)parameters type:(int)type 00048 { 00049 self = [super initWithExpressionType:type]; 00050 00051 if (self) 00052 { 00053 // Cocoa doc: "This method throws an exception immediately if the selector is unknown" 00054 // but operand's value (the target) may be resolved only at runtime. 00055 _selector = aSelector; 00056 _operand = operand; 00057 _arguments = parameters; 00058 _argc = [parameters count]; 00059 _maxargs = [[CPStringFromSelector(_selector) componentsSeparatedByString:@":"] count] - 1; 00060 } 00061 return self; 00062 } 00063 00064 - (BOOL)isEqual:(id)object 00065 { 00066 if (self == object) 00067 return YES; 00068 00069 if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object _function] isEqualToString:[self _function]] || ![[object operand] isEqual:[self operand]] || ![[object arguments] isEqualToArray:[self arguments]]) 00070 return NO; 00071 00072 return YES; 00073 } 00074 00075 - (CPString)_function // OBJJ preprocessor does not like function as a method 00076 { 00077 return CPStringFromSelector(_selector); 00078 } 00079 00080 - (CPString)function 00081 { 00082 return [self _function]; 00083 } 00084 00085 - (CPArray)arguments 00086 { 00087 return _arguments; 00088 } 00089 00090 - (CPExpression)operand 00091 { 00092 return _operand; 00093 } 00094 00095 - (id)expressionValueWithObject:(id)object context:(CPDictionary)context 00096 { 00097 var target = [_operand expressionValueWithObject:object context:context], 00098 objj_args = [target, _selector], 00099 i = 0; 00100 00101 for (; i < _argc; i++) 00102 { 00103 var arg = [_arguments[i] expressionValueWithObject:object context:context]; 00104 objj_args.push(arg); 00105 } 00106 00107 // If we have too much arguments, concatenate remaining args on the last one. 00108 if (_argc > _maxargs) 00109 { 00110 var r = MAX(_maxargs + 1, 2); 00111 objj_args = objj_args.slice(0, r).concat([objj_args.slice(r)]); 00112 } 00113 00114 return objj_msgSend.apply(this, objj_args); 00115 } 00116 00117 - (CPString)description 00118 { 00119 var result = ""; 00120 if ([_operand isEqual:[CPExpression expressionForConstantValue:[CPPredicateUtilities class]]]) 00121 result += CPStringFromSelector(_selector) + "("; 00122 else 00123 { 00124 result += "FUNCTION("; 00125 result += _operand ? [_operand description] + ", ":""; 00126 result += _selector ? CPStringFromSelector(_selector) + ", ":""; 00127 } 00128 00129 for (var i = 0; i < _argc; i++) 00130 result = result + [_arguments[i] description] + ((i + 1 < _argc) ? ", " : ""); 00131 00132 result += ")"; 00133 00134 return result ; 00135 } 00136 00137 - (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables 00138 { 00139 var operand = [[self operand] _expressionWithSubstitutionVariables:variables], 00140 args = [CPArray array], 00141 i = 0; 00142 00143 for (; i < _argc; i++) 00144 [args addObject:[_arguments[i] _expressionWithSubstitutionVariables:variables]]; 00145 00146 return [CPExpression expressionForFunction:operand selectorName:[self _function] arguments:args]; 00147 } 00148 00149 @end 00150 00151 var CPSelectorNameKey = @"CPSelectorName", 00152 CPArgumentsKey = @"CPArguments", 00153 CPOperandKey = @"CPOperand", 00154 CPExpressionTypeKey = @"CPExpressionType"; 00155 00156 @implementation CPExpression_function (CPCoding) 00157 00158 - (id)initWithCoder:(CPCoder)coder 00159 { 00160 var type = [coder decodeIntForKey:CPExpressionTypeKey], 00161 operand = [coder decodeObjectForKey:CPOperandKey], 00162 selector = CPSelectorFromString([coder decodeObjectForKey:CPSelectorNameKey]), 00163 parameters = [coder decodeObjectForKey:CPArgumentsKey]; 00164 00165 return [self initWithTarget:operand selector:selector arguments:parameters type:type]; 00166 } 00167 00168 - (void)encodeWithCoder:(CPCoder)coder 00169 { 00170 [coder encodeObject:[self _function] forKey:CPSelectorNameKey]; 00171 [coder encodeObject:_arguments forKey:CPArgumentsKey]; 00172 [coder encodeObject:_operand forKey:CPOperandKey]; 00173 [coder encodeInt:_type forKey:CPExpressionTypeKey]; 00174 } 00175 00176 @end 00177 00178 // Built-in functions 00179 @implementation CPPredicateUtilities : CPObject 00180 { 00181 id __doxygen__; 00182 } 00183 00184 + (float)sum:(CPArray)parameters 00185 { 00186 var sum = 0, 00187 count = parameters.length; 00188 00189 while (count--) 00190 sum += parameters[count]; 00191 00192 return sum; 00193 } 00194 00195 + (float)count:(CPArray)parameters 00196 { 00197 return [parameters count]; 00198 } 00199 00200 + (float)min:(CPArray)parameters 00201 { 00202 return parameters.sort()[0]; 00203 } 00204 00205 + (float)max:(CPArray)parameters 00206 { 00207 return parameters.sort()[parameters.length - 1]; 00208 } 00209 00210 + (float)average:(CPArray)parameters 00211 { 00212 return [self sum:parameters] / parameters.length; 00213 } 00214 00215 + (id)first:(CPArray)parameters 00216 { 00217 return parameters[0]; 00218 } 00219 00220 + (id)last:(CPArray)parameters 00221 { 00222 return parameters[parameters.length - 1]; 00223 } 00224 00225 + (id)fromObject:(id)object index:(id)anIndex 00226 { 00227 if ([object isKindOfClass:[CPDictionary class]]) 00228 return [object objectForKey:anIndex]; 00229 else ([object isKindOfClass:[CPArray class]]) 00230 return [object objectAtIndex:anIndex]; 00231 00232 [CPException raise:CPInvalidArgumentException reason:@"object[#] requires a CPDictionary or CPArray"]; 00233 } 00234 00235 + (float)add:(int)n to:(int)m 00236 { 00237 return n + m; 00238 } 00239 00240 + (float)from:(int)n substract:(int)m 00241 { 00242 return n - m; 00243 } 00244 00245 + (float)multiply:(float)n by:(int)m 00246 { 00247 return n * m; 00248 } 00249 00250 + (float)divide:(float)n by:(float)m 00251 { 00252 return n / m; 00253 } 00254 00255 + (float)sqrt:(float)n 00256 { 00257 return SQRT(n); 00258 } 00259 00260 + (float)raise:(float)num to:(int)power 00261 { 00262 return POW(num, power); 00263 } 00264 00265 + (float)abs:(float)num 00266 { 00267 return ABS(num); 00268 } 00269 00270 + (CPDate)now:(id)_ 00271 { 00272 return [CPDate date]; 00273 } 00274 00275 + (float)ln:(float)num 00276 { 00277 return LN10(num); 00278 } 00279 00280 + (float)exp:(float)num 00281 { 00282 return EXP(num); 00283 } 00284 00285 + (float)ceiling:(float)num 00286 { 00287 return CEIL(num); 00288 } 00289 00290 + (int)random:(int)num 00291 { 00292 return ROUND(RAND() * num); 00293 } 00294 00295 + (int)modulus:(int)n by:(int)m 00296 { 00297 return n % m; 00298 } 00299 00300 + (float)chs:(int)num 00301 { 00302 return -num; 00303 } 00304 00305 @end