//
//  MPExpression.h
//  MathKit
//
//  Created by Kim Wittenburg on 10.08.14.
//  Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//



/*!
 @header
 This file contains the <code>MPExpression</code> class and the
 <code>MPExpressionElement</code> protocol.

 The <code>MPExpression</code> class is used to represent a mathematical
 expression. It is used in the storage layer of the MathKit Expression System. An
 instance of the <code>MPExpression</code> class stores all contents related to
 an expression and can manipulate them. However it is not able to evaluate the
 represented expression by itself.
 
 <h2>Structure of an Expression</h2>
 
 Expressions consist of two types of elements: string elements and function
 elements. String elements are represented by the <code>NSString</code> class.
 In a valid expression string elements can only contain ASCII valid characters.
 (and some other special characters) that make sense in a mathematical context.
 Functions are represented by the <code>@link
 //apple_ref/occ/cl/MPFunction@/link</code> class. Functions represent everything
 beyond simple text (such as powers, parenthesis and roots).
 
 An expression should be pictured as a sequence of symbols that can either be
 characters or functions. For the purposes of easier processing of expressions
 it is possible to access complete string or function elements. Also there is a
 third way of accessing an expression's contents: You can query individual tokens
 of an expression. Tokens represent logical units inside an expression. For more
 information on tokens see the documentation for <code>@link
 //apple_ref/doc/header/MPToken.h MPToken@/link</code>.
 
 <h2>The Expression Tree</h2>
 Like expressions functions can likewise have expressions as elements (also
 called <i>children</i> in this context). Both expressions and functions are
 mutable. Through this organization expression are organized in a tree-like
 structure called the <i>expression tree</i>. See <code>@link
 //apple_ref/occ/cl/MPFunction@/link</code> for details.
 
 <h2>Terminology</h2>
 
 When working with expressions note that there is a special terminology for an
 expression's contents:
 
 <b>Element:</b><br />
 An element is either an instance of the <code>NSString</code> or <code> @link
 //apple_ref/occ/cl/MPFunction@/link</code> class. String elements can be
 multiple characters long. For example the expression <code>4+2²</code> consists
 of one string element (<code>"4+2"</code>) and one function element (the square
 function). All elements conform to the <code>MPExpressionElement</code>
 protocol.
 
 <b>Token:</b><br />
 Tokens are logical units within an expression. For example the expression
 <code>4+2²</code> consists of 4 tokens: A number token (<code>4</code>), a plus
 sign token (<code>+</code>), another number (<code>2</code>) and a power token
 (the square function). All tokens conform to the <code>@link
 //apple_ref/occ/intf/MPToken@/link</code> protocol.
 
 <b>Symbol:</b><br />
 Symbols are the smallest possible part of an expression. A symbol is either a
 single character or a single function. For example the expression
 <code>4+2²</code> consists of 4 symbols: The characters <code>"4"</code>,
 <code>"+"</code> and <code>"2"</code> and the square function.
 
 <b>Item:</b></br />
 The term <i>item</i> is used to describe any of the previous. When the term
 <i>item</i> is used in the name of a function or method it necessary to specify
 what exactly an item is supposed to be. Usually this is done through reference
 frames.
 
 <b>Reference Frame:</b><br />
 A reference frame is a way to specify what an <i>item</i> is supposed to mean in
 a specific context. It can either be an <i>element</i>, a <i>symbol</i> or a
 <i>token</i>. For more information about reference frames see
 <code>@link MPReferenceFrame@/link</code>.
 
 <b>Children:</b><br />
 Children are sub-elements of functions. The term <i>children</i> normally refers
 to any kind of elements in the context of the expression tree.
 
 This terminology is consistent within the MathKit Expression System. Because
 symbols are the smalles possible unit of measurement elements and tokens both
 consist of one or more symbols. Similarly elements consist of one or more
 tokens. You can convert between different reference frames using the following
 methods:
 <ul>
 <li><code>@link convertIndex:fromReferenceFrame:toReferenceFrame:@/link</code></li>
 <li><code>@link convertIndex:fromReferenceFrame:toReferenceFrame:offset:@/link</code></li>
 <li><code>@link convertRange:fromReferenceFrame:toReferenceFrame:@/link</code></li>
 <li><code>@link convertRange:fromReferenceFrame:toReferenceFrame:leadingOffset:trailingOffset:@/link</code></li>
 </ul>
 
 <h2>Evaluating Expressions</h2>
 A <code>MPExpression</code> instance can not evaluate itself. There are however
 the <code>@link parse:@/link</code> and
 <code>@link parseExpectingVariable:errors:@/link</code> methods. These parse and
 thereby convert a <code>MPExpression</code> instance into a <code>@link
 //apple_ref/occ/cl/MPParsedExpression@/link</code> instance that can be
 evaluated. For more information on evaluation see the <code>@link
 //apple_ref/occ/cl/MPParsedExpression@/link</code> and <code>@link
 //apple_ref/occ/cl/MPTerm@/link</code> class as well as the previously mentioned
 methods.
 */


