DDMathParser author here.
Here's how you add a multiply by two
function:
DDMathEvaluator *evaluator = [DDMathEvaluator sharedMathEvaluator];
// a function takes arguments, variable values, the evaluator, and an error pointer
// and returns a new expression
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError *__autoreleasing *error) {
DDExpression *final = nil;
// multiplyBy2() can only handle a single argument
if ([args count] == 1) {
// get the argument and simply wrap it in a "multiply()" function
DDExpression *argExpression = [args objectAtIndex:0];
DDExpression *twoExpression = [DDExpression numberExpressionWithNumber:@2];
final = [DDExpression functionExpressionWithFunction:DDOperatorMultiply arguments:@[argExpression, twoExpression] error:nil];
} else if (error) {
// there wasn't only one argument
NSString *description = [NSString stringWithFormat:@"multiplyBy2() requires 1 argument. %ld were given", [args count]];
*error = [NSError errorWithDomain:DDMathParserErrorDomain code:DDErrorCodeInvalidNumberOfArguments userInfo:@{NSLocalizedDescriptionKey: description}];
}
return final;
} forName:@"multiplyBy2"];
Now you can do:
NSNumber *result = [@"multiplyBy2(21)" stringByEvaluatingString];
and get back @42
.
What's going on here:
Internally, DDMathEvaluator
essentially has a big NSDictionary
where it keeps a list of all the functions it knows about, keyed off the name of that function, kind of like this:
_functions = @{
@"multiply" : multiplyFunctionBlock,
@"add" : addFunctionBlock,
...
};
(Obviously it's a bit more complicated than that, but that's the basic idea)
When the evaluator evaluates a string and comes across the a function, it looks up in this dictionary what the block for the function is. It retrieves the block, and then executes the block with the arguments (if there are any) from the string. The result of the block is the result of the function.
That result gets substituted back in, and evaluation continues.