162 lines
4.7 KiB
Objective-C
162 lines
4.7 KiB
Objective-C
//
|
|
// 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 "MPFunctionValue.h"
|
|
#import "MPUnexpectedSymbolValue.h"
|
|
#import "MPFactorial.h"
|
|
|
|
#import "MPTokenStream.h"
|
|
#import "MPToken.h"
|
|
|
|
#import "MPExpression.h"
|
|
#import "MPSuffixFunction.h"
|
|
|
|
@implementation MPValueGroup {
|
|
NSMutableArray *_values;
|
|
}
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
_values = [[NSMutableArray alloc] init];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
|
|
{
|
|
self = [self init];
|
|
if (self) {
|
|
[tokenStream beginIgnoringWhitespaceTokens];
|
|
[tokenStream currentToken]; // This will 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;
|
|
if ([currentValue isKindOfClass:[MPSuffixFunction class]]) {
|
|
((MPSuffixFunction *)currentValue).baseValue = nil;
|
|
}
|
|
[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]];
|
|
}
|
|
}
|
|
|
|
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)validate:(NSError *__autoreleasing *)error
|
|
{
|
|
if (_values.count == 0) {
|
|
if (error) {
|
|
*error = MPParseError(8,
|
|
NSLocalizedString(@"Expected Value.", @"Error message. This is displayed when a value was expected but none was found."),
|
|
nil);
|
|
}
|
|
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;
|
|
}
|
|
|
|
@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 |