/*!
    @const      MPIllegalElementException
    @abstract   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
                contains the invalid element in its <code>userInfo</code>
                dictionary. You can query it using the
                <code>MPIllegalElementExceptionElementKey</code> key.
 */
FOUNDATION_EXPORT NSString *const MPIllegalElementException;


/*!
    @const      MPIllegalElementExceptionElementKey
    @abstract   Predefined key for an invalid element that caused a
                <code>MPIllegalElementException</code> to be raised.
 
    @discussion The invalid element can be of any type. Numbers and structs are
                wrapped in an <code>NSNumber</code> or <code>NSValue</code>
                instance respectively.
 */
FOUNDATION_EXPORT NSString *const MPIllegalElementExceptionElementKey;


/*!
    @typedef    MPReferenceFrame
    @abstract   A reference frame specifies the way an <i>item</i> is to be
                interpreted.
 
    @constant   MPElementReferenceFrame
                Specifies that items should be interpreted as elements.
 
    @constant   MPSymbolReferenceFrame
                Specifies that items should be interpreted as symbols.
 
    @constant   MPTokenReferenceFrame
                Specifies that items should be interpreted as tokens.
  */
typedef enum {
    MPElementReferenceFrame,
    MPSymbolReferenceFrame,
    MPTokenReferenceFrame
} MPReferenceFrame;



@class MPExpression, MPFunction, MPRangePath, MPParsedExpression;
@protocol MPExpressionElement, MPToken;


/*!
    @protocol   MPExpressionElement
    @abstract   This protocol defines the functionality an element in an
                expression must have.
 */
@protocol MPExpressionElement <NSObject, NSCopying, NSCoding>

/*!
    @method     isString
    @abstract   Returns wether the receiver is a string.
 
    @discussion A string is defined by being an instance of
                <code>NSString</code>. If this method returns <code>YES</code>
                you can be sure the receiver is an <code>NSString</code>
                instance.
 
    @return     <code>YES</code> if the receiver is a string, <code>NO</code>
                otherwise.
 */
- (BOOL)isString;


/*!
    @method     isFunction
    @abstract   Returns wether the receiver is a function.
 
    @discussion A function is defined by being an instance of
                <code>@link //apple_ref/occ/cl/MPFunction@/link</code>. If this
                method returns <code>YES</code> you can be sure the receiver is a
                <code>@link //apple_ref/occ/cl/MPFunction@/link</code> instance.
 
    @return     <code>YES</code> if the receiver is a function, <code>NO</code>
                otherwise.
 */
- (BOOL)isFunction;


/*!
    @method     length
    @abstract   Calculates the length of the receiver.
 
    @discussion The length of a <code>MPExpressionElement</code> is the number of
                symbols it consists of. For strings this is the number of
                characters in it. Functions have a length of <code>1</code>.
 
    @return     The receiver's length.
 */
- (NSUInteger)length;

@end



/*!
    @class      MPExpression
    @abstract   A <code>MPExpression</code> instance represents a mathematical
                expression.
 
    @discussion A expression consists of string elements and function elements.
                Functions and expressions together make up the expression tree.
  */
