// // MPTerm.h // MathPad // // Created by Kim Wittenburg on 11.11.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // /*! @header The MPTerm class is used to evaluate a mathematical expression. A term is a purely mathematical representation of a part of an expression. A term can be defined with three rules: 1. A number is a term. 2. A variable is a term. 3. A connection of terms with zero or more symbols is also a term. Every mathematical operation (term) is defined in terms of a concrete subclass of MPTerm and sub-terms (children). For example the expression 2+3⋅4 would be a @link //apple_ref/occ/cl/MPSumTerm sum term@/link with two children: A @link //apple_ref/occ/cl/MPNumber number@/link and a @link //apple_ref/occ/cl/MPProductTerm product term@/link. The product term in turn has two children which are both numbers. Subclasses should do the following: 1. Subclasses must implement the @link doEvaluation:@/link method. 2. Subclasses should be immutable and thus define readonly accessors for any children as well as an init method that supplies the necessary values. If a term has children that define variables to be used in one or more of the other children MPTerm offers methods for defining, accessing and undefining variable values. Because a term can not define variables that are accessible in any of its sibling or parent terms all variables defined in a term are automatically undefined when the term is finished evaluating. */ /*! @define ReturnIfNil @abstract This macro returns a value if a test object is nil. @param test The object to be tested. If this parameter is nil the macro returns value. @param value The value to be returned if test is nil. */ #define ReturnIfNil(test, value) if (test == nil) return value /*! @define ReturnNilIfNil @abstract This macro returns nil if a test object is nil. @param test The object to be tested. If this parameter is nil the macro returns nil. */ #define ReturnNilIfNil(test) if (test == nil) return nil @class MPTerm; /*! @class MPTerm @abstract MPTerm is a half abstract class that is the base class for representing an evaluatable mathematical expression. @discussion MPTerm should not be instanciated directly. Instead one of the concrete subclasses should be used. */ @interface MPTerm : NSObject /*! @method evaluate: @abstract Evaluates the receiver. @discussion The result of the evaluation is up to the concrete subclass of MPTerm. Note however that subclasses should not override this method. To implement the custom evaluation behaviour implement the @link doEvaluation:@/link method. To evaluate a term (including children of terms) do use this method. @param error If an error occurs during evaluation it is indirecly returned through this parameter. If you are not interested in errors, pass NULL. @return A NSDecimalNumber containing the result of the evaluation. Depending on the term this should be double precision or higher. */ - (NSDecimalNumber *)evaluate:(NSError *__autoreleasing *)error; /*! @method doEvaluation: @abstract Performs the actual evaluation of the receiver. @discussion This method must be implemented by subclasses but should never be called directly. Call @link evaluate:@/link instead. @param error If an error occurs during evaluation it is indirecly returned through this parameter. If you are not interested in errors, pass NULL. @return A NSDecimalNumber containing the result of the evaluation. Depending on the term this should be double precision or higher. */ - (NSDecimalNumber *)doEvaluation:(NSError *__autoreleasing *)error; /*! @method defineVariable:value:error: @abstract Defines a variable in the shared evaluation context. @discussion A defined variable is available until it is either undefined or the end of the @link doEvaluation:@/link method is reached at which point all variables defined in that method are undefined automatically. If the variableName has already been defined in the same method this method overwrites the value for the variable. If it has been defined in the evaluation method of a parent term this method fails and returns NO. @param variableName The variable to be defined. @param value The value for the variable. @param error If variableName has already been defined in a parent term this parameter is set to an error object that informs the user about a variable redefinition. If you are not interested in errors, pass NULL. @return YES if the variable could be defined, NO if it has previously been declared in a parent term of the currently evaluated one. */ - (BOOL)defineVariable:(NSString *)variableName value:(NSDecimalNumber *)value error:(NSError *__autoreleasing *)error; /*! @method valueForVariable: @abstract Returns the value for a variable from the shared evaluation context. @discussion If variableName is not defined this method returns nil. Normally you do not need to call this method yourself. @param variableName The variable whose value is requested. @param error If variableName is not defined this parameter is set to an error object that informs the user about an undefined variable. If you are not interested in errors, pass NULL. @return The value associated with variableName or nil if it is undefined. */ - (NSDecimalNumber *)valueForVariable:(NSString *)variableName error:(NSError *__autoreleasing *)error; /*! @method undefineVariable: @abstract Removes variableName from the shared evaluation context. @discussion The variable is only removed if it exists and was defined in the same evaluation method. Variables defined by parent terms can not be undefined. Normally you do not need to call this method yourself since all variables defined during the evaluation of a term are automatically undefined afterwards. @param variableName The name of the variable to be undefined. */ - (void)undefineVariable:(NSString *)variableName; @end