//
// 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