Archived
1
This repository has been archived on 2022-08-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mathpad/MathPad/MPFunction.h
2014-11-10 21:45:50 +01:00

321 lines
10 KiB
Objective-C

//
// MPFunction.h
// MathPad
//
// Created by Kim Wittenburg on 18.04.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPExpressionElement.h"
/* Use this macro to implement a custom setter for children of custom MPFunction
* subclasses. This is necessary to maintain the consistency of the expression
* tree. Not implementing a custom setter using this macro or a similar custom
* method will lead to unexpected behaviour.
*/
#define MPFunctionAccessorImplementation(Accessor, variableName) \
- (void)set##Accessor:(MPExpression *)value \
{ \
variableName.parent = nil; \
variableName = value; \
variableName.parent = self; \
[self didChangeChildAtIndex:[self indexOfChild:variableName]]; \
}
@class MPFunction, MPExpression, MPRangePath;
@protocol MPExpressionElement;
/*!
@class MPFunction
@brief The @c MPFunction class represents a mathematical function.
@discussion A mathematical function can be anything that exceeds the
graphical capability of text.
*/
@interface MPFunction : NSObject <NSCoding, NSCopying, MPExpressionElement>
#pragma mark Properties
/* Subclasses should define readwrite properties for all child expressions they
* can have. In the implementation file the property setter should be overridden
* using the @c MPFunctionAccessorImplementation macro. The macro takes two
* parameters: The capitalized name of the property and the name of the
* property's backing variable (usually the property's name prefixed with an
* underscore.
*
* Note that none of the children may be nil at any time.
*/
#pragma mark Working With the Expression Tree
/*!
@methodgroup Working With the Expression Tree
*/
/*!
@property parent
@brief The receiver's parent.
@discussion Expressions and functions are organized in a tree-like structure.
Through this property a function's containing expression can be
accessed.
@warning Do not set this property manually. It will automatically be set
when the function is added to an expression.
@note If you need to know when a function is added to or removed from
an expression you can observe this property.
@return The parent of the receiver or @c nil if the receiver does not
have a parent.
*/
@property (nonatomic, weak) MPExpression *parent;
/*!
@method rootExpression
@brief Returns the root expression from the receiver's expression tree.
@discussion The root expression is the ultimate parent of all expressions and
functions in the expression tree. A root expression does not have
a parent.
@return The root expression from the receiver's expression tree or @c nil
if this function does not have a parent.
*/
- (MPExpression *)rootExpression;
/*!
@method indexPath
@brief Returns the index path of the receiver in the expression tree.
@discussion The index path is calculated by going up the expression tree
collecting the respective index of the receiver. The indexes are
expressed in the element reference frame. If any of the indexes
exceed the respective receiver's bounds a @c NSRangeException is
raised.
@return The index path of the receiver in the expression tree or @c nil
if this function does not have a parent.
*/
- (NSIndexPath *)indexPath;
/*!
@method numberOfChildren
@brief Returns the number of children the receiver has.
@discussion The number of children must be equal to the number of child
accessors as determined by the @c -childrenAccessors method.
@return The number of children of the receiving function.
*/
- (NSUInteger)numberOfChildren;
/*!
@method childAtIndex:
@brief Returns the child at the given index.
@discussion The ordering of children is determined by the order of the
children returned from the @c -childrenAccessors method.
@param index
The index of the requested child.
@return The expression that corresponds to the child at @c index.
*/
- (MPExpression *)childAtIndex:(NSUInteger)index;
/*!
@method setChild:atIndex:
@brief Sets the child at the specified index.
@discussion Although this method does @b not call the respective accessor
methods it behaves exactly as the setter method implemented using
the @c MPFunctionAccessorImplementation macro.
@param child
The child that should replace the previous one.
@param index
The index of the child to be replaced.
*/
- (void)setChild:(MPExpression *)child
atIndex:(NSUInteger)index;
/*!
@method children
@brief Returns the receiver's children.
@discussion The ordering of the children is the same as in the array returned
from @c -childrenAccessors.
@return An array containing all the function's children.
*/
- (NSArray *)children;
/*!
@method indexOfChild:
@brief Returns the index of @c child in the receiver.
@param child
The child to be searched.
@return The index of @c child or @c NSNotFound if none of the receiver's
children is equal to @c child.
*/
- (NSUInteger)indexOfChild:(MPExpression *)child;
/*!
@method elementAtIndexPath:
@brief Returns the element at the specified index path.
@discussion This method @em walks down the expression tree (including other
functions) using the specified index path and finds the
corresponding element. The returned object can be an @c NSString,
a @c MPFunction or an @c MPExpression depending on the element @c
indexPath points to. If any of the indexes exceed the bounds of
the respective receiver an @c NSRangeException is raised.
If the index path does not contain any indexes the receiver
itself is returned.
@param indexPath
The index path the required object is located at. The indexes are
expressed in the element reference frame.
@return The element located at @c indexPath. The element is not copied
before it is returned. Be aware of the fact that any mutations
made to the returned object are reflected in the receiver.
*/
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;
#pragma mark Notifications
/*!
@methodgroup Notifications
*/
/*!
@method didChangeElementsInRangePath:replacementLength:
@brief Notification method that is called if one of the children was
mutated.
@discussion This method is also called when one of the children is changed
via one of the accessor methods.
@param rangePath
The location of the change that happened. Because it may have
happened somewhere deep down in the expression tree a range path
is used.
@param replacementLength
The number of elements that replaced the elements addressed by
the range path.
*/
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
replacementLength:(NSUInteger)replacementLength;
/*!
@method didChangeChildAtIndex:
@brief Convenience method that calls @c
-didChangeElementsInRangePath:replacementLength:
@discussion This method is automatically called when one of the children is
changed using one of the accessor methods or @c
-setChild:atIndex:.
@param index
The index of the child that was changed.
*/
- (void)didChangeChildAtIndex:(NSUInteger)index;
@end
/*!
@category MPFunction (MPSubcalssOverride)
@brief The methods in this category must be implemented by any concrete
subclasses of @c MPFunction.
@discussion @c MPFunction does not implement the functions itself but calls
them at various points. If a subclass does not provide
implementations your app will most likely crash.
*/
@interface MPFunction (MPSubclassOverride)
#pragma mark Working With the Expression Tree
/*!
@methodgroup Working With the Expression Tree
*/
/*!
@method childrenAccessors
@brief Returns the names of the children properties.
@discussion A @c MPFunction subclass should declare a public propertiy for
every child it can have. This method should return the names as
they would be used for key-value-coding.
@return An array of strings describing the names of children a function
has.
*/
- (NSArray *)childrenAccessors;
#pragma mark Evaluating Functions
/*!
@methodgroup Evaluating Functions
*/
/*!
@method validate:
@brief Validates the function and all its children for syntax errors.
@param error
If the validation fails this parameter should be set to an
appropriate value.
@return @c YES if the validation was successful, @c NO otherwise.
*/
- (BOOL)validate:(NSError *__autoreleasing *)error;
/*!
@method evaluate:
@brief Evaluates the function.
@discussion Function evaluation should actually perform math. Also the
implementation of this method assumes that the function and all
children are valid (as determined by the @c -validate: method).
@param error
If a mathematical error occurs it is reflected in this parameter.
Depending on the error this method then either returns @c nil or
@c NaN.
@return The result of the evaluation or @c nil or @c NaN if an evaluation
error occured (such as a division by @c 0).
*/
- (NSDecimalNumber *)evaluate:(NSError *__autoreleasing *)error;
/* In Addition to the above methods MPFunction subclasses should also override
* the NSObject methods -description and -hash.
*/
@end