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">
|
ReferencedContainer = "container:MathPad.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "3B85831C19BB5E5500D76A8D"
|
||||||
|
BuildableName = "MathKitTests.xctest"
|
||||||
|
BlueprintName = "MathKitTests"
|
||||||
|
ReferencedContainer = "container:MathPad.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>SchemeUserState</key>
|
<key>SchemeUserState</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>MathKit.xcscheme</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
<key>MathPad.xcscheme</key>
|
<key>MathPad.xcscheme</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
@@ -12,6 +17,16 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>3B85830C19BB5E5500D76A8D</key>
|
||||||
|
<dict>
|
||||||
|
<key>primary</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>3B85831C19BB5E5500D76A8D</key>
|
||||||
|
<dict>
|
||||||
|
<key>primary</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
<key>3BF9976A18DE623E009CF6C4</key>
|
<key>3BF9976A18DE623E009CF6C4</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>primary</key>
|
<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