Added the MPExpressionTree Classes
This commit is contained in:
197
MathPad/MPValueGroup.m
Normal file
197
MathPad/MPValueGroup.m
Normal file
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// 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<MPValue> 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<MPValue>)tokenStream.currentToken;
|
||||
[tokenStream currentTokenConsumed];
|
||||
}
|
||||
break;
|
||||
|
||||
case MPSinToken:
|
||||
case MPCosToken:
|
||||
case MPTanToken:
|
||||
case MPASinToken:
|
||||
case MPACosToken:
|
||||
case MPATanToken:
|
||||
{
|
||||
[tokenStream currentTokenConsumed];
|
||||
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<MPValue> value in _values) {
|
||||
if (![value validate:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)evaluate
|
||||
{
|
||||
NSDecimalNumber *result = [NSDecimalNumber one];
|
||||
for (id<MPValue> 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<MPValue> value in _values) {
|
||||
[elements addObjectsFromArray:value.expressionElements];
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
- (void)appendValue:(id<MPValue>)value
|
||||
{
|
||||
[_values addObject:value];
|
||||
}
|
||||
|
||||
- (void)insertValue:(id<MPValue>)value
|
||||
atIndex:(NSUInteger)index
|
||||
{
|
||||
[_values insertObject:value
|
||||
atIndex:index];
|
||||
}
|
||||
|
||||
- (void)removeValue:(id<MPValue>)value
|
||||
{
|
||||
[_values removeObject:value];
|
||||
}
|
||||
|
||||
- (void)removeValueAtIndex:(NSUInteger)index
|
||||
{
|
||||
[_values removeObjectAtIndex:index];
|
||||
}
|
||||
|
||||
- (id<MPValue>)valueAtIndex:(NSUInteger)index
|
||||
{
|
||||
return [_values objectAtIndex:index];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation MPTokenStream (MPValueSuffixes)
|
||||
|
||||
- (id<MPValue>)consumeSuffixesForValue:(id<MPValue>)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
|
||||
Reference in New Issue
Block a user