@interface MPExpression : NSObject <NSCopying, NSCoding>

#pragma mark Creation Methods
/*!
 @methodgroup Creation Methods
 */


/*!
    @method     init
    @abstract   Initlializes a new expression.
 
    @discussion This method is a convenience initializer to initialize an
                expression with <code>0</code> elements.
 
    @return     An empty expression.
 */
- (instancetype)init;


/*!
    @method     initWithElement:
    @abstract   Initializes a new expression with the specified
                <code>element</code>.

    @discussion This method is a convenience initializer to initialize an
                expression with a single element.
 
    @param      element
                The element to be added to the expression. The
                <code>element</code> will be copied.
 
    @return     An expression initialized with <code>element</code>.
 */
- (instancetype)initWithElement:(id<MPExpressionElement>)element;


/*!
    @method     initWithElements:
    @abstract   Initializes a new expression with the specified
                <code>elements</code>.
 
    @discussion All elements must conform to the <code>@link
                MPExpressionElement@/link</code> protocol. If one or more objects
                do not conform to that protocol a <code>@link
                MPIllegalElementException@/link</code> is raised.
 
                This method is the designated initializer for the
                <code>MPExpression</code> class.
 
    @param      elements
                The elements that should be added to the expression. Every
                element must conform to the <code>@link
                MPExpressionElement@/link</code> protocol. Each element is copied
                and the copy is then added to the expression. The object in the
                <code>elements</code> array is not modified.
 
    @return     An expression containing <code>elements</code>.
 */
- (instancetype)initWithElements:(NSArray *)elements; /* designated initializer */


#pragma mark Querying Expressions
/*!
 @methodgroup Querying Expressions
 */


/*!
    @property   parent
    @abstract   The receiver's parent.
 
    @discussion The receiver's parent is the function in the expression tree that
                contains the receiver.
       @warning You should never set this property manually. If you are
                implementing a custom subclass of <code>@link
                //apple_ref/occ/cl/MPFunction@/link</code> use the <code>@link
                //apple_ref/occ/macro/MPFunctionAccessorImplementation@/link</code>
                macro.
 
    @return     The parent of the receiver or <code>nil</code> if the receiver is
                the root expression.
 */
@property (nonatomic, weak) MPFunction *parent;


/*!
    @method     rootExpression
    @abstract   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.
 */
- (MPExpression *)rootExpression;


/*!
    @method     indexPath
    @abstract   Returns the index path of the receiver in the expression tree.
 
    @discussion The index path contains the indexes (starting from the root
                expression of the receiver's expression tree) that lead to the
                receiver. The indexes are expressed in the element reference
                frame.
 
    @return     The index path of the receiver in the expression tree.
 */
- (NSIndexPath *)indexPath;


/*!
    @method     countItemsInReferenceFrame:
    @abstract   Returns the number of items in the receiver in the specified
                <code>referenceFrame</code>.
 
    @param      referenceFrame
                The reference frame that should be used to count the items.
 
    @return     The current number of items in the receiver counted in the
                specified <code>referenceFrame</code>.
 */
- (NSUInteger)countItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     itemAtIndex:referenceFrame:
    @abstract   Returns the item at <code>anIndex</code>.
 
    @discussion The item is not copied before it is returned. So be aware that
                if you mutate a <code>@link
                //apple_ref/occ/cl/MPFunction@/link</code> instance returned from
                this function the receiver's expression tree will be updated to
                reflect the change.
 
    @param      anIndex
                The index of the item. If the index is greater than the number of
                items for the respective reference frame a
                <code>NSRangeException</code> is raised.
 
    @param      referenceFrame
                The reference frame that should be used to identify the item at
                <code>anIndex</code>.
 
    @return     The item at <code>anIndex</code>.
 */
- (id)itemAtIndex:(NSUInteger)anIndex
   referenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     elementAtIndex:referenceFrame:
    @abstract   Returns the element at the specified index.
 
    @discussion An element is either a string or a function. If
                <code>anIndex</code> identifies a position inside a string
                element the complete element is returned.
 
                This method always returns elements. To query items in the
                specified reference frame use
                <code>@link itemAtIndex:referenceFrame:@/link</code>.
 
    @param      anIndex
                The index of the element.
 
    @param      referenceFrame
                The reference frame <code>anIndex</code> is specified in.
 
    @return     The element at <code>anIndex</code>.
 */
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
                           referenceFrame:(MPReferenceFrame)referenceFrame;

