// // MPExpressionTree.m // MathPad // // Created by Kim Wittenburg on 09.10.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPExpressionTree.h" @implementation MPExpressionTree { NSRange _variableDefinitionRange; NSMutableArray *_summands; NSRange _range; } - (id)init { self = [super init]; if (self) { _summands = [[NSMutableArray alloc] init]; } return self; } - (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream { self = [self init]; if (self) { MPTokenStreamRecordCurrentLocation(tokenStream); [tokenStream beginIgnoringWhitespaceTokens]; _variableDefinitionRange = NSMakeRange(NSNotFound, 0); self.definedVariable = nil; if (tokenStream.currentToken.tokenType == MPVariableToken) { if (tokenStream.peekNextToken.tokenType == MPEqualsToken) { self.definedVariable = tokenStream.currentToken.stringValue; NSRange variableRange = tokenStream.currentToken.range; [tokenStream currentTokenConsumed]; NSRange equalsRange = tokenStream.currentToken.range; [tokenStream currentTokenConsumed]; _variableDefinitionRange = NSUnionRange(variableRange, equalsRange); } } while ([tokenStream hasMoreTokens]) { [_summands addObject:[[MPSummand alloc] initWithTokenStream:tokenStream]]; } [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; _range = MPTokenStreamRecordedRange(tokenStream); } return self; } - (NSRange)range { return _range; } - (BOOL)validate:(MPParseError *__autoreleasing *)error { return [self validateExpectingVariableDefinition:NO error:error]; } - (BOOL)validateExpectingVariableDefinition:(BOOL)flag error:(MPParseError *__autoreleasing *)error { if (flag) { if (!self.definedVariable) { if (error) { *error = MPParseError(NSMakeRange(self.range.location, 0), @"Expected Variable Definition."); } return NO; } } else { if (self.definedVariable) { if (error) { *error = MPParseError(_variableDefinitionRange, @"Unexpected Variable Definition"); } return NO; } } if (_summands.count == 0) { if (error) { *error = MPParseError(self.range, @"Empty Expression."); } return NO; } for (MPSummand *summand in _summands) { if (![summand validate:error]) { return NO; } } return YES; } - (NSDecimalNumber *)evaluate { NSDecimalNumber *value = [NSDecimalNumber zero]; for (MPSummand *summand in _summands) { NSDecimalNumber *currentValue = [summand evaluate]; if ([currentValue isEqualToNumber:[NSDecimalNumber notANumber]]) { value = currentValue; break; } value = [value decimalNumberByAdding:currentValue]; } return value; } - (NSArray *)expressionElements { NSMutableArray *elements = [[NSMutableArray alloc] init]; if (self.definedVariable) { [elements addObject:[NSString stringWithFormat:@"%@=", self.definedVariable]]; } for (MPSummand *summand in _summands) { [elements addObjectsFromArray:summand.expressionElements]; } return elements; } - (NSArray *)summands { return _summands; } - (void)appendSummand:(MPSummand *)summand { [_summands addObject:summand]; } - (void)insertSummand:(MPSummand *)summand atIndex:(NSUInteger)index { [_summands insertObject:summand atIndex:index]; } - (void)removeSummand:(MPSummand *)summand { [_summands removeObject:summand]; } - (void)removeSummandAtIndex:(NSUInteger)index { [_summands removeObjectAtIndex:index]; } - (MPSummand *)summandAtIndex:(NSUInteger)index { return [_summands objectAtIndex:index]; } @end