Archived
1
This repository has been archived on 2022-08-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mathpad/MathPad/MPExpressionEvaluator.m
Kim Wittenburg 82259f87e2 Model Redesign: Added Reference Frames
Added Inverse Functions
UI Redesign
Cleaned Code
2014-10-07 20:25:54 +02:00

262 lines
8.9 KiB
Objective-C

//
// MPExpressionEvaluator.m
// MathPad
//
// Created by Kim Wittenburg on 31.08.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPExpressionEvaluator.h"
#import "MPExpression.h"
#import "MPFunction.h"
#import "MPMathRules.h"
#import "MPToken.h"
#import "MPFunction+MPToken.h"
#import "MPTokenStream.h"
#import "MPEvaluationContext.h"
#import "MPPowerFunction.h"
@interface MPExpressionEvaluator ()
@property (readwrite, nonatomic, copy) NSString *definedVariable;
- (void)setError:(MPParseError *)error;
@end
@implementation MPExpressionEvaluator {
MPParseError *__autoreleasing *_error;
MPTokenStream *tokenStream;
}
- (id)initWithExpression:(MPExpression *)expression
{
self = [super init];
if (self) {
_expression = expression;
}
return self;
}
#pragma mark Evaluating Expressions
- (void)setError:(MPParseError *)error
{
if (_error) {
error.pathToExpression = self.expression.indexPath;
*_error = error;
}
}
- (MPTerm *)parseExpectingVariable:(BOOL)flag
error:(MPParseError *__autoreleasing *)error
{
_error = error;
tokenStream = [[MPTokenStream alloc] initWithTokens:[self.expression allItemsInReferenceFrame:MPTokenReferenceFrame]];
if (!tokenStream.hasMoreTokens) {
self.error = MPParseError(NSMakeRange(0, 0), @"Empty Expression");
return nil;
}
// Variable Definition
if (flag) {
MPToken *variableToken = [tokenStream nextToken];
MPToken *equalsToken = [tokenStream nextTokenOfType:MPEqualsToken];
if (variableToken.tokenType != MPVariableToken) {
self.error = MPParseError(variableToken.range, @"Expected Variable Definition.");
return nil;
}
if (equalsToken.tokenType != MPEqualsToken) {
self.error = MPParseError(equalsToken.range, @"Expected \"=\".");
return nil;
}
self.definedVariable = variableToken.stringValue;
}
BOOL isAtBeginning = YES;
NSMutableArray *summands = [[NSMutableArray alloc] init];
NSMutableArray *currentSummand = [[NSMutableArray alloc] init];
while (tokenStream.hasMoreTokens) {
MPToken *multiplicationToken = [tokenStream nextTokenOfType:MPMultiplicationSymbolToken];
MPToken *operatorToken = [tokenStream nextTokenOfType:MPOperatorListToken];
NSRange valueRange;
MPTerm *value = [self nextValue:&valueRange];
if (multiplicationToken) {
if (isAtBeginning) {
self.error = MPParseError(multiplicationToken.range, @"Unexpected Symbol. Expected Number.");
return nil;
}
if (operatorToken) {
if (operatorToken.numberOfOperators > [[MPMathRules sharedRules] maximumOperatorChainLengthInMultiplication]) {
self.error = MPParseError(operatorToken.range, @"Too many operators in multiplication");
return nil;
}
[currentSummand addObject:[[MPTerm alloc] initWithNumber:operatorToken.operatorValue]];
}
if (value) {
[currentSummand addObject:value];
} else {
return nil;
}
} else {
if (operatorToken) {
if (operatorToken.numberOfOperators > [[MPMathRules sharedRules] maximumOperatorChainLength]) {
self.error = MPParseError(operatorToken.range, @"Too many operators.");
return nil;
}
[summands addObject:[[MPTerm alloc] initWithFactors:currentSummand.copy]];
currentSummand = [[NSMutableArray alloc] init];
[currentSummand addObject:[[MPTerm alloc] initWithNumber:operatorToken.operatorValue]];
if (value) {
[currentSummand addObject:value];
} else {
return nil;
}
} else if (!value) {
return nil;
} else if (isAtBeginning || [[MPMathRules sharedRules] allowsImplicitMultiplication]) {
[currentSummand addObject:value];
} else {
self.error = MPParseError(NSMakeRange(valueRange.location, 0), @"Implicit Multiplication not allowed here");
return nil;
}
}
isAtBeginning = NO;
}
[summands addObject:[[MPTerm alloc] initWithFactors:currentSummand.copy]];
return [[MPTerm alloc] initWithSummands:summands.copy];
}
- (MPTerm *)nextValue:(NSRangePointer)range
{
MPToken *token = [tokenStream nextToken];
if (range) {
*range = token.range;
}
switch (token.tokenType) {
case MPNumberToken:
{
return [self decoratedTerm:[[MPTerm alloc] initWithNumber:token.number]];
}
case MPVariableToken:
{
if(![[MPEvaluationContext sharedContext] isVariableDefined:token.variable]) {
self.error = MPParseError(token.range, @"Undefined Variable");
return nil;
}
return [self decoratedTerm:[[MPTerm alloc] initWithVariable:token.variable]];
}
case MPGenericFunctionToken:
{
if ([token isKindOfClass:[MPPowerFunction class]]) {
self.error = MPParseError(NSMakeRange(token.range.location, 0), @"No Base for Power");
return nil;
}
return [self decoratedTerm:[((MPFunction *)token) parseWithError:_error]];
}
case MPSinToken:
{
BOOL inverse = [self inverseFunction];
NSRange sinTermRange;
MPTerm *sinTerm = [self nextValue:&sinTermRange];
if (!sinTerm) {
if (range) {
*range = NSUnionRange(token.range, sinTermRange);
}
return nil;
}
return inverse ? [[MPTerm alloc] initWithInverseSinOfTerm:sinTerm] : [[MPTerm alloc] initWithSinOfTerm:sinTerm];
}
case MPCosToken:
{
BOOL inverse = [self inverseFunction];
NSRange cosTermRange;
MPTerm *cosTerm = [self nextValue:&cosTermRange];
if (!cosTerm) {
if (range) {
*range = NSUnionRange(token.range, cosTermRange);
}
return nil;
}
return inverse ? [[MPTerm alloc] initWithInverseCosOfTerm:cosTerm] : [[MPTerm alloc] initWithCosOfTerm:cosTerm];
}
case MPTanToken:
{
BOOL inverse = [self inverseFunction];
NSRange tanTermRange;
MPTerm *tanTerm = [self nextValue:&tanTermRange];
if (!tanTerm) {
if (range) {
*range = NSUnionRange(token.range, tanTermRange);
}
return nil;
}
return inverse ? [[MPTerm alloc] initWithInverseTanOfTerm:tanTerm] : [[MPTerm alloc] initWithTanOfTerm:tanTerm];
}
case MPEOFToken:
{
self.error = MPParseError(token.range, @"Unexpected End. Expected Number.");
return nil;
}
default:
{
self.error = MPParseError(token.range, @"Unexpected Symbol. Expected Number.");
return nil;
}
}
}
- (MPTerm *)decoratedTerm:(MPTerm *)term
{
MPTerm *decoratedTerm = term;
MPToken *facultyToken = [tokenStream nextTokenOfType:MPFactorialToken];
if (facultyToken) {
decoratedTerm = [[MPTerm alloc] initWithFactorialOfTerm:term];
}
MPToken *powerToken = [tokenStream nextTokenOfType:MPGenericFunctionToken];
if ([powerToken isKindOfClass:[MPPowerFunction class]]) {
MPPowerFunction *powerFunction = (MPPowerFunction *)powerToken;
powerFunction.baseTerm = decoratedTerm;
return [powerFunction parseWithError:_error];
} else if (powerToken) {
tokenStream.currentTokenIndex--;
}
return decoratedTerm;
}
- (BOOL)inverseFunction
{
MPToken *powerToken = [tokenStream nextTokenOfType:MPGenericFunctionToken];
if ([powerToken isKindOfClass:[MPPowerFunction class]]) {
MPPowerFunction *powerFunction = (MPPowerFunction *)powerToken;
if (powerFunction.exponentExpression.countElements == 1) {
id<MPExpressionElement> element = [powerFunction.exponentExpression elementAtIndex:0];
if ([element isString]) {
NSString *exponent = [[((NSString *)element) componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@""];
if ([exponent isEqualToString:@"-1"]) {
return YES;
}
}
}
}
if(powerToken) {
tokenStream.currentTokenIndex--;
}
return NO;
}
@end