/*!
    @method     indexOfElement:
    @abstract   Returns the index of <code>element</code> or
                <code>NSNotFound</code> if it was not found.
 
    @param      element
                The element to find.
 
    @return     The index of <code>element</code> expressed in the element
                reference frame.
 */
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element;


/*!
    @method     itemsInRange:referenceFrame:
    @abstract   Returns an array of the items that are located in the specified
                range.
 
    @discussion The objects in the returned array are copied before they are
                returned.
 
                If the <code>range</code> exceeds the receiver's bounds a
                <code>NSRangeException</code> is raised.
 
    @param      aRange
                The requested range within the receiver's bounds.
 
    @param      referenceFrame
                The referenceFrame <code>aRange</code> is expressed in.
 
    @return     An array containing all elements in the specified range. The type
                of the objects depends on the specified
                <code>referenceFrame</code>.
 */
- (NSArray *)itemsInRange:(NSRange)aRange
           referenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     allItemsInReferenceFrame:
    @abstract   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
                returned so be aware that mutations to any of the returned
                objects will update the receiver's expression tree to reflect the
                change.
 
    @return     An array of all items in the receiver.
 */
- (NSArray *)allItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     elementAtIndexPath:
    @abstract   Returns the element at the specified index path.
 
    @discussion This method finds the elements at the respective indexes starting
                at the root expression from the receiver's expression tree.
                The returned object can be a <code>NSString</code>, a
                <code>@link //apple_ref/occ/cl/MPFunction@/link</code> or a
                <code>MPExpression</code> instance depending on the specified
                <code>indexPath</code>. If any of the indexes exceed the bounds
                of the respective receiver a <code>NSRangeException</code> 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 <code>indexPath</code>. The element is not
                copied before it is returned. Be aware of the fact that any
                mutations made to the returned object will update the receiver's
                expression tree to reflect the change.
 */
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;


/*!
    @method     convertIndex:fromReferenceFrame:toReferenceFrame:
    @abstract   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 <code>@link
                convertIndex:fromReferenceFrame:toReferenceFrame:offset:@/link</code>
                instead.
 
    @param      anIndex
                The index to be converted.
 
    @param      fromReferenceFrame
                The reference frame <code>anIndex</code> is specified in.
 
    @param      toReferenceFrame
                The reference frame <code>anIndex</code> should be converted to.
 
    @return     An index specified in the <code>toReferenceFrame</code>. If
                <code>anIndex</code> identifies a location inside an item in the
                <code>toReferenceFrame</code> the index of the corresponding item
                is returned.
 */
- (NSUInteger)convertIndex:(NSUInteger)anIndex
        fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
          toReferenceFrame:(MPReferenceFrame)toReferenceFrame;


/*!
    @method     convertIndex:fromReferenceFrame:toReferenceFrame:offset:
    @abstract   Converts an index from one reference frame to another.
 
    @discussion If <code>anIndex</code> identifies a location inside an item in
                the <code>toReferenceFrame</code> the index of the corresponding
                item is returned. In that case the <code>offset</code> parameter
                will be set to the number of symbols the offset goes into the
                item at the returned index.
 
    @param      anIndex
                The index to be converted.
 
    @param      fromReferenceFrame
                The reference frame <code>anIndex</code> is specified in.
 
    @param      toReferenceFrame
                The reference frame <code>anIndex</code> should be converted to.
 
    @param      offset
                This output parameter will be set to the number of symbols that
                are between the location identified by <code>anIndex</code> 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 <code>NULL</code>.
 
    @return     An index specified in the <code>toReferenceFrame</code>
                corresponding to <code>anIndex</code>.
 */
- (NSUInteger)convertIndex:(NSUInteger)anIndex
        fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
          toReferenceFrame:(MPReferenceFrame)toReferenceFrame
                    offset:(NSUInteger *)offset;


