// // MPValueGroup.m // MathPad // // Created by Kim Wittenburg on 09.10.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPValueGroup.h" #import "MPNumber.h" #import "MPVariable.h" #import "MPFunction+MPValue.h" #import "MPUnexpectedSymbolValue.h" #import "MPFunctionValue.h" #import "MPFactorial.h" #import "MPSuffixFunction.h" @implementation MPValueGroup { NSMutableArray *_values; NSRange _range; } - (id)init { self = [super init]; if (self) { _values = [[NSMutableArray alloc] init]; } return self; } - (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream { self = [self init]; if (self) { [tokenStream beginIgnoringWhitespaceTokens]; MPTokenStreamRecordCurrentLocation(tokenStream); // This will also skip leading whitespaces [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; [tokenStream beginAcceptingWhitespaceTokens]; BOOL checkMoreTokens = YES; while (tokenStream.currentToken.tokenType != MPWhitespaceToken && checkMoreTokens) { id currentValue; switch (tokenStream.currentToken.tokenType) { case MPNumberToken: { currentValue = [[MPNumber alloc] initWithTokenStream:tokenStream]; } break; case MPVariableToken: { currentValue = [[MPVariable alloc] initWithTokenStream:tokenStream]; } break; case MPGenericFunctionToken: { currentValue = (id)tokenStream.currentToken; [tokenStream currentTokenConsumed]; } break; case MPSinToken: case MPCosToken: case MPTanToken: case MPASinToken: case MPACosToken: case MPATanToken: { currentValue = [[MPFunctionValue alloc] initWithTokenStream:tokenStream]; } break; case MPUnidentifiedToken: case MPEqualsToken: currentValue = [[MPUnexpectedSymbolValue alloc] initWithTokenStream:tokenStream]; break; default: checkMoreTokens = NO; break; } if (checkMoreTokens) { [_values addObject:[tokenStream consumeSuffixesForValue:currentValue]]; } } _range = MPTokenStreamRecordedRange(tokenStream); [tokenStream endIgnoringOrAcceptingWhitespaceTokens]; } return self; } - (NSRange)range { return _range; } - (BOOL)validate:(MPParseError *__autoreleasing *)error { if (_values.count == 0) { if (error) { *error = MPParseError(self.range, @"Expected Value"); } return NO; } for (id value in _values) { if (![value validate:error]) { return NO; } } return YES; } - (NSDecimalNumber *)evaluate { NSDecimalNumber *result = [NSDecimalNumber one]; for (id value in _values) { NSDecimalNumber *currentValue = [value evaluate]; if ([currentValue isEqualToNumber:[NSDecimalNumber notANumber]]) { result = currentValue; break; } result = [result decimalNumberByMultiplyingBy:currentValue]; if ([result compare:@(0)] == NSOrderedSame) { break; } } return result; } - (NSArray *)expressionElements { NSMutableArray *elements = [[NSMutableArray alloc] init]; for (id value in _values) { [elements addObjectsFromArray:value.expressionElements]; } return elements; } - (void)appendValue:(id)value { [_values addObject:value]; } - (void)insertValue:(id)value atIndex:(NSUInteger)index { [_values insertObject:value atIndex:index]; } - (void)removeValue:(id)value { [_values removeObject:value]; } - (void)removeValueAtIndex:(NSUInteger)index { [_values removeObjectAtIndex:index]; } - (id)valueAtIndex:(NSUInteger)index { return [_values objectAtIndex:index]; } @end @implementation MPTokenStream (MPValueSuffixes) - (id)consumeSuffixesForValue:(id)value { BOOL repeat = YES; while (repeat) { if (self.currentToken.tokenType == MPFactorialToken) { MPFactorial *factorial = [[MPFactorial alloc] init]; factorial.value = value; value = factorial; [self currentTokenConsumed]; } else if (self.currentToken.tokenType == MPGenericFunctionToken && [self.currentToken isKindOfClass:[MPSuffixFunction class]]) { MPSuffixFunction *token = (MPSuffixFunction *)self.currentToken; token.baseValue = value; value = token; [self currentTokenConsumed]; } else { repeat = NO; } } return value; } @end