Added Documentation
This commit is contained in:
@@ -60,7 +60,7 @@
|
|||||||
3B74BFB319A4C51800E5B5DE /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B74BFB219A4C51800E5B5DE /* CoreText.framework */; };
|
3B74BFB319A4C51800E5B5DE /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B74BFB219A4C51800E5B5DE /* CoreText.framework */; };
|
||||||
3B78C85419C2DA5300516335 /* MPEvaluationContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B78C85219C2DA5300516335 /* MPEvaluationContext.h */; };
|
3B78C85419C2DA5300516335 /* MPEvaluationContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B78C85219C2DA5300516335 /* MPEvaluationContext.h */; };
|
||||||
3B78C85519C2DA5300516335 /* MPEvaluationContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B78C85319C2DA5300516335 /* MPEvaluationContext.m */; };
|
3B78C85519C2DA5300516335 /* MPEvaluationContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B78C85319C2DA5300516335 /* MPEvaluationContext.m */; };
|
||||||
3B7B3A1819CC44E4005849E5 /* MPExpressionTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7B3A1619CC44E4005849E5 /* MPExpressionTokenizer.h */; };
|
3B7B3A1819CC44E4005849E5 /* MPExpressionTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7B3A1619CC44E4005849E5 /* MPExpressionTokenizer.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||||
3B7B3A1919CC44E4005849E5 /* MPExpressionTokenizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B7B3A1719CC44E4005849E5 /* MPExpressionTokenizer.m */; };
|
3B7B3A1919CC44E4005849E5 /* MPExpressionTokenizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B7B3A1719CC44E4005849E5 /* MPExpressionTokenizer.m */; };
|
||||||
3B7B3A2C19CC467E005849E5 /* MPToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7B3A2A19CC467E005849E5 /* MPToken.h */; };
|
3B7B3A2C19CC467E005849E5 /* MPToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7B3A2A19CC467E005849E5 /* MPToken.h */; };
|
||||||
3B7B3A2D19CC467E005849E5 /* MPToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B7B3A2B19CC467E005849E5 /* MPToken.m */; };
|
3B7B3A2D19CC467E005849E5 /* MPToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B7B3A2B19CC467E005849E5 /* MPToken.m */; };
|
||||||
@@ -425,7 +425,8 @@
|
|||||||
3BC46B4B19B38CB60033F13A /* Base Expression Classes */,
|
3BC46B4B19B38CB60033F13A /* Base Expression Classes */,
|
||||||
3B69B68219E6E8A50028E608 /* Expression Tree */,
|
3B69B68219E6E8A50028E608 /* Expression Tree */,
|
||||||
3BB09EBC1905EF210080A5ED /* Functions */,
|
3BB09EBC1905EF210080A5ED /* Functions */,
|
||||||
3BC46B4C19B38CD20033F13A /* Independant Classes */,
|
3B87E35B1900933200259938 /* MPRangePath.h */,
|
||||||
|
3B87E35C1900933200259938 /* MPRangePath.m */,
|
||||||
3BC46B4D19B38CFB0033F13A /* Helpers */,
|
3BC46B4D19B38CFB0033F13A /* Helpers */,
|
||||||
);
|
);
|
||||||
name = Model;
|
name = Model;
|
||||||
@@ -531,15 +532,6 @@
|
|||||||
name = "Base Expression Classes";
|
name = "Base Expression Classes";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
3BC46B4C19B38CD20033F13A /* Independant Classes */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
3B87E35B1900933200259938 /* MPRangePath.h */,
|
|
||||||
3B87E35C1900933200259938 /* MPRangePath.m */,
|
|
||||||
);
|
|
||||||
name = "Independant Classes";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
3BC46B4D19B38CFB0033F13A /* Helpers */ = {
|
3BC46B4D19B38CFB0033F13A /* Helpers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|||||||
@@ -6,11 +6,65 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@const MPIllegalElementException
|
||||||
|
@brief Name for an exception that is raised if an invalid element is
|
||||||
|
added to an expression.
|
||||||
|
|
||||||
|
@discussion This exception may be raised during initialization of an
|
||||||
|
expression or when the expression is mutated. This exception
|
||||||
|
always contains the @c MPIllegalElementExceptionElementKey key in
|
||||||
|
its @c userInfo dictionary.
|
||||||
|
*/
|
||||||
|
FOUNDATION_EXPORT NSString *const MPIllegalElementException;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@const MPIllegalElementExceptionElementKey
|
||||||
|
@brief Predefined key for the invalid element that caused an exception
|
||||||
|
to be raised.
|
||||||
|
|
||||||
|
@discussion The invalid element can be of any type.
|
||||||
|
*/
|
||||||
FOUNDATION_EXPORT NSString *const MPIllegalElementExceptionElementKey;
|
FOUNDATION_EXPORT NSString *const MPIllegalElementExceptionElementKey;
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSString *const MPMathKitErrorDomain;
|
|
||||||
FOUNDATION_EXPORT NSString *const MPExpressionPathErrorKey;
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@const MPMathKitErrorDomain
|
||||||
|
@brief Predefined error domain for errors from the MathKit framework.
|
||||||
|
|
||||||
|
@discussion Errors in MathKit can occur during parsing of expressions or
|
||||||
|
during evaluation of expressions. These two can be distinguished
|
||||||
|
by the error code. Parsing errors have lower error codes.
|
||||||
|
Evaluation errors (math errors) have error codes from @c 100 upwards.
|
||||||
|
*/
|
||||||
|
FOUNDATION_EXPORT NSString *const MPMathKitErrorDomain;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Deal with this:
|
||||||
|
// FOUNDATION_EXPORT NSString *const MPPathToExpressionKey;
|
||||||
|
// FOUNDATION_EXPORT NSString *const MPRangeKey;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@function MPParseError
|
||||||
|
@brief Creates an @c NSError object in the @c MPMathKitErrorDomain.
|
||||||
|
|
||||||
|
@discussion The created error is filled with the passed data if present.
|
||||||
|
|
||||||
|
@param errorCode
|
||||||
|
The error code of the created error.
|
||||||
|
|
||||||
|
@param errorDescription
|
||||||
|
The localized description of the created error. May be @c nil.
|
||||||
|
|
||||||
|
@param underlyingError
|
||||||
|
The underlying error of the created error. May be @c nil.
|
||||||
|
|
||||||
|
@return An @c NSError object initialized with the given data.
|
||||||
|
*/
|
||||||
NS_INLINE NSError * MPParseError(NSInteger errorCode,
|
NS_INLINE NSError * MPParseError(NSInteger errorCode,
|
||||||
NSString *errorDescription,
|
NSString *errorDescription,
|
||||||
NSError *underlyingError) {
|
NSError *underlyingError) {
|
||||||
@@ -27,12 +81,41 @@ NS_INLINE NSError * MPParseError(NSInteger errorCode,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@typedef MPReferenceFrame
|
||||||
|
@brief A reference frame describes what an @em item is.
|
||||||
|
|
||||||
|
@discussion An item may be an element, a symbol or a token. A symbol is the
|
||||||
|
smallest possible size for an item. An element as well as a token
|
||||||
|
consist of one or more symbols. Similarly an element consists of
|
||||||
|
one or more tokens.
|
||||||
|
|
||||||
|
@constant MPElementReferenceFrame
|
||||||
|
Specifies that items should be interpreted as elements. An
|
||||||
|
element is either a @c NSString object or a @c MPFunction object.
|
||||||
|
|
||||||
|
@constant MPSymbolReferenceFrame
|
||||||
|
Specifies that items should be interpreted as symbols. A symbol
|
||||||
|
can be a single character (as they are for example typed in by
|
||||||
|
the user) or a @c MPFunction object.
|
||||||
|
|
||||||
|
@constant MPTokenReferenceFrame
|
||||||
|
Specifies that items should be interpreted as tokens. A token is
|
||||||
|
a logical unit of content in an expression. This can be a single
|
||||||
|
character (e.g. '+'), an arbitrary number of characters (e.g. a
|
||||||
|
number) or a @c MPFunction object.
|
||||||
|
|
||||||
|
All tokens must conform to the @c MPToken protocol.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
||||||
MPElementReferenceFrame,
|
MPElementReferenceFrame,
|
||||||
MPSymbolReferenceFrame,
|
MPSymbolReferenceFrame,
|
||||||
MPTokenReferenceFrame
|
MPTokenReferenceFrame
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPExpression, MPFunction, MPRangePath, MPExpressionTree, MPExpressionEvaluator;
|
@class MPExpression, MPFunction, MPRangePath, MPExpressionTree, MPExpressionEvaluator;
|
||||||
@protocol MPExpressionElement, MPToken;
|
@protocol MPExpressionElement, MPToken;
|
||||||
|
|
||||||
@@ -42,45 +125,28 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
expression.
|
expression.
|
||||||
|
|
||||||
@discussion Every expression consists of string elements (represented by the
|
@discussion Every expression consists of string elements (represented by the
|
||||||
@c NSString class) and functions (represented by the @c
|
@c NSString class) and function elements (represented by the @c
|
||||||
MPFunction class) elements which both can be contained within an
|
MPFunction class). Functions likewise can have expressions as
|
||||||
expression. Functions in turn can have expressions as elements
|
elements (also called @em children in this context). Both
|
||||||
(also called 'children' in this context). Both expressions and
|
expressions and functions are mutable. Through this organization
|
||||||
functions are mutable.
|
expression are organized in a tree-like structure called the
|
||||||
|
'expression tree'.
|
||||||
|
|
||||||
Through this organization expression are organized in a tree-like
|
@note There is also the @c MPExpressionTree class. That class provides
|
||||||
structure (called the 'expression tree') allowing easy and
|
an alternative representation of an expression. The 'expression
|
||||||
logical access to each element.
|
tree' does not refer to that class.
|
||||||
|
|
||||||
To query the contents of an expressions there are two options:
|
|
||||||
You can query on a per-element basis (that is string elements and
|
|
||||||
function elements as described before). This is called the @em
|
|
||||||
index reference frame (or @em indexed reference frame). You also
|
|
||||||
can query an expression on a per-symbol basis. This is called the
|
|
||||||
@em location reference frame (or @c located reference frame).
|
|
||||||
Using the located reference frame is useful if you are dealing
|
|
||||||
with user actions since the user does not necessarily see a
|
|
||||||
visual separation between different elements but only sees the
|
|
||||||
symbols that are drawn on the screen. You can convert between the
|
|
||||||
two reference frames using the following methods:
|
|
||||||
@code
|
|
||||||
- (NSUInteger)indexOfElementAtSymbolLocation:offset: // Converts from the located to the indexed reference frame
|
|
||||||
- (NSUInteger)locationOfElementAtIndex: // Converts from the indexed to the located reference frame
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
In the indexed reference frame both functions and strings have a
|
|
||||||
dimension of 1. In the located reference frame the length of a
|
|
||||||
string is determined by sending it a @c -length message. In that
|
|
||||||
frame functions still have a length of 1.
|
|
||||||
|
|
||||||
An expression can evaluate itself giving you either a
|
An expression can evaluate itself giving you either a
|
||||||
result or possibly an error if the expression was not constructed
|
result or possibly an error if the expression was not constructed
|
||||||
correctly.
|
correctly or could not be evaluated.
|
||||||
*/
|
*/
|
||||||
@interface MPExpression : NSObject <NSCopying, NSCoding>
|
@interface MPExpression : NSObject <NSCopying, NSCoding>
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
/*!
|
||||||
|
@methodgroup Creation Methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -128,12 +194,15 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
element is copied and the copy is then added to the expression.
|
element is copied and the copy is then added to the expression.
|
||||||
The object in the @c elements array is not modified.
|
The object in the @c elements array is not modified.
|
||||||
|
|
||||||
@return An expression containing the elements from @c elements.
|
@return An expression containing @c elements.
|
||||||
*/
|
*/
|
||||||
- (instancetype)initWithElements:(NSArray *)elements; /* designated initializer */
|
- (instancetype)initWithElements:(NSArray *)elements; /* designated initializer */
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Querying Expressions
|
#pragma mark Querying Expressions
|
||||||
|
/*!
|
||||||
|
@methodgroup Querying Expressions
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -142,8 +211,9 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
|
|
||||||
@discussion Expressions are organized in a tree-like structure. Through this
|
@discussion Expressions are organized in a tree-like structure. Through this
|
||||||
property an expression's containing function can be accessed.
|
property an expression's containing function can be accessed.
|
||||||
@warning You should not set this property manually unless you are
|
@warning You should never set this property manually. If you are
|
||||||
implementing a subclass of @c MPFunction.
|
implementing a custom subclass of @c MPFunction use the @c
|
||||||
|
MPFunctionAccessorImplementation macro.
|
||||||
|
|
||||||
@return The parent of the receiver or @c nil if the receiver is the root
|
@return The parent of the receiver or @c nil if the receiver is the root
|
||||||
expression.
|
expression.
|
||||||
@@ -170,7 +240,7 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
|
|
||||||
@discussion The index path is calculated by going up 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
|
collecting the respective index of the receiver. The indexes are
|
||||||
expressed in the indexed reference frame. If any of the indexes
|
expressed in the element reference frame. If any of the indexes
|
||||||
exceed the respective receiver's bounds a @c NSRangeException is
|
exceed the respective receiver's bounds a @c NSRangeException is
|
||||||
raised.
|
raised.
|
||||||
|
|
||||||
@@ -180,41 +250,62 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method numberOfElements
|
@method countItemsInReferenceFrame:
|
||||||
@brief Returns the number of elements in the receiver.
|
@brief Returns the number of items in the receiver in the respective
|
||||||
|
reference frame.
|
||||||
|
|
||||||
@discussion The number of elements may vary from the number of elements that
|
@param referenceFrame
|
||||||
were added to the receiver (using either @c -initWithElements: or
|
The reference frame that should be used to count the items.
|
||||||
one of the several mutation methods). The number of elements is
|
|
||||||
expressed in the indexed reference frame. (The respective method
|
|
||||||
for the located reference frame is @c -length).
|
|
||||||
|
|
||||||
@return The current number of elements in the receiver.
|
@return The current number of items in the receiver counted in the given
|
||||||
|
reference frame.
|
||||||
*/
|
*/
|
||||||
- (NSUInteger)countItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;
|
- (NSUInteger)countItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method elementAtIndex:
|
@method itemAtIndex:referenceFrame:
|
||||||
@brief Returns the element at @c anIndex.
|
@brief Returns the item at @c anIndex.
|
||||||
|
|
||||||
@discussion The element is not copied before it is returned. So be aware that
|
@discussion The item is not copied before it is returned. So be aware that
|
||||||
if you mutate a @c MPFunction object returned from this function
|
if you mutate a @c MPFunction object returned from this function
|
||||||
the changes will be reflected in the receiver.
|
the changes will be reflected in the receiver.
|
||||||
|
|
||||||
@note This method can also be called using indexed subscript
|
|
||||||
getter syntax.
|
|
||||||
|
|
||||||
@param anIndex
|
@param anIndex
|
||||||
The index of the element expressed in the indexed reference
|
The index of the item. If the index is greater than the number of
|
||||||
frame. If the index is greater than or equal to the number of
|
items for the respective reference frame an @c NSRangeException
|
||||||
elements in the receiver an @c NSRangeException is raised.
|
is raised.
|
||||||
|
|
||||||
@return The element at @c anIndex.
|
@param referenceFrame
|
||||||
|
The reference frame that should be used to identify the item at
|
||||||
|
@c anIndex.
|
||||||
|
|
||||||
|
@return The item at @c anIndex.
|
||||||
*/
|
*/
|
||||||
- (id)itemAtIndex:(NSUInteger)anIndex
|
- (id)itemAtIndex:(NSUInteger)anIndex
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method elementAtIndex:referenceFrame:
|
||||||
|
@brief Returns the element at the specified index.
|
||||||
|
|
||||||
|
@discussion An element is either a string or a function. If @c anIndex
|
||||||
|
specifies a position inside a string the complete string element
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
This method does not return any item in any reference frame but
|
||||||
|
only complete elements. Use @c -itemAtIndex:referenceFrame: for
|
||||||
|
that purpose.
|
||||||
|
|
||||||
|
@param anIndex
|
||||||
|
The index of the element.
|
||||||
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame @c anIndex is specified in.
|
||||||
|
|
||||||
|
@return The item at @c anIndex.
|
||||||
|
*/
|
||||||
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
|
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
@@ -226,45 +317,48 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
@param element
|
@param element
|
||||||
The element to find.
|
The element to find.
|
||||||
|
|
||||||
@return The index of @c element expressed in the indexed reference frame.
|
@return The index of @c element expressed in the element reference frame.
|
||||||
*/
|
*/
|
||||||
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element;
|
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method elementsInIndexedRange:
|
@method itemsInRange:referenceFrame:
|
||||||
@brief Returns an array of the elements that are located in the
|
@brief Returns an array of the items that are located in the specified
|
||||||
specified range. The range is specified in the indexed reference
|
range.
|
||||||
frame.
|
|
||||||
|
|
||||||
@discussion The objects in the returned array are not copied before they are
|
@discussion The objects in the returned array are not copied before they are
|
||||||
returned. You should be aware of the fact that mutations to any
|
returned. You should be aware of the fact that mutations to any
|
||||||
returned element will be reflected in the receiver.
|
returned objects will be reflected in the receiver.
|
||||||
|
|
||||||
If the @c range exceeds the receiver's bounds an @c
|
If the @c range exceeds the receiver's bounds an @c
|
||||||
NSRangeException is raised.
|
NSRangeException is raised.
|
||||||
|
|
||||||
@param range
|
@param aRange
|
||||||
The requested range within the receiver's bounds expressed in the
|
The requested range within the receiver's bounds.
|
||||||
indexed reference frame.
|
|
||||||
|
@param referenceFrame
|
||||||
|
The referenceFrame @c aRange is expressed in.
|
||||||
|
|
||||||
@return An array of objects that conform to the @c MPExpressionElement
|
@return An array of objects that conform to the @c MPExpressionElement
|
||||||
protocol (that is @c NSString objects and @c MPFunction objects).
|
protocol (that is @c NSString objects and @c MPFunction objects).
|
||||||
The length of the returned array is equal to the length of the
|
The length of the returned array is equal to the length of the
|
||||||
specified range.
|
specified range.
|
||||||
*/
|
*/
|
||||||
- (NSArray *)itemsInRange:(NSRange)range
|
- (NSArray *)itemsInRange:(NSRange)aRange
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method elements
|
@method allItemsInReferenceFrame:
|
||||||
@brief Returns an array of all elements in the receiver.
|
@brief Returns an array of all items in the receiver for the specified
|
||||||
|
reference frame.
|
||||||
|
|
||||||
@discussion The elements in the returned array are not copied before they are
|
@discussion The elements in the returned array are not copied before they are
|
||||||
returned.
|
returned so be aware that mutations to any of the returned
|
||||||
|
objects will be reflected in the receiver.
|
||||||
|
|
||||||
@return An array of all elements from the receiver.
|
@return An array of all items in the receiver.
|
||||||
*/
|
*/
|
||||||
- (NSArray *)allItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;
|
- (NSArray *)allItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
@@ -285,7 +379,7 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
|
|
||||||
@param indexPath
|
@param indexPath
|
||||||
The index path the required object is located at. The indexes are
|
The index path the required object is located at. The indexes are
|
||||||
expressed in the indexed reference frame.
|
expressed in the element reference frame.
|
||||||
|
|
||||||
@return The element located at @c indexPath. The element is not copied
|
@return The element located at @c indexPath. The element is not copied
|
||||||
before it is returned. Be aware of the fact that any mutations
|
before it is returned. Be aware of the fact that any mutations
|
||||||
@@ -293,19 +387,127 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
*/
|
*/
|
||||||
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
- (NSUInteger)convertIndex:(NSUInteger)index
|
|
||||||
|
/*!
|
||||||
|
@method convertIndex:fromReferenceFrame:toReferenceFrame:
|
||||||
|
@brief Converts an index from one reference frame to another.
|
||||||
|
|
||||||
|
@discussion This method ignores any offsets into items the conversion between
|
||||||
|
reference frames can cause. If you are interested in the offset
|
||||||
|
use @c -convertIndex:fromReferenceFrame:toReferenceFrame:offset:
|
||||||
|
instead.
|
||||||
|
|
||||||
|
@param anIndex
|
||||||
|
The index to be converted.
|
||||||
|
|
||||||
|
@param fromReferenceFrame
|
||||||
|
The reference frame @c anIndex is specified in.
|
||||||
|
|
||||||
|
@param toReferenceFrame
|
||||||
|
The reference frame @c anIndex should be converted to.
|
||||||
|
|
||||||
|
@return An index specified in the @c toReferenceFrame. If @c anIndex
|
||||||
|
specifies a location inside an item in the @c toReferenceFrame
|
||||||
|
the index of the corresponding item is returned.
|
||||||
|
*/
|
||||||
|
- (NSUInteger)convertIndex:(NSUInteger)anIndex
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame;
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame;
|
||||||
|
|
||||||
- (NSUInteger)convertIndex:(NSUInteger)index
|
|
||||||
|
/*!
|
||||||
|
@method convertIndex:fromReferenceFrame:toReferenceFrame:offset:
|
||||||
|
@brief Converts an index from one reference frame to another.
|
||||||
|
|
||||||
|
@discussion If @c anIndex specifies a location inside an item in the @c
|
||||||
|
toReferenceFrame the index of the corresponding item is returned.
|
||||||
|
|
||||||
|
@param anIndex
|
||||||
|
The index to be converted.
|
||||||
|
|
||||||
|
@param fromReferenceFrame
|
||||||
|
The reference frame @c anIndex is specified in.
|
||||||
|
|
||||||
|
@param toReferenceFrame
|
||||||
|
The reference frame @c anIndex should be converted to.
|
||||||
|
|
||||||
|
@param offset
|
||||||
|
This output parameter will be set to the number of symbols that
|
||||||
|
are between the location specified by @c anIndex and the index
|
||||||
|
that is actually returned. The offset is specified in the symbol
|
||||||
|
reference frame. If you are not interested in the offset pass
|
||||||
|
@c NULL.
|
||||||
|
|
||||||
|
@return An index specified in the @c toReferenceFrame corresponding to
|
||||||
|
@c anIndex.
|
||||||
|
*/
|
||||||
|
- (NSUInteger)convertIndex:(NSUInteger)anIndex
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||||
offset:(NSUInteger *)offset;
|
offset:(out NSUInteger *)offset;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method convertRange:fromReferenceFrame:toReferenceFrame:
|
||||||
|
@brief Converts a range from one reference frame to another.
|
||||||
|
|
||||||
|
@discussion This method just converts the location and target of the range
|
||||||
|
separately using @c
|
||||||
|
-convertIndex:fromReferenceFrame:toReferenceFrame:. This method
|
||||||
|
ensures that the returned range definitely includes all items
|
||||||
|
that were specified by @c aRange.
|
||||||
|
|
||||||
|
This method ignores the possibility that the returned range may
|
||||||
|
include more than @a aRange. If you need that information use
|
||||||
|
@c -convertRange:fromReferenceFrame:toReferenceFrame:leadingOffset:trailingOffset:.
|
||||||
|
|
||||||
|
@param aRange
|
||||||
|
The range to be converted.
|
||||||
|
|
||||||
|
@param fromReferenceFrame
|
||||||
|
The reference frame @c aRange is specified in.
|
||||||
|
|
||||||
|
@param toReferenceFrame
|
||||||
|
The reference frame @c aRange is to be converted to.
|
||||||
|
|
||||||
|
@return A range in the @c toReferenceFrame that includes the the items
|
||||||
|
specified by @c aRange.
|
||||||
|
*/
|
||||||
- (NSRange)convertRange:(NSRange)aRange
|
- (NSRange)convertRange:(NSRange)aRange
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame;
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method convertRange:fromReferenceFrame:toReferenceFrame:leadingOffset:trailingOffset:
|
||||||
|
@brief Converts a range from one reference frame to another.
|
||||||
|
|
||||||
|
@discussion This method just converts the location and target of the range
|
||||||
|
separately using @c
|
||||||
|
-convertIndex:fromReferenceFrame:toReferenceFrame:. This method
|
||||||
|
ensures that the returned range definitely includes all items
|
||||||
|
that were specified by @c aRange.
|
||||||
|
|
||||||
|
@param aRange
|
||||||
|
The range to be converted.
|
||||||
|
|
||||||
|
@param fromReferenceFrame
|
||||||
|
The reference frame @c aRange is specified in.
|
||||||
|
|
||||||
|
@param toReferenceFrame
|
||||||
|
The reference frame @c aRange is to be converted to.
|
||||||
|
|
||||||
|
@param leadingOffset
|
||||||
|
The offset of the location of the returned range in respect to
|
||||||
|
the location of @c aRange.
|
||||||
|
|
||||||
|
@param trailingOffset
|
||||||
|
The offset of the last index in the range in respect to the last
|
||||||
|
index of @c aRange.
|
||||||
|
|
||||||
|
@return A range in the @c toReferenceFrame that includes the the items
|
||||||
|
specified by @c aRange.
|
||||||
|
*/
|
||||||
- (NSRange)convertRange:(NSRange)aRange
|
- (NSRange)convertRange:(NSRange)aRange
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||||
@@ -314,17 +516,19 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
|
|
||||||
|
|
||||||
#pragma mark Mutating Expressions
|
#pragma mark Mutating Expressions
|
||||||
|
/*!
|
||||||
|
@methodgroup Mutating Expressions
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method replaceSymbolsInRange:withElements:
|
@method replaceItemsInRange:referenceFrame:withElements:
|
||||||
@brief Replaces the elements in the given range with the contents of the
|
@brief Replaces the elements in the given range with the contents of the
|
||||||
@c elements array.
|
@c elements array.
|
||||||
|
|
||||||
@discussion This is the most primitive mutation method of @c MPExpression.
|
@discussion This is the most primitive mutation method of @c MPExpression.
|
||||||
Every other mutating method utlimately must call this method.
|
Every other mutating method utlimately must call this method.
|
||||||
|
|
||||||
|
|
||||||
After the receiver has been mutated the integrety of the receiver
|
After the receiver has been mutated the integrety of the receiver
|
||||||
is restored. That basically means that subsequent strings are
|
is restored. That basically means that subsequent strings are
|
||||||
joined and empty strings removed. After restoring integrity the
|
joined and empty strings removed. After restoring integrity the
|
||||||
@@ -333,35 +537,98 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
itself. For more information see the documentation on that
|
itself. For more information see the documentation on that
|
||||||
method.
|
method.
|
||||||
|
|
||||||
@param range
|
@param aRange
|
||||||
The @c range of symbols (including functions) to replace
|
The @c range of symbols (including functions) to replace.
|
||||||
specified in the located reference frame.
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame @c aRange is specified in.
|
||||||
|
|
||||||
@param elements
|
@param elements
|
||||||
The elements that should replace the symbols specified by @c
|
The elements that should replace the symbols specified by @c
|
||||||
range.
|
range.
|
||||||
*/
|
*/
|
||||||
- (void)replaceItemsInRange:(NSRange)range
|
- (void)replaceItemsInRange:(NSRange)aRange
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
withElements:(NSArray *)elements;
|
withElements:(NSArray *)elements;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method subexpressionFromIndex:referenceFrame:
|
||||||
|
@brief Creates an expression from the items in the receiver from the
|
||||||
|
specified index to the end.
|
||||||
|
|
||||||
|
@discussion The items from the receiver are copied. Mutations to the returned
|
||||||
|
expression will not change the receiver.
|
||||||
|
|
||||||
|
@param from
|
||||||
|
The index from which to start constructing the subexpression.
|
||||||
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame @c from is specified in.
|
||||||
|
|
||||||
|
@return An expression containing the items from the given index to the
|
||||||
|
end.
|
||||||
|
*/
|
||||||
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
|
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method subexpressionToIndex:referenceFrame:
|
||||||
|
@brief Creates an expression from the items in the receiver from the
|
||||||
|
first item to the end.
|
||||||
|
|
||||||
|
@discussion The items from the receiver are copied. Mutations to the returned
|
||||||
|
expression will not change the receiver.
|
||||||
|
|
||||||
|
@param to
|
||||||
|
The index of the first element not to include in the newly
|
||||||
|
constructed subexpression.
|
||||||
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame @c to is specified in.
|
||||||
|
|
||||||
|
@return An expression containing the items from the first item to the
|
||||||
|
given index.
|
||||||
|
*/
|
||||||
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
|
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
- (MPExpression *)subexpressionWithRange:(NSRange)range
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method subexpressionWithRange:referenceFrame:
|
||||||
|
@brief Creates an expression from the items in the receiver within the
|
||||||
|
specified range.
|
||||||
|
|
||||||
|
@discussion The items from the receiver are copied. Mutations to the returned
|
||||||
|
expression will not change the receiver.
|
||||||
|
|
||||||
|
@param aRange
|
||||||
|
Specifies the items to be included in the newly created
|
||||||
|
subexpression.
|
||||||
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame @c aRange is specified in.
|
||||||
|
|
||||||
|
@return An expression containing the items in @c aRange.
|
||||||
|
*/
|
||||||
|
- (MPExpression *)subexpressionWithRange:(NSRange)aRange
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Evaluating Expressions
|
#pragma mark Evaluating Expressions
|
||||||
|
/*!
|
||||||
|
@methodgroup Evaluating Expressions
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method evaluateWitError:
|
@method evaluateWitError:
|
||||||
@brief Evaluates the receiving expression.
|
@brief Evaluates the receiver.
|
||||||
|
|
||||||
@discussion This is a convenience method for evaluating an expression. If you
|
@discussion This is a convenience method for evaluating an expression. If you
|
||||||
want more control over the evaluation process use the @c
|
want more control over the evaluation process use @c -parse
|
||||||
evaluator property of the receiver.
|
instead.
|
||||||
|
|
||||||
@param error
|
@param error
|
||||||
If the receiver (or any of its elements) contains a syntax error
|
If the receiver (or any of its elements) contains a syntax error
|
||||||
@@ -371,18 +638,36 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
|
|
||||||
@return The result of the evaluation or @c nil of the receiver could not
|
@return The result of the evaluation or @c nil of the receiver could not
|
||||||
be evaluated. In that case the @c error parameter is set to an
|
be evaluated. In that case the @c error parameter is set to an
|
||||||
appropriate value.
|
appropriate value. If @c NaN is returned it means there was a
|
||||||
|
math error. In most cases the error parameter contains an
|
||||||
|
appropriate description of the problem.
|
||||||
*/
|
*/
|
||||||
- (NSDecimalNumber *)evaluateWithError:(NSError *__autoreleasing *)error;
|
- (NSDecimalNumber *)evaluateWithError:(NSError *__autoreleasing *)error;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method parse
|
||||||
|
@brief Parses the receiver.
|
||||||
|
|
||||||
|
@discussion This method returns a valid object even if the expression
|
||||||
|
contains syntax errors. Send the returned object a @c -validate:
|
||||||
|
message to check for syntax errors before you evaluate it. For
|
||||||
|
more information on evaluation see the documentation of @c
|
||||||
|
MPExpressionTree.
|
||||||
|
|
||||||
|
@return A @c MPExpressionTree object that can evaluate the receiver.
|
||||||
|
*/
|
||||||
- (MPExpressionTree *)parse;
|
- (MPExpressionTree *)parse;
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Notifications
|
#pragma mark Notifications
|
||||||
// All notification methods should create a new rangePath with the receiver's index added to the beginning of the path and then ascend the message to it's parent
|
/*!
|
||||||
|
@methodgroup Notifications
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method didChangeElementsInIndexedRangePath:replacementLength:
|
@method didChangeElementsInRangePath:replacementLength:
|
||||||
@brief Called after the receiver has been mutated.
|
@brief Called after the receiver has been mutated.
|
||||||
|
|
||||||
@discussion This method does nothing more than notify it's parent that it has
|
@discussion This method does nothing more than notify it's parent that it has
|
||||||
@@ -395,77 +680,165 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
|||||||
@param rangePath
|
@param rangePath
|
||||||
The range path at which the receiver was changed starting at the
|
The range path at which the receiver was changed starting at the
|
||||||
receiver. The range addressed by @c rangePath is expressed in the
|
receiver. The range addressed by @c rangePath is expressed in the
|
||||||
indexed reference frame.
|
element reference frame.
|
||||||
|
|
||||||
@param replacementLength
|
@param replacementLength
|
||||||
The number of elements replacing the elements specified by @c
|
The number of elements replacing the elements specified by @c
|
||||||
rangePath.
|
rangePath (also specified in the element reference frame).
|
||||||
*/
|
*/
|
||||||
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
replacementLength:(NSUInteger)replacementLength;
|
replacementLength:(NSUInteger)replacementLength;
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Basic NSObject Methods
|
|
||||||
// TODO: Check this
|
|
||||||
// - (BOOL)isEqualToExpression:(MPExpression *)anExpression;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@interface MPExpression (MPExpressionConvenience)
|
@interface MPExpression (MPExpressionConvenience)
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Querying Expressions
|
#pragma mark Querying Expressions
|
||||||
|
/*!
|
||||||
|
@methodgroup Querying Expressions
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method countElements
|
||||||
|
@brief Returns the number of elements in the receiver.
|
||||||
|
|
||||||
|
@return The number of elements in the receiver expressed in the element
|
||||||
|
reference frame.
|
||||||
|
*/
|
||||||
- (NSUInteger)countElements;
|
- (NSUInteger)countElements;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method countSymbols
|
||||||
|
@brief Returns the number of symbols in the receiver.
|
||||||
|
|
||||||
|
@return The number of symbols in the receiver expressed in the symbol
|
||||||
|
reference frame.
|
||||||
|
*/
|
||||||
- (NSUInteger)countSymbols;
|
- (NSUInteger)countSymbols;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method countTokens
|
||||||
|
@brief Returns the number of tokens in the receiver.
|
||||||
|
|
||||||
|
@return The number of tokens in the receiver expressed in the token
|
||||||
|
reference frame.
|
||||||
|
*/
|
||||||
- (NSUInteger)countTokens;
|
- (NSUInteger)countTokens;
|
||||||
|
|
||||||
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)index;
|
|
||||||
- (id<MPExpressionElement>)symbolAtIndex:(NSUInteger)index;
|
/*!
|
||||||
- (id<MPToken>)tokenAtIndex:(NSUInteger)index;
|
@method elementAtIndex:
|
||||||
|
@brief Returns the element at the specified index.
|
||||||
|
|
||||||
|
@param anIndex
|
||||||
|
The index of the element specified in the element reference
|
||||||
|
frame.
|
||||||
|
|
||||||
|
@return The element at @c anIndex.
|
||||||
|
*/
|
||||||
|
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method symbolAtIndex:
|
||||||
|
@brief Returns the symbol at the specified index.
|
||||||
|
|
||||||
|
@param anIndex
|
||||||
|
The index of the symbol specified in the symbol reference frame.
|
||||||
|
|
||||||
|
@return The symbol at @c anIndex.
|
||||||
|
*/
|
||||||
|
- (id<MPExpressionElement>)symbolAtIndex:(NSUInteger)anIndex;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method tokenAtIndex:
|
||||||
|
@brief Returns the token at the specified index.
|
||||||
|
|
||||||
|
@param anIndex
|
||||||
|
The index of the token specified in the token reference frame.
|
||||||
|
|
||||||
|
@return The token at @c anIndex.
|
||||||
|
*/
|
||||||
|
- (id<MPToken>)tokenAtIndex:(NSUInteger)anIndex;
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Mutating Expressions
|
#pragma mark Mutating Expressions
|
||||||
|
/*!
|
||||||
|
@methodgroup Mutating Expressions
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method appendElement:
|
@method appendElement:
|
||||||
@brief Appends @c anElement to the receiver.
|
@brief Appends @c anElement to the receiver.
|
||||||
|
|
||||||
@param anElement
|
@param anElement
|
||||||
The element to append to the receiver.
|
The element to append to the receiver.
|
||||||
*/
|
*/
|
||||||
- (void)appendElement:(id<MPExpressionElement>)anElement;
|
- (void)appendElement:(id<MPExpressionElement>)anElement;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method appendElements:
|
@method appendElements:
|
||||||
@brief Appends the objects from @c elements to the receiver.
|
@brief Appends the objects from @c elements to the receiver.
|
||||||
|
|
||||||
@param elements
|
@param elements
|
||||||
The elements to append to the receiver.
|
The elements to append to the receiver.
|
||||||
*/
|
*/
|
||||||
- (void)appendElements:(NSArray *)elements;
|
- (void)appendElements:(NSArray *)elements;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method insertElement:atIndex:referenceFrame:
|
||||||
|
@brief Inserts @c anElement at the specified index.
|
||||||
|
|
||||||
|
@param anElement
|
||||||
|
The element to be inserted.
|
||||||
|
|
||||||
|
@param index
|
||||||
|
The index where to insert @c anElement.
|
||||||
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame @c index is specified in.
|
||||||
|
*/
|
||||||
- (void)insertElement:(id<MPExpressionElement>)anElement
|
- (void)insertElement:(id<MPExpressionElement>)anElement
|
||||||
atIndex:(NSUInteger)index
|
atIndex:(NSUInteger)index
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method insertElements:atIndex:referenceFrame:
|
||||||
|
@brief Inserts @c elements at the specified index.
|
||||||
|
|
||||||
|
@param elements
|
||||||
|
The elements to be inserted.
|
||||||
|
|
||||||
|
@param index
|
||||||
|
The index where to insert @c elements.
|
||||||
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame @c index is specified in.
|
||||||
|
*/
|
||||||
- (void)insertElements:(NSArray *)elements
|
- (void)insertElements:(NSArray *)elements
|
||||||
atIndex:(NSUInteger)index
|
atIndex:(NSUInteger)index
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method deleteElementsInRange:
|
@method deleteElementsInRange:
|
||||||
@brief Removes the elements specified by @c range from the receiver.
|
@brief Removes the elements specified by @c range from the receiver.
|
||||||
|
|
||||||
@discussion The range is specified in the length reference frame.
|
@param range
|
||||||
|
The range of items to remove from the receiver.
|
||||||
|
|
||||||
If @c range exceeds the receiver's bounds a @c NSRangeException
|
@param referenceFrame
|
||||||
is raised.
|
The reference frame @c range is specified in.
|
||||||
|
|
||||||
@param range
|
|
||||||
The range to remove from the receiver.
|
|
||||||
*/
|
*/
|
||||||
- (void)deleteElementsInRange:(NSRange)range
|
- (void)deleteElementsInRange:(NSRange)range
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|||||||
@@ -20,12 +20,16 @@
|
|||||||
|
|
||||||
#import "NSIndexPath+MPAdditions.h"
|
#import "NSIndexPath+MPAdditions.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NSString *const MPIllegalElementException = @"MPIllegalElementException";
|
||||||
NSString *const MPIllegalElementExceptionElementKey = @"MPIllegalElementExceptionElementKey";
|
NSString *const MPIllegalElementExceptionElementKey = @"MPIllegalElementExceptionElementKey";
|
||||||
|
|
||||||
NSString *const MPMathKitErrorDomain = @"MPMathKitErrorDomain";
|
NSString *const MPMathKitErrorDomain = @"MPMathKitErrorDomain";
|
||||||
NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@interface MPExpression () {
|
@interface MPExpression () {
|
||||||
NSMutableArray * _elements;
|
NSMutableArray * _elements;
|
||||||
}
|
}
|
||||||
@@ -62,11 +66,13 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return [self initWithElements:@[]];
|
return [self initWithElements:@[]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)initWithElement:(id<MPExpressionElement>)element
|
- (instancetype)initWithElement:(id<MPExpressionElement>)element
|
||||||
{
|
{
|
||||||
return [self initWithElements:@[element]];
|
return [self initWithElements:@[element]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)initWithElements:(NSArray *)elements
|
- (instancetype)initWithElements:(NSArray *)elements
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -96,7 +102,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
{
|
{
|
||||||
for (id element in elements) {
|
for (id element in elements) {
|
||||||
if (![element conformsToProtocol:@protocol(MPExpressionElement)]) {
|
if (![element conformsToProtocol:@protocol(MPExpressionElement)]) {
|
||||||
@throw [NSException exceptionWithName:@"MPIllegalElementException"
|
@throw [NSException exceptionWithName:MPIllegalElementException
|
||||||
reason:@"Elements must conform to the MPExpressionElement protocol."
|
reason:@"Elements must conform to the MPExpressionElement protocol."
|
||||||
userInfo:@{MPIllegalElementExceptionElementKey: element}];
|
userInfo:@{MPIllegalElementExceptionElementKey: element}];
|
||||||
}
|
}
|
||||||
@@ -141,6 +147,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Querying Expressions
|
#pragma mark Querying Expressions
|
||||||
|
|
||||||
|
|
||||||
@@ -152,6 +159,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return [self.parent rootExpression];
|
return [self.parent rootExpression];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)indexPath
|
- (NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (self.parent) {
|
if (self.parent) {
|
||||||
@@ -162,6 +170,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)countItemsInReferenceFrame:(MPReferenceFrame)referenceFrame
|
- (NSUInteger)countItemsInReferenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
switch (referenceFrame) {
|
switch (referenceFrame) {
|
||||||
@@ -182,6 +191,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id)itemAtIndex:(NSUInteger)anIndex
|
- (id)itemAtIndex:(NSUInteger)anIndex
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
@@ -210,6 +220,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
|
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
@@ -219,20 +230,23 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return _elements[elementIndex];
|
return _elements[elementIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#warning If multiple equal expressions exist errors may occur...
|
#warning If multiple equal expressions exist errors may occur...
|
||||||
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element
|
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element
|
||||||
{
|
{
|
||||||
return [_elements indexOfObject:element];
|
return [_elements indexOfObject:element];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)itemsInRange:(NSRange)range
|
|
||||||
|
- (NSArray *)itemsInRange:(NSRange)aRange
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
MPExpression *subexpression = [self subexpressionWithRange:range
|
MPExpression *subexpression = [self subexpressionWithRange:aRange
|
||||||
referenceFrame:referenceFrame];
|
referenceFrame:referenceFrame];
|
||||||
return [subexpression allItemsInReferenceFrame:referenceFrame];
|
return [subexpression allItemsInReferenceFrame:referenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSArray *)allItemsInReferenceFrame:(MPReferenceFrame)referenceFrame
|
- (NSArray *)allItemsInReferenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
switch (referenceFrame) {
|
switch (referenceFrame) {
|
||||||
@@ -259,6 +273,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (indexPath.length == 0) {
|
if (indexPath.length == 0) {
|
||||||
@@ -275,26 +290,28 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)convertIndex:(NSUInteger)index
|
|
||||||
|
- (NSUInteger)convertIndex:(NSUInteger)anIndex
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||||
{
|
{
|
||||||
return [self convertIndex:index
|
return [self convertIndex:anIndex
|
||||||
fromReferenceFrame:fromReferenceFrame
|
fromReferenceFrame:fromReferenceFrame
|
||||||
toReferenceFrame:toReferenceFrame
|
toReferenceFrame:toReferenceFrame
|
||||||
offset:NULL];
|
offset:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)convertIndex:(NSUInteger)index
|
|
||||||
|
- (NSUInteger)convertIndex:(NSUInteger)anIndex
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||||
offset:(NSUInteger *)offset
|
offset:(out NSUInteger *)offset
|
||||||
{
|
{
|
||||||
if (fromReferenceFrame == toReferenceFrame || index == 0) {
|
if (fromReferenceFrame == toReferenceFrame || anIndex == 0) {
|
||||||
if (offset) {
|
if (offset) {
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
}
|
}
|
||||||
return index;
|
return anIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSUInteger symbolIndex __block = 0;
|
NSUInteger symbolIndex __block = 0;
|
||||||
@@ -302,16 +319,16 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
case MPElementReferenceFrame:
|
case MPElementReferenceFrame:
|
||||||
[_elements enumerateObjectsUsingBlock:^(id<MPExpressionElement> obj, NSUInteger idx, BOOL *stop) {
|
[_elements enumerateObjectsUsingBlock:^(id<MPExpressionElement> obj, NSUInteger idx, BOOL *stop) {
|
||||||
symbolIndex += obj.length;
|
symbolIndex += obj.length;
|
||||||
*stop = idx >= index - 1;
|
*stop = idx >= anIndex - 1;
|
||||||
}];
|
}];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MPSymbolReferenceFrame:
|
case MPSymbolReferenceFrame:
|
||||||
symbolIndex = index;
|
symbolIndex = anIndex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MPTokenReferenceFrame:
|
case MPTokenReferenceFrame:
|
||||||
symbolIndex = [self.tokens[index] range].location;
|
symbolIndex = [self.tokens[anIndex] range].location;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,7 +368,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
if (NSMaxRange(token.range) < symbolIndex || token.range.location > symbolIndex) {
|
if (NSMaxRange(token.range) < symbolIndex || token.range.location > symbolIndex) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NSUInteger offsetInToken = index - token.range.location;
|
NSUInteger offsetInToken = anIndex - token.range.location;
|
||||||
if (offsetInToken == token.range.length) {
|
if (offsetInToken == token.range.length) {
|
||||||
offsetInToken = 0;
|
offsetInToken = 0;
|
||||||
tokenIndex++;
|
tokenIndex++;
|
||||||
@@ -367,6 +384,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSRange)convertRange:(NSRange)aRange
|
- (NSRange)convertRange:(NSRange)aRange
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||||
@@ -378,6 +396,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
trailingOffset:NULL];
|
trailingOffset:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSRange)convertRange:(NSRange)aRange
|
- (NSRange)convertRange:(NSRange)aRange
|
||||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||||
@@ -399,20 +418,21 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
#pragma mark Mutating Expressions
|
#pragma mark Mutating Expressions
|
||||||
|
|
||||||
|
|
||||||
- (void)replaceItemsInRange:(NSRange)range
|
- (void)replaceItemsInRange:(NSRange)aRange
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
withElements:(NSArray *)elements
|
withElements:(NSArray *)elements
|
||||||
{
|
{
|
||||||
NSUInteger start = [self convertIndex:range.location
|
NSUInteger start = [self convertIndex:aRange.location
|
||||||
fromReferenceFrame:referenceFrame
|
fromReferenceFrame:referenceFrame
|
||||||
toReferenceFrame:MPSymbolReferenceFrame];
|
toReferenceFrame:MPSymbolReferenceFrame];
|
||||||
NSUInteger end = [self convertIndex:NSMaxRange(range)
|
NSUInteger end = [self convertIndex:NSMaxRange(aRange)
|
||||||
fromReferenceFrame:referenceFrame
|
fromReferenceFrame:referenceFrame
|
||||||
toReferenceFrame:MPSymbolReferenceFrame];
|
toReferenceFrame:MPSymbolReferenceFrame];
|
||||||
[self _replaceSymbolsInRange:NSMakeRange(start, end - start)
|
[self _replaceSymbolsInRange:NSMakeRange(start, end - start)
|
||||||
withElements:elements];
|
withElements:elements];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)_replaceSymbolsInRange:(NSRange)range
|
- (void)_replaceSymbolsInRange:(NSRange)range
|
||||||
withElements:(NSArray *)elements
|
withElements:(NSArray *)elements
|
||||||
{
|
{
|
||||||
@@ -439,8 +459,14 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
// Perform the replacement
|
// Perform the replacement
|
||||||
NSMutableArray *newElements = [[NSMutableArray alloc] initWithArray:elements
|
NSMutableArray *newElements = [[NSMutableArray alloc] initWithArray:elements
|
||||||
copyItems:YES];
|
copyItems:YES];
|
||||||
|
NSArray *removedElements = [_elements subarrayWithRange:NSMakeRange(startIndex, endIndex-startIndex)];
|
||||||
[_elements replaceObjectsInRange:NSMakeRange(startIndex, endIndex-startIndex)
|
[_elements replaceObjectsInRange:NSMakeRange(startIndex, endIndex-startIndex)
|
||||||
withObjectsFromArray:newElements];
|
withObjectsFromArray:newElements];
|
||||||
|
for (id<MPExpressionElement> element in removedElements) {
|
||||||
|
if ([element isFunction]) {
|
||||||
|
((MPFunction *)element).parent = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_tokenCache = nil;
|
_tokenCache = nil;
|
||||||
|
|
||||||
@@ -469,6 +495,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
replacementLength:_replacementLength];
|
replacementLength:_replacementLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)_splitElementsAtLocation:(NSUInteger)location
|
- (BOOL)_splitElementsAtLocation:(NSUInteger)location
|
||||||
insertionIndex:(out NSUInteger *)insertionIndex
|
insertionIndex:(out NSUInteger *)insertionIndex
|
||||||
{
|
{
|
||||||
@@ -494,6 +521,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return splitOffset != 0;
|
return splitOffset != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
|
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
@@ -501,6 +529,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
referenceFrame:referenceFrame];
|
referenceFrame:referenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
|
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
@@ -508,12 +537,13 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
referenceFrame:referenceFrame];
|
referenceFrame:referenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPExpression *)subexpressionWithRange:(NSRange)range
|
|
||||||
|
- (MPExpression *)subexpressionWithRange:(NSRange)aRange
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
MPExpression *subexpression = [self copy];
|
MPExpression *subexpression = [self copy];
|
||||||
NSRange preceedingRange = NSMakeRange(0, range.location);
|
NSRange preceedingRange = NSMakeRange(0, aRange.location);
|
||||||
NSUInteger firstOut = NSMaxRange(range);
|
NSUInteger firstOut = NSMaxRange(aRange);
|
||||||
NSRange exceedingRange = NSMakeRange(firstOut, [self countItemsInReferenceFrame:referenceFrame] - firstOut);
|
NSRange exceedingRange = NSMakeRange(firstOut, [self countItemsInReferenceFrame:referenceFrame] - firstOut);
|
||||||
[subexpression deleteElementsInRange:exceedingRange
|
[subexpression deleteElementsInRange:exceedingRange
|
||||||
referenceFrame:referenceFrame];
|
referenceFrame:referenceFrame];
|
||||||
@@ -522,8 +552,10 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return subexpression;
|
return subexpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Evaluating Expressions
|
#pragma mark Evaluating Expressions
|
||||||
|
|
||||||
|
|
||||||
- (NSDecimalNumber *)evaluateWithError:(NSError *__autoreleasing *)error
|
- (NSDecimalNumber *)evaluateWithError:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
MPExpressionTree *tree = [self parse];
|
MPExpressionTree *tree = [self parse];
|
||||||
@@ -537,6 +569,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return [[MPExpressionTree alloc] initWithTokenStream:tokenStream];
|
return [[MPExpressionTree alloc] initWithTokenStream:tokenStream];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Notifications
|
#pragma mark Notifications
|
||||||
|
|
||||||
|
|
||||||
@@ -553,27 +586,6 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
#pragma mark Basic NSObject Methods
|
#pragma mark Basic NSObject Methods
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
- (BOOL)isEqual:(id)object
|
|
||||||
{
|
|
||||||
if (self == object) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
if (object == nil) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
if (![object isKindOfClass:[MPExpression class]]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
return [self isEqualToExpression:(MPExpression *)object];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isEqualToExpression:(MPExpression *)anExpression
|
|
||||||
{
|
|
||||||
return [self.elements isEqualToArray:anExpression.elements];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
#warning Bad Implementation
|
#warning Bad Implementation
|
||||||
@@ -608,6 +620,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)hash
|
- (NSUInteger)hash
|
||||||
{
|
{
|
||||||
return [_elements hash];
|
return [_elements hash];
|
||||||
@@ -633,6 +646,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
return [self initWithElements:[aDecoder decodeObject]];
|
return [self initWithElements:[aDecoder decodeObject]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||||
{
|
{
|
||||||
[aCoder encodeObject:_elements];
|
[aCoder encodeObject:_elements];
|
||||||
@@ -641,51 +655,60 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPExpression (MPExpressionConvenience)
|
@implementation MPExpression (MPExpressionConvenience)
|
||||||
|
|
||||||
#pragma mark Querying Expressions
|
#pragma mark Querying Expressions
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)countElements
|
- (NSUInteger)countElements
|
||||||
{
|
{
|
||||||
return [self countItemsInReferenceFrame:MPElementReferenceFrame];
|
return [self countItemsInReferenceFrame:MPElementReferenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)countSymbols
|
- (NSUInteger)countSymbols
|
||||||
{
|
{
|
||||||
return [self countItemsInReferenceFrame:MPSymbolReferenceFrame];
|
return [self countItemsInReferenceFrame:MPSymbolReferenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)countTokens
|
- (NSUInteger)countTokens
|
||||||
{
|
{
|
||||||
return [self countItemsInReferenceFrame:MPTokenReferenceFrame];
|
return [self countItemsInReferenceFrame:MPTokenReferenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)index
|
|
||||||
|
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
|
||||||
{
|
{
|
||||||
return [self itemAtIndex:index
|
return [self itemAtIndex:anIndex
|
||||||
referenceFrame:MPElementReferenceFrame];
|
referenceFrame:MPElementReferenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<MPExpressionElement>)symbolAtIndex:(NSUInteger)index
|
|
||||||
|
- (id<MPExpressionElement>)symbolAtIndex:(NSUInteger)anIndex
|
||||||
{
|
{
|
||||||
return [self itemAtIndex:index
|
return [self itemAtIndex:anIndex
|
||||||
referenceFrame:MPSymbolReferenceFrame];
|
referenceFrame:MPSymbolReferenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<MPToken>)tokenAtIndex:(NSUInteger)index
|
|
||||||
|
- (id<MPToken>)tokenAtIndex:(NSUInteger)anIndex
|
||||||
{
|
{
|
||||||
return [self itemAtIndex:index
|
return [self itemAtIndex:anIndex
|
||||||
referenceFrame:MPTokenReferenceFrame];
|
referenceFrame:MPTokenReferenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Mutating Expressions
|
#pragma mark Mutating Expressions
|
||||||
|
|
||||||
|
|
||||||
- (void)appendElement:(id<MPExpressionElement>)anElement
|
- (void)appendElement:(id<MPExpressionElement>)anElement
|
||||||
{
|
{
|
||||||
[self appendElements:@[anElement]];
|
[self appendElements:@[anElement]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)appendElements:(NSArray *)elements
|
- (void)appendElements:(NSArray *)elements
|
||||||
{
|
{
|
||||||
[self replaceItemsInRange:NSMakeRange([self countItemsInReferenceFrame:MPSymbolReferenceFrame], 0)
|
[self replaceItemsInRange:NSMakeRange([self countItemsInReferenceFrame:MPSymbolReferenceFrame], 0)
|
||||||
@@ -693,6 +716,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
withElements:elements];
|
withElements:elements];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)insertElement:(id<MPExpressionElement>)anElement
|
- (void)insertElement:(id<MPExpressionElement>)anElement
|
||||||
atIndex:(NSUInteger)index
|
atIndex:(NSUInteger)index
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
@@ -702,6 +726,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
referenceFrame:referenceFrame];
|
referenceFrame:referenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)insertElements:(NSArray *)elements
|
- (void)insertElements:(NSArray *)elements
|
||||||
atIndex:(NSUInteger)index
|
atIndex:(NSUInteger)index
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
@@ -711,6 +736,7 @@ NSString *const MPExpressionPathErrorKey = @"MPExpressionPathErrorKey";
|
|||||||
withElements:elements];
|
withElements:elements];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)deleteElementsInRange:(NSRange)range
|
- (void)deleteElementsInRange:(NSRange)range
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,11 +6,52 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@protocol MPExpressionElement
|
||||||
|
@brief This protocol defines the functionality an element in an
|
||||||
|
expression must have.
|
||||||
|
*/
|
||||||
@protocol MPExpressionElement <NSObject, NSCopying, NSCoding>
|
@protocol MPExpressionElement <NSObject, NSCopying, NSCoding>
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method isString
|
||||||
|
@brief Returns wether the receiver is a string.
|
||||||
|
|
||||||
|
@discussion A string is defined by being an instance of @c NSString. If this
|
||||||
|
method returns @c YES you can be sure it is an @c NSString
|
||||||
|
instance.
|
||||||
|
|
||||||
|
@return @c YES if the receiver is a string, @c NO otherwise.
|
||||||
|
*/
|
||||||
- (BOOL)isString;
|
- (BOOL)isString;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method isFunction
|
||||||
|
@brief Returns wether the receiver is a function.
|
||||||
|
|
||||||
|
@discussion A function is defined by being an instance of @c MPFunction. If
|
||||||
|
this method returns @c YES you can be sure it is a @c MPFunction
|
||||||
|
instance.
|
||||||
|
|
||||||
|
@return @c YES if the receiver is a function, @c NO otherwise.
|
||||||
|
*/
|
||||||
- (BOOL)isFunction;
|
- (BOOL)isFunction;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method length
|
||||||
|
@brief Calculates the length of the receiver.
|
||||||
|
|
||||||
|
@discussion The length of a @c MPExpressionElement is the number of symbols
|
||||||
|
it consists of. For strings this is the number of characters in
|
||||||
|
it. Functions have a length of @c 1.
|
||||||
|
|
||||||
|
@return The receiver's length.
|
||||||
|
*/
|
||||||
- (NSUInteger)length;
|
- (NSUInteger)length;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,10 +6,32 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPExpressionTokenizer, MPExpression;
|
@class MPExpressionTokenizer, MPExpression;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class MPExpressionTokenizer
|
||||||
|
@brief The expression tokenizer class convers an @c MPExpression
|
||||||
|
instance into an array of tokens.
|
||||||
|
*/
|
||||||
@interface MPExpressionTokenizer : NSObject
|
@interface MPExpressionTokenizer : NSObject
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method tokenizeExpression:
|
||||||
|
@brief Converts an @c MPExpression instance into an array of tokens.
|
||||||
|
|
||||||
|
@discussion The objects in the returned array all conform to the @c MPToken
|
||||||
|
protocol. Function tokens are not copied from the @c expression
|
||||||
|
so they can still be mutated.
|
||||||
|
|
||||||
|
@param expression
|
||||||
|
The expression to be tokenized.
|
||||||
|
|
||||||
|
@return An array of objects that conform to the @c MPToken protocol.
|
||||||
|
*/
|
||||||
+ (NSArray *)tokenizeExpression:(MPExpression *)expression; // Returns MPToken's
|
+ (NSArray *)tokenizeExpression:(MPExpression *)expression; // Returns MPToken's
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -15,8 +15,11 @@
|
|||||||
|
|
||||||
#import "NSRegularExpression+MPParsingAdditions.h"
|
#import "NSRegularExpression+MPParsingAdditions.h"
|
||||||
|
|
||||||
|
|
||||||
#define MPRangeExists(range) (range.location != NSNotFound)
|
#define MPRangeExists(range) (range.location != NSNotFound)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPExpressionTokenizer
|
@implementation MPExpressionTokenizer
|
||||||
|
|
||||||
+ (NSArray *)tokenizeExpression:(MPExpression *)expression
|
+ (NSArray *)tokenizeExpression:(MPExpression *)expression
|
||||||
@@ -36,6 +39,8 @@
|
|||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+ (NSArray *)tokenizeElement:(NSString *)element
|
+ (NSArray *)tokenizeElement:(NSString *)element
|
||||||
elementSymbolIndex:(NSUInteger)symbolIndex
|
elementSymbolIndex:(NSUInteger)symbolIndex
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,13 +8,71 @@
|
|||||||
|
|
||||||
#import "MPExpressionTreeElement.h"
|
#import "MPExpressionTreeElement.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPExpressionTree;
|
@class MPExpressionTree;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class MPExpressionTree
|
||||||
|
@brief The @c MPExpressionTree class is the main interface for working
|
||||||
|
with the mathematical representation of an expression.
|
||||||
|
|
||||||
|
@discussion Expressions are represented as a tree structure of elements (all
|
||||||
|
of which must conform to the @c MPExpressionTreeElement
|
||||||
|
protocol). Most messages sent to instances of the @c
|
||||||
|
MPExpressionTree class are cascaded down different parts of an
|
||||||
|
expression in some way.
|
||||||
|
*/
|
||||||
@interface MPExpressionTree : NSObject <MPExpressionTreeElement>
|
@interface MPExpressionTree : NSObject <MPExpressionTreeElement>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property definedVariable
|
||||||
|
@brief The variable this expression defines.
|
||||||
|
|
||||||
|
@discussion A variable definition must be at the beginning of an expression.
|
||||||
|
If it defines a variable it must start with a single letter
|
||||||
|
followed by an equals sign. The single letter is the name of the
|
||||||
|
variable that is defined.
|
||||||
|
*/
|
||||||
@property (nonatomic, copy) NSString *definedVariable;
|
@property (nonatomic, copy) NSString *definedVariable;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property summands
|
||||||
|
@brief The summands that make up the receiver.
|
||||||
|
|
||||||
|
@discussion A expression mathematically can be interpreted as a series of
|
||||||
|
summands. Summands are the different pars of an expression that
|
||||||
|
are separated by + or - symbols. Every object in the returned
|
||||||
|
array is guaranteed to conform to the @c MPExpressionTreeElement
|
||||||
|
protocol.
|
||||||
|
*/
|
||||||
@property (readonly, nonatomic, strong) NSArray *summands;
|
@property (readonly, nonatomic, strong) NSArray *summands;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method validateExpectingVariableDefinition:error:
|
||||||
|
@brief Validates the receiver.
|
||||||
|
|
||||||
|
@discussion Using this method you can validate an expression that contains a
|
||||||
|
variable definition. If a variable definition is expected but not
|
||||||
|
found this method returns @c NO. Likewise @c NO is returned if
|
||||||
|
you do not expect a variable definition but one is found.
|
||||||
|
|
||||||
|
@param flag
|
||||||
|
Specifies wether or not to expect a variable definition at the
|
||||||
|
beginning of the expression.
|
||||||
|
|
||||||
|
@param error
|
||||||
|
If there is a syntax error in the receiver this parameter will be
|
||||||
|
set to an appropriate value. If you are not interested in the
|
||||||
|
type of syntax error pass @c NULL.
|
||||||
|
|
||||||
|
@return @c YES if the receiver is valid, @c NO otherwise. If @c NO is
|
||||||
|
returned the @c error parameter should be set to an appropriate
|
||||||
|
value.
|
||||||
|
*/
|
||||||
- (BOOL)validateExpectingVariableDefinition:(BOOL)flag
|
- (BOOL)validateExpectingVariableDefinition:(BOOL)flag
|
||||||
error:(NSError *__autoreleasing *)error;
|
error:(NSError *__autoreleasing *)error;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
#import "MPExpression.h"
|
#import "MPExpression.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPExpressionTree {
|
@implementation MPExpressionTree {
|
||||||
NSMutableArray *_summands;
|
NSMutableArray *_summands;
|
||||||
}
|
}
|
||||||
@@ -28,6 +30,7 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
|
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
|
||||||
{
|
{
|
||||||
self = [self init];
|
self = [self init];
|
||||||
@@ -51,17 +54,20 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSArray *)summands
|
- (NSArray *)summands
|
||||||
{
|
{
|
||||||
return _summands;
|
return _summands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)validate:(NSError *__autoreleasing *)error
|
- (BOOL)validate:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
return [self validateExpectingVariableDefinition:NO
|
return [self validateExpectingVariableDefinition:NO
|
||||||
error:error];
|
error:error];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)validateExpectingVariableDefinition:(BOOL)flag
|
- (BOOL)validateExpectingVariableDefinition:(BOOL)flag
|
||||||
error:(NSError *__autoreleasing *)error
|
error:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
@@ -100,6 +106,7 @@
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSDecimalNumber *)evaluate
|
- (NSDecimalNumber *)evaluate
|
||||||
{
|
{
|
||||||
NSDecimalNumber *value = [NSDecimalNumber zero];
|
NSDecimalNumber *value = [NSDecimalNumber zero];
|
||||||
|
|||||||
@@ -5,16 +5,85 @@
|
|||||||
// Created by Kim Wittenburg on 09.10.14.
|
// Created by Kim Wittenburg on 09.10.14.
|
||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
// TODO: Replace internal inconsistency exception with something else
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPTokenStream;
|
@class MPTokenStream;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@protocol MPExpressionTreeElement
|
||||||
|
@brief This protocol defines the methods that are essential for dealing
|
||||||
|
with an expression in a mathematical context.
|
||||||
|
|
||||||
|
@discussion Dealing with an expression in a mathematical context involves
|
||||||
|
anything from evaluation to transformation of expressions and
|
||||||
|
equations.
|
||||||
|
*/
|
||||||
@protocol MPExpressionTreeElement <NSObject>
|
@protocol MPExpressionTreeElement <NSObject>
|
||||||
@required
|
@required
|
||||||
|
|
||||||
- (instancetype)init;
|
|
||||||
|
/*!
|
||||||
|
@method initWithTokenStream:
|
||||||
|
@brief Initializes the expression tree element from the given token
|
||||||
|
strem.
|
||||||
|
|
||||||
|
@discussion This method consumes the tokens that make up this element. If the
|
||||||
|
token stream does not start with a token that is appropriate for
|
||||||
|
the initializied expression tree element a @c
|
||||||
|
NSInternalInconsistency exception is raised.
|
||||||
|
|
||||||
|
@param tokenStream
|
||||||
|
The token stream the receiver is to be initialized from.
|
||||||
|
|
||||||
|
@return A new instance.
|
||||||
|
*/
|
||||||
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream;
|
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method validate:
|
||||||
|
@brief Validates the receiver.
|
||||||
|
|
||||||
|
@discussion Validation should only check for syntax errors. Mathematical
|
||||||
|
errors like a division by @c 0 should be handled with in @c
|
||||||
|
-evaluate.
|
||||||
|
|
||||||
|
@param error
|
||||||
|
If there is a syntax error in the receiver this parameter should
|
||||||
|
be set to an appropriate value. If you are not interested in the
|
||||||
|
type of syntax error pass @c NULL.
|
||||||
|
|
||||||
|
@return @c YES if the receiver is valid, @c NO otherwise. If @c NO is
|
||||||
|
returned the @c error parameter should be set to an appropriate
|
||||||
|
value.
|
||||||
|
*/
|
||||||
- (BOOL)validate:(NSError *__autoreleasing *)error;
|
- (BOOL)validate:(NSError *__autoreleasing *)error;
|
||||||
- (NSDecimalNumber *)evaluate;
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method evaluate:
|
||||||
|
@brief Evaluates the receiver.
|
||||||
|
|
||||||
|
@discussion Evaluation does not take syntax errors into account. Before this
|
||||||
|
method is called you must call @c validate: to make sure that the
|
||||||
|
reciever is valid for evaluation. The result of evaluation with
|
||||||
|
@c -validate: returning @c NO may be unexpected or evaluation may
|
||||||
|
completely fail.
|
||||||
|
|
||||||
|
@param error
|
||||||
|
If any errors occur during evaluation (such as division by zero)
|
||||||
|
this parameter will be set to an appropriate value. If you are
|
||||||
|
not interested in errors pass @c NULL.
|
||||||
|
@warning This method is not responsible for syntax validation. Use @c
|
||||||
|
-validate: instead.
|
||||||
|
|
||||||
|
@return The result of the evaluationa or @c nil or @c NaN if evaluation
|
||||||
|
fails. If evaluation fails the @c error parameter will be set to
|
||||||
|
an apporpriate value.
|
||||||
|
*/
|
||||||
|
- (NSDecimalNumber *)evaluate:(NSError *__autoreleasing *)error;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,6 +9,13 @@
|
|||||||
#import "MPFunction.h"
|
#import "MPFunction.h"
|
||||||
#import "MPToken.h"
|
#import "MPToken.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@category MPFunction (MPToken)
|
||||||
|
@brief This category adds @c MPToken protocol conformance to the @c
|
||||||
|
MPFunction class.
|
||||||
|
*/
|
||||||
@interface MPFunction (MPToken) <MPToken>
|
@interface MPFunction (MPToken) <MPToken>
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
return MPGenericFunctionToken;
|
return MPGenericFunctionToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSRange)range
|
- (NSRange)range
|
||||||
{
|
{
|
||||||
NSUInteger selfIndex = [self.parent indexOfElement:self];
|
NSUInteger selfIndex = [self.parent indexOfElement:self];
|
||||||
@@ -26,11 +27,13 @@
|
|||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)exists
|
- (BOOL)exists
|
||||||
{
|
{
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)stringValue
|
- (NSString *)stringValue
|
||||||
{
|
{
|
||||||
return [self description];
|
return [self description];
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
|
|
||||||
#import "MPExpressionElement.h"
|
#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) \
|
#define MPFunctionAccessorImplementation(Accessor, variableName) \
|
||||||
- (void)set##Accessor:(MPExpression *)value \
|
- (void)set##Accessor:(MPExpression *)value \
|
||||||
{ \
|
{ \
|
||||||
@@ -17,51 +24,297 @@
|
|||||||
[self didChangeChildAtIndex:[self indexOfChild:variableName]]; \
|
[self didChangeChildAtIndex:[self indexOfChild:variableName]]; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPFunction, MPExpression, MPRangePath;
|
@class MPFunction, MPExpression, MPRangePath;
|
||||||
@protocol MPExpressionElement;
|
@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>
|
@interface MPFunction : NSObject <NSCoding, NSCopying, MPExpressionElement>
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
|
||||||
|
|
||||||
- (instancetype)init;
|
|
||||||
|
|
||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
// Subclasses should define accessor properties for all sub expressions, which, in the setter, should send didChangeElementAtRangePath:replacementLength: to self with a replacement length of 1.
|
/* 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
|
#pragma mark Working With the Expression Tree
|
||||||
@property (nonatomic, weak) MPExpression *parent; // Documentation: Do not set
|
/*!
|
||||||
|
@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;
|
- (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;
|
- (NSIndexPath *)indexPath;
|
||||||
|
|
||||||
- (NSArray *)childrenAccessors; // Override
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@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;
|
- (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;
|
- (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
|
- (void)setChild:(MPExpression *)child
|
||||||
atIndex:(NSUInteger)index;
|
atIndex:(NSUInteger)index;
|
||||||
|
|
||||||
- (NSArray *)children; // Indexes must equal the ones from the other methods
|
|
||||||
|
/*!
|
||||||
|
@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;
|
- (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;
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
#pragma mark Evaluating Functions
|
|
||||||
|
|
||||||
- (BOOL)validate:(NSError *__autoreleasing *)error; // Override
|
#pragma mark Notifications
|
||||||
- (NSDecimalNumber *)evaluate; // Override
|
/*!
|
||||||
|
@methodgroup Notifications
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma mark Messages
|
|
||||||
|
/*!
|
||||||
|
@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
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
replacementLength:(NSUInteger)replacementLength;
|
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;
|
- (void)didChangeChildAtIndex:(NSUInteger)index;
|
||||||
|
|
||||||
#pragma mark Working With Functions
|
@end
|
||||||
// - (BOOL)isEqualToFunction:(MPFunction *)aFunction; // Override
|
|
||||||
|
|
||||||
- (NSString *)description; // Should be overridden
|
|
||||||
- (NSUInteger)hash;
|
|
||||||
|
|
||||||
- (id)copyWithZone:(NSZone *)zone;
|
|
||||||
|
/*!
|
||||||
|
@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
|
@end
|
||||||
|
|||||||
@@ -12,9 +12,13 @@
|
|||||||
#import "MPRangePath.h"
|
#import "MPRangePath.h"
|
||||||
#import "NSIndexPath+MPAdditions.h"
|
#import "NSIndexPath+MPAdditions.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPFunction
|
@implementation MPFunction
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -29,35 +33,49 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
#pragma mark Working With the Expression Tree
|
||||||
|
|
||||||
|
|
||||||
- (MPExpression *)rootExpression
|
- (MPExpression *)rootExpression
|
||||||
{
|
{
|
||||||
return [self.parent rootExpression];
|
return [self.parent rootExpression];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)indexPath
|
- (NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
|
if (!self.parent) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
NSUInteger selfIndex = [self.parent indexOfElement:self];
|
NSUInteger selfIndex = [self.parent indexOfElement:self];
|
||||||
return [[self.parent indexPath] indexPathByAddingIndex:selfIndex];
|
return [[self.parent indexPath] indexPathByAddingIndex:selfIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)numberOfChildren
|
- (NSUInteger)numberOfChildren
|
||||||
{
|
{
|
||||||
return self.childrenAccessors.count;
|
return self.childrenAccessors.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (MPExpression *)childAtIndex:(NSUInteger)index
|
- (MPExpression *)childAtIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
return [self valueForKey:self.childrenAccessors[index]];
|
return [self valueForKey:self.childrenAccessors[index]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)setChild:(MPExpression *)child
|
- (void)setChild:(MPExpression *)child
|
||||||
atIndex:(NSUInteger)index
|
atIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
[self setValue:child forKey:self.childrenAccessors[index]];
|
[[self valueForKey:self.childrenAccessors[index]] setParent:nil];
|
||||||
|
[self setValue:child
|
||||||
|
forKey:self.childrenAccessors[index]];
|
||||||
|
child.parent = self;
|
||||||
[self didChangeChildAtIndex:index];
|
[self didChangeChildAtIndex:index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSArray *)children
|
- (NSArray *)children
|
||||||
{
|
{
|
||||||
NSUInteger childCount = [self numberOfChildren];
|
NSUInteger childCount = [self numberOfChildren];
|
||||||
@@ -68,8 +86,10 @@
|
|||||||
return [children copy];
|
return [children copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)indexOfChild:(MPExpression *)child
|
- (NSUInteger)indexOfChild:(MPExpression *)child
|
||||||
{
|
{
|
||||||
|
|
||||||
NSUInteger index = 0;
|
NSUInteger index = 0;
|
||||||
for (; index < [self numberOfChildren]; index++) {
|
for (; index < [self numberOfChildren]; index++) {
|
||||||
if ([self childAtIndex:index] == child) {
|
if ([self childAtIndex:index] == child) {
|
||||||
@@ -79,6 +99,7 @@
|
|||||||
return NSNotFound;
|
return NSNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (indexPath.length == 0) {
|
if (indexPath.length == 0) {
|
||||||
@@ -88,7 +109,10 @@
|
|||||||
return [child elementAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
|
return [child elementAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Notifications
|
#pragma mark Notifications
|
||||||
|
|
||||||
|
|
||||||
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
replacementLength:(NSUInteger)replacementLength
|
replacementLength:(NSUInteger)replacementLength
|
||||||
{
|
{
|
||||||
@@ -98,6 +122,7 @@
|
|||||||
replacementLength:replacementLength];
|
replacementLength:replacementLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)didChangeChildAtIndex:(NSUInteger)index
|
- (void)didChangeChildAtIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
MPRangePath *path = [[MPRangePath alloc] initWithRange:NSMakeRange(index, 1)];
|
MPRangePath *path = [[MPRangePath alloc] initWithRange:NSMakeRange(index, 1)];
|
||||||
@@ -105,39 +130,26 @@
|
|||||||
replacementLength:1];
|
replacementLength:1];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Working With Functions
|
|
||||||
/*
|
|
||||||
- (BOOL)isEqual:(id)object
|
|
||||||
{
|
|
||||||
if (self == object) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
if (object == nil) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
if (![object isKindOfClass:[MPFunction class]]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
return [self isEqualToFunction:(MPFunction *)object];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isEqualToFunction:(MPFunction *)aFunction
|
#pragma mark Working With Functions
|
||||||
{
|
|
||||||
return [aFunction isMemberOfClass:[MPFunction class]] && [self isMemberOfClass:[MPFunction class]];
|
|
||||||
}*/
|
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return @"[]";
|
return @"[]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)hash
|
- (NSUInteger)hash
|
||||||
{
|
{
|
||||||
#warning Unimplemented Method
|
#warning Unimplemented Method
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
#pragma mark - NSCopying
|
||||||
|
|
||||||
|
|
||||||
- (id)copyWithZone:(NSZone *)zone
|
- (id)copyWithZone:(NSZone *)zone
|
||||||
{
|
{
|
||||||
id copy = [[self.class allocWithZone:zone] init];
|
id copy = [[self.class allocWithZone:zone] init];
|
||||||
@@ -148,7 +160,10 @@
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - NSCoding
|
#pragma mark - NSCoding
|
||||||
|
|
||||||
|
|
||||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -163,22 +178,28 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||||
{
|
{
|
||||||
[aCoder encodeObject:self.children];
|
[aCoder encodeObject:self.children];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - MPExpressionElement
|
#pragma mark - MPExpressionElement
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)isString
|
- (BOOL)isString
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)isFunction
|
- (BOOL)isFunction
|
||||||
{
|
{
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)length
|
- (NSUInteger)length
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
if (self) {
|
if (self) {
|
||||||
[tokenStream beginIgnoringWhitespaceTokens];
|
[tokenStream beginIgnoringWhitespaceTokens];
|
||||||
|
|
||||||
while (tokenStream.currentToken.tokenType != MPOperatorListToken && tokenStream.currentToken.tokenType != MPEOFToken) {
|
while ([tokenStream hasMoreTokens] && tokenStream.currentToken.tokenType != MPOperatorListToken) {
|
||||||
[_factors addObject:[[MPFactor alloc] initWithTokenStream:tokenStream]];
|
[_factors addObject:[[MPFactor alloc] initWithTokenStream:tokenStream]];
|
||||||
}
|
}
|
||||||
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
|
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
|
||||||
|
|||||||
@@ -8,8 +8,10 @@
|
|||||||
|
|
||||||
#import "MPExpression.h"
|
#import "MPExpression.h"
|
||||||
|
|
||||||
|
/// Convenience Constructor Macro
|
||||||
#define MPMakeRangePath(loc, len) [MPRangePath rangePathWithLocation:(loc) length:(len)]
|
#define MPMakeRangePath(loc, len) [MPRangePath rangePathWithLocation:(loc) length:(len)]
|
||||||
|
|
||||||
|
|
||||||
@class MPRangePath, MPExpression;
|
@class MPRangePath, MPExpression;
|
||||||
|
|
||||||
|
|
||||||
@@ -27,7 +29,11 @@
|
|||||||
*/
|
*/
|
||||||
@interface MPRangePath : NSObject <NSCopying, NSCoding>
|
@interface MPRangePath : NSObject <NSCopying, NSCoding>
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
/*!
|
||||||
|
@methodgroup Creation Methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -80,7 +86,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method emptyRangePath
|
@method rangePath
|
||||||
@brief Allocates and initializes an empty @c NSRangePath instance.
|
@brief Allocates and initializes an empty @c NSRangePath instance.
|
||||||
|
|
||||||
@discussion An empty range path's location has @c 0 indexes and a length of
|
@discussion An empty range path's location has @c 0 indexes and a length of
|
||||||
@@ -88,7 +94,23 @@
|
|||||||
|
|
||||||
@return A newly created @c MPRangePath instance.
|
@return A newly created @c MPRangePath instance.
|
||||||
*/
|
*/
|
||||||
+ (instancetype)emptyRangePath;
|
+ (instancetype)rangePath;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method rangePathWithRange:
|
||||||
|
@brief Allocates a new @c MPRangePath instance and initializes it with
|
||||||
|
the given location and length.
|
||||||
|
|
||||||
|
@discussion The location of @c aRange is translated into an index path for
|
||||||
|
the range path.
|
||||||
|
|
||||||
|
@param aRange
|
||||||
|
The range to be converted into a range path.
|
||||||
|
|
||||||
|
@return A newly created @c MPRangePath instance.
|
||||||
|
*/
|
||||||
|
+ (instancetype)rangePathWithRange:(NSRange)aRange;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -110,22 +132,10 @@
|
|||||||
length:(NSUInteger)length;
|
length:(NSUInteger)length;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@method rangePathWithRange:
|
|
||||||
@brief Allocates a new @c MPRangePath instance and initializes it with
|
|
||||||
the given location and length.
|
|
||||||
|
|
||||||
@discussion The location of @c aRange is translated into an index path for
|
|
||||||
the range path.
|
|
||||||
|
|
||||||
@param aRange
|
|
||||||
The range to be converted into a range path.
|
|
||||||
|
|
||||||
@return A newly created @c MPRangePath instance.
|
|
||||||
*/
|
|
||||||
+ (instancetype)rangePathWithRange:(NSRange)aRange;
|
|
||||||
|
|
||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
/*!
|
||||||
|
@methodgroup Properties
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -165,26 +175,11 @@
|
|||||||
*/
|
*/
|
||||||
- (NSRange)rangeAtLastIndex;
|
- (NSRange)rangeAtLastIndex;
|
||||||
|
|
||||||
#pragma mark Working with Ranges
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Working With Ranges
|
||||||
/*!
|
/*!
|
||||||
@method containsRangePath:
|
@methodgroup Working With Ranges
|
||||||
@brief Checks wether the receiver completely contains @c aRangePath.
|
|
||||||
|
|
||||||
@discussion A range path is contained by another range path if either the
|
|
||||||
receiver's range at its last index contains the index at the
|
|
||||||
respective location of the location path of @c aRangePath or (if
|
|
||||||
the locations are of the same length) the receiver's range at its
|
|
||||||
last index contains the last index's range of @c aRangePath.
|
|
||||||
|
|
||||||
@param aRangePath
|
|
||||||
The range path to check wether it is contained in the receiver.
|
|
||||||
|
|
||||||
@return @c YES if the range path addressed by the receiver also includes
|
|
||||||
@c aRangePath, @c NO otherwise.
|
|
||||||
*/
|
*/
|
||||||
- (BOOL)containsRangePath:(MPRangePath *)aRangePath;
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -207,7 +202,23 @@
|
|||||||
- (BOOL)containsLocation:(NSIndexPath *)location;
|
- (BOOL)containsLocation:(NSIndexPath *)location;
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)isEqual:(id)object;
|
/*!
|
||||||
|
@method containsRangePath:
|
||||||
|
@brief Checks wether the receiver completely contains @c aRangePath.
|
||||||
|
|
||||||
|
@discussion A range path is contained by another range path if either the
|
||||||
|
receiver's range at its last index contains the index at the
|
||||||
|
respective location of the location path of @c aRangePath or (if
|
||||||
|
the locations are of the same length) the receiver's range at its
|
||||||
|
last index contains the last index's range of @c aRangePath.
|
||||||
|
|
||||||
|
@param aRangePath
|
||||||
|
The range path to check wether it is contained in the receiver.
|
||||||
|
|
||||||
|
@return @c YES if the range path addressed by the receiver also includes
|
||||||
|
@c aRangePath, @c NO otherwise.
|
||||||
|
*/
|
||||||
|
- (BOOL)containsRangePath:(MPRangePath *)aRangePath;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -229,6 +240,8 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@interface MPExpression (MPRangeExtension)
|
@interface MPExpression (MPRangeExtension)
|
||||||
|
|
||||||
|
|
||||||
@@ -252,6 +265,27 @@
|
|||||||
- (MPExpression *)subexpressionWithRangePath:(MPRangePath *)aRangePath
|
- (MPExpression *)subexpressionWithRangePath:(MPRangePath *)aRangePath
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method replaceItemsInRangePath:referenceFrame:withElements:
|
||||||
|
@brief Replaces the items in the specified range path with the contents
|
||||||
|
of @c elements.
|
||||||
|
|
||||||
|
@discussion All objects in the @c elements array must conform to the @c
|
||||||
|
MPExpressionElement protocol. If one or more objects do not
|
||||||
|
conform to the protocol a @c MPIllegalElementException will be
|
||||||
|
raised.
|
||||||
|
|
||||||
|
@param rangePath
|
||||||
|
The range path to be replaced. The path of the range path is
|
||||||
|
expressed in the element reference frame. The range of the range
|
||||||
|
path is expressed in the specified @c referenceFrame.
|
||||||
|
|
||||||
|
@param referenceFrame
|
||||||
|
The reference frame to use. This only applies to the range at the
|
||||||
|
last index of the range path. The path of the range path is
|
||||||
|
always expressed in the element reference frame.
|
||||||
|
*/
|
||||||
- (void)replaceItemsInRangePath:(MPRangePath *)rangePath
|
- (void)replaceItemsInRangePath:(MPRangePath *)rangePath
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
withElements:(NSArray *)elements;
|
withElements:(NSArray *)elements;
|
||||||
|
|||||||
@@ -8,16 +8,21 @@
|
|||||||
|
|
||||||
#import "MPRangePath.h"
|
#import "MPRangePath.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPRangePath
|
@implementation MPRangePath
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
return [self initWithLocation:[[NSIndexPath alloc] init]
|
return [self initWithLocation:[[NSIndexPath alloc] init]
|
||||||
length:0];
|
length:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)initWithLocation:(NSIndexPath *)location
|
- (instancetype)initWithLocation:(NSIndexPath *)location
|
||||||
length:(NSUInteger)length
|
length:(NSUInteger)length
|
||||||
{
|
{
|
||||||
@@ -29,17 +34,26 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)initWithRange:(NSRange)aRange
|
- (instancetype)initWithRange:(NSRange)aRange
|
||||||
{
|
{
|
||||||
return [self initWithLocation:[[NSIndexPath alloc] initWithIndex:aRange.location]
|
return [self initWithLocation:[[NSIndexPath alloc] initWithIndex:aRange.location]
|
||||||
length:aRange.length];
|
length:aRange.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)emptyRangePath
|
|
||||||
|
+ (instancetype)rangePath
|
||||||
{
|
{
|
||||||
return [[self alloc] init];
|
return [[self alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+ (instancetype)rangePathWithRange:(NSRange)aRange
|
||||||
|
{
|
||||||
|
return [[self alloc] initWithRange:aRange];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+ (instancetype)rangePathWithLocation:(NSIndexPath *)location
|
+ (instancetype)rangePathWithLocation:(NSIndexPath *)location
|
||||||
length:(NSUInteger)length
|
length:(NSUInteger)length
|
||||||
{
|
{
|
||||||
@@ -47,13 +61,10 @@
|
|||||||
length:length];
|
length:length];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)rangePathWithRange:(NSRange)aRange
|
|
||||||
{
|
|
||||||
return [[self alloc] initWithRange:aRange];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)maxRangePath
|
- (NSIndexPath *)maxRangePath
|
||||||
{
|
{
|
||||||
NSUInteger lastIndex = [self.location indexAtPosition:self.location.length-1];
|
NSUInteger lastIndex = [self.location indexAtPosition:self.location.length-1];
|
||||||
@@ -61,12 +72,21 @@
|
|||||||
return [[self.location indexPathByRemovingLastIndex] indexPathByAddingIndex:newLastIndex];
|
return [[self.location indexPathByRemovingLastIndex] indexPathByAddingIndex:newLastIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSRange)rangeAtLastIndex
|
- (NSRange)rangeAtLastIndex
|
||||||
{
|
{
|
||||||
return NSMakeRange([self.location indexAtPosition:self.location.length-1], self.length);
|
return NSMakeRange([self.location indexAtPosition:self.location.length-1], self.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Working with Ranges
|
|
||||||
|
#pragma mark Working With Ranges
|
||||||
|
|
||||||
|
|
||||||
|
- (BOOL)containsLocation:(NSIndexPath *)location
|
||||||
|
{
|
||||||
|
return [self containsRangePath:[[MPRangePath alloc] initWithLocation:location length:0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)containsRangePath:(MPRangePath *)aRangePath
|
- (BOOL)containsRangePath:(MPRangePath *)aRangePath
|
||||||
{
|
{
|
||||||
@@ -91,10 +111,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)containsLocation:(NSIndexPath *)location
|
|
||||||
{
|
|
||||||
return [self containsRangePath:[[MPRangePath alloc] initWithLocation:location length:0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isEqual:(id)object
|
- (BOOL)isEqual:(id)object
|
||||||
{
|
{
|
||||||
@@ -110,11 +126,13 @@
|
|||||||
return [self isEqualToRangePath:(MPRangePath *)object];
|
return [self isEqualToRangePath:(MPRangePath *)object];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)isEqualToRangePath:(MPRangePath *)aRangePath
|
- (BOOL)isEqualToRangePath:(MPRangePath *)aRangePath
|
||||||
{
|
{
|
||||||
return [self.location isEqual:aRangePath.location] && self.length == aRangePath.length;
|
return [self.location isEqual:aRangePath.location] && self.length == aRangePath.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
NSMutableString *description = [[NSMutableString alloc] initWithString:@"MPRangePath<location="];
|
NSMutableString *description = [[NSMutableString alloc] initWithString:@"MPRangePath<location="];
|
||||||
@@ -129,30 +147,38 @@
|
|||||||
return description.copy;
|
return description.copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
#pragma mark - NSCopying
|
||||||
|
|
||||||
|
|
||||||
- (id)copyWithZone:(NSZone *)zone
|
- (id)copyWithZone:(NSZone *)zone
|
||||||
{
|
{
|
||||||
MPRangePath *copy = [[MPRangePath allocWithZone:zone] initWithLocation:self.location.copy length:self.length];
|
MPRangePath *copy = [[MPRangePath allocWithZone:zone] initWithLocation:self.location.copy length:self.length];
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - NSCoding
|
#pragma mark - NSCoding
|
||||||
|
|
||||||
|
|
||||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||||
{
|
{
|
||||||
return [self initWithLocation:[aDecoder decodeObjectForKey:@"location"]
|
return [self initWithLocation:[aDecoder decodeObjectForKey:@"location"]
|
||||||
length:[aDecoder decodeIntegerForKey:@"length"]];
|
length:[aDecoder decodeIntegerForKey:@"length"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||||
{
|
{
|
||||||
[aCoder encodeObject:self.location forKey:@"location"];
|
[aCoder encodeObject:self.location forKey:@"location"];
|
||||||
[aCoder encodeInteger:self.length forKey:@"length"];
|
[aCoder encodeInteger:self.length forKey:@"length"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPExpression (MPRangeExtension)
|
@implementation MPExpression (MPRangeExtension)
|
||||||
|
|
||||||
- (NSArray *)itemsInRangePath:(MPRangePath *)rangePath
|
- (NSArray *)itemsInRangePath:(MPRangePath *)rangePath
|
||||||
@@ -162,6 +188,7 @@
|
|||||||
return [targetExpression itemsInRange:rangePath.rangeAtLastIndex referenceFrame:referenceFrame];
|
return [targetExpression itemsInRange:rangePath.rangeAtLastIndex referenceFrame:referenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (MPExpression *)subexpressionWithRangePath:(MPRangePath *)aRangePath
|
- (MPExpression *)subexpressionWithRangePath:(MPRangePath *)aRangePath
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
{
|
{
|
||||||
@@ -174,6 +201,7 @@
|
|||||||
referenceFrame:referenceFrame];
|
referenceFrame:referenceFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)replaceItemsInRangePath:(MPRangePath *)rangePath
|
- (void)replaceItemsInRangePath:(MPRangePath *)rangePath
|
||||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||||
withElements:(NSArray *)elements
|
withElements:(NSArray *)elements
|
||||||
|
|||||||
@@ -8,11 +8,37 @@
|
|||||||
|
|
||||||
#import "MPFunction.h"
|
#import "MPFunction.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPSuffixFunction;
|
@class MPSuffixFunction;
|
||||||
@protocol MPValue;
|
@protocol MPValue;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class MPSuffixFunction
|
||||||
|
@brief This is the common superclass for all functions that apply to the
|
||||||
|
value preceeding them.
|
||||||
|
|
||||||
|
@discussion One example for a suffix function is a power. Powers apply to a
|
||||||
|
base value and are evaluated with very high priority. In fact the
|
||||||
|
base value may not be used without previously having evaluated
|
||||||
|
the suffix function.
|
||||||
|
|
||||||
|
Another special thing about suffix functions is that they need to
|
||||||
|
know more than their own children (namely the base value) to be
|
||||||
|
evaluated. To be able to do this suffix functions have a special
|
||||||
|
property @c baseValue that is set before the function is
|
||||||
|
evaluated.
|
||||||
|
*/
|
||||||
@interface MPSuffixFunction : MPFunction
|
@interface MPSuffixFunction : MPFunction
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property baseValue
|
||||||
|
@brief The receiver's base value.
|
||||||
|
|
||||||
|
@discussion The base value is the thing a suffix function applies to (e.g.
|
||||||
|
a power's base).
|
||||||
|
*/
|
||||||
@property (nonatomic, strong) id<MPValue> baseValue;
|
@property (nonatomic, strong) id<MPValue> baseValue;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#import "MPSuffixFunction.h"
|
#import "MPSuffixFunction.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPSuffixFunction
|
@implementation MPSuffixFunction
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,12 +8,54 @@
|
|||||||
|
|
||||||
#import "MPFunction.h"
|
#import "MPFunction.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPSumFunction, MPExpression;
|
@class MPSumFunction, MPExpression;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class MPSumFunction
|
||||||
|
@brief A sum function (generally noted using a capital sigma) evaluates
|
||||||
|
a term repeatedly and sums up the results.
|
||||||
|
|
||||||
|
@discussion A sum function has a start and a target expression indicating how
|
||||||
|
often the sum expression should be evaluated. Both the value of
|
||||||
|
the start expression and the target expressions are included in
|
||||||
|
the iterations.
|
||||||
|
|
||||||
|
Each iteration the sum value is incremented by @c 1. If the start
|
||||||
|
and target expression evaluate to the same value the sum is
|
||||||
|
evaluated once.
|
||||||
|
*/
|
||||||
@interface MPSumFunction : MPFunction
|
@interface MPSumFunction : MPFunction
|
||||||
|
|
||||||
@property (nonatomic, strong) MPExpression *startExpression; // Index 0
|
|
||||||
@property (nonatomic, strong) MPExpression *targetExpression; // Index 1
|
/*!
|
||||||
@property (nonatomic, strong) MPExpression *sumExpression; // Index 2
|
@property startExpression
|
||||||
|
@brief The value of the first iteration.
|
||||||
|
|
||||||
|
@discussion The start expression must define a variable that may be used in
|
||||||
|
the sum expression. If the start expression does not define a
|
||||||
|
variable the sum function will fail on validation.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, strong) MPExpression *startExpression; /* Index 0 */
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property startExpression
|
||||||
|
@brief The value if the last iteration.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, strong) MPExpression *targetExpression; /* Index 1 */
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property sumExpression
|
||||||
|
@brief The sum expression evaluated multiple times.
|
||||||
|
|
||||||
|
@discussion During evaluation of the sum expression the variable defined in
|
||||||
|
the start expression is available. That variable always contains
|
||||||
|
the value of the current iteration.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, strong) MPExpression *sumExpression; /* Index 2 */
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -12,19 +12,25 @@
|
|||||||
#import "MPExpressionTree.h"
|
#import "MPExpressionTree.h"
|
||||||
#import "MPEvaluationContext.h"
|
#import "MPEvaluationContext.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPSumFunction
|
@implementation MPSumFunction
|
||||||
|
|
||||||
|
|
||||||
MPFunctionAccessorImplementation(StartExpression, _startExpression)
|
MPFunctionAccessorImplementation(StartExpression, _startExpression)
|
||||||
MPFunctionAccessorImplementation(TargetExpression, _targetExpression)
|
MPFunctionAccessorImplementation(TargetExpression, _targetExpression)
|
||||||
MPFunctionAccessorImplementation(SumExpression, _sumExpression)
|
MPFunctionAccessorImplementation(SumExpression, _sumExpression)
|
||||||
|
|
||||||
|
|
||||||
- (NSArray *)childrenAccessors
|
- (NSArray *)childrenAccessors
|
||||||
{
|
{
|
||||||
return @[@"startExpression", @"targetExpression", @"sumExpression"];
|
return @[@"startExpression", @"targetExpression", @"sumExpression"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Evaluating Functions
|
#pragma mark Evaluating Functions
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)validate:(NSError *__autoreleasing *)error
|
- (BOOL)validate:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
MPExpressionTree *startTree = [self.startExpression parse];
|
MPExpressionTree *startTree = [self.startExpression parse];
|
||||||
@@ -47,6 +53,7 @@ MPFunctionAccessorImplementation(SumExpression, _sumExpression)
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSDecimalNumber *)evaluate
|
- (NSDecimalNumber *)evaluate
|
||||||
{
|
{
|
||||||
MPExpressionTree *startTree = [self.startExpression parse];
|
MPExpressionTree *startTree = [self.startExpression parse];
|
||||||
@@ -67,8 +74,10 @@ MPFunctionAccessorImplementation(SumExpression, _sumExpression)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Working With Functions
|
#pragma mark Working With Functions
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat:@"Sum(From: %@; To: %@; Using: %@)", self.startExpression, self.targetExpression, self.sumExpression];
|
return [NSString stringWithFormat:@"Sum(From: %@; To: %@; Using: %@)", self.startExpression, self.targetExpression, self.sumExpression];
|
||||||
|
|||||||
@@ -8,11 +8,35 @@
|
|||||||
|
|
||||||
#import "MPExpressionTreeElement.h"
|
#import "MPExpressionTreeElement.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPSummand, MPOperatorChain, MPProduct;
|
@class MPSummand, MPOperatorChain, MPProduct;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class MPSummand
|
||||||
|
@brief A summand is a part of an expression that consists of a list of
|
||||||
|
addition and subtraction operators and a product.
|
||||||
|
*/
|
||||||
@interface MPSummand : NSObject <MPExpressionTreeElement>
|
@interface MPSummand : NSObject <MPExpressionTreeElement>
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property operatorChain
|
||||||
|
@brief The summand's preceeding operators.
|
||||||
|
|
||||||
|
@discussion The operator chain is interpreted as a factor for the @c product
|
||||||
|
property of the summand during evaluation.
|
||||||
|
*/
|
||||||
@property (readonly, nonatomic, strong) MPOperatorChain *operatorChain;
|
@property (readonly, nonatomic, strong) MPOperatorChain *operatorChain;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property product
|
||||||
|
@brief The summand's product.
|
||||||
|
|
||||||
|
@discussion The product is the @em value of a summand.
|
||||||
|
*/
|
||||||
@property (readonly, nonatomic, strong) MPProduct *product;
|
@property (readonly, nonatomic, strong) MPProduct *product;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,11 +6,66 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPToken;
|
@class MPToken;
|
||||||
@protocol MPToken;
|
@protocol MPToken;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@typedef MPTokenType
|
||||||
|
@brief A type of a token identifies its behaviour in a mathematical
|
||||||
|
context.
|
||||||
|
|
||||||
|
@constant MPMultiplicationSymbolToken
|
||||||
|
A multiplication symbol.
|
||||||
|
|
||||||
|
@constant MPOperatorListToken
|
||||||
|
A list of operators (+ and - symbols). The token may be longer
|
||||||
|
than the number of operators if there are spaces between them.
|
||||||
|
|
||||||
|
@constant MPSinToken
|
||||||
|
The sin function.
|
||||||
|
|
||||||
|
@constant MPCosToken
|
||||||
|
The cos function.
|
||||||
|
|
||||||
|
@constant MPTanToken
|
||||||
|
The tan function.
|
||||||
|
|
||||||
|
@constant MPASinToken
|
||||||
|
The asin function.
|
||||||
|
|
||||||
|
@constant MPACosToken
|
||||||
|
The acos function.
|
||||||
|
|
||||||
|
@constant MPATanToken
|
||||||
|
The atan function.
|
||||||
|
|
||||||
|
@constant MPNumberToken
|
||||||
|
A number. This may be an integer or a floating point number.
|
||||||
|
Floating point numbers contain a @c NSLocaleDecimalSeparator.
|
||||||
|
|
||||||
|
@constant MPVariableToken
|
||||||
|
A variable. A variable is exactly one character long.
|
||||||
|
|
||||||
|
@constant MPFactorialToken
|
||||||
|
The factorial symbol (!).
|
||||||
|
|
||||||
|
@constant MPEqualsToken
|
||||||
|
The equals sign.
|
||||||
|
|
||||||
|
@constant MPGenericFunctionToken
|
||||||
|
A function represented by the @c MPFunction class. A token with
|
||||||
|
this token type is guaranteed to be a @c MPFunction instance.
|
||||||
|
|
||||||
|
@constant MPWhitespaceToken
|
||||||
|
A whitespace. This token can typically be ignored.
|
||||||
|
|
||||||
|
@constant MPUnidentifiedToken
|
||||||
|
Any symbol that does not match any other token.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(NSUInteger, MPTokenType) {
|
typedef NS_ENUM(NSUInteger, MPTokenType) {
|
||||||
MPEOFToken = 0,
|
|
||||||
MPMultiplicationSymbolToken,
|
MPMultiplicationSymbolToken,
|
||||||
MPOperatorListToken,
|
MPOperatorListToken,
|
||||||
MPSinToken,
|
MPSinToken,
|
||||||
@@ -29,21 +84,85 @@ typedef NS_ENUM(NSUInteger, MPTokenType) {
|
|||||||
MPUnidentifiedToken,
|
MPUnidentifiedToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@protocol MPToken
|
||||||
|
@brief Tokens represent logical units in an expresion.
|
||||||
|
*/
|
||||||
@protocol MPToken <NSObject>
|
@protocol MPToken <NSObject>
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method tokenType
|
||||||
|
@brief Returns the receiver's token type.
|
||||||
|
|
||||||
|
@discussion The token type identifies what kind of token the receiver is. For
|
||||||
|
more information see the documentation on the @c MPTokenType
|
||||||
|
enum.
|
||||||
|
|
||||||
|
@return The receiver's token type.
|
||||||
|
*/
|
||||||
- (MPTokenType)tokenType;
|
- (MPTokenType)tokenType;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method range
|
||||||
|
@brief Returns the receiver's range.
|
||||||
|
|
||||||
|
@discussion The range identifies where the token is in the expression. It is
|
||||||
|
specified in the symbol reference frame.
|
||||||
|
|
||||||
|
@return The range the token occupies in the expression it was parsed
|
||||||
|
from specified in the symbol reference frame.
|
||||||
|
*/
|
||||||
- (NSRange)range;
|
- (NSRange)range;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method stringValue
|
||||||
|
@brief The string that caused the token to be parsed.
|
||||||
|
|
||||||
|
@discussion Depending on the type of the token the string value can have a
|
||||||
|
fixed or variable length. For example the equals token always has
|
||||||
|
a length of @c 1 whereas a number or whitespace token can be much
|
||||||
|
longer.
|
||||||
|
|
||||||
|
@return The receiver's string value.
|
||||||
|
*/
|
||||||
- (NSString *)stringValue;
|
- (NSString *)stringValue;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class MPToken
|
||||||
|
@brief The @c MPToken class implements the functionality of the @c
|
||||||
|
MPToken protocol. Most tokens are instances of the @c MPToken
|
||||||
|
class.
|
||||||
|
*/
|
||||||
@interface MPToken : NSObject <MPToken>
|
@interface MPToken : NSObject <MPToken>
|
||||||
|
|
||||||
- (instancetype)initEOFTokenAtLocation:(NSUInteger)eofLocation;
|
|
||||||
|
/*!
|
||||||
|
@method initWithTokenType:range:stringValue:
|
||||||
|
@brief Creates a new @c MPToken instance.
|
||||||
|
|
||||||
|
@param tokenType
|
||||||
|
The type of the token.
|
||||||
|
|
||||||
|
@param range
|
||||||
|
The range of the token in the expression. Specified in the symbol
|
||||||
|
reference frame.
|
||||||
|
|
||||||
|
@param input
|
||||||
|
The string value of the token.
|
||||||
|
|
||||||
|
@return A newly initialized token.
|
||||||
|
*/
|
||||||
- (instancetype)initWithTokenType:(MPTokenType)tokenType
|
- (instancetype)initWithTokenType:(MPTokenType)tokenType
|
||||||
range:(NSRange)range
|
range:(NSRange)range
|
||||||
stringValue:(NSString *)input;
|
stringValue:(NSString *)input; /* designated initializer */
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,21 +8,14 @@
|
|||||||
|
|
||||||
#import "MPToken.h"
|
#import "MPToken.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MPToken {
|
@implementation MPToken {
|
||||||
NSRange _range;
|
NSRange _range;
|
||||||
MPTokenType _tokenType;
|
MPTokenType _tokenType;
|
||||||
NSString *_stringValue;
|
NSString *_stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initEOFTokenAtLocation:(NSUInteger)eofLocation
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
_range = NSMakeRange(eofLocation, 0);
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithTokenType:(MPTokenType)tokenType
|
- (instancetype)initWithTokenType:(MPTokenType)tokenType
|
||||||
range:(NSRange)range
|
range:(NSRange)range
|
||||||
stringValue:(NSString *)input
|
stringValue:(NSString *)input
|
||||||
@@ -36,21 +29,25 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSRange)range
|
- (NSRange)range
|
||||||
{
|
{
|
||||||
return _range;
|
return _range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (MPTokenType)tokenType
|
- (MPTokenType)tokenType
|
||||||
{
|
{
|
||||||
return _tokenType;
|
return _tokenType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)stringValue
|
- (NSString *)stringValue
|
||||||
{
|
{
|
||||||
return _stringValue;
|
return _stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return self.stringValue;
|
return self.stringValue;
|
||||||
|
|||||||
@@ -6,23 +6,132 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@class MPTokenStream;
|
@class MPTokenStream;
|
||||||
@protocol MPToken;
|
@protocol MPToken;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@class MPTokenStream
|
||||||
|
@brief This class is a helper class for processing tokens from the
|
||||||
|
beginning of an expression to the end.
|
||||||
|
|
||||||
|
@discussion A token stream is a single-use object. After the stream has
|
||||||
|
reached the end there is no way to reset it.
|
||||||
|
*/
|
||||||
@interface MPTokenStream : NSObject
|
@interface MPTokenStream : NSObject
|
||||||
|
|
||||||
- (instancetype)initWithTokens:(NSArray *)tokens;
|
|
||||||
|
|
||||||
@property (nonatomic, copy) NSArray *tokens;
|
/*!
|
||||||
|
@method initWithTokens:
|
||||||
|
@brief Creates a new token stream that @em streams the contents of the
|
||||||
|
@c tokens array.
|
||||||
|
|
||||||
|
@param tokens
|
||||||
|
The tokens to be @em streamed. All objects in the array must
|
||||||
|
conform to the @c MPToken protocol.
|
||||||
|
|
||||||
|
@return A new token stream.
|
||||||
|
*/
|
||||||
|
- (instancetype)initWithTokens:(NSArray *)tokens; /* designated initializer */
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method beginIgnoringWhitespaceTokens
|
||||||
|
@brief After calling this method a @c -currentToken message will skip
|
||||||
|
whitespace characters before returning the current token.
|
||||||
|
|
||||||
|
@discussion Any call to this method or @c -beginAcceptingWhitespaceTokens
|
||||||
|
must be matched by a @c -endIgnoringOrAcceptingWhitespaceTokens
|
||||||
|
message. Calls to both methods can be nested.
|
||||||
|
|
||||||
|
By default whitespace tokens are accepted.
|
||||||
|
|
||||||
|
@see -beginAcceptingWhitespaceTokens
|
||||||
|
@see -endIgnoringOrAcceptingWhitespaceTokens
|
||||||
|
*/
|
||||||
- (void)beginIgnoringWhitespaceTokens;
|
- (void)beginIgnoringWhitespaceTokens;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method beginAcceptingWhitespaceTokens
|
||||||
|
@brief After calling this method @c -currentToken may return a token of
|
||||||
|
type @c MPWhitespaceToken.
|
||||||
|
|
||||||
|
@discussion Any call to this method or @c -beginAcceptingWhitespaceTokens
|
||||||
|
must be matched by a @c -endIgnoringOrAcceptingWhitespaceTokens
|
||||||
|
message. Calls to both methods can be nested.
|
||||||
|
|
||||||
|
By default whitespace tokens are accepted.
|
||||||
|
|
||||||
|
@see -beginIgnoringWhitespaceTokens
|
||||||
|
@see -endIgnoringOrAcceptingWhitespaceTokens
|
||||||
|
*/
|
||||||
- (void)beginAcceptingWhitespaceTokens;
|
- (void)beginAcceptingWhitespaceTokens;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method endIgnoringOrAcceptingWhitespaceTokens
|
||||||
|
@brief This method balances @c -beginIgnoringWhitespaceTokens and @c
|
||||||
|
-beginAcceptingWhitespaceTokens messages.
|
||||||
|
|
||||||
|
@discussion After this method was
|
||||||
|
calles the whitespace behaviour falls back to the way it behaved
|
||||||
|
before the last @c -beginIgnoringWhitespaceTokens or @c
|
||||||
|
-beginAcceptingWhitespaceTokens message was sent.
|
||||||
|
*/
|
||||||
- (void)endIgnoringOrAcceptingWhitespaceTokens;
|
- (void)endIgnoringOrAcceptingWhitespaceTokens;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method hasMoreTokens
|
||||||
|
@brief Use this method to check wether there are any tokens left.
|
||||||
|
|
||||||
|
@discussion This method repects the whitespace skipping behaviour. That means
|
||||||
|
that if the token stream currently ignores whitespaces and there
|
||||||
|
are only whitespaces left in the stream this method returns @c
|
||||||
|
NO.
|
||||||
|
|
||||||
|
@return @c YES if there are more tokens, @c NO otherwise.
|
||||||
|
*/
|
||||||
- (BOOL)hasMoreTokens;
|
- (BOOL)hasMoreTokens;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method currentToken
|
||||||
|
@brief Returns the receiver's current token.
|
||||||
|
|
||||||
|
@discussion This is one of the core methods of @c MPTokenStream. Subsequent
|
||||||
|
calls to this method will return the same value until @c
|
||||||
|
-currentTokenConsumed is called.
|
||||||
|
|
||||||
|
@return The current token or @c nil if there are no more tokens.
|
||||||
|
*/
|
||||||
- (id<MPToken>)currentToken;
|
- (id<MPToken>)currentToken;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method peekNextToken
|
||||||
|
@brief Looks at the next token and returns it.
|
||||||
|
|
||||||
|
@discussion This method behaves as if you called @c -currentTokenConsumed
|
||||||
|
followed by @c -currentToken except that it does not consume the
|
||||||
|
current token. That means that you can use this method to look at
|
||||||
|
the next token (respecting the current whitespace ignoring
|
||||||
|
behaviour) without changing the @c currentToken.
|
||||||
|
|
||||||
|
@return The next token or @c nil if there is no token after the current
|
||||||
|
one.
|
||||||
|
*/
|
||||||
- (id<MPToken>)peekNextToken;
|
- (id<MPToken>)peekNextToken;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method currentTokenConsumed
|
||||||
|
@brief Marks the current token as consumed and discards it.
|
||||||
|
*/
|
||||||
- (void)currentTokenConsumed;
|
- (void)currentTokenConsumed;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,67 +10,82 @@
|
|||||||
|
|
||||||
#import "MPToken.h"
|
#import "MPToken.h"
|
||||||
|
|
||||||
@implementation MPTokenStream {
|
|
||||||
NSUInteger _currentTokenIndex;
|
|
||||||
NSUInteger eofLocation;
|
|
||||||
|
|
||||||
BOOL *whitespaceIgnores;
|
|
||||||
NSUInteger maxWhitespaceIgnores;
|
@interface MPTokenStream ()
|
||||||
NSUInteger currentWhitespaceState;
|
|
||||||
}
|
@property (nonatomic, copy) NSArray *tokens;
|
||||||
|
@property (nonatomic) NSUInteger currentTokenIndex;
|
||||||
|
@property (nonatomic) NSUInteger eofLocation;
|
||||||
|
|
||||||
|
@property (nonatomic) BOOL *whitespaceIgnores;
|
||||||
|
@property (nonatomic) NSUInteger maxWhitespaceIgnores;
|
||||||
|
@property (nonatomic) NSUInteger currentWhitespaceIgnoreState;
|
||||||
|
|
||||||
|
- (void)pushWhitespaceState:(BOOL)state;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation MPTokenStream
|
||||||
|
|
||||||
- (instancetype)initWithTokens:(NSArray *)tokens
|
- (instancetype)initWithTokens:(NSArray *)tokens
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
self.tokens = tokens;
|
self.tokens = tokens;
|
||||||
whitespaceIgnores = malloc(10 * sizeof(BOOL));
|
self.whitespaceIgnores = malloc(10 * sizeof(BOOL));
|
||||||
maxWhitespaceIgnores = 10;
|
self.maxWhitespaceIgnores = 10;
|
||||||
currentWhitespaceState = 0;
|
self.currentWhitespaceIgnoreState = 0;
|
||||||
[self beginAcceptingWhitespaceTokens];
|
[self beginAcceptingWhitespaceTokens];
|
||||||
_currentTokenIndex = 0;
|
_currentTokenIndex = 0;
|
||||||
if (tokens.count > 0) {
|
if (tokens.count > 0) {
|
||||||
eofLocation = NSMaxRange([tokens.lastObject range]);
|
self.eofLocation = NSMaxRange([tokens.lastObject range]);
|
||||||
} else {
|
} else {
|
||||||
eofLocation = 0;
|
self.eofLocation = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)beginAcceptingWhitespaceTokens
|
- (void)beginAcceptingWhitespaceTokens
|
||||||
{
|
{
|
||||||
[self pushWhitespaceState:YES];
|
[self pushWhitespaceState:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)beginIgnoringWhitespaceTokens
|
- (void)beginIgnoringWhitespaceTokens
|
||||||
{
|
{
|
||||||
[self pushWhitespaceState:NO];
|
[self pushWhitespaceState:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)pushWhitespaceState:(BOOL)state
|
- (void)pushWhitespaceState:(BOOL)state
|
||||||
{
|
{
|
||||||
currentWhitespaceState++;
|
self.currentWhitespaceIgnoreState++;
|
||||||
if (currentWhitespaceState >= maxWhitespaceIgnores) {
|
if (self.currentWhitespaceIgnoreState >= self.maxWhitespaceIgnores) {
|
||||||
maxWhitespaceIgnores += 10;
|
self.maxWhitespaceIgnores += 10;
|
||||||
BOOL *reallocatedWhitespaceIgnores = realloc(whitespaceIgnores, maxWhitespaceIgnores);
|
BOOL *reallocatedWhitespaceIgnores = realloc(self.whitespaceIgnores, self.maxWhitespaceIgnores);
|
||||||
if (reallocatedWhitespaceIgnores) {
|
if (reallocatedWhitespaceIgnores) {
|
||||||
whitespaceIgnores = reallocatedWhitespaceIgnores;
|
self.whitespaceIgnores = reallocatedWhitespaceIgnores;
|
||||||
} else {
|
} else {
|
||||||
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Realloc Failed" userInfo:nil];
|
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Realloc Failed" userInfo:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
whitespaceIgnores[currentWhitespaceState] = state;
|
self.whitespaceIgnores[self.currentWhitespaceIgnoreState] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)endIgnoringOrAcceptingWhitespaceTokens
|
- (void)endIgnoringOrAcceptingWhitespaceTokens
|
||||||
{
|
{
|
||||||
currentWhitespaceState--;
|
self.currentWhitespaceIgnoreState--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)skipWhitespaces
|
- (void)skipWhitespaces
|
||||||
{
|
{
|
||||||
if (whitespaceIgnores[currentWhitespaceState]) {
|
if (self.whitespaceIgnores[self.currentWhitespaceIgnoreState]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (_currentTokenIndex < self.tokens.count) {
|
while (_currentTokenIndex < self.tokens.count) {
|
||||||
@@ -82,21 +97,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)hasMoreTokens
|
- (BOOL)hasMoreTokens
|
||||||
{
|
{
|
||||||
[self skipWhitespaces];
|
[self skipWhitespaces];
|
||||||
return _currentTokenIndex < self.tokens.count;
|
return _currentTokenIndex < self.tokens.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id<MPToken>)currentToken
|
- (id<MPToken>)currentToken
|
||||||
{
|
{
|
||||||
[self skipWhitespaces];
|
[self skipWhitespaces];
|
||||||
if (_currentTokenIndex >= _tokens.count) {
|
if (_currentTokenIndex >= _tokens.count) {
|
||||||
return [[MPToken alloc] initEOFTokenAtLocation:eofLocation];
|
return nil;
|
||||||
}
|
}
|
||||||
return _tokens[_currentTokenIndex];
|
return _tokens[_currentTokenIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id<MPToken>)peekNextToken
|
- (id<MPToken>)peekNextToken
|
||||||
{
|
{
|
||||||
NSUInteger currentTokenIndex = _currentTokenIndex;
|
NSUInteger currentTokenIndex = _currentTokenIndex;
|
||||||
@@ -106,15 +124,17 @@
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)currentTokenConsumed
|
- (void)currentTokenConsumed
|
||||||
{
|
{
|
||||||
[self currentToken];
|
[self currentToken];
|
||||||
++_currentTokenIndex;
|
++_currentTokenIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
free(whitespaceIgnores);
|
free(self.whitespaceIgnores);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,36 +6,158 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@interface NSIndexPath (MPAdditions)
|
@interface NSIndexPath (MPAdditions)
|
||||||
|
|
||||||
- (NSUInteger)firstIndex;
|
|
||||||
- (NSUInteger)lastIndex;
|
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByReplacingLastIndexWithIndex:(NSUInteger)index;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method indexPathByRemovingFirstIndex
|
@property firstIndex
|
||||||
@brief Provides an index path with the indexes in the receiving index path, excluding the first one.
|
@brief The first index from the index path.
|
||||||
@discussion Returns an empty NSIndexPath instance if the receiving index path’s length is 1 or less.
|
|
||||||
@return A new index path with the receiving index path’s indexes, excluding the first one.
|
@discussion If the index path is empty @c NSNotFound is returned.
|
||||||
|
*/
|
||||||
|
@property (readonly, nonatomic) NSUInteger firstIndex;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@property lastIndex
|
||||||
|
@brief The last index from the index path.
|
||||||
|
|
||||||
|
@discussion If the index path is empty @c NSNotFound is returned.
|
||||||
|
*/
|
||||||
|
@property (readonly, nonatomic) NSUInteger lastIndex;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method indexPathByReplacingLastIndexWithIndex:
|
||||||
|
@brief Provides an index path with the index in the receiving index path
|
||||||
|
where the last one is replaced by @c index.
|
||||||
|
|
||||||
|
@discussion If the receiving index path is empty an index path of length @c 1
|
||||||
|
is returned. The last index in the returned index path is @c
|
||||||
|
index.
|
||||||
|
|
||||||
|
@param index
|
||||||
|
The index with which to replace the last index in the receiving
|
||||||
|
index path.
|
||||||
|
|
||||||
|
@return A new index path with @c index as its last index.
|
||||||
|
*/
|
||||||
|
- (NSIndexPath *)indexPathByReplacingLastIndexWithIndex:(NSUInteger)index;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method indexPathByRemovingFirstIndex
|
||||||
|
@brief Provides an index path with the indexes in the receiving index
|
||||||
|
path, excluding the first one.
|
||||||
|
|
||||||
|
@discussion Returns an empty NSIndexPath instance if the receiving index
|
||||||
|
path’s length is 1 or less.
|
||||||
|
|
||||||
|
@return A new index path with the receiving index path’s indexes,
|
||||||
|
excluding the first one.
|
||||||
*/
|
*/
|
||||||
- (NSIndexPath *)indexPathByRemovingFirstIndex;
|
- (NSIndexPath *)indexPathByRemovingFirstIndex;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@method indexPathByPreceedingIndex:
|
@method indexPathByPreceedingIndex:
|
||||||
@brief Provides an index path with the given index followed by the indexes of the receiver.
|
@brief Provides an index path with the given index followed by the
|
||||||
@discussion If the receiver does not contain any indexes the given index is the only index contained in the returned index path.
|
indexes of the receiver.
|
||||||
@param index The index new index preceeding all others
|
|
||||||
@return A new index path with all the receiver's indexes preceeded by @c index.
|
@discussion If the receiver does not contain any indexes the given index is
|
||||||
|
the only index contained in the returned index path.
|
||||||
|
|
||||||
|
@param index
|
||||||
|
The index new index preceeding all others
|
||||||
|
|
||||||
|
@return A new index path with all the receiver's indexes preceeded by @c
|
||||||
|
index.
|
||||||
*/
|
*/
|
||||||
- (NSIndexPath *)indexPathByPreceedingIndex:(NSUInteger)index;
|
- (NSIndexPath *)indexPathByPreceedingIndex:(NSUInteger)index;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method indexPathByIncrementingLastIndex
|
||||||
|
@brief Provides an index path with the indexes in the receiving index
|
||||||
|
path where the last one is incremented by @c 1.
|
||||||
|
|
||||||
|
@discussion If the receiver does not contain any indexes an empty index path
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
@return A new index path with all the receiver's indexes and the last one
|
||||||
|
incremented by @c 1.
|
||||||
|
*/
|
||||||
- (NSIndexPath *)indexPathByIncrementingLastIndex;
|
- (NSIndexPath *)indexPathByIncrementingLastIndex;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method indexPathByDecrementingLastIndex
|
||||||
|
@brief Provides an index path with the indexes in the receiving index
|
||||||
|
path where the last one is decremented by @c 1.
|
||||||
|
|
||||||
|
@discussion If the receiver does not contain any indexes an empty index path
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
@return A new index path with all the receiver's indexes and the last one
|
||||||
|
decremented by @c 1.
|
||||||
|
*/
|
||||||
- (NSIndexPath *)indexPathByDecrementingLastIndex;
|
- (NSIndexPath *)indexPathByDecrementingLastIndex;
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByRemovingIndexesFrom:(NSUInteger)length; // use length indexes from the receiver, exception if too much
|
|
||||||
- (NSIndexPath *)indexPathByRemovingIndexesTo:(NSUInteger)length; // number of indexes from the beginning to exclude
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method indexPathByRemovingIndexesFrom:
|
||||||
|
@brief Provides an index path with the indexes in the recieving index
|
||||||
|
path up to the index at the given position.
|
||||||
|
|
||||||
|
@discussion If @c from is greater or equal to the number of indexes in the
|
||||||
|
receiving index path only the indexes to the end of the receiver
|
||||||
|
are removed.
|
||||||
|
|
||||||
|
@param from
|
||||||
|
The position of the first index to be excluded in the returned
|
||||||
|
index path.
|
||||||
|
|
||||||
|
@return An index path with all indexes from the receiver up to position
|
||||||
|
@c from.
|
||||||
|
*/
|
||||||
|
- (NSIndexPath *)indexPathByRemovingIndexesFrom:(NSUInteger)from;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method indexPathByRemovingIndexesTo:
|
||||||
|
@brief Provides an index path with the indexes in the receiving index
|
||||||
|
path where the first indexes are removed.
|
||||||
|
|
||||||
|
|
||||||
|
@discussion @c to specifies the number of indexes to be removed from the
|
||||||
|
front. Thus the index at position @c to will be included in the
|
||||||
|
returned index path.
|
||||||
|
|
||||||
|
@param to
|
||||||
|
The number of indexes to remove from the front.
|
||||||
|
|
||||||
|
@return A new index path with all the receiver's indexes exept the first
|
||||||
|
@c to ones.
|
||||||
|
*/
|
||||||
|
- (NSIndexPath *)indexPathByRemovingIndexesTo:(NSUInteger)to;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method commonIndexPathWith:
|
||||||
|
@brief Provides an index path that contains the first indexes of the
|
||||||
|
receiver that are equal to the given index path.
|
||||||
|
|
||||||
|
@discussion If one index path is completely included in the other a new index
|
||||||
|
path is returned that is equal to the contained index path.
|
||||||
|
|
||||||
|
@param indexPath
|
||||||
|
The index path to compare the receiver against.
|
||||||
|
|
||||||
|
@return A new index path with the first indexes of the receiver that are
|
||||||
|
also present in @c indexPath.
|
||||||
|
*/
|
||||||
- (NSIndexPath *)commonIndexPathWith:(NSIndexPath *)indexPath;
|
- (NSIndexPath *)commonIndexPathWith:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,23 +8,29 @@
|
|||||||
|
|
||||||
#import "NSIndexPath+MPAdditions.h"
|
#import "NSIndexPath+MPAdditions.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation NSIndexPath (MPAdditions)
|
@implementation NSIndexPath (MPAdditions)
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)firstIndex
|
- (NSUInteger)firstIndex
|
||||||
{
|
{
|
||||||
return [self indexAtPosition:0];
|
return [self indexAtPosition:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)lastIndex
|
- (NSUInteger)lastIndex
|
||||||
{
|
{
|
||||||
return [self indexAtPosition:self.length-1];
|
return [self indexAtPosition:self.length-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByReplacingLastIndexWithIndex:(NSUInteger)index
|
- (NSIndexPath *)indexPathByReplacingLastIndexWithIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
return [[self indexPathByRemovingLastIndex] indexPathByAddingIndex:index];
|
return [[self indexPathByRemovingLastIndex] indexPathByAddingIndex:index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByRemovingFirstIndex
|
- (NSIndexPath *)indexPathByRemovingFirstIndex
|
||||||
{
|
{
|
||||||
if (self.length <= 1) {
|
if (self.length <= 1) {
|
||||||
@@ -39,6 +45,7 @@
|
|||||||
return [[NSIndexPath alloc] initWithIndexes:newIndexes length:self.length-1];
|
return [[NSIndexPath alloc] initWithIndexes:newIndexes length:self.length-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByPreceedingIndex:(NSUInteger)index
|
- (NSIndexPath *)indexPathByPreceedingIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
NSUInteger newIndexes[self.length+1];
|
NSUInteger newIndexes[self.length+1];
|
||||||
@@ -49,8 +56,12 @@
|
|||||||
return [[NSIndexPath alloc] initWithIndexes:newIndexes length:self.length+1];
|
return [[NSIndexPath alloc] initWithIndexes:newIndexes length:self.length+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByIncrementingLastIndex
|
- (NSIndexPath *)indexPathByIncrementingLastIndex
|
||||||
{
|
{
|
||||||
|
if (self.length < 1) {
|
||||||
|
return [[NSIndexPath alloc] init];
|
||||||
|
}
|
||||||
NSUInteger lastIndex = [self lastIndex];
|
NSUInteger lastIndex = [self lastIndex];
|
||||||
lastIndex++;
|
lastIndex++;
|
||||||
return [[self indexPathByRemovingLastIndex] indexPathByAddingIndex:lastIndex];
|
return [[self indexPathByRemovingLastIndex] indexPathByAddingIndex:lastIndex];
|
||||||
@@ -58,29 +69,35 @@
|
|||||||
|
|
||||||
- (NSIndexPath *)indexPathByDecrementingLastIndex
|
- (NSIndexPath *)indexPathByDecrementingLastIndex
|
||||||
{
|
{
|
||||||
|
if (self.length < 1) {
|
||||||
|
return [[NSIndexPath alloc] init];
|
||||||
|
}
|
||||||
NSUInteger lastIndex = [self lastIndex];
|
NSUInteger lastIndex = [self lastIndex];
|
||||||
lastIndex--;
|
lastIndex--;
|
||||||
return [[self indexPathByRemovingLastIndex] indexPathByAddingIndex:lastIndex];
|
return [[self indexPathByRemovingLastIndex] indexPathByAddingIndex:lastIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByRemovingIndexesFrom:(NSUInteger)length
|
|
||||||
|
- (NSIndexPath *)indexPathByRemovingIndexesFrom:(NSUInteger)from
|
||||||
{
|
{
|
||||||
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
|
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
|
||||||
for (NSUInteger position = 0; position < length; position++) {
|
for (NSUInteger position = 0; position < MIN(from, self.length); position++) {
|
||||||
indexPath = [indexPath indexPathByAddingIndex:[self indexAtPosition:position]];
|
indexPath = [indexPath indexPathByAddingIndex:[self indexAtPosition:position]];
|
||||||
}
|
}
|
||||||
return indexPath;
|
return indexPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSIndexPath *)indexPathByRemovingIndexesTo:(NSUInteger)length
|
|
||||||
|
- (NSIndexPath *)indexPathByRemovingIndexesTo:(NSUInteger)to
|
||||||
{
|
{
|
||||||
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
|
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
|
||||||
for (NSUInteger position = length; position < self.length; position++) {
|
for (NSUInteger position = to; position < self.length; position++) {
|
||||||
indexPath = [indexPath indexPathByAddingIndex:[self indexAtPosition:position]];
|
indexPath = [indexPath indexPathByAddingIndex:[self indexAtPosition:position]];
|
||||||
}
|
}
|
||||||
return indexPath;
|
return indexPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSIndexPath *)commonIndexPathWith:(NSIndexPath *)indexPath
|
- (NSIndexPath *)commonIndexPathWith:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
NSIndexPath *commonPath = [[NSIndexPath alloc] init];
|
NSIndexPath *commonPath = [[NSIndexPath alloc] init];
|
||||||
|
|||||||
@@ -6,14 +6,102 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#define MPStringRange(string) NSMakeRange(0, [string length])
|
|
||||||
#define MPStringRangeFrom(from, string) NSMakeRange(from, [string length]-from)
|
|
||||||
|
|
||||||
@interface NSRegularExpression (MPParsingAdditions)
|
@interface NSRegularExpression (MPParsingAdditions)
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method firstMathInString:
|
||||||
|
@brief Returns the first match of the regular expression within the
|
||||||
|
specified string.
|
||||||
|
|
||||||
|
@discussion This is a convenience method that calls @c
|
||||||
|
-firstMatchInString:options:range:
|
||||||
|
|
||||||
|
@param string
|
||||||
|
The string to search.
|
||||||
|
|
||||||
|
@return An NSTextCheckingResult object. This result gives the overall
|
||||||
|
matched range via its range property, and the range of each
|
||||||
|
individual capture group via its rangeAtIndex: method. The range
|
||||||
|
@c {NSNotFound, 0} is returned if one of the capture groups did
|
||||||
|
not participate in this particular match.
|
||||||
|
*/
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string;
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method firstMathInString:fromIndex
|
||||||
|
@brief Returns the first match of the regular expression from the
|
||||||
|
specified index in the string.
|
||||||
|
|
||||||
|
@discussion This is a convenience method that calls @c
|
||||||
|
-firstMatchInString:options:range:
|
||||||
|
|
||||||
|
@param string
|
||||||
|
The string to search.
|
||||||
|
|
||||||
|
@param start
|
||||||
|
The index from which to start searching.
|
||||||
|
|
||||||
|
@return An NSTextCheckingResult object. This result gives the overall
|
||||||
|
matched range via its range property, and the range of each
|
||||||
|
individual capture group via its rangeAtIndex: method. The range
|
||||||
|
@c {NSNotFound, 0} is returned if one of the capture groups did
|
||||||
|
not participate in this particular match.
|
||||||
|
*/
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string fromIndex:(NSUInteger)start;
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string fromIndex:(NSUInteger)start;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method firstMathInString:options:
|
||||||
|
@brief Returns the first match of the regular expression within the
|
||||||
|
specified string.
|
||||||
|
|
||||||
|
@discussion This is a convenience method that calls @c
|
||||||
|
-firstMatchInString:options:range:
|
||||||
|
|
||||||
|
@param string
|
||||||
|
The string to search.
|
||||||
|
|
||||||
|
@param options
|
||||||
|
The matching options to use. See @c NSMatchingOptions for
|
||||||
|
possible values.
|
||||||
|
|
||||||
|
@return An NSTextCheckingResult object. This result gives the overall
|
||||||
|
matched range via its range property, and the range of each
|
||||||
|
individual capture group via its rangeAtIndex: method. The range
|
||||||
|
@c {NSNotFound, 0} is returned if one of the capture groups did
|
||||||
|
not participate in this particular match.
|
||||||
|
*/
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options;
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method firstMathInString:fromIndex
|
||||||
|
@brief Returns the first match of the regular expression from the
|
||||||
|
specified index in the string.
|
||||||
|
|
||||||
|
@discussion This is a convenience method that calls @c
|
||||||
|
-firstMatchInString:options:range:
|
||||||
|
|
||||||
|
@param string
|
||||||
|
The string to search.
|
||||||
|
|
||||||
|
@param options
|
||||||
|
The matching options to use. See @c NSMatchingOptions for
|
||||||
|
possible values.
|
||||||
|
|
||||||
|
@param start
|
||||||
|
The index from which to start searching.
|
||||||
|
|
||||||
|
@return An NSTextCheckingResult object. This result gives the overall
|
||||||
|
matched range via its range property, and the range of each
|
||||||
|
individual capture group via its rangeAtIndex: method. The range
|
||||||
|
@c {NSNotFound, 0} is returned if one of the capture groups did
|
||||||
|
not participate in this particular match.
|
||||||
|
*/
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options fromIndex:(NSUInteger)start;
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options fromIndex:(NSUInteger)start;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,23 +8,28 @@
|
|||||||
|
|
||||||
#import "NSRegularExpression+MPParsingAdditions.h"
|
#import "NSRegularExpression+MPParsingAdditions.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation NSRegularExpression (MPParsingAdditions)
|
@implementation NSRegularExpression (MPParsingAdditions)
|
||||||
|
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string
|
||||||
{
|
{
|
||||||
return [self firstMatchInString:string options:0 range:MPStringRange(string)];
|
return [self firstMatchInString:string options:0 range:NSMakeRange(0, string.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string fromIndex:(NSUInteger)start
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string fromIndex:(NSUInteger)start
|
||||||
{
|
{
|
||||||
return [self firstMatchInString:string options:0 range:NSMakeRange(start, [string length]-start)];
|
return [self firstMatchInString:string options:0 range:NSMakeRange(start, [string length]-start)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options
|
||||||
{
|
{
|
||||||
return [self firstMatchInString:string options:options range:MPStringRange(string)];
|
return [self firstMatchInString:string options:options range:NSMakeRange(0, string.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options fromIndex:(NSUInteger)start
|
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options fromIndex:(NSUInteger)start
|
||||||
{
|
{
|
||||||
return [self firstMatchInString:string options:options range:NSMakeRange(start, [string length]-start)];
|
return [self firstMatchInString:string options:options range:NSMakeRange(start, [string length]-start)];
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
|
|
||||||
#import "MPExpressionElement.h"
|
#import "MPExpressionElement.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@category NSString (MPExpressionElement)
|
||||||
|
@brief This category adds @c MPExpressionElement protocol conformance to
|
||||||
|
the @c NSString class.
|
||||||
|
*/
|
||||||
@interface NSString (MPExpressionElement) <MPExpressionElement>
|
@interface NSString (MPExpressionElement) <MPExpressionElement>
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#import "NSString+MPExpressionElement.h"
|
#import "NSString+MPExpressionElement.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation NSString (MPExpressionElement)
|
@implementation NSString (MPExpressionElement)
|
||||||
|
|
||||||
- (BOOL)isString
|
- (BOOL)isString
|
||||||
@@ -15,6 +17,7 @@
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)isFunction
|
- (BOOL)isFunction
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
XCTAssertEqualObjects(rangePath.location, [[NSIndexPath alloc] initWithIndex:3]);
|
XCTAssertEqualObjects(rangePath.location, [[NSIndexPath alloc] initWithIndex:3]);
|
||||||
XCTAssertEqual(rangePath.length, 2);
|
XCTAssertEqual(rangePath.length, 2);
|
||||||
|
|
||||||
rangePath = [MPRangePath emptyRangePath];
|
rangePath = [MPRangePath rangePath];
|
||||||
XCTAssertEqualObjects(rangePath.location, [[NSIndexPath alloc] init]);
|
XCTAssertEqualObjects(rangePath.location, [[NSIndexPath alloc] init]);
|
||||||
XCTAssertEqual(rangePath.length, 0);
|
XCTAssertEqual(rangePath.length, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user