/*!
    @method     convertRange:fromReferenceFrame:toReferenceFrame:
    @abstract   Converts a range from one reference frame to another.
 
    @discussion This method just converts the location and target of the range
                separately using
                <code>@link
                convertIndex:fromReferenceFrame:toReferenceFrame:@/link</code>.
                It ensures that the returned range definitely includes all items
                that were specified by <code>aRange</code>.
 
                The possibility that the returned range may
                include more symbols than <code>aRange</code> is ignored. If you
                need that information use
                <code>@link
                convertRange:fromReferenceFrame:toReferenceFrame:leadingOffset:trailingOffset:@/link</code>.
 
    @param      aRange
                The range to be converted.
 
    @param      fromReferenceFrame
                The reference frame <code>aRange</code> is specified in.
 
    @param      toReferenceFrame
                The reference frame <code>aRange</code> is to be converted to.
 
    @return     A range in the <code>toReferenceFrame</code> that includes the
                the items identified by <code>aRange</code>.
 */
- (NSRange)convertRange:(NSRange)aRange
     fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
       toReferenceFrame:(MPReferenceFrame)toReferenceFrame;


/*!
    @method     convertRange:fromReferenceFrame:toReferenceFrame:leadingOffset:trailingOffset:
    @abstract   Converts a range from one reference frame to another.
 
    @discussion This method just converts the location and target of the range
                separately using
                <code>@link
                convertIndex:fromReferenceFrame:toReferenceFrame:@/link</code>.
                It ensures that the returned range definitely includes all items
                that were specified by <code>aRange</code>.
 
    @param      aRange
                The range to be converted.
 
    @param      fromReferenceFrame
                The reference frame <code>aRange</code> is specified in.
 
    @param      toReferenceFrame
                The reference frame <code>aRange</code> is to be converted to.
 
    @param      leadingOffset
                The offset of the location of the returned range in respect to
                the location of <code>aRange</code>.
 
    @param      trailingOffset
                The offset of the last index in the range in respect to the last
                index of <code>aRange</code>.
 
    @return     A range in the <code>toReferenceFrame</code> that includes the
                the items specified by <code>aRange</code>.
 */
- (NSRange)convertRange:(NSRange)aRange
     fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
       toReferenceFrame:(MPReferenceFrame)toReferenceFrame
          leadingOffset:(NSUInteger *)leadingOffset
         trailingOffset:(NSUInteger *)trailingOffset;


#pragma mark Mutating Expressions
/*!
 @methodgroup Mutating Expressions
 */


/*!
    @method     replaceItemsInRange:referenceFrame:withElements:
    @abstract   Replaces the elements in the specified range with the contents of
                the <code>elements</code> array.
 
    @discussion This is the most primitive mutation method of
                <code>MPExpression</code>. Every other mutating method must
                ultimately call this method.
 
                After the receiver has been mutated the integrety of the receiver
                is restored. That basically means that subsequent strings are
                joined and empty strings removed. After restoring integrity the
                receiver sends a
                <code>@link
                changedElementsInRangePath:replacementLength:@/link</code> to
                itself. For more information see the documentation on that
                method.
 
    @param      aRange
                The range of symbols (including functions) to replace.
 
    @param      referenceFrame
                The reference frame <code>aRange</code> is specified in.
 
    @param      elements
                The elements that should replace the symbols specified by
                <code>range</code>.
 */
- (void)replaceItemsInRange:(NSRange)aRange
             referenceFrame:(MPReferenceFrame)referenceFrame
               withElements:(NSArray *)elements;


/*!
    @method     changedElementsInRangePath:replacementLength:
    @abstract   This is a notification message that is sent from the receiver to
                itself after it has been mutated.
 
    @discussion This method does nothing more than notify it's parent that it has
                been mutated at the respective range path. If you want to get
                notified about changes in an expression you should override this
                method instead of <code>@link
                replaceItemsInRange:referenceFrame:withElements:@/link</code>
                because this method gives you information about the elements that
                changed during the mutation.
 
    @param      rangePath
                The range path at which the receiver was changed starting at the
                receiver. The range addressed by <code>rangePath</code> is
                expressed in the element reference frame.
 
    @param      replacementLength
                The number of elements replacing the elements specified by
                <code>rangePath</code> (also specified in the element reference
                frame).
 */
