Updated Schemes
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3B85830C19BB5E5500D76A8D"
|
||||
BuildableName = "MathKit.framework"
|
||||
BlueprintName = "MathKit"
|
||||
ReferencedContainer = "container:MathPad.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -38,6 +38,16 @@
|
||||
ReferencedContainer = "container:MathPad.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3B85831C19BB5E5500D76A8D"
|
||||
BuildableName = "MathKitTests.xctest"
|
||||
BlueprintName = "MathKitTests"
|
||||
ReferencedContainer = "container:MathPad.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>MathKit.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>MathPad.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
@@ -12,6 +17,16 @@
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>3B85830C19BB5E5500D76A8D</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>3B85831C19BB5E5500D76A8D</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>3BF9976A18DE623E009CF6C4</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// MPExpression+MPDisplayExtension.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 23.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPModel.h"
|
||||
|
||||
@interface MPExpression (MPDisplayExtension)
|
||||
|
||||
- (void)subexpressionChangedAtRangePath:(MPRangePath *)rangePath;
|
||||
|
||||
@end
|
||||
|
||||
@interface MPFunction (MPDisplayExtension)
|
||||
|
||||
- (void)subexpressionChangedAtRangePath:(MPRangePath *)rangePath;
|
||||
|
||||
@end
|
||||
@@ -1,33 +0,0 @@
|
||||
//
|
||||
// MPExpression+MPDisplayExtension.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 23.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPDisplayExtension.h"
|
||||
|
||||
@implementation MPExpression (MPDisplayExtension)
|
||||
|
||||
- (void)subexpressionChangedAtRangePath:(MPRangePath *)rangePath
|
||||
{
|
||||
NSUInteger index = [self.parent indexOfChild:self];
|
||||
NSIndexPath *newLocation = [rangePath.location indexPathByPrecedingIndex:index];
|
||||
[self.parent subexpressionChangedAtRangePath:[[MPRangePath alloc] initWithLocation:newLocation
|
||||
length:rangePath.length]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPFunction (MPDisplayExtension)
|
||||
|
||||
- (void)subexpressionChangedAtRangePath:(MPRangePath *)rangePath
|
||||
{
|
||||
NSUInteger index = [self.parent indexOfSymbol:self];
|
||||
NSIndexPath *newLocation = [rangePath.location indexPathByPrecedingIndex:index];
|
||||
[self.parent subexpressionChangedAtRangePath:[[MPRangePath alloc] initWithLocation:newLocation
|
||||
length:rangePath.length]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,28 +0,0 @@
|
||||
//
|
||||
// MPElementParser.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 10.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPParsedProduct.h"
|
||||
#import "MPParseError.h"
|
||||
|
||||
#define MPMaximumOperatorChainLength NSUIntegerMax
|
||||
|
||||
@interface MPElementParser : NSObject
|
||||
|
||||
- (NSArray *)parseElement:(NSString *)string
|
||||
previousProduct:(MPParsedProduct *)previousProduct
|
||||
nextFactor:(id<MPParsedFactor>)nextFactor
|
||||
definesVariable:(BOOL)flag
|
||||
definedVariable:(NSString *__autoreleasing *)variableName
|
||||
error:(out MPParseError *__autoreleasing *)error;
|
||||
- (NSArray *)parseElement:(NSString *)string
|
||||
previousProduct:(MPParsedProduct *)previousProduct
|
||||
nextFactor:(id<MPParsedFactor>)nextFactor
|
||||
error:(out MPParseError *__autoreleasing *)error;
|
||||
|
||||
@end
|
||||
@@ -1,345 +0,0 @@
|
||||
//
|
||||
// MPElementParser.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 10.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPElementParser.h"
|
||||
#import "NSRegularExpression+MPParsingAdditions.h"
|
||||
#import "MPMathRules.h"
|
||||
|
||||
#import "MPParsedFactor.h"
|
||||
#import "MPParsedNumber.h"
|
||||
#import "MPParsedVariable.h"
|
||||
#import "MPParsedOperator.h"
|
||||
|
||||
#define MPMultiplicationSymbol @"*"
|
||||
|
||||
@interface MPElementParser ()
|
||||
|
||||
@property (nonatomic) NSString *input;
|
||||
@property (nonatomic) NSUInteger parsePosition;
|
||||
|
||||
- (BOOL)allowsImplicitMultiplication;
|
||||
- (BOOL)maximumOperatorChainLength;
|
||||
- (BOOL)maximumOperatorChainLengthInMultiplication;
|
||||
- (BOOL)maximumOperatorChainLengthInFunction;
|
||||
|
||||
- (void)setError:(MPParseError *)error;
|
||||
|
||||
- (BOOL)isAtEnd;
|
||||
|
||||
- (NSRange)parseVariableDefinition:(NSString *__autoreleasing *)variableName;
|
||||
|
||||
- (NSRange)parseWhitespaces;
|
||||
- (NSRange)parseMultiplicationSymbol;
|
||||
- (MPParsedOperator *)parseOperators;
|
||||
- (id<MPParsedFactor>)parseValue;
|
||||
- (MPParsedNumber *)parseNumber;
|
||||
- (MPParsedVariable *)parseVariable;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPElementParser {
|
||||
MPParseError *__autoreleasing *outError;
|
||||
}
|
||||
|
||||
#pragma mark Helpers
|
||||
- (BOOL)allowsImplicitMultiplication
|
||||
{
|
||||
return [MPMathRules sharedRules].allowsImplicitMultiplication;
|
||||
}
|
||||
|
||||
- (BOOL)maximumOperatorChainLength
|
||||
{
|
||||
return [MPMathRules sharedRules].maximumOperatorChainLength;
|
||||
}
|
||||
|
||||
- (BOOL)maximumOperatorChainLengthInFunction
|
||||
{
|
||||
return [MPMathRules sharedRules].maximumOperatorChainLengthInFunction;
|
||||
}
|
||||
|
||||
- (BOOL)maximumOperatorChainLengthInMultiplication
|
||||
{
|
||||
return [MPMathRules sharedRules].maximumOperatorChainLengthInMultiplication;
|
||||
}
|
||||
|
||||
#pragma mark Parsing Methods
|
||||
|
||||
- (BOOL)isAtEnd
|
||||
{
|
||||
return self.parsePosition >= self.input.length;
|
||||
}
|
||||
|
||||
- (void)setError:(MPParseError *)error
|
||||
{
|
||||
if (outError != NULL) {
|
||||
*outError = error;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)parseElement:(NSString *)string
|
||||
previousProduct:(MPParsedProduct *)previousProduct
|
||||
nextFactor:(id<MPParsedFactor>)nextFactor
|
||||
error:(out MPParseError *__autoreleasing *)error
|
||||
{
|
||||
return [self parseElement:string
|
||||
previousProduct:previousProduct
|
||||
nextFactor:nextFactor
|
||||
definesVariable:NO
|
||||
definedVariable:NULL
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (NSArray *)parseElement:(NSString *)string
|
||||
previousProduct:(MPParsedProduct *)previousProduct
|
||||
nextFactor:(id<MPParsedFactor>)nextFactor
|
||||
definesVariable:(BOOL)flag
|
||||
definedVariable:(NSString *__autoreleasing *)variableName
|
||||
error:(out MPParseError *__autoreleasing *)error
|
||||
{
|
||||
self.input = string;
|
||||
outError = error;
|
||||
self.parsePosition = 0;
|
||||
|
||||
NSString *definedVariable;
|
||||
NSRange variableDefinitionRange = [self parseVariableDefinition:&definedVariable];
|
||||
if (flag) {
|
||||
if (!definedVariable) {
|
||||
self.error = MPParseError(NSMakeRange(0, 0), @"Expected Variable Definition");
|
||||
return nil;
|
||||
} else if (variableName) {
|
||||
*variableName = definedVariable;
|
||||
}
|
||||
} else if (definedVariable) {
|
||||
self.error = MPParseError(variableDefinitionRange, @"Unexpected Variable Definition");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *products = [[NSMutableArray alloc] init];
|
||||
MPParsedProduct *currentProduct = previousProduct;
|
||||
|
||||
while (YES) {
|
||||
[self parseWhitespaces];
|
||||
|
||||
NSRange multiplicationSymbolRange = [self parseMultiplicationSymbol];
|
||||
BOOL hasMultiplicationSymbol = multiplicationSymbolRange.location != NSNotFound;
|
||||
|
||||
MPParsedOperator *operators = [self parseOperators];
|
||||
|
||||
// NSRange functionRange = ...
|
||||
// BOOL hasFunction = functionRange.location != NSNotFound;
|
||||
|
||||
id<MPParsedFactor> value = [self parseValue];
|
||||
|
||||
|
||||
if (!value.exists) {
|
||||
if ([self isAtEnd] && nextFactor != nil) {
|
||||
if (hasMultiplicationSymbol) {
|
||||
if (operators.numberOfOperators > self.maximumOperatorChainLengthInFunction) {
|
||||
self.error = MPParseError(operators.range, @"Too many operators in multiplication.");
|
||||
return nil;
|
||||
}
|
||||
[currentProduct addFactor:operators];
|
||||
} else if (operators.exists) {
|
||||
if (operators.numberOfOperators > self.maximumOperatorChainLength) {
|
||||
self.error = MPParseError(operators.range, @"Too many operators.");
|
||||
return nil;
|
||||
}
|
||||
[products addObject:currentProduct];
|
||||
currentProduct = [[MPParsedProduct alloc] init];
|
||||
[currentProduct addFactor:operators];
|
||||
} else if (self.allowsImplicitMultiplication) {
|
||||
if (!currentProduct) {
|
||||
currentProduct = [[MPParsedProduct alloc] init];
|
||||
}
|
||||
} else {
|
||||
self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Implicit Multiplication not allowed.");
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
} else if ([self isAtEnd]) {
|
||||
if (hasMultiplicationSymbol || operators.exists) {
|
||||
self.error = MPParseError(NSMakeRange(self.parsePosition, 0), @"Unexpected End. Expected Number.");
|
||||
return nil;
|
||||
}
|
||||
} else {
|
||||
self.error = MPParseError(NSMakeRange(self.parsePosition, 1), @"Unexpected Symbol. Expected Number.");
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (hasMultiplicationSymbol) {
|
||||
if (currentProduct) {
|
||||
if (operators.numberOfOperators > self.maximumOperatorChainLengthInMultiplication) {
|
||||
self.error = MPParseError(operators.range, @"Too many operators in multiplication.");
|
||||
return nil;
|
||||
}
|
||||
[currentProduct addFactor:operators];
|
||||
[currentProduct addFactor:value];
|
||||
} else {
|
||||
self.error = MPParseError(multiplicationSymbolRange, @"Unexpected Symbol. Expected Number.");
|
||||
return nil;
|
||||
}
|
||||
} else if (operators.exists) {
|
||||
if (operators.numberOfOperators > self.maximumOperatorChainLength) {
|
||||
self.error = MPParseError(operators.range, @"Too many operators.");
|
||||
return nil;
|
||||
}
|
||||
if (currentProduct) {
|
||||
[products addObject:currentProduct];
|
||||
}
|
||||
currentProduct = [[MPParsedProduct alloc] initWithFactor:operators];
|
||||
[currentProduct addFactor:value];
|
||||
} else if (!currentProduct) {
|
||||
currentProduct = [[MPParsedProduct alloc] initWithFactor:value];
|
||||
} else if (self.allowsImplicitMultiplication) {
|
||||
[currentProduct addFactor:value];
|
||||
} else {
|
||||
self.error = MPParseError(NSMakeRange(value.range.location, 0), @"Implicit Multiplication not allowed.");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextFactor) {
|
||||
[currentProduct addFactor:nextFactor];
|
||||
}
|
||||
[products addObject:currentProduct];
|
||||
return products;
|
||||
}
|
||||
|
||||
static NSRegularExpression *variableDefinitionRegex;
|
||||
- (NSRange)parseVariableDefinition:(NSString *__autoreleasing *)variableName
|
||||
{
|
||||
if (!variableDefinitionRegex) {
|
||||
variableDefinitionRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*([A-Za-z])\\s*=\\s*"
|
||||
options:0
|
||||
error:NULL];
|
||||
}
|
||||
|
||||
NSTextCheckingResult *match = [variableDefinitionRegex firstMatchInString:self.input
|
||||
fromIndex:self.parsePosition];
|
||||
if (!match) {
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
self.parsePosition = NSMaxRange(match.range);
|
||||
NSRange variableDefinitionRange = [match rangeAtIndex:1];
|
||||
*variableName = [self.input substringWithRange:variableDefinitionRange];
|
||||
return variableDefinitionRange;
|
||||
}
|
||||
|
||||
static NSRegularExpression *whitespaceRegex;
|
||||
- (NSRange)parseWhitespaces
|
||||
{
|
||||
if (!whitespaceRegex) {
|
||||
whitespaceRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*"
|
||||
options:0
|
||||
error:NULL];
|
||||
}
|
||||
NSTextCheckingResult *match = [whitespaceRegex firstMatchInString:self.input
|
||||
fromIndex:self.parsePosition];
|
||||
if (match) {
|
||||
self.parsePosition = NSMaxRange(match.range);
|
||||
return match.range;
|
||||
} else {
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static NSRegularExpression *multiplicationSymbolRegex;
|
||||
- (NSRange)parseMultiplicationSymbol
|
||||
{
|
||||
if (!multiplicationSymbolRegex) {
|
||||
NSString *multiplicationSymbolString = [NSRegularExpression escapedPatternForString:MPMultiplicationSymbol];
|
||||
NSString *multiplicationSymbolRegexString = [NSString stringWithFormat:@"\\A\\s*(%@)\\s*", multiplicationSymbolString];
|
||||
multiplicationSymbolRegex = [NSRegularExpression regularExpressionWithPattern:multiplicationSymbolRegexString
|
||||
options:0
|
||||
error:NULL];
|
||||
}
|
||||
NSTextCheckingResult *match = [multiplicationSymbolRegex firstMatchInString:self.input
|
||||
fromIndex:self.parsePosition];
|
||||
if (!match) {
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
self.parsePosition = NSMaxRange(match.range);
|
||||
return [match rangeAtIndex:1];
|
||||
}
|
||||
|
||||
static NSRegularExpression *operatorsRegex;
|
||||
- (MPParsedOperator *)parseOperators
|
||||
{
|
||||
if (!operatorsRegex) {
|
||||
operatorsRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*([+-](?:\\s*[+-])*)\\s*"
|
||||
options:0
|
||||
error:NULL];
|
||||
}
|
||||
NSTextCheckingResult *match = [operatorsRegex firstMatchInString:self.input
|
||||
fromIndex:self.parsePosition];
|
||||
NSRange matchRange;
|
||||
if (!match) {
|
||||
matchRange = NSMakeRange(NSNotFound, 0);
|
||||
} else {
|
||||
self.parsePosition = NSMaxRange(match.range);
|
||||
matchRange = [match rangeAtIndex:1];
|
||||
}
|
||||
return [[MPParsedOperator alloc] initWithRange:matchRange
|
||||
inString:self.input];
|
||||
}
|
||||
|
||||
- (id<MPParsedFactor>)parseValue
|
||||
{
|
||||
MPParsedNumber *parsedNumber = [self parseNumber];
|
||||
if (!parsedNumber.exists) {
|
||||
MPParsedVariable *parsedVariable = [self parseVariable];
|
||||
if (parsedVariable.exists) {
|
||||
return parsedVariable;
|
||||
}
|
||||
}
|
||||
return parsedNumber;
|
||||
}
|
||||
|
||||
- (MPParsedNumber *)parseNumber
|
||||
{
|
||||
NSString *decimalSeparatorRegexString = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
|
||||
NSString *numberRegexFormat = [NSString stringWithFormat:@"\\A\\s*((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))\\s*", decimalSeparatorRegexString, decimalSeparatorRegexString];
|
||||
NSRegularExpression *numberRegex = [NSRegularExpression regularExpressionWithPattern:numberRegexFormat
|
||||
options:0
|
||||
error:NULL];
|
||||
NSTextCheckingResult *match = [numberRegex firstMatchInString:self.input
|
||||
fromIndex:self.parsePosition];
|
||||
NSRange matchRange;
|
||||
if (!match) {
|
||||
matchRange = NSMakeRange(NSNotFound, 0);
|
||||
} else {
|
||||
self.parsePosition = NSMaxRange(match.range);
|
||||
matchRange = [match rangeAtIndex:1];
|
||||
}
|
||||
return [[MPParsedNumber alloc] initWithRange:matchRange
|
||||
inString:self.input];
|
||||
}
|
||||
|
||||
static NSRegularExpression *variableRegex;
|
||||
- (MPParsedVariable *)parseVariable
|
||||
{
|
||||
if (!variableRegex) {
|
||||
variableRegex = [NSRegularExpression regularExpressionWithPattern:@"\\A\\s*([A-Za-z])\\s*"
|
||||
options:0
|
||||
error:NULL];
|
||||
}
|
||||
NSTextCheckingResult *match = [variableRegex firstMatchInString:self.input
|
||||
fromIndex:self.parsePosition];
|
||||
NSRange matchRange;
|
||||
if (!match) {
|
||||
matchRange = NSMakeRange(NSNotFound, 0);
|
||||
} else {
|
||||
self.parsePosition = NSMaxRange(match.range);
|
||||
matchRange = [match rangeAtIndex:1];
|
||||
}
|
||||
return [[MPParsedVariable alloc] initWithRange:matchRange
|
||||
inString:self.input];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// MPException_Private.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 19.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MathPad_MPException_Private_h
|
||||
#define MathPad_MPException_Private_h
|
||||
|
||||
extern NSString *MPIllegalSymbolExceptionReason;
|
||||
|
||||
#endif
|
||||
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// MPFunction+MPParsedFactor.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <MathKit/MathKit.h>
|
||||
#import "MPParsedFactor.h"
|
||||
|
||||
@interface MPFunction (MPParsedFactor) <MPParsedFactor>
|
||||
|
||||
@end
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// MPFunction+MPParsedFactor.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPFunction+MPParsedFactor.h"
|
||||
|
||||
@implementation MPFunction (MPParsedFactor)
|
||||
|
||||
- (instancetype)initWithRange:(NSRange)range
|
||||
inString:(NSString *)string
|
||||
{
|
||||
return [self init];
|
||||
}
|
||||
|
||||
- (BOOL)exists
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSRange)range
|
||||
{
|
||||
NSUInteger selfIndex = [self.parent indexOfElement:self];
|
||||
return NSMakeRange([self.parent locationOfElementAtIndex:selfIndex], 1);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,20 +0,0 @@
|
||||
//
|
||||
// YYParse.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 05.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPMath.yy.h"
|
||||
#import "MPMath.tab.h"
|
||||
#import "MPParsedElement.h"
|
||||
|
||||
#ifndef MathPad_YYParse_h
|
||||
#define MathPad_YYParse_h
|
||||
|
||||
extern MPParsedElement *parseResult;
|
||||
|
||||
int yyparse();
|
||||
|
||||
#endif
|
||||
@@ -1,16 +0,0 @@
|
||||
%option noyywrap
|
||||
%{
|
||||
@import Foundation;
|
||||
#include "MPMath.tab.h"
|
||||
%}
|
||||
%%
|
||||
/* Ignore Whitespaces */
|
||||
[ \t\n] ;
|
||||
/* Operators. Divisions are automatically transformed into fractions and dealt
|
||||
with elsewhere. */
|
||||
\+ { return PLUS; }
|
||||
- { return MINUS; }
|
||||
\* { return DOT; }
|
||||
/* Numbers */
|
||||
[0-9]+(\.[0-9]+)? { yylval.number = atof(yytext); return NUMBER; }
|
||||
%%
|
||||
@@ -1,126 +0,0 @@
|
||||
%{
|
||||
#import "MPMath.h"
|
||||
#define AT @
|
||||
|
||||
MPParsedElement *parseResult;
|
||||
|
||||
int yylex();
|
||||
int yyparse();
|
||||
FILE *yyin;
|
||||
|
||||
void yyerror(const char *s);
|
||||
%}
|
||||
|
||||
%error-verbose
|
||||
|
||||
%initial-action
|
||||
{
|
||||
parseResult = [[MPParsedElement alloc] init];
|
||||
};
|
||||
|
||||
%union {
|
||||
double number;
|
||||
}
|
||||
/* Terminals */
|
||||
%token PLUS
|
||||
%left MINUS
|
||||
%token DOT
|
||||
%token <number> NUMBER
|
||||
|
||||
/* Nonterminals */
|
||||
%type <number> summands
|
||||
%type <number> factor
|
||||
%type <number> product
|
||||
|
||||
%%
|
||||
|
||||
element:
|
||||
factor { parseResult.isFactor = YES;
|
||||
parseResult.factor = $1;
|
||||
}
|
||||
| operator
|
||||
| prefix summands suffix
|
||||
;
|
||||
|
||||
factor:
|
||||
DOT product DOT { $$ = $2;
|
||||
}
|
||||
| DOT product { $$ = $2;
|
||||
}
|
||||
| product DOT { $$ = $1;
|
||||
}
|
||||
| product { $$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
product:
|
||||
product DOT product { $$ = $1 * $3;
|
||||
}
|
||||
| product product { $$ = $1 * $2;
|
||||
}
|
||||
| NUMBER { $$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
operator:
|
||||
PLUS { parseResult.suffixMultiplicator = 1;
|
||||
parseResult.hasSuffixMultiplicator = YES;
|
||||
}
|
||||
| MINUS { parseResult.suffixMultiplicator = -1;
|
||||
parseResult.hasSuffixMultiplicator = YES;
|
||||
NSLog(AT"Op");
|
||||
}
|
||||
| DOT { parseResult.isFactor = YES;
|
||||
parseResult.factor = 1;
|
||||
}
|
||||
| { parseResult.isFactor = YES;
|
||||
parseResult.factor = 1;
|
||||
}
|
||||
;
|
||||
|
||||
prefix:
|
||||
DOT product { parseResult.prefixMultiplicator = $2;
|
||||
parseResult.hasPrefixMultiplicator = YES;
|
||||
parseResult.prefixOperatorExplicit = YES;
|
||||
}
|
||||
| product { parseResult.prefixMultiplicator = $1;
|
||||
parseResult.hasPrefixMultiplicator = YES;
|
||||
parseResult.prefixOperatorExplicit = YES;
|
||||
}
|
||||
| { parseResult.hasPrefixMultiplicator = NO;
|
||||
}
|
||||
;
|
||||
|
||||
summands:
|
||||
summands summand
|
||||
| summand
|
||||
;
|
||||
|
||||
summand:
|
||||
PLUS product { [parseResult.summands addObject:AT($2)];
|
||||
}
|
||||
| MINUS product { [parseResult.summands addObject:AT(-$2)];
|
||||
}
|
||||
;
|
||||
|
||||
suffix:
|
||||
PLUS { parseResult.suffixMultiplicator = 1;
|
||||
parseResult.hasSuffixMultiplicator = YES;
|
||||
}
|
||||
| MINUS { parseResult.suffixMultiplicator = -1;
|
||||
parseResult.hasSuffixMultiplicator = YES;
|
||||
}
|
||||
| DOT { parseResult.suffixMultiplicator = 0;
|
||||
parseResult.hasSuffixMultiplicator = YES;
|
||||
}
|
||||
| { parseResult.hasSuffixMultiplicator = NO;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void yyerror(const char *s) {
|
||||
NSLog(@"EEK, parse error! Message: %s", s);
|
||||
// might as well halt now:
|
||||
exit(-1);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// MPModel.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 20.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
/*
|
||||
This is a convenience header which imports all model classes defined by MathPad.
|
||||
*/
|
||||
|
||||
#ifndef MathPad_MPModel_h
|
||||
#define MathPad_MPModel_h
|
||||
|
||||
#import "MPException.h"
|
||||
#import "MPExpression.h"
|
||||
#import "MPFunction.h"
|
||||
#import "MPRangePath.h"
|
||||
|
||||
#import "NSIndexPath+MPAdditions.h"
|
||||
|
||||
#endif
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// MPParsedElement.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 05.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "MPParseError.h"
|
||||
|
||||
@interface MPParsedElement : NSObject <NSCopying>
|
||||
|
||||
@property (nonatomic, copy) NSString *definedVariable;
|
||||
@property (nonatomic) NSUInteger afterVariableDefinitionIndex; // Only set if defineVariable != nil
|
||||
|
||||
@property (nonatomic) BOOL isFactor;
|
||||
|
||||
// If isFactor is YES this is the factor otherwise it is the independant summant
|
||||
// of the element (may be 0).
|
||||
@property (nonatomic) NSDecimalNumber *value;
|
||||
|
||||
@property (nonatomic, getter = isPrefixOperatorExplicit) BOOL prefixOperatorExplicit;
|
||||
@property (nonatomic, getter = isPrefixValueExplicit) BOOL prefixValueExplicit;
|
||||
@property (nonatomic) NSDecimalNumber *prefixMultiplicator;
|
||||
|
||||
@property (nonatomic, getter = isSuffixOperatorExplicit) BOOL suffixOperatorExplicit;
|
||||
@property (nonatomic, getter = isSuffixValueExplicit) BOOL suffixValueExplicit;
|
||||
@property (nonatomic) NSDecimalNumber *suffixMultiplicator;
|
||||
@property (nonatomic) NSUInteger suffixIndex;
|
||||
|
||||
// No error checking done
|
||||
- (NSDecimalNumber *)valueAtBeginning;
|
||||
- (NSDecimalNumber *)valueAtEnd;
|
||||
- (NSDecimalNumber *)standaloneValue;
|
||||
|
||||
// For error checking
|
||||
- (BOOL)isValidElementAtBeginning:(MPParseError **)error;
|
||||
- (BOOL)isValidStandaloneElement:(MPParseError **)error;
|
||||
- (BOOL)isValidElementAtEnd:(MPParseError **)error;
|
||||
- (BOOL)isValidVariableDefinition:(MPParseError **)error;
|
||||
|
||||
@end
|
||||
@@ -1,123 +0,0 @@
|
||||
//
|
||||
// MPParsedElement.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 05.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPParsedElement.h"
|
||||
|
||||
@implementation MPParsedElement
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)valueAtBeginning
|
||||
{
|
||||
NSDecimalNumber *value = self.value;
|
||||
if (self.prefixValueExplicit) {
|
||||
value = [value decimalNumberByAdding:self.prefixMultiplicator];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)valueAtEnd
|
||||
{
|
||||
NSDecimalNumber *value = self.value;
|
||||
if (self.suffixValueExplicit) {
|
||||
value = [value decimalNumberByAdding:self.suffixMultiplicator];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)standaloneValue
|
||||
{
|
||||
if (self.isFactor) {
|
||||
return self.value;
|
||||
}
|
||||
NSDecimalNumber *value = self.value;
|
||||
if (self.prefixValueExplicit) {
|
||||
value = [value decimalNumberByAdding:self.prefixMultiplicator];
|
||||
}
|
||||
if (self.suffixValueExplicit) {
|
||||
value = [value decimalNumberByAdding:self.suffixMultiplicator];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
- (BOOL)isValidElementAtBeginning:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
if (self.prefixOperatorExplicit) {
|
||||
if (error) {
|
||||
*error = MPParseError(0, @"Expected Number");
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isValidStandaloneElement:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
return [self isValidElementAtBeginning:error] && [self isValidElementAtEnd:error];
|
||||
}
|
||||
|
||||
- (BOOL)isValidElementAtEnd:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
if (self.suffixOperatorExplicit) {
|
||||
if (error) {
|
||||
*error = MPParseError(self.suffixIndex, @"Expected Number");
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isValidVariableDefinition:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
if (self.definedVariable == nil) {
|
||||
if (error) {
|
||||
*error = MPParseError(0, @"Expected Variable Definition");
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return [self isValidElementAtBeginning:error];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject Overrides
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
NSMutableString *description = [[NSMutableString alloc] initWithString:@"MPParsedElement<"];
|
||||
if (self.isFactor) {
|
||||
[description appendFormat:@"factor=%@%@%@", self.prefixOperatorExplicit?@"*":@"", self.value, self.suffixOperatorExplicit?@"*":@""];
|
||||
} else {
|
||||
[description appendFormat:@"prefix=%@%@ prefixValueExplicit=%@", self.prefixOperatorExplicit?@"*":@"", self.prefixMultiplicator, self.prefixValueExplicit?@"YES":@"NO"];
|
||||
[description appendFormat:@" suffix=%@%@ suffixValueExplicit=%@", self.suffixMultiplicator, self.suffixOperatorExplicit?@"*":@"", self.suffixValueExplicit?@"YES":@"NO"];
|
||||
[description appendFormat:@" value=%@", self.value];
|
||||
}
|
||||
[description appendString:@">"];
|
||||
return [description copy];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
MPParsedElement *copy = [[MPParsedElement allocWithZone:zone] init];
|
||||
copy.isFactor = self.isFactor;
|
||||
copy.value = self.value;
|
||||
copy.prefixOperatorExplicit = self.prefixOperatorExplicit;
|
||||
copy.prefixValueExplicit = self.prefixValueExplicit;
|
||||
copy.prefixMultiplicator = self.prefixMultiplicator;
|
||||
copy.suffixOperatorExplicit = self.suffixOperatorExplicit;
|
||||
copy.suffixValueExplicit = self.suffixValueExplicit;
|
||||
copy.suffixMultiplicator = self.suffixMultiplicator;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,20 +0,0 @@
|
||||
//
|
||||
// MPParsedFactor.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPParseError.h"
|
||||
|
||||
@protocol MPParsedFactor <NSObject>
|
||||
|
||||
- (instancetype)initWithRange:(NSRange)range inString:(NSString *)string;
|
||||
|
||||
- (NSRange)range;
|
||||
- (BOOL)exists;
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
|
||||
|
||||
@end
|
||||
@@ -1,60 +0,0 @@
|
||||
//
|
||||
// MPParsedFactor.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 10.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPParsedFactor.h"
|
||||
|
||||
@implementation MPParsedFactor {
|
||||
NSDecimalNumber *_value;
|
||||
}
|
||||
|
||||
+ (MPParsedFactor *)factorWithDecimalNumber:(NSDecimalNumber *)number
|
||||
{
|
||||
return [[MPParsedFactor alloc] initWithDecimalNumber:number];
|
||||
}
|
||||
|
||||
+ (MPParsedFactor *)sinFactorWithFactor:(MPParsedFactor *)factor
|
||||
{
|
||||
double value = factor.value.doubleValue;
|
||||
NSDecimalNumber *actualNumber = [[NSDecimalNumber alloc] initWithDouble:sin(value)];
|
||||
return [[MPParsedFactor alloc] initWithDecimalNumber:actualNumber];
|
||||
}
|
||||
|
||||
+ (MPParsedFactor *)cosFactorWithFactor:(MPParsedFactor *)factor
|
||||
{
|
||||
double value = factor.value.doubleValue;
|
||||
NSDecimalNumber *actualNumber = [[NSDecimalNumber alloc] initWithDouble:cos(value)];
|
||||
return [[MPParsedFactor alloc] initWithDecimalNumber:actualNumber];
|
||||
}
|
||||
|
||||
+ (MPParsedFactor *)tanFactorWithFactor:(MPParsedFactor *)factor
|
||||
{
|
||||
double value = factor.value.doubleValue;
|
||||
NSDecimalNumber *actualNumber = [[NSDecimalNumber alloc] initWithDouble:tan(value)];
|
||||
return [[MPParsedFactor alloc] initWithDecimalNumber:actualNumber];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDecimalNumber:(NSDecimalNumber *)number
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_value = number;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)value
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"MPParsedFactor<%@>", _value];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// MPParsedNumber.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPParsedFactor.h"
|
||||
|
||||
@interface MPParsedNumber : NSObject <MPParsedFactor>
|
||||
|
||||
- (NSDecimalNumber *)number;
|
||||
|
||||
@end
|
||||
@@ -1,42 +0,0 @@
|
||||
//
|
||||
// MPParsedNumber.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPParsedNumber.h"
|
||||
|
||||
@interface MPParsedNumber ()
|
||||
@property (nonatomic) NSRange range;
|
||||
@property (nonatomic, strong) NSDecimalNumber *number;
|
||||
@end
|
||||
|
||||
@implementation MPParsedNumber
|
||||
|
||||
- (instancetype)initWithRange:(NSRange)range
|
||||
inString:(NSString *)string
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_range = range;
|
||||
if (range.location != NSNotFound) {
|
||||
NSString *stringValue = [string substringWithRange:range];
|
||||
_number = [NSDecimalNumber decimalNumberWithString:stringValue];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)exists
|
||||
{
|
||||
return self.range.location != NSNotFound;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
return self.number;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// MPParsedOperator.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPParsedFactor.h"
|
||||
|
||||
@interface MPParsedOperator : NSObject <MPParsedFactor>
|
||||
|
||||
- (NSUInteger)numberOfOperators;
|
||||
- (NSDecimalNumber *)multiplicator;
|
||||
|
||||
@end
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// MPParsedOperator.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPParsedOperator.h"
|
||||
|
||||
@interface MPParsedOperator ()
|
||||
@property (nonatomic) NSRange range;
|
||||
@property (nonatomic) NSUInteger numberOfOperators;
|
||||
@property (nonatomic, strong) NSDecimalNumber *multiplicator;
|
||||
@end
|
||||
|
||||
@implementation MPParsedOperator
|
||||
|
||||
- (instancetype)initWithRange:(NSRange)range
|
||||
inString:(NSString *)string
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_range = range;
|
||||
if (range.location == NSNotFound) {
|
||||
_multiplicator = [NSDecimalNumber one];
|
||||
_numberOfOperators = 0;
|
||||
} else {
|
||||
NSString *stringValue = [string substringWithRange:range];
|
||||
NSString *operators = [[stringValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@""];
|
||||
NSInteger multiplicator = 1;
|
||||
for (NSUInteger characterIndex = 0; characterIndex < operators.length; characterIndex++) {
|
||||
if ([[operators substringWithRange:NSMakeRange(characterIndex, 1)] isEqualToString:@"-"]) {
|
||||
multiplicator *= -1;
|
||||
}
|
||||
}
|
||||
_multiplicator = [[NSDecimalNumber alloc] initWithInteger:multiplicator];
|
||||
_numberOfOperators = operators.length;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)exists
|
||||
{
|
||||
return self.range.location != NSNotFound;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
return self.multiplicator;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// MPParsedSummand.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 10.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPParsedFactor.h"
|
||||
|
||||
@interface MPParsedProduct : NSObject
|
||||
|
||||
- (instancetype)init; // designated initializer
|
||||
- (instancetype)initWithFactor:(id<MPParsedFactor>)factor; // designated initializer.
|
||||
|
||||
@property (readonly, nonatomic, strong) NSArray *factors;
|
||||
- (void)addFactor:(id<MPParsedFactor>)factor;
|
||||
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
|
||||
|
||||
@end
|
||||
@@ -1,64 +0,0 @@
|
||||
//
|
||||
// MPParsedSummand.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 10.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPParsedProduct.h"
|
||||
|
||||
@implementation MPParsedProduct {
|
||||
NSMutableArray *_factors;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_factors = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFactor:(id<MPParsedFactor>)factor
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_factors = [[NSMutableArray alloc] initWithObjects:factor, nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)factors
|
||||
{
|
||||
return _factors;
|
||||
}
|
||||
|
||||
- (void)addFactor:(id<MPParsedFactor>)factor
|
||||
{
|
||||
[_factors addObject:factor];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
if (_factors.count == 0) {
|
||||
return [NSDecimalNumber zero];
|
||||
}
|
||||
NSDecimalNumber *value = [NSDecimalNumber one];
|
||||
for (id<MPParsedFactor> factor in _factors) {
|
||||
NSDecimalNumber *factorValue = [factor evaluateWithError:error];
|
||||
if (!factorValue) {
|
||||
return nil;
|
||||
}
|
||||
value = [value decimalNumberByMultiplyingBy:factorValue];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"MPParsedProduct<%@>", [_factors componentsJoinedByString:@"*"]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// MPParsedVariable.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MPParsedFactor.h"
|
||||
|
||||
@interface MPParsedVariable : NSObject <MPParsedFactor>
|
||||
|
||||
- (NSString *)variableName;
|
||||
|
||||
@end
|
||||
@@ -1,47 +0,0 @@
|
||||
//
|
||||
// MPParsedVariable.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 13.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPParsedVariable.h"
|
||||
#import "MPEvaluationContext.h"
|
||||
|
||||
@interface MPParsedVariable ()
|
||||
@property (nonatomic) NSRange range;
|
||||
@property (nonatomic, strong) NSString *variableName;
|
||||
@end
|
||||
|
||||
@implementation MPParsedVariable
|
||||
|
||||
- (instancetype)initWithRange:(NSRange)range
|
||||
inString:(NSString *)string
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_range = range;
|
||||
if (range.location != NSNotFound) {
|
||||
_variableName = [string substringWithRange:range];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)exists
|
||||
{
|
||||
return self.range.location != NSNotFound;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
NSDecimalNumber *value = [[MPEvaluationContext sharedContext] valueForVariableName:self.variableName];
|
||||
if (!value) {
|
||||
*error = MPParseError(self.range, @"Undefined Variable.");
|
||||
return nil;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,39 +0,0 @@
|
||||
//
|
||||
// MPRange.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 18.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
@interface MPRange : NSObject <NSCopying, NSCoding>
|
||||
|
||||
#pragma mark Creation Methods
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithLocation:(NSIndexPath *)location
|
||||
length:(NSUInteger)length;
|
||||
- (instancetype)initWithRange:(NSRange)aRange;
|
||||
|
||||
+ (instancetype)emptyRange;
|
||||
+ (instancetype)rangeWithLocation:(NSIndexPath *)location
|
||||
length:(NSUInteger)length;
|
||||
+ (instancetype)rangeWithRange:(NSRange)aRange;
|
||||
|
||||
#pragma mark Properties
|
||||
|
||||
@property (nonatomic, strong) NSIndexPath *location;
|
||||
@property (nonatomic) NSUInteger length;
|
||||
|
||||
- (NSIndexPath *)maxRange;
|
||||
- (NSRange)rangeAtLastIndex;
|
||||
|
||||
#pragma mark Working with Ranges
|
||||
|
||||
- (BOOL)containsRange:(MPRange *)aRange;
|
||||
- (BOOL)containsLocation:(NSIndexPath *)location;
|
||||
|
||||
- (BOOL)isEqual:(id)object;
|
||||
- (BOOL)isEqualToRange:(MPRange *)aRange;
|
||||
|
||||
@end
|
||||
@@ -1,140 +0,0 @@
|
||||
//
|
||||
// MPRange.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 18.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPRange.h"
|
||||
|
||||
@implementation MPRange
|
||||
|
||||
#pragma mark Creation Methods
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithLocation:[[NSIndexPath alloc] init]
|
||||
length:0];
|
||||
}
|
||||
|
||||
- (instancetype)initWithLocation:(NSIndexPath *)location
|
||||
length:(NSUInteger)length
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_location = location;
|
||||
_length = length;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithRange:(NSRange)aRange
|
||||
{
|
||||
return [self initWithLocation:[[NSIndexPath alloc] initWithIndex:aRange.location]
|
||||
length:aRange.length];
|
||||
}
|
||||
|
||||
+ (instancetype)emptyRange
|
||||
{
|
||||
return [[self alloc] init];
|
||||
}
|
||||
|
||||
+ (instancetype)rangeWithLocation:(NSIndexPath *)location
|
||||
length:(NSUInteger)length
|
||||
{
|
||||
return [[self alloc] initWithLocation:location
|
||||
length:length];
|
||||
}
|
||||
|
||||
+ (instancetype)rangeWithRange:(NSRange)aRange
|
||||
{
|
||||
return [[self alloc] initWithRange:aRange];
|
||||
}
|
||||
|
||||
#pragma mark Properties
|
||||
|
||||
- (NSIndexPath *)maxRange
|
||||
{
|
||||
NSUInteger lastIndex = [self.location indexAtPosition:self.location.length-1];
|
||||
NSUInteger newLastIndex = lastIndex + self.length;
|
||||
return [[self.location indexPathByRemovingLastIndex] indexPathByAddingIndex:newLastIndex];
|
||||
}
|
||||
|
||||
- (NSRange)rangeAtLastIndex
|
||||
{
|
||||
return NSMakeRange([self.location indexAtPosition:self.location.length-1], self.length);
|
||||
}
|
||||
|
||||
#pragma mark Working with Ranges
|
||||
|
||||
- (BOOL)containsRange:(MPRange *)aRange
|
||||
{
|
||||
if (aRange.location.length < self.location.length) {
|
||||
return NO;
|
||||
}
|
||||
// Compare indices (except the last one)
|
||||
for (NSUInteger pos = 0; pos < self.location.length-1; pos++) {
|
||||
NSUInteger selfIndex = [self.location indexAtPosition:pos];
|
||||
NSUInteger otherIndex = [aRange.location indexAtPosition:pos];
|
||||
if (selfIndex != otherIndex) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
// Compare range at last index
|
||||
NSUInteger selfIndex = [self.location indexAtPosition:self.location.length-1];
|
||||
NSUInteger otherIndex = [aRange.location indexAtPosition:self.location.length-1];
|
||||
if (aRange.location.length > self.location.length) {
|
||||
return NSLocationInRange(otherIndex, self.rangeAtLastIndex);
|
||||
} else {
|
||||
return otherIndex >= selfIndex && NSMaxRange(aRange.rangeAtLastIndex) <= NSMaxRange(self.rangeAtLastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)containsLocation:(NSIndexPath *)location
|
||||
{
|
||||
return [self containsRange:[[MPRange alloc] initWithLocation:location length:0]];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (object == nil) {
|
||||
return NO;
|
||||
}
|
||||
if (![object isKindOfClass:[MPRange class]]) {
|
||||
return NO;
|
||||
}
|
||||
return [self isEqualToRange:(MPRange *)object];
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToRange:(MPRange *)aRange
|
||||
{
|
||||
return [self.location isEqual:aRange.location] && self.length == aRange.length;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
MPRange *copy = [[MPRange allocWithZone:zone] initWithLocation:self.location.copy length:self.length];
|
||||
return copy;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
return [self initWithLocation:[aDecoder decodeObjectForKey:@"location"]
|
||||
length:[aDecoder decodeIntegerForKey:@"length"]];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[aCoder encodeObject:self.location forKey:@"location"];
|
||||
[aCoder encodeInteger:self.length forKey:@"length"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// MPView.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 21.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
/*
|
||||
This is a convenience header which imports all view classes defined by MathPad.
|
||||
*/
|
||||
|
||||
#ifndef MathPad_MPView_h
|
||||
#define MathPad_MPView_h
|
||||
|
||||
#import "MPExpressionView.h"
|
||||
#import "MPExpressionStorage.h"
|
||||
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// NSIndexPath+MPRemoveFirstIndex.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 23.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSIndexPath (MPRemoveFirstIndex)
|
||||
|
||||
/*!
|
||||
@method indexPathByRemovingFirstIndex
|
||||
@brief Provides an index path with the indexes in the receiving index path, excluding the first one.
|
||||
@discussion Returns an empty NSIndexPath instance if the receiving index path’s length is 1 or less.
|
||||
@return New index path with the receiving index path’s indexes, excluding the first one.
|
||||
*/
|
||||
- (NSIndexPath *)indexPathByRemovingFirstIndex;
|
||||
|
||||
@end
|
||||
@@ -1,27 +0,0 @@
|
||||
//
|
||||
// NSIndexPath+MPRemoveFirstIndex.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 23.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSIndexPath+MPRemoveFirstIndex.h"
|
||||
|
||||
@implementation NSIndexPath (MPRemoveFirstIndex)
|
||||
|
||||
- (NSIndexPath *)indexPathByRemovingFirstIndex
|
||||
{
|
||||
if (self.length <= 1) {
|
||||
return [[NSIndexPath alloc] init];
|
||||
}
|
||||
NSUInteger indexes[self.length];
|
||||
[self getIndexes:indexes];
|
||||
NSUInteger newIndexes[self.length-1];
|
||||
for (NSUInteger i = 0; i < self.length-1; i++) {
|
||||
newIndexes[i] = indexes[i+1];
|
||||
}
|
||||
return [[NSIndexPath alloc] initWithIndexes:newIndexes length:self.length-1];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// NSIndexPath+MPRemoveFirstIndex.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 23.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSIndexPath (MPReverseIndexPath)
|
||||
|
||||
/*!
|
||||
@method indexPathByRemovingFirstIndex
|
||||
@brief Provides an index path with the indexes in the receiving index path, excluding the first one.
|
||||
@discussion Returns an empty NSIndexPath instance if the receiving index path’s length is 1 or less.
|
||||
@return New index path with the receiving index path’s indexes, excluding the first one.
|
||||
*/
|
||||
- (NSIndexPath *)indexPathByRemovingFirstIndex;
|
||||
|
||||
- (NSIndexPath *)indexPathByPrecedingIndex:(NSUInteger)index;
|
||||
|
||||
@end
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// NSIndexPath+MPRemoveFirstIndex.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 23.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSIndexPath+MPReverseIndexPath.h"
|
||||
|
||||
@implementation NSIndexPath (MPReverseIndexPath)
|
||||
|
||||
- (NSIndexPath *)indexPathByRemovingFirstIndex
|
||||
{
|
||||
if (self.length <= 1) {
|
||||
return [[NSIndexPath alloc] init];
|
||||
}
|
||||
NSUInteger indexes[self.length];
|
||||
[self getIndexes:indexes];
|
||||
NSUInteger newIndexes[self.length-1];
|
||||
for (NSUInteger i = 0; i < self.length-1; i++) {
|
||||
newIndexes[i] = indexes[i+1];
|
||||
}
|
||||
return [[NSIndexPath alloc] initWithIndexes:newIndexes length:self.length-1];
|
||||
}
|
||||
|
||||
- (NSIndexPath *)indexPathByPrecedingIndex:(NSUInteger)index
|
||||
{
|
||||
NSUInteger newIndexes[self.length+1];
|
||||
newIndexes[0] = index;
|
||||
for (NSUInteger i = 0; i < self.length; i++) {
|
||||
newIndexes[i+1] = [self indexAtPosition:i];
|
||||
}
|
||||
return [[NSIndexPath alloc] initWithIndexes:newIndexes length:self.length+1];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// NSObject+MPStringTest.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 20.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSObject (MPStringTest)
|
||||
|
||||
/*!
|
||||
@method isString
|
||||
@brief Returns wether the receiver is a string object.
|
||||
@discussion A string object is an instance of the @c NSString class or any of its subclasses (for example @c NSMutableString). For an @c NSAttributedString this method returns @c NO.
|
||||
@return @c YES if the receiver is an instance of @c NSString or a subclass, @c NO otherwise.
|
||||
*/
|
||||
- (BOOL)isString;
|
||||
|
||||
@end
|
||||
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// NSObject+MPStringTest.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 20.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+MPStringTest.h"
|
||||
|
||||
@implementation NSObject (MPStringTest)
|
||||
|
||||
- (BOOL)isString
|
||||
{
|
||||
return [self isKindOfClass:[NSString class]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// NSTextStorage+MPSetContents.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 21.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface NSTextStorage (MPSetContents)
|
||||
|
||||
/*!
|
||||
@method setString:
|
||||
@brief Replaces the contents of the receiver with @c aString.
|
||||
@discussion This method sends the receiver a @c replaceCharactersInRange:withString: with a range including all characters of the receiver and @c aString. See @c replaceCharactersInRange:withString: for details.
|
||||
@param aString A string specifying the characters to replace the receiver's current contents.
|
||||
*/
|
||||
- (void)setString:(NSString *)aString;
|
||||
|
||||
@end
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// NSTextStorage+MPSetContents.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 21.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSTextStorage+MPSetContents.h"
|
||||
|
||||
@implementation NSTextStorage (MPSetContents)
|
||||
|
||||
- (void)setString:(NSString *)string
|
||||
{
|
||||
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:string];
|
||||
[self setAttributedString:attributedString];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,61 +0,0 @@
|
||||
//
|
||||
// MPMutableExpressionTests.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 19.04.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "MPExpression.h"
|
||||
#import "MPFunction.h"
|
||||
|
||||
@interface MPMutableExpressionTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPMutableExpressionTests
|
||||
|
||||
- (void)testMutating {
|
||||
MPMutableExpression *testExpression = [[MPMutableExpression alloc] initWithSymbols:@[@"1234", [[MPFunction alloc] init], @"5678", [[MPFunction alloc] init]]];
|
||||
|
||||
[testExpression appendString:@"90"];
|
||||
XCTAssertEqual([testExpression numberOfSymbols], 5);
|
||||
// 1234 [] 5678 [] 90
|
||||
|
||||
[testExpression deleteSymbolsInRange:NSMakeRange(2, 4)];
|
||||
XCTAssertEqual([testExpression numberOfSymbols], 3);
|
||||
// 12678 [] 90
|
||||
|
||||
[testExpression insertFunction:[[MPFunction alloc] init]
|
||||
atIndex:2];
|
||||
XCTAssertEqual([testExpression numberOfSymbols], 5);
|
||||
// 12 [] 678 [] 90
|
||||
|
||||
[testExpression replaceSymbolsInRange:NSMakeRange(2, 5)
|
||||
withSymbols:@[[[MPFunction alloc] init]]];
|
||||
XCTAssertEqual([testExpression numberOfSymbols], 3);
|
||||
// 12 [] 90
|
||||
|
||||
[testExpression setString:@"abc"];
|
||||
XCTAssertEqual([testExpression numberOfSymbols], 1);
|
||||
// abc
|
||||
|
||||
[testExpression setString:@""];
|
||||
XCTAssertEqual([testExpression numberOfSymbols], 0);
|
||||
//
|
||||
|
||||
[testExpression setString:@"1234"];
|
||||
XCTAssertEqual([testExpression numberOfSymbols], 1);
|
||||
}
|
||||
|
||||
- (void)testInvalidMutatingRange {
|
||||
@try {
|
||||
MPMutableExpression *testExpression = [[MPMutableExpression alloc] initWithSymbols:@[@"1234", [[MPFunction alloc] init], @"5678", [[MPFunction alloc] init]]];
|
||||
[testExpression deleteSymbolsInRange:NSMakeRange(5, 17)];
|
||||
XCTFail(@"Should have raised an exception");
|
||||
}
|
||||
@catch (NSException *exception) {}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// MathPadTests.m
|
||||
// MathPadTests
|
||||
//
|
||||
// Created by Kim Wittenburg on 23.03.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface MathPadTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation MathPadTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testExample
|
||||
{
|
||||
XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user