Archived
1

Model Redesign: Added Reference Frames

Added Inverse Functions
UI Redesign
Cleaned Code
This commit is contained in:
Kim Wittenburg
2014-10-07 20:25:54 +02:00
parent 8f2f773909
commit 82259f87e2
40 changed files with 1124 additions and 998 deletions

View File

@@ -13,84 +13,32 @@
#import "NSIndexPath+MPAdditions.h"
#import "MPException.h"
#import "MPExpressionTokenizer.h"
#import "MPExpressionEvaluator.h"
#import "MPToken.h"
@interface MPExpression () {
NSMutableArray *__strong _elements;
NSMutableArray * _elements;
}
- (void)fixElements;
@end
@interface MPExpression (MPExpressionPrivate)
- (NSArray *)tokens;
- (void)validateElements:(NSArray *)elements;
- (void)fixElements;
- (NSUInteger)lengthOfElements:(NSArray *)elements;
- (BOOL)splitElementsAtLocation:(NSUInteger)location
insertionIndex:(out NSUInteger *)insertionIndex;
@end
@implementation MPExpression (MPExpressionPrivate)
- (void)validateElements:(NSArray *)elements
{
for (id element in elements) {
if (![element conformsToProtocol:@protocol(MPExpressionElement)]) {
@throw [NSException exceptionWithName:MPIllegalElementException
reason:@"Elements must conform to the MPExpressionElement protocol."
userInfo:@{MPIllegalElementExceptionElementKey: element}];
}
}
}
- (NSUInteger)lengthOfElements:(NSArray *)elements
{
NSUInteger length = 0;
for (id<MPExpressionElement> element in elements) {
length += element.length;
}
return length;
}
- (BOOL)splitElementsAtLocation:(NSUInteger)location
insertionIndex:(out NSUInteger *)insertionIndex
{
if (location == 0) {
*insertionIndex = 0;
return NO;
}
NSUInteger splitOffset;
NSUInteger splitElementIndex = [self indexOfElementAtLocation:location
offset:&splitOffset];
if (splitOffset != 0) {
NSString *splitElement = (NSString *)self.elements[splitElementIndex];
NSString *leftPart = [splitElement substringToIndex:splitOffset];
NSString *rightPart = [splitElement substringFromIndex:splitOffset];
[_elements replaceObjectsInRange:NSMakeRange(splitElementIndex, 1)
withObjectsFromArray:@[leftPart, rightPart]];
++splitElementIndex;
}
*insertionIndex = splitElementIndex;
return splitOffset != 0;
}
- (void)_replaceSymbolsInRange:(NSRange)range
withElements:(NSArray *)elements;
- (BOOL)_splitElementsAtLocation:(NSUInteger)location
insertionIndex:(out NSUInteger *)insertionIndex;
@end
@implementation MPExpression {
NSUInteger _cachedLength;
NSArray *_tokenCache;
NSRange _editedRange;
BOOL _didSplitStartOnEditing;
@@ -117,7 +65,6 @@
self = [super init];
if (self) {
[self validateElements:elements];
_cachedLength = 0;
_elements = [[NSMutableArray alloc] initWithArray:elements
copyItems:YES];
[self fixElements];
@@ -129,11 +76,32 @@
#pragma mark Private Methods
- (NSArray *)tokens
{
if (!_tokenCache) {
_tokenCache = [MPExpressionTokenizer tokenizeExpression:self];
}
return _tokenCache;
}
- (void)validateElements:(NSArray *)elements
{
for (id element in elements) {
if (![element conformsToProtocol:@protocol(MPExpressionElement)]) {
@throw [NSException exceptionWithName:MPIllegalElementException
reason:@"Elements must conform to the MPExpressionElement protocol."
userInfo:@{MPIllegalElementExceptionElementKey: element}];
}
}
}
- (void)fixElements
{
for (NSUInteger index = 0; index < self.elements.count; index++) {
id<MPExpressionElement> next = index+1 < self.elements.count ? self.elements[index+1] : nil;
id<MPExpressionElement> current = self.elements[index];
for (NSUInteger index = 0; index < _elements.count; index++) {
id<MPExpressionElement> next = index+1 < _elements.count ? _elements[index+1] : nil;
id<MPExpressionElement> current = _elements[index];
if ([current isString]) {
if (current.length == 0) {
[_elements removeObjectAtIndex:index];
@@ -166,38 +134,283 @@
}
}
#pragma mark Querying Expressions
- (NSUInteger)numberOfElements
- (MPExpression *)rootExpression
{
return self.elements.count;
if (self.parent == nil) {
return self;
}
return [self.parent rootExpression];
}
- (NSIndexPath *)indexPath
{
if (self.parent) {
NSUInteger selfIndex = [self.parent indexOfChild:self];
return [[self.parent indexPath] indexPathByAddingIndex:selfIndex];
} else {
return [[NSIndexPath alloc] init];
}
}
- (NSUInteger)countItemsInReferenceFrame:(MPReferenceFrame)referenceFrame
{
switch (referenceFrame) {
case MPElementReferenceFrame:
return _elements.count;
case MPSymbolReferenceFrame:
{
NSUInteger count = 0;
for (id<MPExpressionElement> element in _elements) {
count += element.length;
}
return count;
}
case MPTokenReferenceFrame:
return self.tokens.count;
}
}
- (id)itemAtIndex:(NSUInteger)anIndex
referenceFrame:(MPReferenceFrame)referenceFrame
{
switch (referenceFrame) {
case MPElementReferenceFrame:
return _elements[anIndex];
case MPSymbolReferenceFrame:
{
NSUInteger location = 0;
NSUInteger elementIndex = 0;
id <MPExpressionElement> element = nil;
while (location < anIndex) {
element = _elements[elementIndex++];
location += element.length;
}
if (location == anIndex && element.isFunction) {
return element;
}
NSUInteger indexInString = location - element.length + anIndex;
return [((NSString *)element) substringWithRange:NSMakeRange(indexInString, 1)];
}
case MPTokenReferenceFrame:
return self.tokens[anIndex];
}
}
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
referenceFrame:(MPReferenceFrame)referenceFrame
{
return self.elements[anIndex];
NSUInteger elementIndex = [self convertIndex:anIndex
fromReferenceFrame:referenceFrame
toReferenceFrame:MPElementReferenceFrame];
return _elements[elementIndex];
}
- (NSArray *)elementsInIndexedRange:(NSRange)range
#warning If multiple equal expressions exist errors may occur...
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element
{
return [self.elements subarrayWithRange:range];
return [_elements indexOfObject:element];
}
- (NSArray *)elements
- (NSArray *)itemsInRange:(NSRange)range
referenceFrame:(MPReferenceFrame)referenceFrame
{
return _elements;
MPExpression *subexpression = [self subexpressionWithRange:range
referenceFrame:referenceFrame];
return [subexpression allItemsInReferenceFrame:referenceFrame];
}
- (NSArray *)allItemsInReferenceFrame:(MPReferenceFrame)referenceFrame
{
switch (referenceFrame) {
case MPElementReferenceFrame:
return _elements;
case MPSymbolReferenceFrame:
{
NSMutableArray *symbols = [[NSMutableArray alloc] init];
for (id<MPExpressionElement> element in _elements) {
if ([element isString]) {
for (NSUInteger i = 0; i < [element length]; i++) {
NSString *ichar = [NSString stringWithFormat:@"%c", [((NSString *)element) characterAtIndex:i]];
[symbols addObject:ichar];
}
} else {
[symbols addObject:element];
}
}
}
case MPTokenReferenceFrame:
return self.tokens;
}
}
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.length == 0) {
return self;
}
id<MPExpressionElement> element = _elements[[indexPath indexAtPosition:0]];
if (indexPath.length == 1) {
return element;
}
if ([element isFunction]) {
return [(MPFunction *)element elementAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
}
// TODO: Raise appropriate exeption.
return nil;
}
- (NSUInteger)convertIndex:(NSUInteger)index
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
{
return [self convertIndex:index
fromReferenceFrame:fromReferenceFrame
toReferenceFrame:toReferenceFrame
offset:NULL];
}
- (NSUInteger)convertIndex:(NSUInteger)index
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
offset:(NSUInteger *)offset
{
if (fromReferenceFrame == toReferenceFrame || index == 0) {
if (offset) {
*offset = 0;
}
return index;
}
NSUInteger symbolIndex __block = 0;
switch (fromReferenceFrame) {
case MPElementReferenceFrame:
[_elements enumerateObjectsUsingBlock:^(id<MPExpressionElement> obj, NSUInteger idx, BOOL *stop) {
symbolIndex += obj.length;
*stop = idx >= index - 1;
}];
break;
case MPSymbolReferenceFrame:
symbolIndex = index;
break;
case MPTokenReferenceFrame:
[_elements enumerateObjectsUsingBlock:^(id<MPToken> obj, NSUInteger idx, BOOL *stop) {
symbolIndex = NSMaxRange(obj.range);
*stop = idx >= index - 1;
}];
break;
}
switch (toReferenceFrame) {
case MPElementReferenceFrame:
{
NSUInteger totalLength = 0;
NSUInteger elementIndex = 0;
id<MPExpressionElement> element;
while (totalLength < symbolIndex) {
element = _elements[elementIndex++];
totalLength += element.length;
}
--elementIndex;
NSUInteger offsetInElement = element.length - totalLength + symbolIndex;
if (offsetInElement == element.length) {
offsetInElement = 0;
elementIndex++;
}
if (offset) {
*offset = offsetInElement;
}
return elementIndex;
}
case MPSymbolReferenceFrame:
if (offset) {
*offset = 0;
}
return symbolIndex;
case MPTokenReferenceFrame:
{
NSUInteger totalLength = 0;
NSUInteger tokenIndex = 0;
id<MPToken> token;
while (totalLength < symbolIndex) {
token = self.tokens[tokenIndex++];
totalLength = NSMaxRange(token.range);
}
NSUInteger offsetInToken = token.range.length - totalLength + symbolIndex;
if (offsetInToken == token.range.length) {
offsetInToken = 0;
tokenIndex++;
}
if (offset) {
*offset = offsetInToken;
}
return tokenIndex;
}
}
}
- (NSRange)convertRange:(NSRange)aRange
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
{
return [self convertRange:aRange
fromReferenceFrame:fromReferenceFrame
toReferenceFrame:toReferenceFrame
leadingOffset:NULL
trailingOffset:NULL];
}
- (NSRange)convertRange:(NSRange)aRange
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
leadingOffset:(NSUInteger *)leadingOffset
trailingOffset:(NSUInteger *)trailingOffset
{
NSUInteger start = [self convertIndex:aRange.location
fromReferenceFrame:fromReferenceFrame
toReferenceFrame:toReferenceFrame
offset:leadingOffset];
NSUInteger end = [self convertIndex:NSMaxRange(aRange)
fromReferenceFrame:fromReferenceFrame
toReferenceFrame:toReferenceFrame
offset:trailingOffset];
return NSMakeRange(start, end - start);
}
#pragma mark Mutating Expressions
- (void)replaceSymbolsInRange:(NSRange)range
- (void)replaceItemsInRange:(NSRange)range
referenceFrame:(MPReferenceFrame)referenceFrame
withElements:(NSArray *)elements
{
NSUInteger start = [self convertIndex:range.location
fromReferenceFrame:referenceFrame
toReferenceFrame:MPSymbolReferenceFrame];
NSUInteger end = [self convertIndex:NSMaxRange(range)
fromReferenceFrame:referenceFrame
toReferenceFrame:MPSymbolReferenceFrame];
[self _replaceSymbolsInRange:NSMakeRange(start, end - start)
withElements:elements];
}
- (void)_replaceSymbolsInRange:(NSRange)range
withElements:(NSArray *)elements
{
if (NSMaxRange(range) > self.length) {
if (NSMaxRange(range) > [self countItemsInReferenceFrame:MPSymbolReferenceFrame]) {
@throw [NSException exceptionWithName:NSRangeException
reason:@"Range out of bounds of expression"
userInfo:nil];
@@ -207,15 +420,15 @@
// Locate the position, split the elements
NSUInteger startIndex; // startIndex is inclusive
BOOL didSplitStart = NO;
if ([self numberOfElements] == 0) {
if (_elements.count == 0) {
startIndex = 0;
} else {
didSplitStart = [self splitElementsAtLocation:range.location
insertionIndex:&startIndex];
didSplitStart = [self _splitElementsAtLocation:range.location
insertionIndex:&startIndex];
}
NSUInteger endIndex; // endIndex is exclusive
BOOL didSplitEnd = [self splitElementsAtLocation:NSMaxRange(range)
insertionIndex:&endIndex];
BOOL didSplitEnd = [self _splitElementsAtLocation:NSMaxRange(range)
insertionIndex:&endIndex];
// Perform the replacement
NSMutableArray *newElements = [[NSMutableArray alloc] initWithArray:elements
@@ -223,7 +436,7 @@
[_elements replaceObjectsInRange:NSMakeRange(startIndex, endIndex-startIndex)
withObjectsFromArray:newElements];
_cachedLength = 0;
_tokenCache = nil;
NSUInteger editLocation = startIndex - (didSplitStart ? 1 : 0);
NSUInteger editLength = endIndex - startIndex;
@@ -246,37 +459,78 @@
}
[self fixElements];
[self.evaluator expressionDidChangeInRange:_editedRange
replacementLength:_replacementLength];
[self didChangeElementsInIndexedRangePath:[[MPRangePath alloc] initWithRange:_editedRange]
[self didChangeElementsInRangePath:[[MPRangePath alloc] initWithRange:_editedRange]
replacementLength:_replacementLength];
}
- (BOOL)_splitElementsAtLocation:(NSUInteger)location
insertionIndex:(out NSUInteger *)insertionIndex
{
if (location == 0) {
*insertionIndex = 0;
return NO;
}
NSUInteger splitOffset;
NSUInteger splitElementIndex = [self convertIndex:location
fromReferenceFrame:MPSymbolReferenceFrame
toReferenceFrame:MPElementReferenceFrame
offset:&splitOffset];
if (splitOffset != 0) {
NSString *splitElement = (NSString *)_elements[splitElementIndex];
NSString *leftPart = [splitElement substringToIndex:splitOffset];
NSString *rightPart = [splitElement substringFromIndex:splitOffset];
[_elements replaceObjectsInRange:NSMakeRange(splitElementIndex, 1)
withObjectsFromArray:@[leftPart, rightPart]];
++splitElementIndex;
}
*insertionIndex = splitElementIndex;
return splitOffset != 0;
}
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
referenceFrame:(MPReferenceFrame)referenceFrame
{
return [self subexpressionWithRange:NSMakeRange(from, [self countItemsInReferenceFrame:referenceFrame] - from)
referenceFrame:referenceFrame];
}
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
referenceFrame:(MPReferenceFrame)referenceFrame
{
return [self subexpressionWithRange:NSMakeRange(0, to)
referenceFrame:referenceFrame];
}
- (MPExpression *)subexpressionWithRange:(NSRange)range
referenceFrame:(MPReferenceFrame)referenceFrame
{
MPExpression *subexpression = [self copy];
NSRange preceedingRange = NSMakeRange(0, range.location);
NSUInteger firstOut = NSMaxRange(range);
NSRange exceedingRange = NSMakeRange(firstOut, [self countItemsInReferenceFrame:referenceFrame] - firstOut);
[subexpression deleteElementsInRange:exceedingRange
referenceFrame:referenceFrame];
[subexpression deleteElementsInRange:preceedingRange
referenceFrame:referenceFrame];
return subexpression;
}
#pragma mark Evaluating Expressions
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
{
MPTerm *term = [self.evaluator parseExpectingVariable:NO
error:error];
MPExpressionEvaluator *evaluator = [[MPExpressionEvaluator alloc] initWithExpression:self];
MPTerm *term = [evaluator parseExpectingVariable:NO
error:error];
return [term evaluate];
}
@synthesize evaluator = _evaluator;
- (MPExpressionEvaluator *)evaluator
{
if (!_evaluator) {
_evaluator = [[MPExpressionEvaluator alloc] initWithExpression:self];
}
return _evaluator;
}
#pragma mark Notifications
- (void)didChangeElementsInIndexedRangePath:(MPRangePath *)rangePath
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
replacementLength:(NSUInteger)replacementLength
{
NSUInteger selfIndex = [self.parent indexOfChild:self];
@@ -315,11 +569,11 @@
#warning Bad Implementation
NSMutableString *description = [[NSMutableString alloc] init];
NSUInteger index = 0;
for (id element in self.elements) {
for (id element in _elements) {
if ([element isString]) {
NSMutableString *correctedSymbol = [[element stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy];
// Prefix operator
if (element != self.elements[0]) {
if (element != _elements[0]) {
unichar prefix = [correctedSymbol characterAtIndex:0];
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:prefix]) {
[correctedSymbol insertString:@"*"
@@ -327,14 +581,14 @@
}
}
// Suffix operator
if (element != [self.elements lastObject]) {
if (element != [_elements lastObject]) {
unichar suffix = [correctedSymbol characterAtIndex:correctedSymbol.length-1];
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:suffix]) {
[correctedSymbol appendString:@"*"];
}
}
[description appendString:correctedSymbol];
} else if (index > 0 && [self.elements[index-1] isKindOfClass:[MPFunction class]]) {
} else if (index > 0 && [_elements[index-1] isKindOfClass:[MPFunction class]]) {
[description appendFormat:@"*%@", [element description]];
} else {
[description appendString:[element description]];
@@ -346,7 +600,7 @@
- (NSUInteger)hash
{
return [self.elements hash];
return [_elements hash];
}
@@ -355,7 +609,7 @@
- (id)copyWithZone:(NSZone *)zone
{
MPExpression *copy = [[MPExpression allocWithZone:zone] initWithElements:self.elements];
MPExpression *copy = [[MPExpression allocWithZone:zone] initWithElements:_elements];
return copy;
}
@@ -371,211 +625,52 @@
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.elements];
[aCoder encodeObject:_elements];
}
@end
@implementation MPExpression (MPExpressionExtension)
@implementation MPExpression (MPExpressionConvenience)
#pragma mark Querying Expressions
- (NSUInteger)length
- (NSUInteger)countElements
{
if (_cachedLength == 0) {
_cachedLength = [self lengthOfElements:self.elements];
}
return _cachedLength;
return [self countItemsInReferenceFrame:MPElementReferenceFrame];
}
- (MPExpression *)rootExpression
- (NSUInteger)countSymbols
{
if (self.parent == nil) {
return self;
}
return [self.parent rootExpression];
return [self countItemsInReferenceFrame:MPSymbolReferenceFrame];
}
- (NSIndexPath *)indexPath
- (NSUInteger)countTokens
{
if (self.parent) {
NSUInteger selfIndex = [self.parent indexOfChild:self];
return [[self.parent indexPath] indexPathByAddingIndex:selfIndex];
} else {
return [[NSIndexPath alloc] init];
}
return [self countItemsInReferenceFrame:MPTokenReferenceFrame];
}
- (id)objectAtIndexedSubscript:(NSUInteger)idx
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)index
{
return [self elementAtIndex:idx];
return [self itemAtIndex:index
referenceFrame:MPElementReferenceFrame];
}
#pragma mark Working With Expressions
- (id<MPExpressionElement>)elementAtLocation:(NSUInteger)location
- (id<MPExpressionElement>)symbolAtIndex:(NSUInteger)index
{
NSUInteger index = [self indexOfElementAtLocation:location offset:NULL];
return [self elementAtIndex:index];
return [self itemAtIndex:index
referenceFrame:MPSymbolReferenceFrame];
}
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
- (id<MPToken>)tokenAtIndex:(NSUInteger)index
{
if (indexPath.length == 0) {
return self;
}
id<MPExpressionElement> element = [self elementAtIndex:[indexPath indexAtPosition:0]];
if (indexPath.length == 1) {
return element;
}
if ([element isFunction]) {
return [(MPFunction *)element elementAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
}
return nil;
}
- (NSArray *)elementsInIndexedRangePath:(MPRangePath *)rangePath
{
MPExpression *targetExpression = [self elementAtIndexPath:[rangePath.location indexPathByRemovingLastIndex]];
return [targetExpression elementsInIndexedRange:rangePath.rangeAtLastIndex];
}
#warning If multiple equal expressions exist errors may occur...
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element
{
return [self.elements indexOfObject:element];
}
#pragma mark Converting Between Indexes and Locations
- (NSUInteger)indexOfElementAtLocation:(NSUInteger)location
offset:(out NSUInteger *)offset
{
if (location == 0) {
if (offset != NULL) {
*offset = 0;
}
return 0;
}
// Calculating elementIndex and splitOffset
NSUInteger totalLength = 0;
NSUInteger elementIndex = 0;
NSUInteger elementLength = 0;
for (id<MPExpressionElement> element in self.elements) {
elementLength = element.length;
totalLength += elementLength;
if (totalLength >= location) {
break;
}
++elementIndex;
}
NSUInteger elementOffset = elementLength - (totalLength - location);
id<MPExpressionElement> element = self.elements[elementIndex];
if (elementOffset == element.length) {
elementOffset = 0;
elementIndex++;
}
if (offset != NULL) {
*offset = elementOffset;
}
return elementIndex;
}
- (NSUInteger)locationOfElementAtIndex:(NSUInteger)index
{
NSUInteger location = 0;
for (NSUInteger i = 0; i < index; i++) {
location += [self elementAtIndex:i].length;
}
return location;
}
- (NSRange)indexedRangeForRange:(NSRange)aRange
{
NSUInteger startLocation = aRange.location;
NSUInteger endLocation = NSMaxRange(aRange);
NSUInteger startIndex = [self indexOfElementAtLocation:startLocation offset:NULL];
NSUInteger endIndex = [self indexOfElementAtLocation:endLocation offset:NULL];
return NSMakeRange(startIndex, endIndex-startIndex);
}
- (NSRange)rangeForIndexedRange:(NSRange)aRange
{
NSUInteger startIndex = aRange.location;
NSUInteger endIndex = NSMaxRange(aRange);
NSUInteger startLocation = [self locationOfElementAtIndex:startIndex];
NSUInteger endLocation = [self locationOfElementAtIndex:endIndex];
return NSMakeRange(startLocation, endLocation-startLocation);
return [self itemAtIndex:index
referenceFrame:MPTokenReferenceFrame];
}
#pragma mark Mutating Expressions
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
{
NSUInteger fromLocation = [self locationOfElementAtIndex:from];
return [self subexpressionFromLocation:fromLocation];
}
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
{
NSUInteger toLocation = [self locationOfElementAtIndex:to];
return [self subexpressionToLocation:toLocation];
}
- (MPExpression *)subexpressionWithIndexedRange:(NSRange)range
{
NSRange locationRange = [self rangeForIndexedRange:range];
return [self subexpressionWithRange:locationRange];
}
- (MPExpression *)subexpressionFromLocation:(NSUInteger)from
{
return [self subexpressionWithRange:NSMakeRange(from, self.length - from)];
}
- (MPExpression *)subexpressionToLocation:(NSUInteger)to
{
return [self subexpressionWithRange:NSMakeRange(0, to)];
}
- (MPExpression *)subexpressionWithRange:(NSRange)range
{
MPExpression *subexpression = [self copy];
NSRange preceedingRange = NSMakeRange(0, range.location);
NSUInteger firstOut = NSMaxRange(range);
NSRange exceedingRange = NSMakeRange(firstOut, self.length-firstOut);
[subexpression deleteElementsInRange:exceedingRange];
[subexpression deleteElementsInRange:preceedingRange];
return subexpression;
}
- (void)replaceElementsInIndexedRange:(NSRange)range
withElements:(NSArray *)elements
{
[self replaceSymbolsInRange:[self rangeForIndexedRange:range]
withElements:elements];
}
- (void)replaceSymbolsInRangePath:(MPRangePath *)rangePath
withElements:(NSArray *)elements
{
MPExpression *targetExpression = [self elementAtIndexPath:[rangePath.location indexPathByRemovingLastIndex]];
[targetExpression replaceSymbolsInRange:rangePath.rangeAtLastIndex
withElements:elements];
}
- (void)appendElement:(id<MPExpressionElement>)anElement
{
[self appendElements:@[anElement]];
@@ -583,49 +678,35 @@
- (void)appendElements:(NSArray *)elements
{
[self replaceSymbolsInRange:NSMakeRange(self.length, 0) withElements:elements];
[self replaceItemsInRange:NSMakeRange([self countItemsInReferenceFrame:MPSymbolReferenceFrame], 0)
referenceFrame:MPSymbolReferenceFrame
withElements:elements];
}
- (void)insertElement:(id<MPExpressionElement>)anElement
atIndex:(NSUInteger)index
referenceFrame:(MPReferenceFrame)referenceFrame
{
[self insertElement:anElement
atLocation:[self locationOfElementAtIndex:index]];
[self insertElements:@[anElement]
atIndex:index
referenceFrame:referenceFrame];
}
- (void)insertElements:(NSArray *)elements
atIndex:(NSUInteger)index
referenceFrame:(MPReferenceFrame)referenceFrame
{
[self insertElements:elements
atLocation:[self locationOfElementAtIndex:index]];
}
- (void)insertElement:(id<MPExpressionElement>)anElement
atLocation:(NSUInteger)location
{
[self insertElements:@[anElement] atLocation:location];
}
- (void)insertElements:(NSArray *)elements
atLocation:(NSUInteger)location
{
[self replaceSymbolsInRange:NSMakeRange(location, 0) withElements:elements];
}
- (void)deleteElementsInIndexedRange:(NSRange)range
{
[self deleteElementsInIndexedRange:[self rangeForIndexedRange:range]];
[self replaceItemsInRange:NSMakeRange(index, 0)
referenceFrame:referenceFrame
withElements:elements];
}
- (void)deleteElementsInRange:(NSRange)range
referenceFrame:(MPReferenceFrame)referenceFrame
{
[self replaceSymbolsInRange:range withElements:@[]];
}
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx
{
[self replaceSymbolsInRange:NSMakeRange(idx, 1)
withElements:@[obj]];
[self replaceItemsInRange:range
referenceFrame:referenceFrame
withElements:@[]];
}
@end