- (void)changedElementsInRangePath:(MPRangePath *)rangePath
                 replacementLength:(NSUInteger)replacementLength;


/*!
    @method     subexpressionFromIndex:referenceFrame:
    @abstract   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's expression tree.
 
    @param      from
                The index from which to start constructing the subexpression.
 
    @param      referenceFrame
                The reference frame <code>from</code> is specified in.
 
    @return     An expression containing the items from the specified index to
                the end of the receiver.
 */
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
                          referenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     subexpressionToIndex:referenceFrame:
    @abstract   Creates an expression from the items in the receiver from the
                first to the specified item.
 
    @discussion The items from the receiver are copied. Mutations to the returned
                expression will not change the receiver's expression tree.
 
    @param      to
                The index of the first element not to include in the newly
                constructed subexpression.
 
    @param      referenceFrame
                The reference frame <code>to</code> is specified in.
 
    @return     An expression containing the items from the first item to the one
                at the specified index.
 */
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
                        referenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     subexpressionWithRange:referenceFrame:
    @abstract   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's expression tree.
 
    @param      aRange
                Specifies the items to be included in the newly created
                subexpression.
 
    @param      referenceFrame
                The reference frame <code>aRange</code> is specified in.
 
    @return     An expression containing the items in <code>aRange</code>.
 */
- (MPExpression *)subexpressionWithRange:(NSRange)aRange
                          referenceFrame:(MPReferenceFrame)referenceFrame;


#pragma mark Evaluating Expressions
/*!
 @methodgroup Evaluating Expressions
 */


/*!
    @method     parse:
    @abstract   Parses the receiver.
 
    @discussion This is a convenience method that calls <code>@link
                parseExpectingVariable:errors:@/link</code> with <code>NO</code>
                as the first argument.
                
    @param      errors
                If the receiver (or any of its elements) contain syntax errors
                this parameter is set to an appropriate value. All items in the
                array are <code>NSError</code> instances. This parameter is never
                set to an empty array. Pass <code>NULL</code> if you are not
                interested in any errors that might occur.
 
    @return     A <code>@link //apple_ref/occ/cl/MPParsedExpression@/link</code>
                instance that represents the receiver and can be evaluated or
                <code>nil</code> if an error occurs. In that case the
                <code>errors</code> parameter is set to an array containing at
                least one <code>NSError</code> instance.
 */
- (MPParsedExpression *)parse:(NSArray *__autoreleasing *)errors;


/*!
    @method     parseExpectingVariable:errors:
    @abstract   Parses the receiver.
 
    @param      flag
                If <code>YES</code> the receiver must (exept for whitespaces)
                begin with a single letter followed by an equals sign. If it
                doesn't the expression is considered invalid. Specify
                <code>NO</code> If the expression should be evaluatable by itself.
 
    @param      errors
                If the receiver (or any of its elements) contain syntax errors
                this parameter is set to an appropriate value. All items in the
                array are <code>NSError</code> instances. This parameter is never
                set to an empty array. Pass <code>NULL</code> if you are not
                interested in any errors that might occur.
 
    @return     A <code>@link //apple_ref/occ/cl/MPParsedExpression@/link</code>
                instance that represents the receiver and can be evaluated or
                <code>nil</code> if an error occurs. In that case the
                <code>errors</code> parameter is set to an array containing at
                least one <code>NSError</code> instance.
 */
- (MPParsedExpression *)parseExpectingVariable:(BOOL)flag
                                        errors:(NSArray *__autoreleasing *)errors;

@end



/*!
    @category   MPExpression (MPExpressionConvenience)
    @abstract   This category defines convenience methods for the
                <code>MPExpression</code> class.
 
    @discussion All convenience methods are completely defined in terms of other
                methods of the <code>MPExpression</code> class.
 */
@interface MPExpression (MPExpressionConvenience)

