-
Notifications
You must be signed in to change notification settings - Fork 154
The Math Evaluator
Evaluation is part of the expression's logic, but it uses the Math Evaluator quite extensively.
Evaluating a number expression is trivial. It simply returns the underlying NSNumber
object.
Evaluating a variable is also relatively straight-forward. First, the variable is looked up in the passed substitutions dictionary. If the substitutions dictionary doesn't contain a match, then the expression consult's the math evaluator's variable resolver block. If no replacement is available, then an error is generated and evaluation aborts.
Otherwise, the object is examined:
- if the substitution value is another expression, that expression is evaluated and its return value becomes the variables value.
- if the substitution value is a string, that string is evaluated as an expression, and its return value becomes the variables value
- if the substitution value is a number, the number is used directly
- any other substitution value generates an error
Evaluating a function is where the math evaluator is used. First, the math evaluator looks to see if the function is one of the built-in functions. If it is, it invokes the default implementation.
If the function is not one of the built-in functions, then the evaluator checks to see if a function has been registered for the defined name. If it has, then that function is used. If not, then the math evaluator attempts to resolve the function as a variable (if that property is enabled), which goes the the variable evaluation route, explained above.
If a value still has not been obtained, the math evaluator attempts to consult the function resolver to acquire a "just in time" function definition.
Finally, if that fails, an error is generated and evaluation aborts.
If a function definition is found, it is invoked with four arguments:
- the array of
DDExpression
objects that are the arguments to the function - the substitution dictionary
- the math evaluator
- the
NSError**
(for reporting errors)
The return value of the DDMathFunction
is another DDExpression
object, although some leniency is allowed: NSNumbers
are returned directly and NSStrings
are parsed and evaluated to extract a numerical value.
The math evaluator allows you to specify the unit in which angles are measured. The two options are DDAngleMeasurementModeRadians
(the default) and DDAngleMeasurementModeDegrees
.
When the measurement mode is in radians, the following is true:
sin(π/2) = 1
asin(0.7071067811865475) = .785398163
sin(45) = 0.8509035245341184
However, the when measurement mode is in degrees, the evaluation changes:
sin(π/2) = 0.02741213359204429
asin(0.7071067811865475) = 45
sin(45) = 0.7071067811865475
DDMathEvaluator
has two properties that allow you to lazily resolve functions and variables: functionResolver
and variableResolver
.
Lazy function resolution can be very handy when using DDMathParser
to process user-generated input. For example, you can use lazy function resolution to process a string like this:
"age/2 + 7"
According to the rules of argumentless functions, this will be parsed as:
(age() / 2) + 7
The advantage of this is that users do not need to understand the syntax for variables and their need for the leading $
character.
By specifying the appropriate block for the functionResolver
, you can process these functions as if they were variables. The Demo in the repository contains an example of a function resolver. Alternatively, you could simply specify that unknown functions should be resolved as variables, and specify a the value through the variables dictionary or via the variable resolver.
Like with functions, you can specify a block to lazily resolve unknown variables. The block, however, is much simpler: it takes a single string argument (the name of the variable) and returns an NSNumber
.