Internal Redesign:
- Combined MPExpression and MPMutableExpression - Abstracted children of MPExpression into MPExpressionElement protocol - Abstracted most of MPExpressionLayout and MPFunctionLayout into common superclass MPLayout
This commit is contained in:
@@ -9,20 +9,20 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
3B0F69A919028C6000817707 /* MPException.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69A819028C6000817707 /* MPException.m */; };
|
3B0F69A919028C6000817707 /* MPException.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69A819028C6000817707 /* MPException.m */; };
|
||||||
3B0F69AC1902A82C00817707 /* MPExpressionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69AB1902A82C00817707 /* MPExpressionTests.m */; };
|
3B0F69AC1902A82C00817707 /* MPExpressionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69AB1902A82C00817707 /* MPExpressionTests.m */; };
|
||||||
3B0F69AD1902AD2200817707 /* MPExpression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E3581900857C00259938 /* MPExpression.m */; };
|
|
||||||
3B0F69AE1902AD2800817707 /* MPException.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69A819028C6000817707 /* MPException.m */; };
|
3B0F69AE1902AD2800817707 /* MPException.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69A819028C6000817707 /* MPException.m */; };
|
||||||
3B0F69B01902AD2E00817707 /* MPFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35F19009D5F00259938 /* MPFunction.m */; };
|
3B0F69B01902AD2E00817707 /* MPFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35F19009D5F00259938 /* MPFunction.m */; };
|
||||||
|
3B528D10199417E10054DB5F /* MPExpressionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B528D0F199417E10054DB5F /* MPExpressionLayout.m */; };
|
||||||
|
3B528D13199417E90054DB5F /* MPFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B528D12199417E90054DB5F /* MPFunctionLayout.m */; };
|
||||||
|
3B528D1619941F5B0054DB5F /* MPExpressionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B528D0F199417E10054DB5F /* MPExpressionLayout.m */; };
|
||||||
|
3B528D1819941F5B0054DB5F /* MPFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B528D12199417E90054DB5F /* MPFunctionLayout.m */; };
|
||||||
|
3B53AD5F1997E0FB00C925C4 /* MPExpression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFAC38E1997B61300B3EF67 /* MPExpression.m */; };
|
||||||
|
3B688D9919982DF50006B4AB /* MPLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B688D9819982DF50006B4AB /* MPLayout.m */; };
|
||||||
3B87E3561900856F00259938 /* MPExpressionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E3551900856F00259938 /* MPExpressionView.m */; };
|
3B87E3561900856F00259938 /* MPExpressionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E3551900856F00259938 /* MPExpressionView.m */; };
|
||||||
3B87E3591900857C00259938 /* MPExpression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E3581900857C00259938 /* MPExpression.m */; };
|
|
||||||
3B87E36019009D5F00259938 /* MPFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35F19009D5F00259938 /* MPFunction.m */; };
|
3B87E36019009D5F00259938 /* MPFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35F19009D5F00259938 /* MPFunction.m */; };
|
||||||
3BB09EB21905DE500080A5ED /* MPExpressionStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EB11905DE500080A5ED /* MPExpressionStorage.m */; };
|
3BB09EB21905DE500080A5ED /* MPExpressionStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EB11905DE500080A5ED /* MPExpressionStorage.m */; };
|
||||||
3BB09EC91906FD830080A5ED /* MPSumFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EC81906FD830080A5ED /* MPSumFunction.m */; };
|
3BB09EC91906FD830080A5ED /* MPSumFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EC81906FD830080A5ED /* MPSumFunction.m */; };
|
||||||
3BB09ED0190713F00080A5ED /* MPExpressionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09ECF190713F00080A5ED /* MPExpressionLayout.m */; };
|
3BB09EDE190728220080A5ED /* NSIndexPath+MPAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EDD190728220080A5ED /* NSIndexPath+MPAdditions.m */; };
|
||||||
3BB09ED3190713FC0080A5ED /* MPFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09ED2190713FC0080A5ED /* MPFunctionLayout.m */; };
|
|
||||||
3BB09EDE190728220080A5ED /* NSIndexPath+MPReverseIndexPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EDD190728220080A5ED /* NSIndexPath+MPReverseIndexPath.m */; };
|
|
||||||
3BB09EE1190736160080A5ED /* MPSumFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EE0190736160080A5ED /* MPSumFunctionLayout.m */; };
|
3BB09EE1190736160080A5ED /* MPSumFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EE0190736160080A5ED /* MPSumFunctionLayout.m */; };
|
||||||
3BBBA358190327B700824E74 /* MPMutableExpressionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBBA357190327B700824E74 /* MPMutableExpressionTests.m */; };
|
|
||||||
3BBBA35D1903F8A700824E74 /* NSObject+MPStringTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBBA35C1903F8A700824E74 /* NSObject+MPStringTest.m */; };
|
|
||||||
3BBBA35E1903FD3600824E74 /* MPRangePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35C1900933200259938 /* MPRangePath.m */; };
|
3BBBA35E1903FD3600824E74 /* MPRangePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35C1900933200259938 /* MPRangePath.m */; };
|
||||||
3BBBA35F1903FD3600824E74 /* MPRangePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35C1900933200259938 /* MPRangePath.m */; };
|
3BBBA35F1903FD3600824E74 /* MPRangePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35C1900933200259938 /* MPRangePath.m */; };
|
||||||
3BBBA3951905704200824E74 /* MPRangeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBBA3941905704200824E74 /* MPRangeTests.m */; };
|
3BBBA3951905704200824E74 /* MPRangeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBBA3941905704200824E74 /* MPRangeTests.m */; };
|
||||||
@@ -37,7 +37,8 @@
|
|||||||
3BF9979118DE623E009CF6C4 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BF9979018DE623E009CF6C4 /* XCTest.framework */; };
|
3BF9979118DE623E009CF6C4 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BF9979018DE623E009CF6C4 /* XCTest.framework */; };
|
||||||
3BF9979218DE623E009CF6C4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BF9976E18DE623E009CF6C4 /* Cocoa.framework */; };
|
3BF9979218DE623E009CF6C4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BF9976E18DE623E009CF6C4 /* Cocoa.framework */; };
|
||||||
3BF9979A18DE623E009CF6C4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3BF9979818DE623E009CF6C4 /* InfoPlist.strings */; };
|
3BF9979A18DE623E009CF6C4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3BF9979818DE623E009CF6C4 /* InfoPlist.strings */; };
|
||||||
3BFCFF491905AAF30001FE33 /* NSTextStorage+MPSetContents.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFCFF481905AAF30001FE33 /* NSTextStorage+MPSetContents.m */; };
|
3BFAC38F1997B61300B3EF67 /* MPExpression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFAC38E1997B61300B3EF67 /* MPExpression.m */; };
|
||||||
|
3BFAC39C1997BC7600B3EF67 /* NSString+MPExpressionElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFAC39B1997BC7600B3EF67 /* NSString+MPExpressionElement.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -54,10 +55,14 @@
|
|||||||
3B0F69A719028BC600817707 /* MPException.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPException.h; sourceTree = "<group>"; };
|
3B0F69A719028BC600817707 /* MPException.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPException.h; sourceTree = "<group>"; };
|
||||||
3B0F69A819028C6000817707 /* MPException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPException.m; sourceTree = "<group>"; };
|
3B0F69A819028C6000817707 /* MPException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPException.m; sourceTree = "<group>"; };
|
||||||
3B0F69AB1902A82C00817707 /* MPExpressionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionTests.m; sourceTree = "<group>"; };
|
3B0F69AB1902A82C00817707 /* MPExpressionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionTests.m; sourceTree = "<group>"; };
|
||||||
|
3B528D0D199417740054DB5F /* MPLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLayout.h; sourceTree = "<group>"; };
|
||||||
|
3B528D0E199417E10054DB5F /* MPExpressionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionLayout.h; sourceTree = "<group>"; };
|
||||||
|
3B528D0F199417E10054DB5F /* MPExpressionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionLayout.m; sourceTree = "<group>"; };
|
||||||
|
3B528D11199417E90054DB5F /* MPFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunctionLayout.h; sourceTree = "<group>"; };
|
||||||
|
3B528D12199417E90054DB5F /* MPFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFunctionLayout.m; sourceTree = "<group>"; };
|
||||||
|
3B688D9819982DF50006B4AB /* MPLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLayout.m; sourceTree = "<group>"; };
|
||||||
3B87E3541900856F00259938 /* MPExpressionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionView.h; sourceTree = "<group>"; };
|
3B87E3541900856F00259938 /* MPExpressionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionView.h; sourceTree = "<group>"; };
|
||||||
3B87E3551900856F00259938 /* MPExpressionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionView.m; sourceTree = "<group>"; };
|
3B87E3551900856F00259938 /* MPExpressionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionView.m; sourceTree = "<group>"; };
|
||||||
3B87E3571900857C00259938 /* MPExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpression.h; sourceTree = "<group>"; };
|
|
||||||
3B87E3581900857C00259938 /* MPExpression.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpression.m; sourceTree = "<group>"; };
|
|
||||||
3B87E35B1900933200259938 /* MPRangePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRangePath.h; sourceTree = "<group>"; };
|
3B87E35B1900933200259938 /* MPRangePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRangePath.h; sourceTree = "<group>"; };
|
||||||
3B87E35C1900933200259938 /* MPRangePath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRangePath.m; sourceTree = "<group>"; };
|
3B87E35C1900933200259938 /* MPRangePath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRangePath.m; sourceTree = "<group>"; };
|
||||||
3B87E35E19009D5F00259938 /* MPFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunction.h; sourceTree = "<group>"; };
|
3B87E35E19009D5F00259938 /* MPFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunction.h; sourceTree = "<group>"; };
|
||||||
@@ -66,18 +71,11 @@
|
|||||||
3BB09EB11905DE500080A5ED /* MPExpressionStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionStorage.m; sourceTree = "<group>"; };
|
3BB09EB11905DE500080A5ED /* MPExpressionStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionStorage.m; sourceTree = "<group>"; };
|
||||||
3BB09EC71906FD830080A5ED /* MPSumFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSumFunction.h; sourceTree = "<group>"; };
|
3BB09EC71906FD830080A5ED /* MPSumFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSumFunction.h; sourceTree = "<group>"; };
|
||||||
3BB09EC81906FD830080A5ED /* MPSumFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSumFunction.m; sourceTree = "<group>"; };
|
3BB09EC81906FD830080A5ED /* MPSumFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSumFunction.m; sourceTree = "<group>"; };
|
||||||
3BB09ECE190713F00080A5ED /* MPExpressionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionLayout.h; sourceTree = "<group>"; };
|
3BB09EDC190728220080A5ED /* NSIndexPath+MPAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexPath+MPAdditions.h"; sourceTree = "<group>"; };
|
||||||
3BB09ECF190713F00080A5ED /* MPExpressionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionLayout.m; sourceTree = "<group>"; };
|
3BB09EDD190728220080A5ED /* NSIndexPath+MPAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexPath+MPAdditions.m"; sourceTree = "<group>"; };
|
||||||
3BB09ED1190713FC0080A5ED /* MPFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunctionLayout.h; sourceTree = "<group>"; };
|
|
||||||
3BB09ED2190713FC0080A5ED /* MPFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFunctionLayout.m; sourceTree = "<group>"; };
|
|
||||||
3BB09EDC190728220080A5ED /* NSIndexPath+MPReverseIndexPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexPath+MPReverseIndexPath.h"; sourceTree = "<group>"; };
|
|
||||||
3BB09EDD190728220080A5ED /* NSIndexPath+MPReverseIndexPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexPath+MPReverseIndexPath.m"; sourceTree = "<group>"; };
|
|
||||||
3BB09EDF190736160080A5ED /* MPSumFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSumFunctionLayout.h; sourceTree = "<group>"; };
|
3BB09EDF190736160080A5ED /* MPSumFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSumFunctionLayout.h; sourceTree = "<group>"; };
|
||||||
3BB09EE0190736160080A5ED /* MPSumFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSumFunctionLayout.m; sourceTree = "<group>"; };
|
3BB09EE0190736160080A5ED /* MPSumFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSumFunctionLayout.m; sourceTree = "<group>"; };
|
||||||
3BBBA357190327B700824E74 /* MPMutableExpressionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMutableExpressionTests.m; sourceTree = "<group>"; };
|
|
||||||
3BBBA3591903EA9B00824E74 /* MPModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPModel.h; sourceTree = "<group>"; };
|
3BBBA3591903EA9B00824E74 /* MPModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPModel.h; sourceTree = "<group>"; };
|
||||||
3BBBA35B1903F8A700824E74 /* NSObject+MPStringTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MPStringTest.h"; sourceTree = "<group>"; };
|
|
||||||
3BBBA35C1903F8A700824E74 /* NSObject+MPStringTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MPStringTest.m"; sourceTree = "<group>"; };
|
|
||||||
3BBBA38419047FC900824E74 /* MPView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPView.h; sourceTree = "<group>"; };
|
3BBBA38419047FC900824E74 /* MPView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPView.h; sourceTree = "<group>"; };
|
||||||
3BBBA3941905704200824E74 /* MPRangeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRangeTests.m; sourceTree = "<group>"; };
|
3BBBA3941905704200824E74 /* MPRangeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRangeTests.m; sourceTree = "<group>"; };
|
||||||
3BF9976B18DE623E009CF6C4 /* MathPad.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MathPad.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
3BF9976B18DE623E009CF6C4 /* MathPad.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MathPad.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -99,8 +97,11 @@
|
|||||||
3BF9979018DE623E009CF6C4 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
3BF9979018DE623E009CF6C4 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
||||||
3BF9979718DE623E009CF6C4 /* MathPadTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MathPadTests-Info.plist"; sourceTree = "<group>"; };
|
3BF9979718DE623E009CF6C4 /* MathPadTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MathPadTests-Info.plist"; sourceTree = "<group>"; };
|
||||||
3BF9979918DE623E009CF6C4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
3BF9979918DE623E009CF6C4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
3BFCFF471905AAF30001FE33 /* NSTextStorage+MPSetContents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTextStorage+MPSetContents.h"; sourceTree = "<group>"; };
|
3BFAC38D1997B61300B3EF67 /* MPExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpression.h; sourceTree = "<group>"; };
|
||||||
3BFCFF481905AAF30001FE33 /* NSTextStorage+MPSetContents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTextStorage+MPSetContents.m"; sourceTree = "<group>"; };
|
3BFAC38E1997B61300B3EF67 /* MPExpression.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpression.m; sourceTree = "<group>"; };
|
||||||
|
3BFAC3961997B67400B3EF67 /* MPExpressionElement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPExpressionElement.h; sourceTree = "<group>"; };
|
||||||
|
3BFAC39A1997BC7600B3EF67 /* NSString+MPExpressionElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+MPExpressionElement.h"; sourceTree = "<group>"; };
|
||||||
|
3BFAC39B1997BC7600B3EF67 /* NSString+MPExpressionElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+MPExpressionElement.m"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -127,14 +128,18 @@
|
|||||||
3B87E350190082B300259938 /* Model */ = {
|
3B87E350190082B300259938 /* Model */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
3BBBA35A1903F89100824E74 /* Categories */,
|
|
||||||
3BBBA3591903EA9B00824E74 /* MPModel.h */,
|
3BBBA3591903EA9B00824E74 /* MPModel.h */,
|
||||||
3B87E3571900857C00259938 /* MPExpression.h */,
|
3BFAC38D1997B61300B3EF67 /* MPExpression.h */,
|
||||||
3B87E3581900857C00259938 /* MPExpression.m */,
|
3BFAC38E1997B61300B3EF67 /* MPExpression.m */,
|
||||||
|
3BFAC3961997B67400B3EF67 /* MPExpressionElement.h */,
|
||||||
3B87E35E19009D5F00259938 /* MPFunction.h */,
|
3B87E35E19009D5F00259938 /* MPFunction.h */,
|
||||||
3B87E35F19009D5F00259938 /* MPFunction.m */,
|
3B87E35F19009D5F00259938 /* MPFunction.m */,
|
||||||
|
3BFAC39A1997BC7600B3EF67 /* NSString+MPExpressionElement.h */,
|
||||||
|
3BFAC39B1997BC7600B3EF67 /* NSString+MPExpressionElement.m */,
|
||||||
3B87E35B1900933200259938 /* MPRangePath.h */,
|
3B87E35B1900933200259938 /* MPRangePath.h */,
|
||||||
3B87E35C1900933200259938 /* MPRangePath.m */,
|
3B87E35C1900933200259938 /* MPRangePath.m */,
|
||||||
|
3BB09EDC190728220080A5ED /* NSIndexPath+MPAdditions.h */,
|
||||||
|
3BB09EDD190728220080A5ED /* NSIndexPath+MPAdditions.m */,
|
||||||
3B0F69A719028BC600817707 /* MPException.h */,
|
3B0F69A719028BC600817707 /* MPException.h */,
|
||||||
3B0F69A819028C6000817707 /* MPException.m */,
|
3B0F69A819028C6000817707 /* MPException.m */,
|
||||||
3BB09EBC1905EF210080A5ED /* Functions */,
|
3BB09EBC1905EF210080A5ED /* Functions */,
|
||||||
@@ -194,10 +199,12 @@
|
|||||||
3BB09ED819071C270080A5ED /* Private */ = {
|
3BB09ED819071C270080A5ED /* Private */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
3BB09ECE190713F00080A5ED /* MPExpressionLayout.h */,
|
3B528D0D199417740054DB5F /* MPLayout.h */,
|
||||||
3BB09ECF190713F00080A5ED /* MPExpressionLayout.m */,
|
3B688D9819982DF50006B4AB /* MPLayout.m */,
|
||||||
3BB09ED1190713FC0080A5ED /* MPFunctionLayout.h */,
|
3B528D0E199417E10054DB5F /* MPExpressionLayout.h */,
|
||||||
3BB09ED2190713FC0080A5ED /* MPFunctionLayout.m */,
|
3B528D0F199417E10054DB5F /* MPExpressionLayout.m */,
|
||||||
|
3B528D11199417E90054DB5F /* MPFunctionLayout.h */,
|
||||||
|
3B528D12199417E90054DB5F /* MPFunctionLayout.m */,
|
||||||
);
|
);
|
||||||
name = Private;
|
name = Private;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -211,19 +218,6 @@
|
|||||||
name = "Function Layouts";
|
name = "Function Layouts";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
3BBBA35A1903F89100824E74 /* Categories */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
3BBBA35B1903F8A700824E74 /* NSObject+MPStringTest.h */,
|
|
||||||
3BBBA35C1903F8A700824E74 /* NSObject+MPStringTest.m */,
|
|
||||||
3BFCFF471905AAF30001FE33 /* NSTextStorage+MPSetContents.h */,
|
|
||||||
3BFCFF481905AAF30001FE33 /* NSTextStorage+MPSetContents.m */,
|
|
||||||
3BB09EDC190728220080A5ED /* NSIndexPath+MPReverseIndexPath.h */,
|
|
||||||
3BB09EDD190728220080A5ED /* NSIndexPath+MPReverseIndexPath.m */,
|
|
||||||
);
|
|
||||||
name = Categories;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
3BF9976218DE623E009CF6C4 = {
|
3BF9976218DE623E009CF6C4 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -292,7 +286,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
3B0F69AB1902A82C00817707 /* MPExpressionTests.m */,
|
3B0F69AB1902A82C00817707 /* MPExpressionTests.m */,
|
||||||
3BBBA357190327B700824E74 /* MPMutableExpressionTests.m */,
|
|
||||||
3BBBA3941905704200824E74 /* MPRangeTests.m */,
|
3BBBA3941905704200824E74 /* MPRangeTests.m */,
|
||||||
3BF9979618DE623E009CF6C4 /* Supporting Files */,
|
3BF9979618DE623E009CF6C4 /* Supporting Files */,
|
||||||
);
|
);
|
||||||
@@ -408,17 +401,17 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
3B688D9919982DF50006B4AB /* MPLayout.m in Sources */,
|
||||||
3BB09EE1190736160080A5ED /* MPSumFunctionLayout.m in Sources */,
|
3BB09EE1190736160080A5ED /* MPSumFunctionLayout.m in Sources */,
|
||||||
3B87E3561900856F00259938 /* MPExpressionView.m in Sources */,
|
3B87E3561900856F00259938 /* MPExpressionView.m in Sources */,
|
||||||
3BFCFF491905AAF30001FE33 /* NSTextStorage+MPSetContents.m in Sources */,
|
|
||||||
3BB09EC91906FD830080A5ED /* MPSumFunction.m in Sources */,
|
3BB09EC91906FD830080A5ED /* MPSumFunction.m in Sources */,
|
||||||
3BB09EB21905DE500080A5ED /* MPExpressionStorage.m in Sources */,
|
3BB09EB21905DE500080A5ED /* MPExpressionStorage.m in Sources */,
|
||||||
3BF9977B18DE623E009CF6C4 /* main.m in Sources */,
|
3BF9977B18DE623E009CF6C4 /* main.m in Sources */,
|
||||||
3B87E3591900857C00259938 /* MPExpression.m in Sources */,
|
3BFAC38F1997B61300B3EF67 /* MPExpression.m in Sources */,
|
||||||
3BB09ED3190713FC0080A5ED /* MPFunctionLayout.m in Sources */,
|
3BFAC39C1997BC7600B3EF67 /* NSString+MPExpressionElement.m in Sources */,
|
||||||
3BB09ED0190713F00080A5ED /* MPExpressionLayout.m in Sources */,
|
3B528D10199417E10054DB5F /* MPExpressionLayout.m in Sources */,
|
||||||
3BBBA35D1903F8A700824E74 /* NSObject+MPStringTest.m in Sources */,
|
3B528D13199417E90054DB5F /* MPFunctionLayout.m in Sources */,
|
||||||
3BB09EDE190728220080A5ED /* NSIndexPath+MPReverseIndexPath.m in Sources */,
|
3BB09EDE190728220080A5ED /* NSIndexPath+MPAdditions.m in Sources */,
|
||||||
3B87E36019009D5F00259938 /* MPFunction.m in Sources */,
|
3B87E36019009D5F00259938 /* MPFunction.m in Sources */,
|
||||||
3B0F69A919028C6000817707 /* MPException.m in Sources */,
|
3B0F69A919028C6000817707 /* MPException.m in Sources */,
|
||||||
3BBBA35E1903FD3600824E74 /* MPRangePath.m in Sources */,
|
3BBBA35E1903FD3600824E74 /* MPRangePath.m in Sources */,
|
||||||
@@ -430,13 +423,14 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
3BBBA358190327B700824E74 /* MPMutableExpressionTests.m in Sources */,
|
3B528D1619941F5B0054DB5F /* MPExpressionLayout.m in Sources */,
|
||||||
|
3B528D1819941F5B0054DB5F /* MPFunctionLayout.m in Sources */,
|
||||||
3B0F69AE1902AD2800817707 /* MPException.m in Sources */,
|
3B0F69AE1902AD2800817707 /* MPException.m in Sources */,
|
||||||
3B0F69AC1902A82C00817707 /* MPExpressionTests.m in Sources */,
|
3B0F69AC1902A82C00817707 /* MPExpressionTests.m in Sources */,
|
||||||
3BBBA3951905704200824E74 /* MPRangeTests.m in Sources */,
|
3BBBA3951905704200824E74 /* MPRangeTests.m in Sources */,
|
||||||
3B0F69B01902AD2E00817707 /* MPFunction.m in Sources */,
|
3B0F69B01902AD2E00817707 /* MPFunction.m in Sources */,
|
||||||
|
3B53AD5F1997E0FB00C925C4 /* MPExpression.m in Sources */,
|
||||||
3BBBA35F1903FD3600824E74 /* MPRangePath.m in Sources */,
|
3BBBA35F1903FD3600824E74 /* MPRangePath.m in Sources */,
|
||||||
3B0F69AD1902AD2200817707 /* MPExpression.m in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13C1021" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13E28" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
<customObject id="-2" userLabel="File's Owner" customClass="MPDocument">
|
<customObject id="-2" userLabel="File's Owner" customClass="MPDocument">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="resultExpressionView" destination="lcd-Ip-jjR" id="1NN-l5-30k"/>
|
<outlet property="resultExpressionView" destination="lcd-Ip-jjR" id="1NN-l5-30k"/>
|
||||||
<outlet property="termExpressionView" destination="fqc-IQ-ceJ" id="br9-0u-qYk"/>
|
|
||||||
<outlet property="window" destination="xOd-HO-29H" id="JIz-fz-R2o"/>
|
<outlet property="window" destination="xOd-HO-29H" id="JIz-fz-R2o"/>
|
||||||
</connections>
|
</connections>
|
||||||
</customObject>
|
</customObject>
|
||||||
@@ -17,22 +16,18 @@
|
|||||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||||
<rect key="contentRect" x="133" y="235" width="507" height="240"/>
|
<rect key="contentRect" x="133" y="235" width="507" height="240"/>
|
||||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1080"/>
|
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||||
<value key="minSize" type="size" width="94" height="86"/>
|
<value key="minSize" type="size" width="94" height="86"/>
|
||||||
<view key="contentView" id="gIp-Ho-8D9">
|
<view key="contentView" id="gIp-Ho-8D9">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="507" height="240"/>
|
<rect key="frame" x="0.0" y="0.0" width="507" height="240"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="fqc-IQ-ceJ" customClass="MPExpressionView">
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="lcd-Ip-jjR" customClass="MPExpressionView">
|
||||||
<rect key="frame" x="20" y="124" width="467" height="96"/>
|
<rect key="frame" x="20" y="124" width="467" height="96"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
</customView>
|
</customView>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="lcd-Ip-jjR" customClass="MPExpressionView">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="IMg-L0-qdu">
|
||||||
<rect key="frame" x="20" y="20" width="467" height="96"/>
|
<rect key="frame" x="209" y="13" width="88" height="32"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
|
||||||
</customView>
|
|
||||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IMg-L0-qdu">
|
|
||||||
<rect key="frame" x="405" y="-7" width="88" height="32"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Change" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Xxz-j2-fsI">
|
<buttonCell key="cell" type="push" title="Change" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Xxz-j2-fsI">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
@@ -44,14 +39,12 @@
|
|||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="lcd-Ip-jjR" firstAttribute="top" secondItem="fqc-IQ-ceJ" secondAttribute="bottom" constant="8" symbolic="YES" id="GTC-QI-4wc"/>
|
<constraint firstAttribute="trailing" secondItem="lcd-Ip-jjR" secondAttribute="trailing" constant="20" symbolic="YES" id="3tX-J3-Wte"/>
|
||||||
<constraint firstItem="fqc-IQ-ceJ" firstAttribute="trailing" secondItem="lcd-Ip-jjR" secondAttribute="trailing" id="Pth-4c-GNR"/>
|
<constraint firstItem="IMg-L0-qdu" firstAttribute="top" secondItem="lcd-Ip-jjR" secondAttribute="bottom" constant="83" id="62S-rU-IWO"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="lcd-Ip-jjR" secondAttribute="bottom" constant="20" symbolic="YES" id="VNk-bs-YOH"/>
|
<constraint firstItem="lcd-Ip-jjR" firstAttribute="leading" secondItem="gIp-Ho-8D9" secondAttribute="leading" constant="20" symbolic="YES" id="XN3-k3-tOU"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="fqc-IQ-ceJ" secondAttribute="trailing" constant="20" symbolic="YES" id="fER-QH-XqN"/>
|
<constraint firstItem="lcd-Ip-jjR" firstAttribute="top" secondItem="gIp-Ho-8D9" secondAttribute="top" constant="20" symbolic="YES" id="gqS-BG-xpS"/>
|
||||||
<constraint firstItem="fqc-IQ-ceJ" firstAttribute="top" secondItem="gIp-Ho-8D9" secondAttribute="top" constant="20" symbolic="YES" id="kpD-MX-yOS"/>
|
<constraint firstItem="IMg-L0-qdu" firstAttribute="centerX" secondItem="lcd-Ip-jjR" secondAttribute="centerX" id="sCM-Pj-4wd"/>
|
||||||
<constraint firstItem="fqc-IQ-ceJ" firstAttribute="leading" secondItem="gIp-Ho-8D9" secondAttribute="leading" constant="20" symbolic="YES" id="to2-nb-CUV"/>
|
<constraint firstAttribute="bottom" secondItem="IMg-L0-qdu" secondAttribute="bottom" constant="20" symbolic="YES" id="tNe-R6-QlG"/>
|
||||||
<constraint firstItem="fqc-IQ-ceJ" firstAttribute="leading" secondItem="lcd-Ip-jjR" secondAttribute="leading" id="xJa-Qd-Ytg"/>
|
|
||||||
<constraint firstItem="lcd-Ip-jjR" firstAttribute="top" secondItem="gIp-Ho-8D9" secondAttribute="top" constant="124" id="xrY-1x-QCm"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<connections>
|
<connections>
|
||||||
|
|||||||
@@ -59,9 +59,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Actions
|
#pragma mark Actions
|
||||||
|
|
||||||
- (IBAction)changeExpression:(id)sender {
|
- (IBAction)changeExpression:(id)sender {
|
||||||
[self.resultExpressionView.expressionStorage insertString:@"abc" atIndex:6];
|
[self.resultExpressionView.expressionStorage insertElement:@"abc" atLocation:6];
|
||||||
|
self.resultExpressionView.needsDisplay = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#ifndef MathPad_MPException_h
|
#ifndef MathPad_MPException_h
|
||||||
#define MathPad_MPException_h
|
#define MathPad_MPException_h
|
||||||
|
|
||||||
extern NSString *MPIllegalSymbolException;
|
extern NSString *MPIllegalElementException;
|
||||||
extern NSString *MPIllegalSymbolExceptionSymbolKey;
|
extern NSString *MPIllegalElementExceptionElementKey;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,5 +8,5 @@
|
|||||||
|
|
||||||
#import "MPException.h"
|
#import "MPException.h"
|
||||||
|
|
||||||
NSString *MPIllegalSymbolException = @"MPIllegalSymbolException";
|
NSString *MPIllegalElementException = @"MPIllegalSymbolException";
|
||||||
NSString *MPIllegalSymbolExceptionSymbolKey = @"MPIllegalSymbolExceptionSymbolKey";
|
NSString *MPIllegalElementExceptionElementKey = @"MPIllegalSymbolExceptionSymbolKey";
|
||||||
@@ -2,124 +2,82 @@
|
|||||||
// MPExpression.h
|
// MPExpression.h
|
||||||
// MathPad
|
// MathPad
|
||||||
//
|
//
|
||||||
// Created by Kim Wittenburg on 17.04.14.
|
// Created by Kim Wittenburg on 10.08.14.
|
||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@import Foundation;
|
||||||
|
#import "NSString+MPExpressionElement.h"
|
||||||
|
|
||||||
@class MPExpression, MPFunction, MPRangePath;
|
@class MPExpression, MPFunction, MPRangePath;
|
||||||
|
@protocol MPExpressionElement;
|
||||||
|
|
||||||
extern NSString *MPAdditionOperator;
|
@interface MPExpression : NSObject <NSCopying, NSCoding>
|
||||||
extern NSString *MPSubtractionOperator;
|
|
||||||
extern NSString *MPMultiplicationOperator;
|
|
||||||
extern NSString *MPDivisionOperator;
|
|
||||||
|
|
||||||
@interface MPExpression : NSObject <NSCopying, NSMutableCopying, NSCoding>
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
- (instancetype)init; // Convenience
|
||||||
- (instancetype)initWithSymbols:(NSArray *)symbols;
|
- (instancetype)initWithElement:(id<MPExpressionElement>)element; // Convenience
|
||||||
|
- (instancetype)initWithElements:(NSArray *)elements; // Designated Initializer
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
#pragma mark Working With the Expression Tree
|
||||||
|
@property (nonatomic, weak) MPFunction *parent; // Set automatically, nil for root expression
|
||||||
|
|
||||||
@property (nonatomic, weak) MPFunction *parent; // Documentation: Do not set, may be nil
|
- (void)fixElements; // Called automatically, removes empty elements, joins subsequent strings
|
||||||
|
|
||||||
- (void)fixSymbols;
|
|
||||||
|
|
||||||
#pragma mark Primitive Methods
|
#pragma mark Primitive Methods
|
||||||
|
- (NSUInteger)length;
|
||||||
- (NSUInteger)numberOfSymbols;
|
- (NSUInteger)numberOfElements;
|
||||||
- (id)symbolAtIndex:(NSUInteger)index; // Either an NSString or a MPFunction (which can be mutated)
|
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)index;
|
||||||
|
- (NSArray *)elementsInRange:(NSRange)range;
|
||||||
|
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element;
|
||||||
|
- (void)replaceElementsInRange:(NSRange)range withElements:(NSArray *)elements;
|
||||||
|
// TODO: - (NSUInteger)indexOfElementAtLocation:(NSUInteger)location;
|
||||||
|
|
||||||
- (double)doubleValue; // Evaluates Expression
|
- (double)doubleValue; // Evaluates Expression
|
||||||
|
|
||||||
|
#pragma mark Notifications
|
||||||
|
// All notification methods should create a new rangePath with the receiver's index added to the beginning of the path and then ascend the message to it's parent
|
||||||
|
// TODO: More notifications
|
||||||
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
|
replacementLength:(NSUInteger)replacementLength;
|
||||||
|
|
||||||
|
#pragma mark Basic NSObject Methods
|
||||||
|
- (BOOL)isEqualToExpression:(MPExpression *)anExpression;
|
||||||
|
|
||||||
|
- (NSString *)description;
|
||||||
|
- (NSUInteger)hash;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface MPExpression (MPExpressionExtensionMethods)
|
@interface MPExpression (MPExpressionExtension)
|
||||||
|
|
||||||
+ (NSArray *)operators;
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
|
||||||
|
|
||||||
- (id)init;
|
|
||||||
- (instancetype)initWithString:(NSString *)aString;
|
|
||||||
- (instancetype)initWithFunction:(MPFunction *)aFunction;
|
|
||||||
|
|
||||||
+ (instancetype)expression;
|
|
||||||
+ (instancetype)expressionWithString:(NSString *)aString;
|
|
||||||
+ (instancetype)expressionWithFunction:(MPFunction *)aFunction;
|
|
||||||
+ (instancetype)expressionWithSymbols:(NSArray *)symbols;
|
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
#pragma mark Working With the Expression Tree
|
||||||
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath; // Returns an MPExpression or id<MPExpressionElement>
|
||||||
- (NSUInteger)indexOfSymbol:(id)symbol;
|
- (NSArray *)elementsInRangePath:(MPRangePath *)rangePath;
|
||||||
- (id)symbolAtIndexPath:(NSIndexPath *)indexPath; // May also return MPExpression
|
|
||||||
|
|
||||||
#pragma mark Working With Expressions
|
#pragma mark Working With Expressions
|
||||||
|
|
||||||
- (NSUInteger)length;
|
- (MPExpression *)subexpressionFromLocation:(NSUInteger)from;
|
||||||
|
- (MPExpression *)subexpressionToLocation:(NSUInteger)to;
|
||||||
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from;
|
|
||||||
- (MPExpression *)subexpressionToIndex:(NSUInteger)to;
|
|
||||||
- (MPExpression *)subexpressionWithRange:(NSRange)range;
|
- (MPExpression *)subexpressionWithRange:(NSRange)range;
|
||||||
|
|
||||||
- (BOOL)isEqualToExpression:(MPExpression *)anExpression;
|
|
||||||
|
|
||||||
- (MPExpression *)expressionByAppendingString:(NSString *)aString;
|
#pragma mark Mutating Expressions
|
||||||
- (MPExpression *)expressionByAppendingFunction:(MPFunction *)aFunction;
|
- (void)appendElement:(id<MPExpressionElement>)anElement;
|
||||||
- (MPExpression *)expressionByAppendingExpression:(MPExpression *)anExpression;
|
- (void)appendElements:(NSArray *)elements;
|
||||||
- (MPExpression *)expressionByAppendingSymbols:(NSArray *)symbols;
|
|
||||||
|
- (void)insertElement:(id<MPExpressionElement>)anElement atLocation:(NSUInteger)index;
|
||||||
|
- (void)insertElements:(NSArray *)elements atLocation:(NSUInteger)index;
|
||||||
|
|
||||||
|
- (void)deleteElementsInRange:(NSRange)range;
|
||||||
|
|
||||||
#pragma mark Evaluating Expressions
|
#pragma mark Evaluating Expressions
|
||||||
|
|
||||||
- (float)floatValue;
|
- (float)floatValue;
|
||||||
- (int)intValue;
|
- (int)intValue;
|
||||||
- (NSInteger)integerValue;
|
- (NSInteger)integerValue;
|
||||||
- (long long)longLongValue;
|
- (long long)longLongValue;
|
||||||
|
|
||||||
#pragma mark Querying an Expression's Contents
|
#pragma mark Querying Expressions
|
||||||
|
- (NSArray *)elements;
|
||||||
- (NSArray *)symbols;
|
|
||||||
|
|
||||||
- (NSString *)description;
|
|
||||||
|
|
||||||
- (NSUInteger)hash;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MPExpression (MPChangeNotificationExtension)
|
|
||||||
|
|
||||||
- (void)symbolsChangedInRangePath:(MPRangePath *)rangePath replacementLength:(NSUInteger)length;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MPMutableExpression : MPExpression
|
|
||||||
|
|
||||||
- (void)replaceSymbolsInRange:(NSRange)range
|
|
||||||
withSymbols:(NSArray *)symbols;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MPMutableExpression (MPMutableExpressionExtensionMethods)
|
|
||||||
|
|
||||||
- (void)insertString:(NSString *)aString
|
|
||||||
atIndex:(NSUInteger)loc;
|
|
||||||
- (void)insertFunction:(MPFunction *)aFunction
|
|
||||||
atIndex:(NSUInteger)loc;
|
|
||||||
- (void)insertExpression:(MPExpression *)anExpression
|
|
||||||
atIndex:(NSUInteger)loc;
|
|
||||||
- (void)insertSymbols:(NSArray *)symbols
|
|
||||||
atIndex:(NSUInteger)loc;
|
|
||||||
|
|
||||||
- (void)deleteSymbolsInRange:(NSRange)range;
|
|
||||||
|
|
||||||
- (void)appendString:(NSString *)aString;
|
|
||||||
- (void)appendFunction:(MPFunction *)aFunction;
|
|
||||||
- (void)appendExpression:(MPExpression *)anExpression;
|
|
||||||
- (void)appendSymbols:(NSArray *)symbols;
|
|
||||||
|
|
||||||
- (void)setString:(NSString *)aString;
|
|
||||||
- (void)setFunction:(MPFunction *)aFunction;
|
|
||||||
- (void)setExpression:(MPExpression *)anExpression;
|
|
||||||
- (void)setSymbols:(NSArray *)symbols;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -2,88 +2,228 @@
|
|||||||
// MPExpression.m
|
// MPExpression.m
|
||||||
// MathPad
|
// MathPad
|
||||||
//
|
//
|
||||||
// Created by Kim Wittenburg on 17.04.14.
|
// Created by Kim Wittenburg on 10.08.14.
|
||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "MPExpression.h"
|
#import "MPExpression.h"
|
||||||
#import "MPFunction.h"
|
#import "MPFunction.h"
|
||||||
#import "MPException.h"
|
|
||||||
#import "MPRangePath.h"
|
#import "MPRangePath.h"
|
||||||
|
|
||||||
#import "NSObject+MPStringTest.h"
|
#import "NSIndexPath+MPAdditions.h"
|
||||||
#import "NSIndexPath+MPReverseIndexPath.h"
|
#import "MPException.h"
|
||||||
|
|
||||||
NSString *MPAdditionOperator = @"+";
|
@interface MPExpression ()
|
||||||
NSString *MPSubtractionOperator = @"-";
|
@property (readonly, nonatomic, strong) NSMutableArray *elements;
|
||||||
NSString *MPMultiplicationOperator = @"*";
|
@end
|
||||||
NSString *MPDivisionOperator = @"/";
|
|
||||||
|
|
||||||
@interface MPExpression (MPExpressionPrivate)
|
@interface MPExpression (MPExpressionPrivate)
|
||||||
|
|
||||||
- (NSInteger)lengthOfSymbol:(id)symbol;
|
- (void)validateElements:(NSArray *)elements;
|
||||||
- (void)validateSymbols:(NSArray *)symbols;
|
- (BOOL)splitElementsAtLocation:(NSUInteger)location
|
||||||
- (void)getSplitOffset:(out NSUInteger *)offset
|
insertionIndex:(out NSUInteger *)insertionIndex;
|
||||||
inSymbolAtIndex:(out NSUInteger *)symbolIndex
|
- (NSUInteger)calculateSplitOffsetForSplitLocation:(NSUInteger)location
|
||||||
forSplitLocation:(NSUInteger)loc;
|
inElementAtIndex:(out NSUInteger *)elementIndex;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPExpression (MPExpressionPrivate)
|
||||||
|
|
||||||
|
- (void)validateElements:(NSArray *)elements
|
||||||
|
{
|
||||||
|
for (id element in elements) {
|
||||||
|
if (![element conformsToProtocol:@protocol(MPExpressionElement)]) {
|
||||||
|
@throw [NSException exceptionWithName:MPIllegalElementException
|
||||||
|
reason:@"Elements must conform to the MPExpressionElement protocol."
|
||||||
|
userInfo:@{MPIllegalElementExceptionElementKey: element}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)splitElementsAtLocation:(NSUInteger)location
|
||||||
|
insertionIndex:(out NSUInteger *)insertionIndex
|
||||||
|
{
|
||||||
|
if (location == 0) {
|
||||||
|
*insertionIndex = 0;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
NSUInteger splitElementIndex;
|
||||||
|
NSUInteger splitOffset = [self calculateSplitOffsetForSplitLocation:location
|
||||||
|
inElementAtIndex:&splitElementIndex];
|
||||||
|
id<MPExpressionElement> splitElement = self.elements[splitElementIndex];
|
||||||
|
if (splitOffset == splitElement.length) {
|
||||||
|
splitOffset = 0;
|
||||||
|
splitElementIndex++;
|
||||||
|
}
|
||||||
|
if (splitOffset != 0) {
|
||||||
|
NSString *stringElement = (NSString *)splitElement;
|
||||||
|
NSString *leftPart = [stringElement substringToIndex:splitOffset];
|
||||||
|
NSString *rightPart = [stringElement substringFromIndex:splitOffset];
|
||||||
|
[self.elements replaceObjectsInRange:NSMakeRange(splitElementIndex, 1)
|
||||||
|
withObjectsFromArray:@[leftPart, rightPart]];
|
||||||
|
++splitElementIndex;
|
||||||
|
}
|
||||||
|
*insertionIndex = splitElementIndex;
|
||||||
|
return splitOffset != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)calculateSplitOffsetForSplitLocation:(NSUInteger)location
|
||||||
|
inElementAtIndex:(out NSUInteger *)elementIndex
|
||||||
|
{
|
||||||
|
NSUInteger length = 0;
|
||||||
|
NSUInteger index = 0;
|
||||||
|
NSUInteger elementLength = 0;
|
||||||
|
for (id<MPExpressionElement> element in self.elements) {
|
||||||
|
elementLength = element.length;
|
||||||
|
length += elementLength;
|
||||||
|
if (length >= location) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
*elementIndex = index;
|
||||||
|
return elementLength - (length - location);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPExpression {
|
@implementation MPExpression {
|
||||||
@package
|
NSUInteger _cachedLength;
|
||||||
__strong NSArray *_symbols;
|
NSRange editedRange;
|
||||||
NSInteger _length;
|
NSRange replacementRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
@synthesize elements = _elements;
|
||||||
|
|
||||||
- (instancetype)initWithSymbols:(NSArray *)symbols
|
#pragma mark Creation Methods
|
||||||
|
- (instancetype)init
|
||||||
|
{
|
||||||
|
return [self initWithElements:@[]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithElement:(id<MPExpressionElement>)element
|
||||||
|
{
|
||||||
|
return [self initWithElements:@[element]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithElements:(NSArray *)elements
|
||||||
{
|
{
|
||||||
[self validateSymbols:symbols];
|
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_symbols = [[NSArray alloc] initWithArray:symbols
|
_cachedLength = 0;
|
||||||
|
_elements = [[NSMutableArray alloc] initWithCapacity:elements.count];
|
||||||
|
_elements = [[NSMutableArray alloc] initWithArray:elements
|
||||||
copyItems:YES];
|
copyItems:YES];
|
||||||
[self fixSymbols];
|
[self fixElements];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
#pragma mark Working With the Expression Tree
|
||||||
|
- (void)fixElements
|
||||||
- (void)fixSymbols
|
|
||||||
{
|
{
|
||||||
NSMutableArray *mutableSymbols = [_symbols mutableCopy];
|
for (NSUInteger index = 0; index < self.elements.count; index++) {
|
||||||
for (NSInteger index = 0; index < mutableSymbols.count; index++) {
|
id<MPExpressionElement> next = index+1 < self.elements.count ? self.elements[index+1] :nil;
|
||||||
id next = index+1 < mutableSymbols.count ? mutableSymbols[index+1] : nil;
|
id<MPExpressionElement> current = self.elements[index];
|
||||||
id current = mutableSymbols[index];
|
|
||||||
if ([current isString]) {
|
if ([current isString]) {
|
||||||
if ([current length] == 0) {
|
if (current.length == 0) {
|
||||||
[mutableSymbols removeObjectAtIndex:index];
|
[self.elements removeObjectAtIndex:index];
|
||||||
index--;
|
if (index < replacementRange.location) {
|
||||||
|
replacementRange.location--;
|
||||||
|
} else if (index < NSMaxRange(replacementRange)-1) {
|
||||||
|
replacementRange.length--;
|
||||||
|
} else if (index == NSMaxRange(replacementRange)) {
|
||||||
|
editedRange.length++;
|
||||||
|
}
|
||||||
|
--index;
|
||||||
} else if ([next isString]) {
|
} else if ([next isString]) {
|
||||||
NSString *new = [NSString stringWithFormat:@"%@%@", current, next];
|
NSString *new = [NSString stringWithFormat:@"%@%@", current, next];
|
||||||
[mutableSymbols replaceObjectAtIndex:index withObject:new];
|
[self.elements replaceObjectsInRange:NSMakeRange(index, 2)
|
||||||
[mutableSymbols removeObjectAtIndex:index+1];
|
withObjectsFromArray:@[new]];
|
||||||
index--;
|
if (index < replacementRange.location) {
|
||||||
|
replacementRange.location--;
|
||||||
|
} else if (index < NSMaxRange(replacementRange)-1) {
|
||||||
|
replacementRange.length--;
|
||||||
|
} else if (index == NSMaxRange(replacementRange)-1) {
|
||||||
|
editedRange.length++;
|
||||||
|
}
|
||||||
|
--index;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
[(MPFunction *)current setParent:self];
|
[(MPFunction *)current setParent:self];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_symbols = [mutableSymbols copy];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Primitive Methods
|
#pragma mark Primitive Methods
|
||||||
|
- (NSUInteger)length
|
||||||
- (NSUInteger)numberOfSymbols
|
|
||||||
{
|
{
|
||||||
return [_symbols count];
|
if (_cachedLength == 0) {
|
||||||
|
for (id<MPExpressionElement> element in self.elements) {
|
||||||
|
_cachedLength += element.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _cachedLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)symbolAtIndex:(NSUInteger)index
|
- (NSUInteger)numberOfElements
|
||||||
{
|
{
|
||||||
return _symbols[index];
|
return self.elements.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)index
|
||||||
|
{
|
||||||
|
return self.elements[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)elementsInRange:(NSRange)range
|
||||||
|
{
|
||||||
|
return [self.elements subarrayWithRange:range];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element
|
||||||
|
{
|
||||||
|
return [self.elements indexOfObject:element];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replaceElementsInRange:(NSRange)range
|
||||||
|
withElements:(NSArray *)elements
|
||||||
|
{
|
||||||
|
if (NSMaxRange(range) > self.length) {
|
||||||
|
@throw [NSException exceptionWithName:NSRangeException
|
||||||
|
reason:@"Range out of bounds of expression"
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
[self validateElements:elements];
|
||||||
|
|
||||||
|
// Locate the position, split the elements
|
||||||
|
NSUInteger startIndex;
|
||||||
|
BOOL didSplitStart = NO;
|
||||||
|
if ([self numberOfElements] == 0) {
|
||||||
|
startIndex = 0;
|
||||||
|
} else {
|
||||||
|
didSplitStart = [self splitElementsAtLocation:range.location
|
||||||
|
insertionIndex:&startIndex];
|
||||||
|
}
|
||||||
|
NSUInteger endIndex;
|
||||||
|
BOOL didSplitEnd = [self splitElementsAtLocation:NSMaxRange(range)
|
||||||
|
insertionIndex:&endIndex];
|
||||||
|
|
||||||
|
// Perform the replacement
|
||||||
|
NSArray *newElements = [[NSArray alloc] initWithArray:elements
|
||||||
|
copyItems:YES];
|
||||||
|
[self.elements replaceObjectsInRange:NSMakeRange(startIndex, endIndex-startIndex)
|
||||||
|
withObjectsFromArray:newElements];
|
||||||
|
|
||||||
|
|
||||||
|
_cachedLength = 0;
|
||||||
|
NSUInteger editingStart = startIndex - (didSplitStart?1:0);
|
||||||
|
NSUInteger editingLength = endIndex - startIndex + (didSplitStart?1:0) + (didSplitEnd?1:0);
|
||||||
|
editedRange = NSMakeRange(editingStart, editingLength);
|
||||||
|
replacementRange = NSMakeRange(startIndex, elements.count);
|
||||||
|
[self fixElements];
|
||||||
|
MPRangePath *changePath = [[MPRangePath alloc] initWithRange:editedRange];
|
||||||
|
[self didChangeElementsInRangePath:changePath replacementLength:replacementRange.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (double)doubleValue
|
- (double)doubleValue
|
||||||
@@ -92,218 +232,18 @@ NSString *MPDivisionOperator = @"/";
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
#pragma mark Notifications
|
||||||
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
- (id)copyWithZone:(NSZone *)zone
|
replacementLength:(NSUInteger)replacementLength
|
||||||
{
|
{
|
||||||
MPExpression *copy = [[MPExpression allocWithZone:zone] initWithSymbols:_symbols];
|
NSUInteger selfIndex = [self.parent indexOfChild:self];
|
||||||
return copy;
|
MPRangePath *newPath = rangePath.copy;
|
||||||
|
newPath.location = [newPath.location indexPathByPreceedingIndex:selfIndex];
|
||||||
|
[self.parent didChangeElementsInRangePath:newPath
|
||||||
|
replacementLength:replacementLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSMutableCopying
|
#pragma mark Basic NSObject Methods
|
||||||
|
|
||||||
- (id)mutableCopyWithZone:(NSZone *)zone
|
|
||||||
{
|
|
||||||
MPMutableExpression *mutableCopy = [[MPMutableExpression allocWithZone:zone] initWithSymbols:_symbols];
|
|
||||||
return mutableCopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSCoding
|
|
||||||
|
|
||||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
|
||||||
{
|
|
||||||
// TODO: Test Coding
|
|
||||||
return [self initWithSymbols:[aDecoder decodeObject]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
|
||||||
{
|
|
||||||
[aCoder encodeObject:_symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPExpression (MPExpressionPrivate)
|
|
||||||
|
|
||||||
- (NSInteger)lengthOfSymbol:(id)symbol
|
|
||||||
{
|
|
||||||
if ([symbol isString]) {
|
|
||||||
return [symbol length];
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)validateSymbols:(NSArray *)symbols
|
|
||||||
{
|
|
||||||
for (id symbol in symbols) {
|
|
||||||
if (!([symbol isString]
|
|
||||||
|| [symbol isKindOfClass:[MPFunction class]])) {
|
|
||||||
@throw [NSException exceptionWithName:MPIllegalSymbolException
|
|
||||||
reason:@"Only NSString and MPFunction objects are valid symbols."
|
|
||||||
userInfo:@{MPIllegalSymbolExceptionSymbolKey: symbol}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)getSplitOffset:(out NSUInteger *)offset
|
|
||||||
inSymbolAtIndex:(out NSUInteger *)symbolIndex
|
|
||||||
forSplitLocation:(NSUInteger)loc
|
|
||||||
{
|
|
||||||
NSUInteger length = 0;
|
|
||||||
NSUInteger index = 0;
|
|
||||||
NSUInteger symbolLength = 0;
|
|
||||||
for (id symbol in _symbols) {
|
|
||||||
symbolLength = [self lengthOfSymbol:symbol];
|
|
||||||
length += symbolLength;
|
|
||||||
if (length >= loc) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
*offset = symbolLength - (length - loc);
|
|
||||||
*symbolIndex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPExpression (MPExpressionExtensionMethods)
|
|
||||||
|
|
||||||
+ (NSArray *)operators
|
|
||||||
{
|
|
||||||
return @[MPAdditionOperator, MPSubtractionOperator, MPMultiplicationOperator, MPDivisionOperator];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
|
||||||
|
|
||||||
- (instancetype)init
|
|
||||||
{
|
|
||||||
return [self initWithSymbols:@[]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithString:(NSString *)aString
|
|
||||||
{
|
|
||||||
return [self initWithSymbols:@[aString]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithFunction:(MPFunction *)aFunction
|
|
||||||
{
|
|
||||||
return [self initWithSymbols:@[aFunction]];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)expression
|
|
||||||
{
|
|
||||||
return [[self alloc] init];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)expressionWithString:(NSString *)aString
|
|
||||||
{
|
|
||||||
return [[self alloc] initWithString:aString];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)expressionWithFunction:(MPFunction *)aFunction
|
|
||||||
{
|
|
||||||
return [[self alloc] initWithFunction:aFunction];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)expressionWithSymbols:(NSArray *)symbols
|
|
||||||
{
|
|
||||||
return [[self alloc] initWithSymbols:symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
|
||||||
|
|
||||||
- (NSUInteger)indexOfSymbol:(id)symbol
|
|
||||||
{
|
|
||||||
return [_symbols indexOfObject:symbol];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)symbolAtIndexPath:(NSIndexPath *)indexPath
|
|
||||||
{
|
|
||||||
if (indexPath.length == 0) {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
id symbol = [self symbolAtIndex:[indexPath indexAtPosition:0]];
|
|
||||||
if (indexPath.length == 1) {
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
if ([symbol isKindOfClass:[MPFunction class]]) {
|
|
||||||
return [symbol symbolAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Working With Expressions
|
|
||||||
|
|
||||||
- (NSUInteger)length
|
|
||||||
{
|
|
||||||
if (_length == 0) {
|
|
||||||
for (id symbol in _symbols) {
|
|
||||||
_length += [self lengthOfSymbol:symbol];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _length;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
|
|
||||||
{
|
|
||||||
return [self subexpressionWithRange:NSMakeRange(from, [self length] - from)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
|
|
||||||
{
|
|
||||||
return [self subexpressionWithRange:NSMakeRange(0, to)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPExpression *)subexpressionWithRange:(NSRange)range
|
|
||||||
{
|
|
||||||
if (NSMaxRange(range) > self.length) {
|
|
||||||
@throw [NSException exceptionWithName:NSRangeException
|
|
||||||
reason:@"Range outside bounds of expression."
|
|
||||||
userInfo:nil];
|
|
||||||
}
|
|
||||||
if (range.location == self.length || NSMaxRange(range) == 0 || range.length == 0) {
|
|
||||||
// Speed this up
|
|
||||||
return [[MPExpression alloc] init];
|
|
||||||
}
|
|
||||||
NSUInteger startOffset;
|
|
||||||
NSUInteger startSymbolIndex;
|
|
||||||
[self getSplitOffset:&startOffset
|
|
||||||
inSymbolAtIndex:&startSymbolIndex
|
|
||||||
forSplitLocation:range.location];
|
|
||||||
id startSymbol = _symbols[startSymbolIndex];
|
|
||||||
if (startOffset == [self lengthOfSymbol:startSymbol]) {
|
|
||||||
startOffset = 0;
|
|
||||||
startSymbolIndex++;
|
|
||||||
startSymbol = _symbols[startSymbolIndex];
|
|
||||||
} else if ([startSymbol isString]) {
|
|
||||||
startSymbol = [startSymbol substringFromIndex:startOffset];
|
|
||||||
}
|
|
||||||
NSUInteger endOffset;
|
|
||||||
NSUInteger endSymbolIndex;
|
|
||||||
[self getSplitOffset:&endOffset
|
|
||||||
inSymbolAtIndex:&endSymbolIndex
|
|
||||||
forSplitLocation:NSMaxRange(range)];
|
|
||||||
id endSymbol = _symbols[endSymbolIndex];
|
|
||||||
if ([endSymbol isString]) {
|
|
||||||
endSymbol = [endSymbol substringToIndex:endOffset];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
NSMutableArray *symbols = [[NSMutableArray alloc] initWithCapacity:endSymbolIndex-startSymbolIndex+1];
|
|
||||||
[symbols addObject:startSymbol];
|
|
||||||
if (endSymbolIndex > startSymbolIndex + 1) {
|
|
||||||
NSInteger restLength = endSymbolIndex - startSymbolIndex - 1;
|
|
||||||
[symbols addObjectsFromArray:[_symbols subarrayWithRange:NSMakeRange(startSymbolIndex+1, restLength)]];
|
|
||||||
}
|
|
||||||
if (endSymbolIndex > startSymbolIndex) {
|
|
||||||
[symbols addObject:endSymbol];
|
|
||||||
} else if (endSymbolIndex == startSymbolIndex && [startSymbol isString]) {
|
|
||||||
NSString *result = [_symbols[startSymbolIndex] substringWithRange:NSMakeRange(startOffset, endOffset-startOffset)];
|
|
||||||
[symbols replaceObjectAtIndex:0
|
|
||||||
withObject:result];
|
|
||||||
}
|
|
||||||
return [[MPExpression alloc] initWithSymbols:symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isEqual:(id)object
|
- (BOOL)isEqual:(id)object
|
||||||
{
|
{
|
||||||
@@ -321,32 +261,141 @@ NSString *MPDivisionOperator = @"/";
|
|||||||
|
|
||||||
- (BOOL)isEqualToExpression:(MPExpression *)anExpression
|
- (BOOL)isEqualToExpression:(MPExpression *)anExpression
|
||||||
{
|
{
|
||||||
// TODO: Use ->_symbols or .symbols
|
return [self.elements isEqualToArray:anExpression.elements];
|
||||||
return [_symbols isEqualToArray:anExpression->_symbols];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPExpression *)expressionByAppendingString:(NSString *)aString
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return [self expressionByAppendingSymbols:@[aString]];
|
NSMutableString *description = [[NSMutableString alloc] init];
|
||||||
|
NSUInteger index = 0;
|
||||||
|
for (id element in self.elements) {
|
||||||
|
if ([element isString]) {
|
||||||
|
NSMutableString *correctedSymbol = [[element stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy];
|
||||||
|
// Prefix operator
|
||||||
|
if (element != self.elements[0]) {
|
||||||
|
unichar prefix = [correctedSymbol characterAtIndex:0];
|
||||||
|
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:prefix]) {
|
||||||
|
[correctedSymbol insertString:@"*"
|
||||||
|
atIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Suffix operator
|
||||||
|
if (element != [self.elements lastObject]) {
|
||||||
|
unichar suffix = [correctedSymbol characterAtIndex:correctedSymbol.length-1];
|
||||||
|
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:suffix]) {
|
||||||
|
[correctedSymbol appendString:@"*"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[description appendString:correctedSymbol];
|
||||||
|
} else if (index > 0 && [self.elements[index-1] isKindOfClass:[MPFunction class]]) {
|
||||||
|
[description appendFormat:@"*%@", [element description]];
|
||||||
|
} else {
|
||||||
|
[description appendString:[element description]];
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPExpression *)expressionByAppendingFunction:(MPFunction *)aFunction
|
- (NSUInteger)hash
|
||||||
{
|
{
|
||||||
return [self expressionByAppendingSymbols:@[aFunction]];
|
return [self.elements hash];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPExpression *)expressionByAppendingExpression:(MPExpression *)anExpression
|
#pragma mark - NSCopying
|
||||||
|
- (id)copyWithZone:(NSZone *)zone
|
||||||
{
|
{
|
||||||
return [self expressionByAppendingSymbols:anExpression.symbols];
|
MPExpression *copy = [[MPExpression allocWithZone:zone] initWithElements:self.elements];
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPExpression *)expressionByAppendingSymbols:(NSArray *)symbols
|
#pragma mark - NSCoding
|
||||||
|
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||||
{
|
{
|
||||||
return [[MPExpression alloc] initWithSymbols:[_symbols arrayByAddingObjectsFromArray:symbols]];
|
// TODO: Test Coding
|
||||||
|
return [self initWithElements:[aDecoder decodeObject]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:self.elements];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPExpression (MPExpressionExtension)
|
||||||
|
|
||||||
|
#pragma mark Working With the Expression Tree
|
||||||
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
if (indexPath.length == 0) {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
id<MPExpressionElement> element = [self elementAtIndex:[indexPath indexAtPosition:0]];
|
||||||
|
if (indexPath.length == 1) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
if ([element isFunction]) {
|
||||||
|
return [(MPFunction *)element elementAtIndexPath:[indexPath indexPathByRemovingLastIndex]];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)elementsInRangePath:(MPRangePath *)rangePath
|
||||||
|
{
|
||||||
|
MPExpression *targetExpression = [self elementAtIndexPath:[rangePath.location indexPathByRemovingLastIndex]];
|
||||||
|
return [targetExpression elementsInRange:rangePath.rangeAtLastIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Working With Expressions
|
||||||
|
- (MPExpression *)subexpressionFromLocation:(NSUInteger)from
|
||||||
|
{
|
||||||
|
return [self subexpressionWithRange:NSMakeRange(from, self.length - from)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPExpression *)subexpressionToLocation:(NSUInteger)to
|
||||||
|
{
|
||||||
|
return [self subexpressionWithRange:NSMakeRange(0, to)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPExpression *)subexpressionWithRange:(NSRange)range
|
||||||
|
{
|
||||||
|
MPExpression *subexpression = [self copy];
|
||||||
|
NSRange preceedingRange = NSMakeRange(0, range.location);
|
||||||
|
NSUInteger firstOut = NSMaxRange(range);
|
||||||
|
NSRange exceedingRange = NSMakeRange(firstOut, self.length-firstOut);
|
||||||
|
[subexpression deleteElementsInRange:exceedingRange];
|
||||||
|
[subexpression deleteElementsInRange:preceedingRange];
|
||||||
|
return subexpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Mutating Expressions
|
||||||
|
- (void)appendElement:(id<MPExpressionElement>)anElement
|
||||||
|
{
|
||||||
|
[self appendElements:@[anElement]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appendElements:(NSArray *)elements
|
||||||
|
{
|
||||||
|
[self replaceElementsInRange:NSMakeRange(self.length, 0) withElements:elements];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertElement:(id<MPExpressionElement>)anElement atLocation:(NSUInteger)index
|
||||||
|
{
|
||||||
|
[self insertElements:@[anElement] atLocation:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertElements:(NSArray *)elements atLocation:(NSUInteger)index
|
||||||
|
{
|
||||||
|
[self replaceElementsInRange:NSMakeRange(index, 0) withElements:elements];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)deleteElementsInRange:(NSRange)range
|
||||||
|
{
|
||||||
|
[self replaceElementsInRange:range withElements:@[]];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Evaluating Expressions
|
#pragma mark Evaluating Expressions
|
||||||
|
|
||||||
- (float)floatValue
|
- (float)floatValue
|
||||||
{
|
{
|
||||||
return (float)[self doubleValue];
|
return (float)[self doubleValue];
|
||||||
@@ -367,290 +416,4 @@ NSString *MPDivisionOperator = @"/";
|
|||||||
return (long long)[self doubleValue];
|
return (long long)[self doubleValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Querying an Expression's Contents
|
|
||||||
|
|
||||||
- (NSArray *)symbols
|
|
||||||
{
|
|
||||||
// _symbols is immutable so it is ok to just return it instead of making a copy
|
|
||||||
return _symbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)description
|
|
||||||
{
|
|
||||||
NSMutableString *description = [[NSMutableString alloc] init];
|
|
||||||
NSUInteger index = 0;
|
|
||||||
for (id symbol in _symbols) {
|
|
||||||
if ([symbol isString]) {
|
|
||||||
NSMutableString *correctedSymbol = [[symbol stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy];
|
|
||||||
// Prefix operator
|
|
||||||
if (symbol != _symbols[0]) {
|
|
||||||
unichar prefix = [correctedSymbol characterAtIndex:0];
|
|
||||||
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:prefix]) {
|
|
||||||
[correctedSymbol insertString:@"*"
|
|
||||||
atIndex:0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Suffix operator
|
|
||||||
if (symbol != [_symbols lastObject]) {
|
|
||||||
unichar suffix = [correctedSymbol characterAtIndex:correctedSymbol.length-1];
|
|
||||||
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:suffix]) {
|
|
||||||
[correctedSymbol appendString:@"*"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[description appendString:correctedSymbol];
|
|
||||||
} else if (index > 0 && [_symbols[index-1] isKindOfClass:[MPFunction class]]) {
|
|
||||||
[description appendFormat:@"*%@", [symbol description]];
|
|
||||||
} else {
|
|
||||||
[description appendString:[symbol description]];
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSUInteger)hash
|
|
||||||
{
|
|
||||||
return [_symbols hash];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPExpression (MPChangeNotificationExtension)
|
|
||||||
|
|
||||||
- (void)symbolsChangedInRangePath:(MPRangePath *)rangePath replacementLength:(NSUInteger)length
|
|
||||||
{
|
|
||||||
if (!self.parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NSUInteger selfIndex = [self.parent indexOfChild:self];
|
|
||||||
NSIndexPath *newLocation = [rangePath.location indexPathByPrecedingIndex:selfIndex];
|
|
||||||
MPRangePath *newPath = [[MPRangePath alloc] initWithLocation:newLocation length:rangePath.length];
|
|
||||||
[self.parent symbolsChangedInRangePath:newPath replacementLength:length];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPMutableExpression {
|
|
||||||
NSRange editedRange;
|
|
||||||
NSRange replacementRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithSymbols:(NSArray *)symbols
|
|
||||||
{
|
|
||||||
[self validateSymbols:symbols];
|
|
||||||
self = [super initWithSymbols:nil];
|
|
||||||
if (self) {
|
|
||||||
editedRange = NSMakeRange(0, 0);
|
|
||||||
replacementRange = NSMakeRange(0, 0);
|
|
||||||
_symbols = [[NSMutableArray alloc] initWithArray:symbols
|
|
||||||
copyItems:YES];
|
|
||||||
[self fixSymbols];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)fixSymbols
|
|
||||||
{
|
|
||||||
NSMutableArray *mutableSymbols = (NSMutableArray *)_symbols;
|
|
||||||
for (NSInteger index = 0; index < mutableSymbols.count; index++) {
|
|
||||||
id next = index+1 < mutableSymbols.count ? mutableSymbols[index+1] : nil;
|
|
||||||
id current = mutableSymbols[index];
|
|
||||||
if ([current isString]) {
|
|
||||||
if ([current length] == 0) {
|
|
||||||
[mutableSymbols removeObjectAtIndex:index];
|
|
||||||
if (index < replacementRange.location) {
|
|
||||||
replacementRange.location--;
|
|
||||||
} else if (index < NSMaxRange(replacementRange)-1) {
|
|
||||||
replacementRange.length--;
|
|
||||||
} else if (index == NSMaxRange(replacementRange)) {
|
|
||||||
editedRange.length++;
|
|
||||||
}
|
|
||||||
index--;
|
|
||||||
} else if ([next isString]) {
|
|
||||||
NSString *new = [NSString stringWithFormat:@"%@%@", current, next];
|
|
||||||
[mutableSymbols replaceObjectAtIndex:index withObject:new];
|
|
||||||
[mutableSymbols removeObjectAtIndex:index+1];
|
|
||||||
if (index < replacementRange.location) {
|
|
||||||
replacementRange.location--;
|
|
||||||
} else if (index < NSMaxRange(replacementRange)-1) {
|
|
||||||
replacementRange.length--;
|
|
||||||
} else if (index == NSMaxRange(replacementRange)-1) {
|
|
||||||
editedRange.length++;
|
|
||||||
}
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
[(MPFunction *)current setParent:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *)symbols
|
|
||||||
{
|
|
||||||
// Return an immutable array:
|
|
||||||
return [_symbols copy];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)replaceSymbolsInRange:(NSRange)range
|
|
||||||
withSymbols:(NSArray *)symbols
|
|
||||||
{
|
|
||||||
if (NSMaxRange(range) > self.length) {
|
|
||||||
@throw [NSException exceptionWithName:NSRangeException
|
|
||||||
reason:@"Range out of bounds of expression."
|
|
||||||
userInfo:nil];
|
|
||||||
}
|
|
||||||
[self validateSymbols:symbols];
|
|
||||||
|
|
||||||
// Locate the position, split the symbols
|
|
||||||
NSUInteger startIndex;
|
|
||||||
BOOL didSplitStart = NO;
|
|
||||||
if ([self numberOfSymbols] == 0) {
|
|
||||||
startIndex = 0;
|
|
||||||
} else {
|
|
||||||
[self splitSymbolsAtLocation:range.location
|
|
||||||
insertionIndex:&startIndex
|
|
||||||
didSplit:&didSplitStart];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the deletion
|
|
||||||
NSUInteger endIndex;
|
|
||||||
BOOL didSplitEnd = NO;
|
|
||||||
[self splitSymbolsAtLocation:NSMaxRange(range)
|
|
||||||
insertionIndex:&endIndex
|
|
||||||
didSplit:&didSplitEnd];
|
|
||||||
if (range.length > 0) {
|
|
||||||
NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init];
|
|
||||||
for (NSUInteger index = startIndex; index < endIndex; index++) {
|
|
||||||
[indexes addIndex:index];
|
|
||||||
}
|
|
||||||
// TODO: Replace with removeObjectsInRange:
|
|
||||||
[(NSMutableArray *)_symbols removeObjectsAtIndexes:indexes];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the insertion
|
|
||||||
if (symbols.count > 0) {
|
|
||||||
NSArray *newSymbols = [[NSArray alloc] initWithArray:symbols copyItems:YES];
|
|
||||||
[(NSMutableArray *)_symbols replaceObjectsInRange:NSMakeRange(startIndex, 0)
|
|
||||||
withObjectsFromArray:newSymbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalidate length and revalidate structure
|
|
||||||
_length = 0;
|
|
||||||
NSUInteger editingStart = startIndex - (didSplitStart?1:0);
|
|
||||||
NSUInteger editingLength = endIndex - startIndex + (didSplitStart?1:0) + (didSplitEnd?1:0);
|
|
||||||
editedRange = NSMakeRange(editingStart, editingLength);
|
|
||||||
replacementRange = NSMakeRange(startIndex, symbols.count);
|
|
||||||
[self fixSymbols];
|
|
||||||
MPRangePath *changePath = [[MPRangePath alloc] initWithRange:editedRange];
|
|
||||||
[self symbolsChangedInRangePath:changePath replacementLength:replacementRange.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)splitSymbolsAtLocation:(NSUInteger)loc
|
|
||||||
insertionIndex:(out NSUInteger *)insertionIndex
|
|
||||||
didSplit:(out BOOL *)flag;
|
|
||||||
{
|
|
||||||
NSUInteger splitSymbolIndex;
|
|
||||||
NSUInteger splitOffset;
|
|
||||||
[self getSplitOffset:&splitOffset
|
|
||||||
inSymbolAtIndex:&splitSymbolIndex
|
|
||||||
forSplitLocation:loc];
|
|
||||||
id splitSymbol = _symbols[splitSymbolIndex];
|
|
||||||
NSInteger splitSymbolLength = [self lengthOfSymbol:splitSymbol];
|
|
||||||
if (splitOffset == splitSymbolLength) {
|
|
||||||
splitOffset = 0;
|
|
||||||
splitSymbolIndex++;
|
|
||||||
}
|
|
||||||
if (splitOffset != 0) {
|
|
||||||
NSString *leftPart = [splitSymbol substringToIndex:splitOffset];
|
|
||||||
NSString *rightPart = [splitSymbol substringFromIndex:splitOffset];
|
|
||||||
[(NSMutableArray *)_symbols replaceObjectAtIndex:splitSymbolIndex
|
|
||||||
withObject:leftPart];
|
|
||||||
splitSymbolIndex++;
|
|
||||||
[(NSMutableArray *)_symbols insertObject:rightPart
|
|
||||||
atIndex:splitSymbolIndex];
|
|
||||||
}
|
|
||||||
*flag = splitOffset != 0;
|
|
||||||
*insertionIndex = splitSymbolIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPMutableExpression (MPMutableExpressionExtensionMethods)
|
|
||||||
|
|
||||||
- (void)insertString:(NSString *)aString
|
|
||||||
atIndex:(NSUInteger)loc
|
|
||||||
{
|
|
||||||
[self insertSymbols:@[aString]
|
|
||||||
atIndex:loc];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)insertFunction:(MPFunction *)aFunction
|
|
||||||
atIndex:(NSUInteger)loc
|
|
||||||
{
|
|
||||||
[self insertSymbols:@[aFunction]
|
|
||||||
atIndex:loc];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)insertExpression:(MPExpression *)anExpression
|
|
||||||
atIndex:(NSUInteger)loc
|
|
||||||
{
|
|
||||||
[self insertSymbols:anExpression.symbols
|
|
||||||
atIndex:loc];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)insertSymbols:(NSArray *)symbols
|
|
||||||
atIndex:(NSUInteger)loc
|
|
||||||
{
|
|
||||||
[self replaceSymbolsInRange:NSMakeRange(loc, 0)
|
|
||||||
withSymbols:symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)deleteSymbolsInRange:(NSRange)range
|
|
||||||
{
|
|
||||||
[self replaceSymbolsInRange:range
|
|
||||||
withSymbols:@[]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)appendString:(NSString *)aString
|
|
||||||
{
|
|
||||||
[self appendSymbols:@[aString]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)appendFunction:(MPFunction *)aFunction
|
|
||||||
{
|
|
||||||
[self appendSymbols:@[aFunction]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)appendExpression:(MPExpression *)anExpression
|
|
||||||
{
|
|
||||||
[self appendSymbols:anExpression.symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)appendSymbols:(NSArray *)symbols
|
|
||||||
{
|
|
||||||
[self replaceSymbolsInRange:NSMakeRange(self.length, 0)
|
|
||||||
withSymbols:symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setString:(NSString *)aString
|
|
||||||
{
|
|
||||||
[self setSymbols:@[aString]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setFunction:(MPFunction *)aFunction
|
|
||||||
{
|
|
||||||
[self setSymbols:@[aFunction]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setExpression:(MPExpression *)anExpression
|
|
||||||
{
|
|
||||||
[self setSymbols:anExpression.symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setSymbols:(NSArray *)symbols
|
|
||||||
{
|
|
||||||
[self replaceSymbolsInRange:NSMakeRange(0, self.length)
|
|
||||||
withSymbols:symbols];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
24
MathPad/MPExpressionElement.h
Normal file
24
MathPad/MPExpressionElement.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// MPExpressionElement.h
|
||||||
|
// MathPad
|
||||||
|
//
|
||||||
|
// Created by Kim Wittenburg on 10.08.14.
|
||||||
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@import Foundation;
|
||||||
|
|
||||||
|
@protocol MPExpressionElement <NSObject, NSCoding>
|
||||||
|
|
||||||
|
- (BOOL)isString;
|
||||||
|
- (BOOL)isFunction;
|
||||||
|
|
||||||
|
- (NSUInteger)length;
|
||||||
|
|
||||||
|
- (double)doubleValue;
|
||||||
|
- (float)floatValue;
|
||||||
|
- (int)intValue;
|
||||||
|
- (NSInteger)integerValue;
|
||||||
|
- (long long)longLongValue;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -2,64 +2,18 @@
|
|||||||
// MPExpressionLayout.h
|
// MPExpressionLayout.h
|
||||||
// MathPad
|
// MathPad
|
||||||
//
|
//
|
||||||
// Created by Kim Wittenburg on 22.04.14.
|
// Created by Kim Wittenburg on 07.08.14.
|
||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
@import Cocoa;
|
||||||
|
#import "MPLayout.h"
|
||||||
|
#import "MPExpression.h"
|
||||||
|
|
||||||
@class MPExpressionLayout, MPFunctionLayout, MPExpressionStorage, MPExpressionView, MPExpression;
|
@interface MPExpressionLayout : MPLayout
|
||||||
|
|
||||||
@interface MPExpressionLayout : NSObject {
|
- (instancetype)initRootLayoutWithExpressionStorage:(MPExpressionStorage *)expressionStorage;
|
||||||
BOOL _valid;
|
|
||||||
NSSize _cachedSize;
|
|
||||||
NSMutableArray *_symbolCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
@property (readonly, nonatomic, weak) MPExpression *expression; // Convenience
|
||||||
|
|
||||||
// -init not supported
|
|
||||||
- (id)initRootLayoutWithExpressionStorage:(MPExpressionStorage *)expressionStorage;
|
|
||||||
- (id)initWithExpressionPath:(NSIndexPath *)expressionPath
|
|
||||||
parent:(MPFunctionLayout *)parent;
|
|
||||||
|
|
||||||
#pragma mark Properties
|
|
||||||
|
|
||||||
@property (readonly, nonatomic, weak) MPFunctionLayout *parent;
|
|
||||||
|
|
||||||
@property (readonly, nonatomic, weak) MPExpressionStorage *expressionStorage;
|
|
||||||
@property (readonly, nonatomic, strong) NSIndexPath *expressionPath;
|
|
||||||
|
|
||||||
@property (nonatomic, weak) MPExpressionView *expressionView;
|
|
||||||
|
|
||||||
- (MPExpression *)expression; // Convenience
|
|
||||||
- (NSLayoutManager *)layoutManager;
|
|
||||||
- (NSTextContainer *)textContainer;
|
|
||||||
- (NSTextStorage *)textStorage;
|
|
||||||
|
|
||||||
#pragma mark Cache Methods
|
|
||||||
|
|
||||||
- (void)invalidate;
|
|
||||||
- (void)editedExpressionInRange:(NSRange)range
|
|
||||||
replacementLength:(NSUInteger)length;
|
|
||||||
|
|
||||||
- (BOOL)hasCacheForSymbolAtIndex:(NSUInteger)index;
|
|
||||||
- (MPFunctionLayout *)functionLayoutForFunctionAtIndex:(NSUInteger)index;
|
|
||||||
- (NSSize)cachedSizeForSymbolAtIndex:(NSUInteger)index;
|
|
||||||
- (void)cacheSize:(NSSize)size forSymbolAtIndex:(NSUInteger)index;
|
|
||||||
|
|
||||||
#pragma mark Sizes Calculation Methods
|
|
||||||
|
|
||||||
- (NSSize)sizeForAllSymbols;
|
|
||||||
- (NSSize)sizeForSymbolAtIndex:(NSUInteger)index;
|
|
||||||
- (NSSize)sizeForSymbolsInRange:(NSRange)range;
|
|
||||||
|
|
||||||
#pragma mark Drawing Methods
|
|
||||||
|
|
||||||
- (void)drawSymbolAtIndex:(NSUInteger)index
|
|
||||||
atPoint:(NSPoint)point;
|
|
||||||
- (void)drawSymbolsInRange:(NSRange)range
|
|
||||||
atPoint:(NSPoint)point;
|
|
||||||
- (void)drawAllSymbolsAtPoint:(NSPoint)point;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -2,45 +2,69 @@
|
|||||||
// MPExpressionLayout.m
|
// MPExpressionLayout.m
|
||||||
// MathPad
|
// MathPad
|
||||||
//
|
//
|
||||||
// Created by Kim Wittenburg on 22.04.14.
|
// Created by Kim Wittenburg on 07.08.14.
|
||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "MPExpressionLayout.h"
|
#import "MPExpressionLayout.h"
|
||||||
#import "MPExpressionStorage.h"
|
|
||||||
#import "MPFunctionLayout.h"
|
#import "MPFunctionLayout.h"
|
||||||
#import "MPModel.h"
|
|
||||||
#import "MPExpressionView.h"
|
@interface MPExpressionLayout (MPPathGeneration)
|
||||||
|
|
||||||
|
- (NSBezierPath *)bezierPathForChildAtIndex:(NSUInteger)index;
|
||||||
|
- (NSBezierPath *)generateBezierPathForString:(NSString *)aString;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPExpressionLayout (MPPathGeneration)
|
||||||
|
|
||||||
|
- (NSBezierPath *)bezierPathForChildAtIndex:(NSUInteger)index
|
||||||
|
{
|
||||||
|
id symbol = [self.expression elementAtIndex:index];
|
||||||
|
if ([symbol isString]) {
|
||||||
|
return [self cachableObjectForIndex:index
|
||||||
|
generator:^id{
|
||||||
|
return [self generateBezierPathForString:symbol];
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
MPLayout *layout = [self childLayoutAtIndex:index];
|
||||||
|
return layout.bezierPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSBezierPath *)generateBezierPathForString:(NSString *)aString
|
||||||
|
{
|
||||||
|
NSAttributedString *text = [[NSAttributedString alloc] initWithString:aString
|
||||||
|
attributes:@{NSFontAttributeName: [NSFont fontWithName:@"Lucida Grande" size:18.0]}];
|
||||||
|
self.textStorage.attributedString = text;
|
||||||
|
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
|
||||||
|
NSGlyph glyphs[glyphRange.length+1];
|
||||||
|
NSUInteger actualGlyphCount = [self.layoutManager getGlyphs:glyphs
|
||||||
|
range:glyphRange];
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||||
|
[path moveToPoint:NSZeroPoint];
|
||||||
|
[path appendBezierPathWithGlyphs:glyphs
|
||||||
|
count:actualGlyphCount
|
||||||
|
inFont:[NSFont fontWithName:@"Lucida Grande" size:18.0]];
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation MPExpressionLayout
|
@implementation MPExpressionLayout
|
||||||
|
|
||||||
# pragma mark Creation Methods
|
# pragma mark Creation Methods
|
||||||
|
|
||||||
- (instancetype)initRootLayoutWithExpressionStorage:(MPExpressionStorage *)expressionStorage
|
- (instancetype)initRootLayoutWithExpressionStorage:(MPExpressionStorage *)expressionStorage
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_symbolCache = [[NSMutableArray alloc] init];
|
|
||||||
_expressionStorage = expressionStorage;
|
_expressionStorage = expressionStorage;
|
||||||
_expressionPath = [[NSIndexPath alloc] init];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithExpressionPath:(NSIndexPath *)expressionPath
|
|
||||||
parent:(MPFunctionLayout *)parent
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
_symbolCache = [[NSMutableArray alloc] init];
|
|
||||||
_expressionPath = expressionPath;
|
|
||||||
_parent = parent;
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
@synthesize expressionStorage = _expressionStorage;
|
@synthesize expressionStorage = _expressionStorage;
|
||||||
- (MPExpressionStorage *)expressionStorage
|
- (MPExpressionStorage *)expressionStorage
|
||||||
{
|
{
|
||||||
@@ -52,172 +76,50 @@
|
|||||||
|
|
||||||
- (MPExpression *)expression
|
- (MPExpression *)expression
|
||||||
{
|
{
|
||||||
return [self.expressionStorage symbolAtIndexPath:self.expressionPath];
|
return [self.expressionStorage elementAtIndexPath:self.path];
|
||||||
}
|
|
||||||
|
|
||||||
- (NSLayoutManager *)layoutManager
|
|
||||||
{
|
|
||||||
return self.expressionStorage.layoutManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSTextContainer *)textContainer
|
|
||||||
{
|
|
||||||
return self.expressionStorage.textContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSTextStorage *)textStorage
|
|
||||||
{
|
|
||||||
return self.expressionStorage.textStorage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Cache Methods
|
#pragma mark Cache Methods
|
||||||
|
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
|
||||||
// TODO: Return nil from caching with illegal index
|
|
||||||
|
|
||||||
- (void)invalidate
|
|
||||||
{
|
{
|
||||||
_valid = NO;
|
id cachedObject = [self cachableObjectForIndex:index generator:^id{
|
||||||
[self.parent invalidate];
|
NSIndexPath *indexPath = [self.path indexPathByAddingIndex:index];
|
||||||
[self.expressionView setNeedsDisplay:YES];
|
MPFunctionLayout *layout = [MPFunctionLayout functionLayoutForFunctionAtIndexPath:indexPath
|
||||||
}
|
parent:self];
|
||||||
|
return layout;
|
||||||
- (void)editedExpressionInRange:(NSRange)range replacementLength:(NSUInteger)length
|
}];
|
||||||
{
|
if ([cachedObject isKindOfClass:[NSBezierPath class]]) {
|
||||||
// TODO: New symbols may also be inserted in the middle or at the beginning
|
|
||||||
NSInteger changeInLength = length - range.length;
|
|
||||||
while (_symbolCache.count < (self.expression.numberOfSymbols + changeInLength)) {
|
|
||||||
[_symbolCache addObject:[NSNull null]];
|
|
||||||
}
|
|
||||||
NSMutableArray *newPlaceholders = [[NSMutableArray alloc] initWithCapacity:length];
|
|
||||||
while (newPlaceholders.count < length) {
|
|
||||||
[newPlaceholders addObject:[NSNull null]];
|
|
||||||
}
|
|
||||||
[_symbolCache replaceObjectsInRange:range withObjectsFromArray:newPlaceholders];
|
|
||||||
[self invalidate];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)hasCacheForSymbolAtIndex:(NSUInteger)index
|
|
||||||
{
|
|
||||||
if (index >= _symbolCache.count) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
return _symbolCache[index] != [NSNull null];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPFunctionLayout *)functionLayoutForFunctionAtIndex:(NSUInteger)index;
|
|
||||||
{
|
|
||||||
if ([self hasCacheForSymbolAtIndex:index]) {
|
|
||||||
id cacheObject = _symbolCache[index];
|
|
||||||
if ([cacheObject isKindOfClass:[NSValue class]]) {
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
return cacheObject;
|
return cachedObject;
|
||||||
}
|
|
||||||
MPFunctionLayout *layout = [MPFunctionLayout functionLayoutForFunctionAtIndexPath:[self.expressionPath indexPathByAddingIndex:index] parent:self];
|
|
||||||
while (index >= _symbolCache.count) {
|
|
||||||
[_symbolCache addObject:[NSNull null]];
|
|
||||||
}
|
|
||||||
_symbolCache[index] = layout;
|
|
||||||
return layout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSSize)cachedSizeForSymbolAtIndex:(NSUInteger)index
|
- (NSSize)sizeForChildAtIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
id cachedSymbol = _symbolCache[index];
|
id symbol = [self.expression elementAtIndex:index];
|
||||||
if ([cachedSymbol isKindOfClass:[NSValue class]]) {
|
|
||||||
return [cachedSymbol sizeValue];
|
|
||||||
}
|
|
||||||
return [(MPFunctionLayout *)cachedSymbol sizeOfFunction];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cacheSize:(NSSize)size forSymbolAtIndex:(NSUInteger)index
|
|
||||||
{
|
|
||||||
while (index >= _symbolCache.count) {
|
|
||||||
[_symbolCache addObject:[NSNull null]];
|
|
||||||
}
|
|
||||||
_symbolCache[index] = [NSValue valueWithSize:size];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Size Calculation Methods
|
|
||||||
|
|
||||||
- (NSSize)sizeForAllSymbols
|
|
||||||
{
|
|
||||||
if (!_valid) {
|
|
||||||
_cachedSize = [self sizeForSymbolsInRange:NSMakeRange(0, self.expression.numberOfSymbols)];
|
|
||||||
_valid = YES;
|
|
||||||
}
|
|
||||||
return _cachedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)sizeForSymbolsInRange:(NSRange)range
|
|
||||||
{
|
|
||||||
NSSize size = NSMakeSize(0, 0);
|
|
||||||
for (NSUInteger index = range.location; index < NSMaxRange(range); index++) {
|
|
||||||
NSSize symbolSize = [self sizeForSymbolAtIndex:index];
|
|
||||||
size.width += symbolSize.width;
|
|
||||||
size.height = MAX(size.height, symbolSize.height);
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)sizeForSymbolAtIndex:(NSUInteger)index
|
|
||||||
{
|
|
||||||
if ([self hasCacheForSymbolAtIndex:index]) {
|
|
||||||
return [self cachedSizeForSymbolAtIndex:index];
|
|
||||||
}
|
|
||||||
id symbol = [self.expression symbolAtIndex:index];
|
|
||||||
if ([symbol isString]) {
|
if ([symbol isString]) {
|
||||||
[self.textStorage setString:symbol];
|
return [self bezierPathForChildAtIndex:index].bounds.size;
|
||||||
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
|
|
||||||
NSSize symbolSize = [self.layoutManager boundingRectForGlyphRange:glyphRange
|
|
||||||
inTextContainer:self.textContainer].size;
|
|
||||||
[self cacheSize:symbolSize
|
|
||||||
forSymbolAtIndex:index];
|
|
||||||
|
|
||||||
return symbolSize;
|
|
||||||
} else {
|
} else {
|
||||||
MPFunctionLayout *layout = [self functionLayoutForFunctionAtIndex:index];
|
return [self childLayoutAtIndex:index].size;
|
||||||
return [layout sizeOfFunction];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Drawing Methods
|
#pragma mark Drawing Methods
|
||||||
|
- (NSBezierPath *)generateBezierPath
|
||||||
- (void)drawSymbolAtIndex:(NSUInteger)index
|
|
||||||
atPoint:(NSPoint)point
|
|
||||||
{
|
{
|
||||||
id symbol = [self.expression symbolAtIndex:index];
|
NSBezierPath *fullPath = [NSBezierPath bezierPath];
|
||||||
// point.x = point.y = 0;
|
[fullPath moveToPoint:NSZeroPoint];
|
||||||
NSLog(@"draw Symbol: %@ at Point: (x: %f, y: %f)", symbol, point.x, point.y);
|
NSUInteger x = 0;
|
||||||
if ([symbol isString]) {
|
for (NSInteger index = 0; index < self.expression.numberOfElements; ++index) {
|
||||||
[self.textStorage setString:symbol];
|
NSAffineTransform *transform = [NSAffineTransform transform];
|
||||||
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
|
// TODO: Translate by the right amount
|
||||||
[self.layoutManager drawGlyphsForGlyphRange:glyphRange
|
[transform translateXBy:x yBy:0];
|
||||||
atPoint:point];
|
NSBezierPath *path = [self bezierPathForChildAtIndex:index].copy;
|
||||||
} else {
|
[path transformUsingAffineTransform:transform];
|
||||||
MPFunctionLayout *layout = [self functionLayoutForFunctionAtIndex:index];
|
[fullPath appendBezierPath:path];
|
||||||
NSLog(@"layout: %@, index: %ld", layout, index);
|
x += path.bounds.size.width;
|
||||||
[layout drawFunctionAtPoint:point];
|
|
||||||
}
|
}
|
||||||
}
|
return fullPath;
|
||||||
|
|
||||||
- (void)drawSymbolsInRange:(NSRange)range
|
|
||||||
atPoint:(NSPoint)point
|
|
||||||
{
|
|
||||||
NSSize overallSize = [self sizeForSymbolsInRange:range];
|
|
||||||
CGFloat x = point.x;
|
|
||||||
for (NSUInteger index = range.location; index < NSMaxRange(range); index++) {
|
|
||||||
NSSize symbolSize = [self sizeForSymbolAtIndex:index];
|
|
||||||
CGFloat dy = (overallSize.height - symbolSize.height) / 2;
|
|
||||||
[self drawSymbolAtIndex:index
|
|
||||||
atPoint:NSMakePoint(x, point.y + dy)];
|
|
||||||
x += symbolSize.width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawAllSymbolsAtPoint:(NSPoint)point
|
|
||||||
{
|
|
||||||
[self drawSymbolsInRange:NSMakeRange(0, [self.expression numberOfSymbols]) atPoint:point];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
@class MPExpressionStorage, MPExpressionLayout;
|
@class MPExpressionStorage, MPExpressionLayout;
|
||||||
|
|
||||||
@interface MPExpressionStorage : MPMutableExpression
|
@interface MPExpressionStorage : MPExpression
|
||||||
|
|
||||||
@property (nonatomic, strong) MPExpressionLayout *expressionLayout;
|
@property (nonatomic, strong) MPExpressionLayout *rootLayout;
|
||||||
|
|
||||||
- (NSLayoutManager *)layoutManager;
|
- (NSLayoutManager *)layoutManager;
|
||||||
- (NSTextContainer *)textContainer;
|
- (NSTextContainer *)textContainer;
|
||||||
|
|||||||
@@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
@implementation MPExpressionStorage
|
@implementation MPExpressionStorage
|
||||||
|
|
||||||
- (instancetype)initWithSymbols:(NSArray *)symbols
|
- (instancetype)initWithElements:(NSArray *)elements
|
||||||
{
|
{
|
||||||
self = [super initWithSymbols:symbols];
|
self = [super initWithElements:elements];
|
||||||
if (self) {
|
if (self) {
|
||||||
_expressionLayout = [[MPExpressionLayout alloc] initRootLayoutWithExpressionStorage:self];
|
_rootLayout = [[MPExpressionLayout alloc] initRootLayoutWithExpressionStorage:self];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -59,24 +59,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)symbolsChangedInRangePath:(MPRangePath *)rangePath replacementLength:(NSUInteger)length
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
|
replacementLength:(NSUInteger)replacementLength
|
||||||
{
|
{
|
||||||
if (rangePath.location.length == 0) {
|
if (rangePath.location.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
id current = self.expressionLayout;
|
MPLayout *current = self.rootLayout;
|
||||||
for (NSUInteger position = 1; position < rangePath.location.length-1; position++) {
|
for (NSUInteger index = 1; index < rangePath.location.length-1; index++) {
|
||||||
if ([current isKindOfClass:[MPExpressionLayout class]]) {
|
current = [current childLayoutAtIndex:index];
|
||||||
current = [(MPExpressionLayout *)current functionLayoutForFunctionAtIndex:position];
|
|
||||||
} else {
|
|
||||||
current = [(MPFunctionLayout *)current expressionLayoutForChildAtIndex:position];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ([current isKindOfClass:[MPExpressionLayout class]]) {
|
|
||||||
[(MPExpressionLayout *)current editedExpressionInRange:rangePath.rangeAtLastIndex replacementLength:length];
|
|
||||||
} else {
|
|
||||||
[(MPFunctionLayout *)current editedChildAtIndex:[rangePath.location indexAtPosition:rangePath.location.length-1]];
|
|
||||||
}
|
}
|
||||||
|
[current clearCacheInRange:rangePath.rangeAtLastIndex replacementLength:replacementLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
@property (readonly, nonatomic, strong) MPExpressionStorage *expressionStorage;
|
@property (readonly, nonatomic, strong) MPExpressionStorage *expressionStorage;
|
||||||
- (MPExpressionLayout *)expressionLayout; // Convenience Method
|
|
||||||
|
|
||||||
@property (nonatomic, getter = isEditable) BOOL editable;
|
@property (nonatomic, getter = isEditable) BOOL editable;
|
||||||
@property (nonatomic, strong) MPRangePath *selection;
|
@property (nonatomic, strong) MPRangePath *selection;
|
||||||
|
|||||||
@@ -7,13 +7,15 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPExpressionView.h"
|
#import "MPExpressionView.h"
|
||||||
#import "MPExpressionLayout.h"
|
|
||||||
#import "MPExpressionStorage.h"
|
#import "MPExpressionStorage.h"
|
||||||
|
#import "MPExpressionLayout.h"
|
||||||
#import "NSObject+MPStringTest.h"
|
|
||||||
|
|
||||||
#import "MPSumFunction.h"
|
#import "MPSumFunction.h"
|
||||||
|
|
||||||
|
@interface MPExpressionView (MPCursor)
|
||||||
|
@property (nonatomic, strong) NSTimer *cursorTimer;
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation MPExpressionView
|
@implementation MPExpressionView
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
@@ -47,23 +49,20 @@
|
|||||||
|
|
||||||
- (void)initializeObjects
|
- (void)initializeObjects
|
||||||
{
|
{
|
||||||
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithSymbols:@[@"12 345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]];
|
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithElements:@[@"12345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]];
|
||||||
_expressionStorage = expressionStorage;
|
_expressionStorage = expressionStorage;
|
||||||
[self.expressionLayout setExpressionView:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
- (void)setExpressionStorage:(MPExpressionStorage *)expressionStorage
|
- (BOOL)isFlipped
|
||||||
{
|
{
|
||||||
[_expressionStorage.expressionLayout setExpressionView:nil];
|
return NO;
|
||||||
_expressionStorage = expressionStorage;
|
|
||||||
[_expressionStorage.expressionLayout setExpressionView:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPExpressionLayout *)expressionLayout
|
- (void)setExpressionStorage:(MPExpressionStorage *)expressionStorage
|
||||||
{
|
{
|
||||||
return self.expressionStorage.expressionLayout;
|
_expressionStorage = expressionStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Drawing Methods
|
#pragma mark Drawing Methods
|
||||||
@@ -74,11 +73,10 @@
|
|||||||
[[NSColor whiteColor] set];
|
[[NSColor whiteColor] set];
|
||||||
NSRectFill(self.bounds);
|
NSRectFill(self.bounds);
|
||||||
[[NSColor blackColor] set];
|
[[NSColor blackColor] set];
|
||||||
NSSize expressionSize = [self.expressionLayout sizeForAllSymbols];
|
NSSize expressionSize = [self.expressionStorage.rootLayout size];
|
||||||
CGFloat y = (self.bounds.size.height - expressionSize.height) / 2;
|
CGFloat y = (self.bounds.size.height - expressionSize.height) / 2;
|
||||||
NSLog(@"%f", self.bounds.origin.y);
|
|
||||||
NSPoint point = NSMakePoint(self.bounds.origin.x, self.bounds.origin.y + y);
|
NSPoint point = NSMakePoint(self.bounds.origin.x, self.bounds.origin.y + y);
|
||||||
[self.expressionLayout drawAllSymbolsAtPoint:point];
|
[self.expressionStorage.rootLayout drawAtPoint:point];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,58 +6,47 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@import Foundation;
|
||||||
|
#import "MPExpressionElement.h"
|
||||||
|
|
||||||
@class MPFunction, MPExpression, MPRangePath;
|
@class MPFunction, MPExpression, MPRangePath;
|
||||||
|
|
||||||
@interface MPFunction : NSObject <NSCopying, NSCoding>
|
@interface MPFunction : NSObject <NSCoding, NSCopying, MPExpressionElement>
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
|
||||||
- (instancetype)init;
|
- (instancetype)init;
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
#pragma mark Properties
|
||||||
|
// Subclasses should define accessor properties for all sub expressions, which, in the setter, should send didChangeElementAtRangePath:replacementLength: to self with a replacement length of 1.
|
||||||
|
|
||||||
|
#pragma mark Working With the Expression Tree
|
||||||
@property (nonatomic, weak) MPExpression *parent; // Documentation: Do not set
|
@property (nonatomic, weak) MPExpression *parent; // Documentation: Do not set
|
||||||
|
|
||||||
- (NSUInteger)numberOfChildren;
|
- (NSUInteger)numberOfChildren; // Override
|
||||||
- (MPExpression *)childAtIndex:(NSUInteger)index;
|
- (MPExpression *)childAtIndex:(NSUInteger)index; // Override
|
||||||
- (void)setChild:(MPExpression *)child
|
- (void)setChild:(MPExpression *)child
|
||||||
atIndex:(NSUInteger)index;
|
atIndex:(NSUInteger)index; // Override
|
||||||
|
|
||||||
#pragma mark Evaluating Functions
|
|
||||||
|
|
||||||
- (double)doubleValue;
|
|
||||||
|
|
||||||
#pragma mark Working With Functions
|
|
||||||
|
|
||||||
- (BOOL)isEqualToFunction:(MPFunction *)aFunction;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MPFunction (MPFunctionExtensionMethods)
|
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
|
||||||
|
|
||||||
// May be overridden for performance improvements
|
// May be overridden for performance improvements
|
||||||
- (NSArray *)children;
|
- (NSArray *)children; // Indexes must equal the ones from the native methods
|
||||||
- (NSUInteger)indexOfChild:(MPExpression *)child;
|
- (NSUInteger)indexOfChild:(MPExpression *)child;
|
||||||
|
|
||||||
- (id)symbolAtIndexPath:(NSIndexPath *)indexPath;
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
#pragma mark Evaluating Functions
|
#pragma mark Evaluating Functions
|
||||||
|
- (double)doubleValue; // Override
|
||||||
|
|
||||||
- (float)floatValue;
|
#pragma mark Messages
|
||||||
- (int)intValue;
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
- (NSInteger)integerValue;
|
replacementLength:(NSUInteger)replacementLength;
|
||||||
- (long long)longLongValue;
|
- (void)didChangeChild:(MPExpression *)child;
|
||||||
|
- (void)didChangeChildAtIndex:(NSUInteger)index;
|
||||||
|
|
||||||
- (NSString *)description;
|
#pragma mark Working With Functions
|
||||||
|
- (BOOL)isEqualToFunction:(MPFunction *)aFunction; // Override
|
||||||
|
|
||||||
- (NSUInteger)hash;
|
- (NSString *)description; // Should be overridden
|
||||||
|
- (NSUInteger)hash;// Override
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MPFunction (MPDisplayExtension)
|
|
||||||
|
|
||||||
- (void)symbolsChangedInRangePath:(MPRangePath *)rangePath replacementLength:(NSUInteger)length;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,12 +10,11 @@
|
|||||||
#import "MPExpression.h"
|
#import "MPExpression.h"
|
||||||
#import "MPRangePath.h"
|
#import "MPRangePath.h"
|
||||||
|
|
||||||
#import "NSIndexPath+MPReverseIndexPath.h"
|
#import "NSIndexPath+MPAdditions.h"
|
||||||
|
|
||||||
@implementation MPFunction
|
@implementation MPFunction
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -25,7 +24,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
#pragma mark Working With the Expression Tree
|
||||||
|
|
||||||
- (NSUInteger)numberOfChildren
|
- (NSUInteger)numberOfChildren
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -38,63 +36,10 @@
|
|||||||
|
|
||||||
- (void)setChild:(MPExpression *)child
|
- (void)setChild:(MPExpression *)child
|
||||||
atIndex:(NSUInteger)index
|
atIndex:(NSUInteger)index
|
||||||
{}
|
|
||||||
|
|
||||||
#pragma mark Evaluating Functions
|
|
||||||
|
|
||||||
- (double)doubleValue
|
|
||||||
{
|
{
|
||||||
return 0;
|
[self didChangeChildAtIndex:index];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Working With Functions
|
|
||||||
|
|
||||||
- (BOOL)isEqual:(id)object
|
|
||||||
{
|
|
||||||
if (self == object) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
if (object == nil) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
if (![object isKindOfClass:[MPFunction class]]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
return [self isEqualToFunction:(MPFunction *)object];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isEqualToFunction:(MPFunction *)aFunction
|
|
||||||
{
|
|
||||||
return [aFunction isMemberOfClass:[MPFunction class]] && [self isMemberOfClass:[MPFunction class]];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
|
||||||
|
|
||||||
- (id)copyWithZone:(NSZone *)zone
|
|
||||||
{
|
|
||||||
return [[MPFunction allocWithZone:zone] init];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSCoding
|
|
||||||
|
|
||||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
|
||||||
{}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPFunction (MPFunctionExtensionMethods)
|
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
|
||||||
|
|
||||||
- (NSArray *)children
|
- (NSArray *)children
|
||||||
{
|
{
|
||||||
NSUInteger childCount = [self numberOfChildren];
|
NSUInteger childCount = [self numberOfChildren];
|
||||||
@@ -116,16 +61,115 @@
|
|||||||
return NSNotFound;
|
return NSNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)symbolAtIndexPath:(NSIndexPath *)indexPath
|
- (id)elementAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (indexPath.length == 0) {
|
if (indexPath.length == 0) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
MPExpression *child = [self childAtIndex:[indexPath indexAtPosition:0]];
|
MPExpression *child = [self childAtIndex:[indexPath indexAtPosition:0]];
|
||||||
return [child symbolAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
|
return [child elementAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Evaluating Functions
|
#pragma mark Evaluating Functions
|
||||||
|
- (double)doubleValue
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Notifications
|
||||||
|
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||||
|
replacementLength:(NSUInteger)replacementLength
|
||||||
|
{
|
||||||
|
NSUInteger selfIndex = [self.parent indexOfElement:self];
|
||||||
|
MPRangePath *newPath = rangePath.copy;
|
||||||
|
newPath.location = [newPath.location indexPathByPreceedingIndex:selfIndex];
|
||||||
|
[self.parent didChangeElementsInRangePath:newPath
|
||||||
|
replacementLength:replacementLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didChangeChild:(MPExpression *)child
|
||||||
|
{
|
||||||
|
[self didChangeChildAtIndex:[self indexOfChild:child]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didChangeChildAtIndex:(NSUInteger)index
|
||||||
|
{
|
||||||
|
MPRangePath *path = [[MPRangePath alloc] initWithRange:NSMakeRange(index, 1)];
|
||||||
|
[self didChangeElementsInRangePath:path
|
||||||
|
replacementLength:1];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Working With Functions
|
||||||
|
- (BOOL)isEqual:(id)object
|
||||||
|
{
|
||||||
|
if (self == object) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
if (object == nil) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (![object isKindOfClass:[MPFunction class]]) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return [self isEqualToFunction:(MPFunction *)object];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqualToFunction:(MPFunction *)aFunction
|
||||||
|
{
|
||||||
|
return [aFunction isMemberOfClass:[MPFunction class]] && [self isMemberOfClass:[MPFunction class]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)description
|
||||||
|
{
|
||||||
|
return @"[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSCopying
|
||||||
|
- (id)copyWithZone:(NSZone *)zone
|
||||||
|
{
|
||||||
|
return [[MPFunction allocWithZone:zone] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSCoding
|
||||||
|
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
NSArray *children = [aDecoder decodeObject];
|
||||||
|
NSInteger index = 0;
|
||||||
|
for (MPExpression *child in children) {
|
||||||
|
[self setChild:child atIndex:index];
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:self.children];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - MPExpressionElement
|
||||||
|
- (BOOL)isString
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isFunction
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)length
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
- (float)floatValue
|
- (float)floatValue
|
||||||
{
|
{
|
||||||
@@ -147,26 +191,4 @@
|
|||||||
return (long long)[self doubleValue];
|
return (long long)[self doubleValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description
|
|
||||||
{
|
|
||||||
return @"[]";
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSUInteger)hash
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPFunction (MPDisplayExtension)
|
|
||||||
|
|
||||||
- (void)symbolsChangedInRangePath:(MPRangePath *)rangePath replacementLength:(NSUInteger)length
|
|
||||||
{
|
|
||||||
NSUInteger index = [self.parent indexOfSymbol:self];
|
|
||||||
NSIndexPath *newLocation = [rangePath.location indexPathByPrecedingIndex:index];
|
|
||||||
MPRangePath *newRangePath = [[MPRangePath alloc] initWithLocation:newLocation length:rangePath.length];
|
|
||||||
[self.parent symbolsChangedInRangePath:newRangePath replacementLength:length];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -2,56 +2,30 @@
|
|||||||
// MPFunctionLayout.h
|
// MPFunctionLayout.h
|
||||||
// MathPad
|
// MathPad
|
||||||
//
|
//
|
||||||
// Created by Kim Wittenburg on 22.04.14.
|
// Created by Kim Wittenburg on 07.08.14.
|
||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
@import Cocoa;
|
||||||
|
#import "MPLayout.h"
|
||||||
|
|
||||||
@class MPFunctionLayout, MPExpressionLayout, MPExpressionStorage, MPFunction;
|
@interface MPFunctionLayout : MPLayout
|
||||||
|
|
||||||
@interface MPFunctionLayout : NSObject {
|
+ (MPFunctionLayout *)functionLayoutForFunctionAtIndexPath:(NSIndexPath *)path
|
||||||
@protected
|
|
||||||
BOOL _valid;
|
|
||||||
NSSize _cachedSize;
|
|
||||||
NSMutableArray *_childCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
|
||||||
|
|
||||||
+ (instancetype)functionLayoutForFunctionAtIndexPath:(NSIndexPath *)functionPath
|
|
||||||
parent:(MPExpressionLayout *)parent;
|
parent:(MPExpressionLayout *)parent;
|
||||||
|
|
||||||
- (id)initWithFunctionPath:(NSIndexPath *)functionPath
|
@property (readonly, nonatomic, weak) MPFunction *function; // Convenience
|
||||||
parent:(MPExpressionLayout *)parent;
|
|
||||||
|
@end
|
||||||
#pragma mark Properties
|
|
||||||
|
@interface MPFunctionLayout (MPSubclassOverride)
|
||||||
@property (readonly, nonatomic, weak) MPExpressionLayout *parent;
|
|
||||||
|
// Should also implement accessor method for special function type:
|
||||||
@property (readonly, nonatomic, strong) NSIndexPath *functionPath;
|
// - (MPCustomFunction *)customFunction
|
||||||
|
// {
|
||||||
- (MPExpressionStorage *)expressionStorage;
|
// return (MPCustomFunction *)self.function;
|
||||||
- (MPFunction *)function; // Convenience
|
// }
|
||||||
- (NSLayoutManager *)layoutManager;
|
|
||||||
- (NSTextContainer *)textContainer;
|
- (NSBezierPath *)generateBezierPath;
|
||||||
- (NSTextStorage *)textStorage;
|
|
||||||
|
|
||||||
#pragma mark Cache Methods
|
|
||||||
|
|
||||||
- (void)invalidate;
|
|
||||||
- (void)editedChildAtIndex:(NSUInteger)index;
|
|
||||||
|
|
||||||
- (BOOL)hasCacheForChildAtIndex:(NSUInteger)index;
|
|
||||||
- (MPExpressionLayout *)expressionLayoutForChildAtIndex:(NSUInteger)index;
|
|
||||||
|
|
||||||
#pragma mark Size Calculation Methods
|
|
||||||
|
|
||||||
- (NSSize)sizeOfFunction;
|
|
||||||
- (NSSize)calculateSize;
|
|
||||||
|
|
||||||
#pragma mark Drawing Methods
|
|
||||||
|
|
||||||
- (void)drawFunctionAtPoint:(NSPoint)point;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -2,14 +2,13 @@
|
|||||||
// MPFunctionLayout.m
|
// MPFunctionLayout.m
|
||||||
// MathPad
|
// MathPad
|
||||||
//
|
//
|
||||||
// Created by Kim Wittenburg on 22.04.14.
|
// Created by Kim Wittenburg on 07.08.14.
|
||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "MPFunctionLayout.h"
|
#import "MPFunctionLayout.h"
|
||||||
#import "MPExpressionLayout.h"
|
|
||||||
#import "MPExpressionStorage.h"
|
|
||||||
#import "MPFunction.h"
|
#import "MPFunction.h"
|
||||||
|
#import "MPExpressionLayout.h"
|
||||||
|
|
||||||
#import "MPSumFunction.h"
|
#import "MPSumFunction.h"
|
||||||
#import "MPSumFunctionLayout.h"
|
#import "MPSumFunctionLayout.h"
|
||||||
@@ -17,114 +16,43 @@
|
|||||||
@implementation MPFunctionLayout
|
@implementation MPFunctionLayout
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
+ (MPFunctionLayout *)functionLayoutForFunctionAtIndexPath:(NSIndexPath *)path
|
||||||
+ (instancetype)functionLayoutForFunctionAtIndexPath:(NSIndexPath *)functionPath
|
|
||||||
parent:(MPExpressionLayout *)parent
|
parent:(MPExpressionLayout *)parent
|
||||||
{
|
{
|
||||||
MPFunction *function = [parent.expressionStorage symbolAtIndexPath:functionPath];
|
MPFunction *function = [parent.expressionStorage elementAtIndexPath:path];
|
||||||
Class class = [function class];
|
Class class = [function class];
|
||||||
if (class == [MPSumFunction class]) {
|
if (class == [MPSumFunction class]) {
|
||||||
return [[MPSumFunctionLayout alloc] initWithFunctionPath:functionPath parent:parent];
|
return [[MPSumFunctionLayout alloc] initWithPath:path parent:parent];
|
||||||
}
|
}
|
||||||
return nil;
|
return [[self alloc] initWithPath:path parent:parent];
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFunctionPath:(NSIndexPath *)functionPath
|
|
||||||
parent:(MPExpressionLayout *)parent
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
_functionPath = functionPath;
|
|
||||||
_parent = parent;
|
|
||||||
_childCache = [[NSMutableArray alloc] init];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
- (MPExpressionStorage *)expressionStorage
|
|
||||||
{
|
|
||||||
return self.parent.expressionStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPFunction *)function
|
- (MPFunction *)function
|
||||||
{
|
{
|
||||||
return [self.expressionStorage symbolAtIndexPath:self.functionPath];
|
return [self.expressionStorage elementAtIndexPath:self.path];
|
||||||
}
|
|
||||||
|
|
||||||
- (NSLayoutManager *)layoutManager
|
|
||||||
{
|
|
||||||
return self.expressionStorage.layoutManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSTextContainer *)textContainer
|
|
||||||
{
|
|
||||||
return self.expressionStorage.textContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSTextStorage *)textStorage
|
|
||||||
{
|
|
||||||
return self.expressionStorage.textStorage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Cache Methods
|
#pragma mark Cache Methods
|
||||||
|
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
|
||||||
- (void)invalidate
|
|
||||||
{
|
{
|
||||||
_valid = NO;
|
return [self cachableObjectForIndex:index generator:^id{
|
||||||
[self.parent invalidate];
|
NSIndexPath *childPath = [self.path indexPathByAddingIndex:index];
|
||||||
|
MPExpressionLayout *layout = [[MPExpressionLayout alloc] initWithPath:childPath
|
||||||
|
parent:self];
|
||||||
|
return layout;
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)editedChildAtIndex:(NSUInteger)index
|
- (NSSize)sizeForChildAtIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
if ([self hasCacheForChildAtIndex:index]) {
|
MPLayout *childLayout = [self childLayoutAtIndex:index];
|
||||||
_childCache[index] = [NSNull null];
|
return [childLayout size];
|
||||||
}
|
|
||||||
[self invalidate];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)hasCacheForChildAtIndex:(NSUInteger)index
|
- (NSBezierPath *)generateBezierPath
|
||||||
{
|
|
||||||
if (index >= _childCache.count) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
return _childCache[index] != [NSNull null];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPExpressionLayout *)expressionLayoutForChildAtIndex:(NSUInteger)index
|
|
||||||
{
|
|
||||||
if ([self hasCacheForChildAtIndex:index]) {
|
|
||||||
return _childCache[index];
|
|
||||||
}
|
|
||||||
while (index >= _childCache.count) {
|
|
||||||
[_childCache addObject:[NSNull null]];
|
|
||||||
}
|
|
||||||
MPExpressionLayout *expressionLayout = [[MPExpressionLayout alloc] initWithExpressionPath:[self.functionPath indexPathByAddingIndex:index] parent:self];
|
|
||||||
_childCache[index] = expressionLayout;
|
|
||||||
return expressionLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Size Calculation Methods
|
|
||||||
|
|
||||||
- (NSSize)sizeOfFunction
|
|
||||||
{
|
|
||||||
if (!_valid) {
|
|
||||||
_cachedSize = [self calculateSize];
|
|
||||||
_valid = YES;
|
|
||||||
}
|
|
||||||
return _cachedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)calculateSize
|
|
||||||
{
|
|
||||||
return NSMakeSize(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Drawing Methods
|
|
||||||
|
|
||||||
- (void)drawFunctionAtPoint:(NSPoint)point
|
|
||||||
{
|
{
|
||||||
|
return [NSBezierPath bezierPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
56
MathPad/MPLayout.h
Normal file
56
MathPad/MPLayout.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// MPDrawable.h
|
||||||
|
// MathPad
|
||||||
|
//
|
||||||
|
// Created by Kim Wittenburg on 07.08.14.
|
||||||
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@import Cocoa;
|
||||||
|
#import "MPExpressionStorage.h"
|
||||||
|
|
||||||
|
#define MPNull [NSNull null]
|
||||||
|
|
||||||
|
@interface MPLayout : NSObject
|
||||||
|
|
||||||
|
#pragma mark Creation Methods
|
||||||
|
- (instancetype)init;
|
||||||
|
- (instancetype)initWithPath:(NSIndexPath *)path
|
||||||
|
parent:(MPLayout *)parent;
|
||||||
|
|
||||||
|
#pragma mark Text System Objects
|
||||||
|
@property (readonly, nonatomic, weak) MPExpressionStorage *expressionStorage;
|
||||||
|
@property (readonly, nonatomic, weak) NSLayoutManager *layoutManager;
|
||||||
|
@property (readonly, nonatomic, weak) NSTextContainer *textContainer;
|
||||||
|
@property (readonly, nonatomic, weak) NSTextStorage *textStorage;
|
||||||
|
|
||||||
|
#pragma mark Cache Tree
|
||||||
|
@property (readonly, nonatomic, weak) MPLayout *parent;
|
||||||
|
@property (readonly, nonatomic, strong) NSIndexPath *path;
|
||||||
|
|
||||||
|
#pragma mark Cache Methods
|
||||||
|
// Querying Caches
|
||||||
|
- (id)cachableObjectForIndex:(NSUInteger)index
|
||||||
|
generator:(id(^)())generator;
|
||||||
|
|
||||||
|
// Clearing Caches
|
||||||
|
- (void)clearCacheInRange:(NSRange)range
|
||||||
|
replacementLength:(NSUInteger)replacementLength;
|
||||||
|
- (void)invalidate;
|
||||||
|
|
||||||
|
#pragma mark Calculation and Drawing Methods
|
||||||
|
// @property (nonatomic) BOOL usesSmallSize;
|
||||||
|
- (NSSize)size;
|
||||||
|
|
||||||
|
- (NSBezierPath *)bezierPath;
|
||||||
|
- (NSBezierPath *)bezierPathAtOrigin:(NSPoint)point;
|
||||||
|
|
||||||
|
- (void)drawAtPoint:(NSPoint)point;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MPLayout (MPSubclassImplement)
|
||||||
|
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index; // To be implemented
|
||||||
|
- (NSSize)sizeForChildAtIndex:(NSUInteger)index; // To be implemented
|
||||||
|
- (NSBezierPath *)generateBezierPath; // To be implemented
|
||||||
|
@end
|
||||||
159
MathPad/MPLayout.m
Normal file
159
MathPad/MPLayout.m
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
//
|
||||||
|
// MPLayout.m
|
||||||
|
// MathPad
|
||||||
|
//
|
||||||
|
// Created by Kim Wittenburg on 11.08.14.
|
||||||
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPLayout.h"
|
||||||
|
|
||||||
|
@interface MPLayout ()
|
||||||
|
|
||||||
|
// Querying Caches
|
||||||
|
- (BOOL)hasCacheForElementAtIndex:(NSUInteger)index;
|
||||||
|
|
||||||
|
// Storing Caches
|
||||||
|
- (void)cacheObject:(id)anObject
|
||||||
|
forElementAtIndex:(NSUInteger)index;
|
||||||
|
- (void)ensureCacheSizeForIndex:(NSUInteger)index;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPLayout {
|
||||||
|
NSMutableArray *_cache;
|
||||||
|
NSBezierPath *_cachedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Creation Methods
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_cache = [[NSMutableArray alloc] init];
|
||||||
|
_cachedPath = nil;
|
||||||
|
_path = [[NSIndexPath alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithPath:(NSIndexPath *)path
|
||||||
|
parent:(MPLayout *)parent
|
||||||
|
{
|
||||||
|
self = [self init];
|
||||||
|
if (self) {
|
||||||
|
_path = path;
|
||||||
|
_parent = parent;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma Text System Objects
|
||||||
|
- (MPExpressionStorage *)expressionStorage
|
||||||
|
{
|
||||||
|
return self.parent.expressionStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSLayoutManager *)layoutManager
|
||||||
|
{
|
||||||
|
return self.expressionStorage.layoutManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSTextContainer *)textContainer
|
||||||
|
{
|
||||||
|
return self.expressionStorage.textContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSTextStorage *)textStorage
|
||||||
|
{
|
||||||
|
return self.expressionStorage.textStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Cache Tree
|
||||||
|
// Querying Caches
|
||||||
|
- (BOOL)hasCacheForElementAtIndex:(NSUInteger)index
|
||||||
|
{
|
||||||
|
if (index >= _cache.count) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return _cache[index] != MPNull;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)cachableObjectForIndex:(NSUInteger)index
|
||||||
|
generator:(id (^)())generator
|
||||||
|
{
|
||||||
|
if ([self hasCacheForElementAtIndex:index]) {
|
||||||
|
return _cache[index];
|
||||||
|
}
|
||||||
|
id object = generator();
|
||||||
|
[self cacheObject:object
|
||||||
|
forElementAtIndex:index];
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storing Caches
|
||||||
|
- (void)cacheObject:(id)anObject
|
||||||
|
forElementAtIndex:(NSUInteger)index
|
||||||
|
{
|
||||||
|
[self ensureCacheSizeForIndex:index];
|
||||||
|
_cache[index] = anObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)ensureCacheSizeForIndex:(NSUInteger)index
|
||||||
|
{
|
||||||
|
while (index >= _cache.count) {
|
||||||
|
[_cache addObject:MPNull];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clearing Caches
|
||||||
|
- (void)clearCacheInRange:(NSRange)range
|
||||||
|
replacementLength:(NSUInteger)replacementLength
|
||||||
|
{
|
||||||
|
NSMutableArray *placeholders = [[NSMutableArray alloc] initWithCapacity:replacementLength];
|
||||||
|
while (placeholders.count < replacementLength) {
|
||||||
|
[placeholders addObject:MPNull];
|
||||||
|
}
|
||||||
|
[_cache replaceObjectsInRange:range
|
||||||
|
withObjectsFromArray:placeholders];
|
||||||
|
[self invalidate];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)invalidate
|
||||||
|
{
|
||||||
|
_cachedPath = nil;
|
||||||
|
[self.parent invalidate];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Calculation Methods
|
||||||
|
- (NSSize)size
|
||||||
|
{
|
||||||
|
return self.bezierPath.bounds.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSBezierPath *)bezierPath
|
||||||
|
{
|
||||||
|
if (!_cachedPath) {
|
||||||
|
_cachedPath = [self generateBezierPath];
|
||||||
|
}
|
||||||
|
return _cachedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSBezierPath *)bezierPathAtOrigin:(NSPoint)point
|
||||||
|
{
|
||||||
|
NSAffineTransform *transform = [NSAffineTransform transform];
|
||||||
|
[transform translateXBy:point.x
|
||||||
|
yBy:point.y];
|
||||||
|
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||||
|
[path appendBezierPath:self.bezierPath];
|
||||||
|
[path transformUsingAffineTransform:transform];
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawAtPoint:(NSPoint)point
|
||||||
|
{
|
||||||
|
NSBezierPath *path = [self bezierPathAtOrigin:point];
|
||||||
|
[path fill];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -18,8 +18,6 @@
|
|||||||
#import "MPFunction.h"
|
#import "MPFunction.h"
|
||||||
#import "MPRangePath.h"
|
#import "MPRangePath.h"
|
||||||
|
|
||||||
#import "NSObject+MPStringTest.h"
|
#import "NSIndexPath+MPAdditions.h"
|
||||||
#import "NSTextStorage+MPSetContents.h"
|
|
||||||
#import "NSIndexPath+MPReverseIndexPath.h"
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,8 +6,12 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@import Foundation;
|
||||||
|
|
||||||
#import "MPExpression.h"
|
#import "MPExpression.h"
|
||||||
|
|
||||||
|
@class MPRangePath, MPExpression;
|
||||||
|
|
||||||
@interface MPRangePath : NSObject <NSCopying, NSCoding>
|
@interface MPRangePath : NSObject <NSCopying, NSCoding>
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPRangePath.h"
|
#import "MPRangePath.h"
|
||||||
|
#import "MPExpression.h"
|
||||||
|
|
||||||
@implementation MPRangePath
|
@implementation MPRangePath
|
||||||
|
|
||||||
@@ -143,7 +144,7 @@
|
|||||||
|
|
||||||
- (MPExpression *)subexpressionWithRangePath:(MPRangePath *)aRangePath
|
- (MPExpression *)subexpressionWithRangePath:(MPRangePath *)aRangePath
|
||||||
{
|
{
|
||||||
MPExpression *targetExpression = [self symbolAtIndexPath:[aRangePath.location indexPathByRemovingLastIndex]];
|
MPExpression *targetExpression = [self elementAtIndexPath:[aRangePath.location indexPathByRemovingLastIndex]];
|
||||||
if (![targetExpression isKindOfClass:[MPExpression class]]) {
|
if (![targetExpression isKindOfClass:[MPExpression class]]) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@import Foundation;
|
||||||
#import "MPFunction.h"
|
#import "MPFunction.h"
|
||||||
|
|
||||||
@class MPSumFunction, MPExpression;
|
@class MPSumFunction, MPExpression;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
@implementation MPSumFunction
|
@implementation MPSumFunction
|
||||||
|
|
||||||
#pragma mark Creation Methods
|
#pragma mark Creation Methods
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -27,8 +26,32 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Working With the Expression Tree
|
#pragma mark Properties
|
||||||
|
- (void)setStartExpression:(MPExpression *)startExpression
|
||||||
|
{
|
||||||
|
_startExpression.parent = nil;
|
||||||
|
_startExpression = startExpression;
|
||||||
|
_startExpression.parent = self;
|
||||||
|
[self didChangeChildAtIndex:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTargetExpression:(MPExpression *)targetExpression
|
||||||
|
{
|
||||||
|
_targetExpression.parent = nil;
|
||||||
|
_targetExpression = targetExpression;
|
||||||
|
_targetExpression.parent = self;
|
||||||
|
[self didChangeChildAtIndex:1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSumExpression:(MPExpression *)sumExpression
|
||||||
|
{
|
||||||
|
_sumExpression.parent = nil;
|
||||||
|
_sumExpression = sumExpression;
|
||||||
|
_sumExpression.parent = self;
|
||||||
|
[self didChangeChildAtIndex:2];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Working With the Expression Tree
|
||||||
- (NSUInteger)numberOfChildren
|
- (NSUInteger)numberOfChildren
|
||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
@@ -48,36 +71,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)children
|
|
||||||
{
|
|
||||||
return @[self.startExpression, self.targetExpression, self.sumExpression];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setChild:(MPExpression *)child
|
- (void)setChild:(MPExpression *)child
|
||||||
atIndex:(NSUInteger)index
|
atIndex:(NSUInteger)index
|
||||||
{
|
{
|
||||||
switch (index) {
|
switch (index) {
|
||||||
// TODO: Copy child?
|
// TODO: Copy child?
|
||||||
case 0:
|
case 0:
|
||||||
self.startExpression.parent = nil;
|
|
||||||
self.startExpression = child;
|
self.startExpression = child;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
self.targetExpression.parent = nil;
|
|
||||||
self.targetExpression = child;
|
self.targetExpression = child;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
self.sumExpression.parent = nil;
|
|
||||||
self.sumExpression = child;
|
self.sumExpression = child;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
child.parent = self;
|
[self didChangeChildAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)children
|
||||||
|
{
|
||||||
|
return @[self.startExpression, self.targetExpression, self.sumExpression];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Evaluating Functions
|
#pragma mark Evaluating Functions
|
||||||
|
|
||||||
- (double)doubleValue
|
- (double)doubleValue
|
||||||
{
|
{
|
||||||
#warning Implementation
|
#warning Implementation
|
||||||
@@ -85,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Working With Functions
|
#pragma mark Working With Functions
|
||||||
|
|
||||||
- (BOOL)isEqualToFunction:(MPFunction *)aFunction
|
- (BOOL)isEqualToFunction:(MPFunction *)aFunction
|
||||||
{
|
{
|
||||||
if (![aFunction isKindOfClass:[MPSumFunction class]]) {
|
if (![aFunction isKindOfClass:[MPSumFunction class]]) {
|
||||||
@@ -106,8 +124,13 @@
|
|||||||
return [NSString stringWithFormat:@"Sum(From: %@; To: %@; Using: %@)", self.startExpression, self.targetExpression, self.sumExpression];
|
return [NSString stringWithFormat:@"Sum(From: %@; To: %@; Using: %@)", self.startExpression, self.targetExpression, self.sumExpression];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
- (NSUInteger)hash
|
||||||
|
{
|
||||||
|
#warning Unimplemented Method
|
||||||
|
return [super hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSCopying
|
||||||
- (id)copyWithZone:(NSZone *)zone
|
- (id)copyWithZone:(NSZone *)zone
|
||||||
{
|
{
|
||||||
MPSumFunction *copy = [[MPSumFunction allocWithZone:zone] init];
|
MPSumFunction *copy = [[MPSumFunction allocWithZone:zone] init];
|
||||||
|
|||||||
@@ -16,20 +16,21 @@
|
|||||||
return (MPSumFunction *)self.function;
|
return (MPSumFunction *)self.function;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSSize)calculateSize
|
- (NSBezierPath *)generateBezierPath
|
||||||
{
|
{
|
||||||
NSAttributedString *text = [[NSAttributedString alloc] initWithString:@"∑" attributes:@{NSFontAttributeName: [NSFont fontWithName:@"HelveticaNeue" size:50.0]}];
|
NSAttributedString *text = [[NSAttributedString alloc] initWithString:@"∑"
|
||||||
[self.textStorage setAttributedString:text];
|
attributes:@{NSFontAttributeName: [NSFont fontWithName:@"Lucida Grande" size:18.0]}];
|
||||||
|
self.textStorage.attributedString = text;
|
||||||
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
|
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
|
||||||
return [self.layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:self.textContainer].size;
|
NSGlyph glyphs[glyphRange.length+1];
|
||||||
}
|
NSUInteger actualGylphCount = [self.layoutManager getGlyphs:glyphs
|
||||||
|
range:glyphRange];
|
||||||
- (void)drawFunctionAtPoint:(NSPoint)point
|
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||||
{
|
[path moveToPoint:NSZeroPoint];
|
||||||
NSAttributedString *text = [[NSAttributedString alloc] initWithString:@"∑" attributes:@{NSFontAttributeName: [NSFont fontWithName:@"HelveticaNeue" size:50.0]}];
|
[path appendBezierPathWithGlyphs:glyphs
|
||||||
[self.textStorage setAttributedString:text];
|
count:actualGylphCount
|
||||||
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
|
inFont:[NSFont fontWithName:@"Lucida Grande" size:18.0]];
|
||||||
[self.layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:point];
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
30
MathPad/NSIndexPath+MPAdditions.h
Normal file
30
MathPad/NSIndexPath+MPAdditions.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// NSIndexPath+MPRemoveFirstIndex.h
|
||||||
|
// MathPad
|
||||||
|
//
|
||||||
|
// Created by Kim Wittenburg on 23.04.14.
|
||||||
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@import Foundation;
|
||||||
|
|
||||||
|
@interface NSIndexPath (MPAdditions)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@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 A new index path with the receiving index path’s indexes, excluding the first one.
|
||||||
|
*/
|
||||||
|
- (NSIndexPath *)indexPathByRemovingFirstIndex;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@method indexPathByPreceedingIndex:
|
||||||
|
@brief Provides an index path with the given index followed by the indexes of the receiver.
|
||||||
|
@discussion If the receiver does not contain any indexes the given index is the only index contained in the returned index path.
|
||||||
|
@param index The index new index preceeding all others
|
||||||
|
@return A new index path with all the receiver's indexes preceeded by @c index.
|
||||||
|
*/
|
||||||
|
- (NSIndexPath *)indexPathByPreceedingIndex:(NSUInteger)index;
|
||||||
|
|
||||||
|
@end
|
||||||
37
MathPad/NSIndexPath+MPAdditions.m
Normal file
37
MathPad/NSIndexPath+MPAdditions.m
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// NSIndexPath+MPRemoveFirstIndex.m
|
||||||
|
// MathPad
|
||||||
|
//
|
||||||
|
// Created by Kim Wittenburg on 23.04.14.
|
||||||
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NSIndexPath+MPAdditions.h"
|
||||||
|
|
||||||
|
@implementation NSIndexPath (MPAdditions)
|
||||||
|
|
||||||
|
- (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 *)indexPathByPreceedingIndex:(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
|
||||||
14
MathPad/NSString+MPExpressionElement.h
Normal file
14
MathPad/NSString+MPExpressionElement.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// NSString+MPExpressionElement.h
|
||||||
|
// MathPad
|
||||||
|
//
|
||||||
|
// Created by Kim Wittenburg on 10.08.14.
|
||||||
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@import Foundation;
|
||||||
|
#import "MPExpressionElement.h"
|
||||||
|
|
||||||
|
@interface NSString (MPExpressionElement) <MPExpressionElement>
|
||||||
|
|
||||||
|
@end
|
||||||
49
MathPad/NSString+MPExpressionElement.m
Normal file
49
MathPad/NSString+MPExpressionElement.m
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// NSString+MPExpressionElement.m
|
||||||
|
// MathPad
|
||||||
|
//
|
||||||
|
// Created by Kim Wittenburg on 10.08.14.
|
||||||
|
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NSString+MPExpressionElement.h"
|
||||||
|
|
||||||
|
@implementation NSString (MPExpressionElement)
|
||||||
|
|
||||||
|
- (BOOL)isString
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isFunction
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (double)doubleValue
|
||||||
|
{
|
||||||
|
#warning Unimplemented Method
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)floatValue
|
||||||
|
{
|
||||||
|
return (float)[self doubleValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)intValue
|
||||||
|
{
|
||||||
|
return (int)[self doubleValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)integerValue
|
||||||
|
{
|
||||||
|
return (NSInteger)[self doubleValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (long long)longLongValue
|
||||||
|
{
|
||||||
|
return (long long)[self doubleValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -20,119 +20,119 @@
|
|||||||
- (void)testInitialization {
|
- (void)testInitialization {
|
||||||
// Test empty expression
|
// Test empty expression
|
||||||
MPExpression *testExpression = [[MPExpression alloc] init];
|
MPExpression *testExpression = [[MPExpression alloc] init];
|
||||||
XCTAssertEqual([testExpression numberOfSymbols], 0);
|
XCTAssertEqual(testExpression.numberOfElements, 0);
|
||||||
|
|
||||||
// Test expression with string
|
// Test expression with string
|
||||||
testExpression = [[MPExpression alloc] initWithString:@"1234+5678"];
|
testExpression = [[MPExpression alloc] initWithElement:@"1234+5678"];
|
||||||
XCTAssertEqual([testExpression numberOfSymbols], 1);
|
XCTAssertEqual(testExpression.numberOfElements, 1);
|
||||||
XCTAssertEqualObjects([testExpression symbolAtIndex:0], @"1234+5678");
|
XCTAssertEqualObjects([testExpression elementAtIndex:0], @"1234+5678");
|
||||||
|
|
||||||
// Test expression with function
|
// Test expression with function
|
||||||
testExpression = [[MPExpression alloc] initWithFunction:[[MPFunction alloc] init]];
|
testExpression = [[MPExpression alloc] initWithElement:[[MPFunction alloc] init]];
|
||||||
XCTAssertEqual([testExpression numberOfSymbols], 1);
|
XCTAssertEqual([testExpression numberOfElements], 1);
|
||||||
XCTAssertEqualObjects([testExpression symbolAtIndex:0], [[MPFunction alloc] init]);
|
XCTAssertEqualObjects([testExpression elementAtIndex:0], [[MPFunction alloc] init]);
|
||||||
|
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[@"1234", [[MPFunction alloc] init], @"17", [[MPFunction alloc] init]]];
|
testExpression = [[MPExpression alloc] initWithElements:@[@"1234", [[MPFunction alloc] init], @"17", [[MPFunction alloc] init]]];
|
||||||
XCTAssertEqual([testExpression numberOfSymbols], 4);
|
XCTAssertEqual([testExpression numberOfElements], 4);
|
||||||
XCTAssertEqualObjects([testExpression symbolAtIndex:2], @"17");
|
XCTAssertEqualObjects([testExpression elementAtIndex:2], @"17");
|
||||||
|
|
||||||
// Test expression with subsequent strings
|
// Test expression with subsequent strings
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[@"1234", @"5678"]];
|
testExpression = [[MPExpression alloc] initWithElements:@[@"1234", @"5678"]];
|
||||||
XCTAssertEqual([testExpression numberOfSymbols], 1);
|
XCTAssertEqual([testExpression numberOfElements], 1);
|
||||||
XCTAssertEqualObjects([testExpression symbolAtIndex:0], @"12345678");
|
XCTAssertEqualObjects([testExpression elementAtIndex:0], @"12345678");
|
||||||
|
|
||||||
// Test expression with only empty string
|
// Test expression with only empty string
|
||||||
testExpression = [[MPExpression alloc] initWithString:@""];
|
testExpression = [[MPExpression alloc] initWithElement:@""];
|
||||||
XCTAssertEqual([testExpression numberOfSymbols], 0);
|
XCTAssertEqual([testExpression numberOfElements], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testSubexpressions {
|
- (void)testSubexpressions {
|
||||||
MPExpression *testExpression = [MPExpression expressionWithSymbols:@[@"1234", [[MPFunction alloc] init], @"17", [[MPFunction alloc] init]]];
|
MPExpression *testExpression = [[MPExpression alloc] initWithElements:@[@"1234", [[MPFunction alloc] init], @"17", [[MPFunction alloc] init]]];
|
||||||
|
|
||||||
/********** subexpressionFromIndex: **********/
|
/********** subexpressionFromIndex: **********/
|
||||||
// Test with start index at front
|
// Test with start index at front
|
||||||
MPExpression *subexpression = [testExpression subexpressionFromIndex:0];
|
MPExpression *subexpression = [testExpression subexpressionFromLocation:0];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 4);
|
XCTAssertEqual([subexpression numberOfElements], 4);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], @"1234");
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], @"1234");
|
||||||
|
|
||||||
// Test with start index in first symbol
|
// Test with start index in first element
|
||||||
subexpression = [testExpression subexpressionFromIndex:2];
|
subexpression = [testExpression subexpressionFromLocation:2];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 4);
|
XCTAssertEqual([subexpression numberOfElements], 4);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], @"34");
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], @"34");
|
||||||
|
|
||||||
// Test with start index in middle symbol starting with a literal
|
// Test with start index in middle element starting with a literal
|
||||||
subexpression = [testExpression subexpressionFromIndex:6];
|
subexpression = [testExpression subexpressionFromLocation:6];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 2);
|
XCTAssertEqual([subexpression numberOfElements], 2);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], @"7");
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], @"7");
|
||||||
|
|
||||||
// Test with start index in middle symbol starting with a function
|
// Test with start index in middle element starting with a function
|
||||||
subexpression = [testExpression subexpressionFromIndex:4];
|
subexpression = [testExpression subexpressionFromLocation:4];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 3);
|
XCTAssertEqual([subexpression numberOfElements], 3);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], [[MPFunction alloc] init]);
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], [[MPFunction alloc] init]);
|
||||||
|
|
||||||
// Test with start index in last symbol
|
// Test with start index in last element
|
||||||
subexpression = [testExpression subexpressionFromIndex:7];
|
subexpression = [testExpression subexpressionFromLocation:7];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 1);
|
XCTAssertEqual([subexpression numberOfElements], 1);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], [[MPFunction alloc] init]);
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], [[MPFunction alloc] init]);
|
||||||
|
|
||||||
// Test with start index at end
|
// Test with start index at end
|
||||||
subexpression = [testExpression subexpressionFromIndex:8];
|
subexpression = [testExpression subexpressionFromLocation:8];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 0);
|
XCTAssertEqual([subexpression numberOfElements], 0);
|
||||||
|
|
||||||
/********** subexpressionToIndex: **********/
|
/********** subexpressionToIndex: **********/
|
||||||
// Test with end index at front
|
// Test with end index at front
|
||||||
subexpression = [testExpression subexpressionToIndex:0];
|
subexpression = [testExpression subexpressionToLocation:0];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 0);
|
XCTAssertEqual([subexpression numberOfElements], 0);
|
||||||
|
|
||||||
// Test with end index in first symbol
|
// Test with end index in first Element
|
||||||
subexpression = [testExpression subexpressionToIndex:2];
|
subexpression = [testExpression subexpressionToLocation:2];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 1);
|
XCTAssertEqual([subexpression numberOfElements], 1);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], @"12");
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], @"12");
|
||||||
|
|
||||||
// Test with end index in middle symbol ending with a literal
|
// Test with end index in middle Element ending with a literal
|
||||||
subexpression = [testExpression subexpressionToIndex:6];
|
subexpression = [testExpression subexpressionToLocation:6];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 3);
|
XCTAssertEqual([subexpression numberOfElements], 3);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:2], @"1");
|
XCTAssertEqualObjects([subexpression elementAtIndex:2], @"1");
|
||||||
|
|
||||||
// Test with end index in middle symbol ending with a function
|
// Test with end index in middle Element ending with a function
|
||||||
subexpression = [testExpression subexpressionToIndex:5];
|
subexpression = [testExpression subexpressionToLocation:5];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 2);
|
XCTAssertEqual([subexpression numberOfElements], 2);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:1], [[MPFunction alloc] init]);
|
XCTAssertEqualObjects([subexpression elementAtIndex:1], [[MPFunction alloc] init]);
|
||||||
|
|
||||||
// Test with end index at end
|
// Test with end index at end
|
||||||
subexpression = [testExpression subexpressionToIndex:8];
|
subexpression = [testExpression subexpressionToLocation:8];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 4);
|
XCTAssertEqual([subexpression numberOfElements], 4);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:3], [[MPFunction alloc] init]);
|
XCTAssertEqualObjects([subexpression elementAtIndex:3], [[MPFunction alloc] init]);
|
||||||
|
|
||||||
/********** subexpressionWithRange: **********/
|
/********** subexpressionWithRange: **********/
|
||||||
// Test with empty range
|
// Test with empty range
|
||||||
subexpression = [testExpression subexpressionWithRange:NSMakeRange(4, 0)];
|
subexpression = [testExpression subexpressionWithRange:NSMakeRange(4, 0)];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 0);
|
XCTAssertEqual([subexpression numberOfElements], 0);
|
||||||
|
|
||||||
// Test with start and end in first symbol
|
// Test with start and end in first element
|
||||||
subexpression = [testExpression subexpressionWithRange:NSMakeRange(1, 2)];
|
subexpression = [testExpression subexpressionWithRange:NSMakeRange(1, 2)];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 1);
|
XCTAssertEqual([subexpression numberOfElements], 1);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], @"23");
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], @"23");
|
||||||
|
|
||||||
// Test with start in first and end in middle after function
|
// Test with start in first and end in middle after function
|
||||||
subexpression = [testExpression subexpressionWithRange:NSMakeRange(2, 3)];
|
subexpression = [testExpression subexpressionWithRange:NSMakeRange(2, 3)];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 2);
|
XCTAssertEqual([subexpression numberOfElements], 2);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], @"34");
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], @"34");
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:1], [[MPFunction alloc] init]);
|
XCTAssertEqualObjects([subexpression elementAtIndex:1], [[MPFunction alloc] init]);
|
||||||
|
|
||||||
// Test with start in first and end in middle after literal
|
// Test with start in first and end in middle after literal
|
||||||
subexpression = [testExpression subexpressionWithRange:NSMakeRange(2, 4)];
|
subexpression = [testExpression subexpressionWithRange:NSMakeRange(2, 4)];
|
||||||
XCTAssertEqual([subexpression numberOfSymbols], 3);
|
XCTAssertEqual([subexpression numberOfElements], 3);
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:0], @"34");
|
XCTAssertEqualObjects([subexpression elementAtIndex:0], @"34");
|
||||||
XCTAssertEqualObjects([subexpression symbolAtIndex:2], @"1");
|
XCTAssertEqualObjects([subexpression elementAtIndex:2], @"1");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testSubexpressionsIllegalRange {
|
- (void)testSubexpressionsIllegalRange {
|
||||||
MPExpression *testExpression = [MPExpression expressionWithSymbols:@[@"1234", [[MPFunction alloc] init], @"17", [[MPFunction alloc] init]]];
|
MPExpression *testExpression = [[MPExpression alloc] initWithElements:@[@"1234", [[MPFunction alloc] init], @"17", [[MPFunction alloc] init]]];
|
||||||
|
|
||||||
// Test with start index beyond end
|
// Test with start index beyond end
|
||||||
@try {
|
@try {
|
||||||
[testExpression subexpressionFromIndex:10];
|
[testExpression subexpressionFromLocation:10];
|
||||||
XCTFail(@"Should have raised an exception.");
|
XCTFail(@"Should have raised an exception.");
|
||||||
}
|
}
|
||||||
@catch (NSException *exception) {}
|
@catch (NSException *exception) {}
|
||||||
@@ -146,11 +146,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)testEqualExpressions {
|
- (void)testEqualExpressions {
|
||||||
MPExpression *expression1 = [[MPExpression alloc] initWithString:@"123"];
|
MPExpression *expression1 = [[MPExpression alloc] initWithElement:@"123"];
|
||||||
MPExpression *expression2 = [[MPExpression alloc] initWithString:@"1234"];
|
MPExpression *expression2 = [[MPExpression alloc] initWithElement:@"1234"];
|
||||||
MPExpression *expression3 = [[MPExpression alloc] initWithFunction:[[MPFunction alloc] init]];
|
MPExpression *expression3 = [[MPExpression alloc] initWithElement:[[MPFunction alloc] init]];
|
||||||
MPExpression *expression4 = [[MPExpression alloc] initWithSymbols:@[[[MPFunction alloc] init], @"123"]];
|
MPExpression *expression4 = [[MPExpression alloc] initWithElements:@[[[MPFunction alloc] init], @"123"]];
|
||||||
MPExpression *expression5 = [[MPExpression alloc] initWithSymbols:@[[[MPFunction alloc] init], @"123"]];
|
MPExpression *expression5 = [[MPExpression alloc] initWithElements:@[[[MPFunction alloc] init], @"123"]];
|
||||||
|
|
||||||
XCTAssertNotEqualObjects(expression1, expression2);
|
XCTAssertNotEqualObjects(expression1, expression2);
|
||||||
XCTAssertNotEqualObjects(expression1, expression3);
|
XCTAssertNotEqualObjects(expression1, expression3);
|
||||||
@@ -159,68 +159,83 @@
|
|||||||
XCTAssertEqualObjects(expression4, expression5);
|
XCTAssertEqualObjects(expression4, expression5);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testAppendSymbols {
|
|
||||||
MPExpression *expression1 = [[MPExpression alloc] initWithString:@"123"];
|
|
||||||
MPExpression *expression2 = [expression1 expressionByAppendingFunction:[[MPFunction alloc] init]];
|
|
||||||
MPExpression *expression3 = [[MPExpression alloc] initWithSymbols:@[@"123", [[MPFunction alloc] init]]];
|
|
||||||
|
|
||||||
XCTAssertEqualObjects(expression2, expression3);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)testDescription {
|
- (void)testDescription {
|
||||||
// Test Simple Expressions
|
// Test Simple Expressions
|
||||||
MPExpression *testExpression = [[MPExpression alloc] initWithString:@"1234"];
|
MPExpression *testExpression = [[MPExpression alloc] initWithElement:@"1234"];
|
||||||
XCTAssertEqualObjects([testExpression description], @"1234");
|
XCTAssertEqualObjects([testExpression description], @"1234");
|
||||||
|
|
||||||
testExpression = [[MPExpression alloc] initWithFunction:[[MPFunction alloc] init]];
|
testExpression = [[MPExpression alloc] initWithElement:[[MPFunction alloc] init]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"[]");
|
XCTAssertEqualObjects([testExpression description], @"[]");
|
||||||
|
|
||||||
// Test function after literal without explicit operator
|
// Test function after literal without explicit operator
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[@"123", [[MPFunction alloc] init]]];
|
testExpression = [[MPExpression alloc] initWithElements:@[@"123", [[MPFunction alloc] init]]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"123*[]");
|
XCTAssertEqualObjects([testExpression description], @"123*[]");
|
||||||
|
|
||||||
// Test function after literal with explicit operator
|
// Test function after literal with explicit operator
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[@"123+", [[MPFunction alloc] init]]];
|
testExpression = [[MPExpression alloc] initWithElements:@[@"123+", [[MPFunction alloc] init]]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"123+[]");
|
XCTAssertEqualObjects([testExpression description], @"123+[]");
|
||||||
|
|
||||||
// Test literal after function without explicit operator
|
// Test literal after function without explicit operator
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[[[MPFunction alloc] init], @"123"]];
|
testExpression = [[MPExpression alloc] initWithElements:@[[[MPFunction alloc] init], @"123"]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"[]*123");
|
XCTAssertEqualObjects([testExpression description], @"[]*123");
|
||||||
|
|
||||||
// Test literal after function with explicit operator
|
// Test literal after function with explicit operator
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[[[MPFunction alloc] init], @"-123"]];
|
testExpression = [[MPExpression alloc] initWithElements:@[[[MPFunction alloc] init], @"-123"]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"[]-123");
|
XCTAssertEqualObjects([testExpression description], @"[]-123");
|
||||||
|
|
||||||
// Test function after function without explicit operator
|
// Test function after function without explicit operator
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[[[MPFunction alloc] init], [[MPFunction alloc] init]]];
|
testExpression = [[MPExpression alloc] initWithElements:@[[[MPFunction alloc] init], [[MPFunction alloc] init]]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"[]*[]");
|
XCTAssertEqualObjects([testExpression description], @"[]*[]");
|
||||||
|
|
||||||
// Test function after function with explicit operator
|
// Test function after function with explicit operator
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[[[MPFunction alloc] init], @"-", [[MPFunction alloc] init]]];
|
testExpression = [[MPExpression alloc] initWithElements:@[[[MPFunction alloc] init], @"-", [[MPFunction alloc] init]]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"[]-[]");
|
XCTAssertEqualObjects([testExpression description], @"[]-[]");
|
||||||
|
|
||||||
|
|
||||||
// Test whitespaces in literal
|
// Test whitespaces in literal
|
||||||
testExpression = [[MPExpression alloc] initWithSymbols:@[@" 123 + ", [[MPFunction alloc] init]]];
|
testExpression = [[MPExpression alloc] initWithElements:@[@" 123 + ", [[MPFunction alloc] init]]];
|
||||||
XCTAssertEqualObjects([testExpression description], @"123 +[]");
|
XCTAssertEqualObjects([testExpression description], @"123 +[]");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testCopying {
|
- (void)testCopying {
|
||||||
MPExpression *baseExpression = [[MPExpression alloc] initWithFunction:[[MPFunction alloc] init]];
|
MPExpression *baseExpression = [[MPExpression alloc] initWithElement:[[MPFunction alloc] init]];
|
||||||
MPExpression *copy = [baseExpression copy];
|
MPExpression *copy = [baseExpression copy];
|
||||||
|
|
||||||
|
XCTAssertEqual(baseExpression.numberOfElements, copy.numberOfElements);
|
||||||
XCTAssertNotEqual(copy, baseExpression);
|
XCTAssertNotEqual(copy, baseExpression);
|
||||||
XCTAssertNotEqual([baseExpression symbolAtIndex:0], [copy symbolAtIndex:0]);
|
XCTAssertNotEqual([baseExpression elementAtIndex:0], [copy elementAtIndex:0]);
|
||||||
|
XCTAssertEqualObjects(baseExpression, copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testMutableCopying {
|
- (void)testMutating {
|
||||||
MPExpression *baseExpression = [[MPExpression alloc] initWithString:@"123"];
|
MPExpression *testExpression = [[MPExpression alloc] initWithElements:@[@"1234", [[MPFunction alloc] init], @"5678", [[MPFunction alloc] init]]];
|
||||||
MPMutableExpression *expression1 = [baseExpression mutableCopy];
|
|
||||||
[expression1 appendFunction:[[MPFunction alloc] init]];
|
|
||||||
MPExpression *expression2 = [[MPExpression alloc] initWithSymbols:@[@"123", [[MPFunction alloc] init]]];
|
|
||||||
|
|
||||||
XCTAssertEqualObjects(expression1, expression2);
|
[testExpression appendElement:@"90"];
|
||||||
XCTAssertNotEqualObjects(baseExpression, expression1);
|
XCTAssertEqual([testExpression numberOfElements], 5);
|
||||||
|
// 1234 [] 5678 [] 90
|
||||||
|
|
||||||
|
[testExpression deleteElementsInRange:NSMakeRange(2, 4)];
|
||||||
|
XCTAssertEqual([testExpression numberOfElements], 3);
|
||||||
|
// 12678 [] 90
|
||||||
|
|
||||||
|
[testExpression insertElement:[[MPFunction alloc] init]
|
||||||
|
atLocation:2];
|
||||||
|
XCTAssertEqual([testExpression numberOfElements], 5);
|
||||||
|
// 12 [] 678 [] 90
|
||||||
|
|
||||||
|
[testExpression replaceElementsInRange:NSMakeRange(2, 5)
|
||||||
|
withElements:@[[[MPFunction alloc] init]]];
|
||||||
|
XCTAssertEqual([testExpression numberOfElements], 3);
|
||||||
|
// 12 [] 90
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testInvalidMutatingRange {
|
||||||
|
@try {
|
||||||
|
MPExpression *testExpression = [[MPExpression alloc] initWithElements:@[@"1234", [[MPFunction alloc] init], @"5678", [[MPFunction alloc] init]]];
|
||||||
|
[testExpression deleteElementsInRange:NSMakeRange(5, 17)];
|
||||||
|
XCTFail(@"Should have raised an exception");
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test evaluating expressions
|
// TODO: Test evaluating expressions
|
||||||
|
|||||||
Reference in New Issue
Block a user