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
2014-09-30 22:18:51 +02:00

264 lines
8.0 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;
@property (nonatomic, strong) NSArray *tokens;
- (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;
}
@synthesize lexer = _lexer;
- (void)setLexer:(MPExpressionTokenizer *)lexer
{
_lexer = lexer;
self.tokens = nil;
}
- (MPExpressionTokenizer *)lexer
{
if (!_lexer) {
_lexer = [[MPExpressionTokenizer alloc] init];
}
return _lexer;
}
- (NSArray *)tokens
{
if (!_tokens) {
_tokens = [self.lexer tokenizeExpression:self.expression];
}
return _tokens;
}
- (void)expressionDidChangeInRange:(NSRange)range
replacementLength:(NSUInteger)replacementLength
{
self.tokens = nil;
}
#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.tokens];
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:
{
return [self decoratedTerm:[((MPFunction *)token) parseWithError:_error]];
}
case MPSinToken:
{
NSRange sinTermRange;
MPTerm *sinTerm = [self nextValue:&sinTermRange];
if (!sinTerm) {
if (range) {
*range = NSUnionRange(token.range, sinTermRange);
}
return nil;
}
return [[MPTerm alloc] initWithSinOfTerm:sinTerm];
}
case MPCosToken:
{
NSRange cosTermRange;
MPTerm *cosTerm = [self nextValue:&cosTermRange];
if (!cosTerm) {
if (range) {
*range = NSUnionRange(token.range, cosTermRange);
}
return nil;
}
return [[MPTerm alloc] initWithSinOfTerm:cosTerm];
}
case MPTanToken:
{
NSRange tanTermRange;
MPTerm *tanTerm = [self nextValue:&tanTermRange];
if (!tanTerm) {
if (range) {
*range = NSUnionRange(token.range, tanTermRange);
}
return nil;
}
return [[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 {
tokenStream.currentLocation--;
}
return decoratedTerm;
}
@end