#pragma mark Querying Expressions
/*!
 @methodgroup Querying Expressions
 */


/*!
    @method     countElements
    @abstract   Returns the number of elements in the receiver.
 
    @return     The number of elements in the receiver expressed in the element
                reference frame.
 */
- (NSUInteger)countElements;


/*!
    @method     countSymbols
    @abstract   Returns the number of symbols in the receiver.
 
    @return     The number of symbols in the receiver expressed in the symbol
                reference frame.
 */
- (NSUInteger)countSymbols;


/*!
    @method     countTokens
    @abstract   Returns the number of tokens in the receiver.
 
    @return     The number of tokens in the receiver expressed in the token
                reference frame.
 */
- (NSUInteger)countTokens;


/*!
    @method     elementAtIndex:
    @abstract   Returns the element at the specified index.
 
    @param      anIndex
                The index of the element specified in the element reference
                frame.
 
    @return     The element at <code>anIndex</code>.
 */
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex;


/*!
    @method     symbolAtIndex:
    @abstract   Returns the symbol at the specified index.
 
    @param      anIndex
                The index of the symbol specified in the symbol reference frame.
 
    @return     The symbol at <code>anIndex</code>.
 */
- (id<MPExpressionElement>)symbolAtIndex:(NSUInteger)anIndex;


/*!
    @method     tokenAtIndex:
    @abstract   Returns the token at the specified index.
 
    @param      anIndex
                The index of the token specified in the token reference frame.
 
    @return     The token at <code>anIndex</code>.
 */
- (id<MPToken>)tokenAtIndex:(NSUInteger)anIndex;


#pragma mark Mutating Expressions
/*!
 @methodgroup Mutating Expressions
 */


/*!
    @method     appendElement:
    @abstract   Appends <code>anElement</code> to the receiver.
 
    @param      anElement
                The element to append to the receiver.
 */
- (void)appendElement:(id<MPExpressionElement>)anElement;


/*!
    @method     appendElements:
    @abstract   Appends the objects from <code>elements</code> to the receiver.

    @discussion All objects in the <code>elements</code> array must conform to
                the <code>@link MPExpressionElement@/link</code> protocol. If at
                least one element does not conform to that protocol a <code>@link
                MPIllegalElementException@/link</code> is raised.
 
    @param      elements
                The elements to append to the receiver.
 */
- (void)appendElements:(NSArray *)elements;


/*!
    @method     insertElement:atIndex:referenceFrame:
    @abstract   Inserts <code>anElement</code> at the specified index.
 
    @param      anElement
                The element to be inserted.
 
    @param      index
                The index where to insert <code>anElement</code>.
 
    @param      referenceFrame
                The reference frame <code>index</code> is specified in.
 */
- (void)insertElement:(id<MPExpressionElement>)anElement
              atIndex:(NSUInteger)index
       referenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     insertElements:atIndex:referenceFrame:
    @abstract   Inserts <code>elements</code> at the specified index.
 
    @discussion All objects in the <code>elements</code> array must conform to
                the <code>@link MPExpressionElement@/link</code> protocol. If at
                least one element does not conform to that protocol a <code>@link
                MPIllegalElementException@/link</code> is raised.
 
    @param      elements
                The elements to be inserted.
 
    @param      index
                The index where to insert <code>elements</code>.
 
    @param      referenceFrame
                The reference frame <code>index</code> is specified in.
 */
- (void)insertElements:(NSArray *)elements
               atIndex:(NSUInteger)index
        referenceFrame:(MPReferenceFrame)referenceFrame;


/*!
    @method     deleteElementsInRange:referenceFrame:
    @abstract   Removes the elements identified by <code>range</code> from the
                receiver.
 
    @discussion If <code>range</code> exceeds the receiver's bounds a
                <code>NSRangeException</code> is raised.
 
    @param      range
                The range of items to remove from the receiver.
 
    @param      referenceFrame
                The reference frame <code>range</code> is specified in.
 */
- (void)deleteElementsInRange:(NSRange)range
               referenceFrame:(MPReferenceFrame)referenceFrame;

@end
