Archived
1

Added the MPExpressionTree Classes

This commit is contained in:
Kim Wittenburg
2014-10-13 23:53:04 +02:00
parent 82259f87e2
commit 5592128926
60 changed files with 1981 additions and 725 deletions

View File

@@ -18,6 +18,37 @@
3B5FF73C19DB2FF500C8348A /* MPPowerFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B5FF73A19DB2FF500C8348A /* MPPowerFunction.m */; };
3B69B66C19DB41B90028E608 /* MPPowerFunctionLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B66A19DB41B90028E608 /* MPPowerFunctionLayout.h */; };
3B69B66D19DB41B90028E608 /* MPPowerFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B66B19DB41B90028E608 /* MPPowerFunctionLayout.m */; };
3B69B67C19E4915E0028E608 /* MPFractionFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B67A19E4915E0028E608 /* MPFractionFunction.h */; };
3B69B67D19E4915E0028E608 /* MPFractionFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B67B19E4915E0028E608 /* MPFractionFunction.m */; };
3B69B68019E493630028E608 /* MPFractionFunctionLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B67E19E493630028E608 /* MPFractionFunctionLayout.h */; };
3B69B68119E493630028E608 /* MPFractionFunctionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B67F19E493630028E608 /* MPFractionFunctionLayout.m */; };
3B69B68519E6E8B20028E608 /* MPExpressionTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B68319E6E8B20028E608 /* MPExpressionTree.h */; };
3B69B68619E6E8B20028E608 /* MPExpressionTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B68419E6E8B20028E608 /* MPExpressionTree.m */; };
3B69B68919E6E9280028E608 /* MPSummand.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B68719E6E9280028E608 /* MPSummand.h */; };
3B69B68A19E6E9280028E608 /* MPSummand.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B68819E6E9280028E608 /* MPSummand.m */; };
3B69B68D19E6EB0D0028E608 /* MPProduct.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B68B19E6EB0D0028E608 /* MPProduct.h */; };
3B69B68E19E6EB0D0028E608 /* MPProduct.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B68C19E6EB0D0028E608 /* MPProduct.m */; };
3B69B69019E6ED6E0028E608 /* MPExpressionTreeElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B68F19E6ED6E0028E608 /* MPExpressionTreeElement.h */; };
3B69B69719E6F0780028E608 /* MPValueGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B69519E6F0780028E608 /* MPValueGroup.h */; };
3B69B69819E6F0780028E608 /* MPValueGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B69619E6F0780028E608 /* MPValueGroup.m */; };
3B69B69D19E6F2110028E608 /* MPNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B69B19E6F2110028E608 /* MPNumber.h */; };
3B69B69E19E6F2110028E608 /* MPNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B69C19E6F2110028E608 /* MPNumber.m */; };
3B69B6A119E6F2420028E608 /* MPVariable.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B69F19E6F2420028E608 /* MPVariable.h */; };
3B69B6A219E6F2420028E608 /* MPVariable.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6A019E6F2420028E608 /* MPVariable.m */; };
3B69B6A919E6F2AF0028E608 /* MPFunction+MPValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B6A719E6F2AF0028E608 /* MPFunction+MPValue.h */; };
3B69B6AA19E6F2AF0028E608 /* MPFunction+MPValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6A819E6F2AF0028E608 /* MPFunction+MPValue.m */; };
3B69B6B119E8175F0028E608 /* MPFactor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B6AF19E8175F0028E608 /* MPFactor.h */; };
3B69B6B219E8175F0028E608 /* MPFactor.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6B019E8175F0028E608 /* MPFactor.m */; };
3B69B6B519E88E750028E608 /* MPUnexpectedSymbolValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B6B319E88E750028E608 /* MPUnexpectedSymbolValue.h */; };
3B69B6B619E88E750028E608 /* MPUnexpectedSymbolValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6B419E88E750028E608 /* MPUnexpectedSymbolValue.m */; };
3B69B6B919E935E20028E608 /* MPSuffixFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B6B719E935E20028E608 /* MPSuffixFunction.h */; };
3B69B6BA19E935E20028E608 /* MPSuffixFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6B819E935E20028E608 /* MPSuffixFunction.m */; };
3B69B6BD19E948740028E608 /* MPFunctionValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B6BB19E948740028E608 /* MPFunctionValue.h */; };
3B69B6BE19E948740028E608 /* MPFunctionValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6BC19E948740028E608 /* MPFunctionValue.m */; };
3B69B6C119E953590028E608 /* MPFactorial.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B6BF19E953590028E608 /* MPFactorial.h */; };
3B69B6C219E953590028E608 /* MPFactorial.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6C019E953590028E608 /* MPFactorial.m */; };
3B69B6C519E95B250028E608 /* MPOperatorChain.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B69B6C319E95B250028E608 /* MPOperatorChain.h */; };
3B69B6C619E95B250028E608 /* MPOperatorChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B69B6C419E95B250028E608 /* MPOperatorChain.m */; };
3B7172EA19C7147000FEAA5B /* FunctionsButtonDisclosure@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B7172E819C7147000FEAA5B /* FunctionsButtonDisclosure@2x.png */; };
3B7172EB19C7147000FEAA5B /* FunctionsButtonDisclosure.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B7172E919C7147000FEAA5B /* FunctionsButtonDisclosure.png */; };
3B7172EE19C9FA8E00FEAA5B /* MPParenthesisFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7172EC19C9FA8E00FEAA5B /* MPParenthesisFunction.h */; };
@@ -42,7 +73,6 @@
3B85833819BB63BD00D76A8D /* MPExpression.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BFAC38D1997B61300B3EF67 /* MPExpression.h */; settings = {ATTRIBUTES = (Public, ); }; };
3B85833919BB63C500D76A8D /* MPExpressionElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BFAC3961997B67400B3EF67 /* MPExpressionElement.h */; settings = {ATTRIBUTES = (Public, ); }; };
3B85833A19BB63D400D76A8D /* MPFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B87E35E19009D5F00259938 /* MPFunction.h */; settings = {ATTRIBUTES = (Public, ); }; };
3B85833E19BB651400D76A8D /* MPExpressionEvaluator.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BC46B4719B38C980033F13A /* MPExpressionEvaluator.h */; };
3B85834119BB651E00D76A8D /* MPRangePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B87E35B1900933200259938 /* MPRangePath.h */; settings = {ATTRIBUTES = (Public, ); }; };
3B85834219BB652900D76A8D /* MPException.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B0F69A719028BC600817707 /* MPException.h */; settings = {ATTRIBUTES = (Public, ); }; };
3B85834319BB653700D76A8D /* MPSumFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BB09EC71906FD830080A5ED /* MPSumFunction.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -55,14 +85,11 @@
3B85834A19BB65B600D76A8D /* MPFunctionLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B528D11199417E90054DB5F /* MPFunctionLayout.h */; };
3B85834B19BB65B600D76A8D /* MPSumFunctionLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BB09EDF190736160080A5ED /* MPSumFunctionLayout.h */; };
3B85834C19BB661100D76A8D /* MathKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B85833219BB5F2D00D76A8D /* MathKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
3BAF938D19D6D508002C5EC6 /* MPTerm.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BAF938B19D6D508002C5EC6 /* MPTerm.h */; };
3BAF938E19D6D508002C5EC6 /* MPTerm.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BAF938C19D6D508002C5EC6 /* MPTerm.m */; };
3BB18AA519CDB3A900986DA0 /* MPTokenStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BB18AA319CDB3A900986DA0 /* MPTokenStream.h */; };
3BB18AA619CDB3A900986DA0 /* MPTokenStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB18AA419CDB3A900986DA0 /* MPTokenStream.m */; };
3BBEA92C19BB680B00133766 /* MathKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3B85830D19BB5E5500D76A8D /* MathKit.framework */; };
3BBEA93519BB79A700133766 /* MPExpression.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFAC38E1997B61300B3EF67 /* MPExpression.m */; };
3BBEA93619BB79A700133766 /* MPFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35F19009D5F00259938 /* MPFunction.m */; };
3BBEA93719BB79A700133766 /* MPExpressionEvaluator.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BC46B4819B38C980033F13A /* MPExpressionEvaluator.m */; };
3BBEA93A19BB79A700133766 /* MPSumFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB09EC81906FD830080A5ED /* MPSumFunction.m */; };
3BBEA93B19BB79A700133766 /* MPRangePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B87E35C1900933200259938 /* MPRangePath.m */; };
3BBEA93C19BB79A700133766 /* MPException.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B0F69A819028C6000817707 /* MPException.m */; };
@@ -152,6 +179,37 @@
3B688D9819982DF50006B4AB /* MPLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLayout.m; sourceTree = "<group>"; };
3B69B66A19DB41B90028E608 /* MPPowerFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPowerFunctionLayout.h; sourceTree = "<group>"; };
3B69B66B19DB41B90028E608 /* MPPowerFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPowerFunctionLayout.m; sourceTree = "<group>"; };
3B69B67A19E4915E0028E608 /* MPFractionFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFractionFunction.h; sourceTree = "<group>"; };
3B69B67B19E4915E0028E608 /* MPFractionFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFractionFunction.m; sourceTree = "<group>"; };
3B69B67E19E493630028E608 /* MPFractionFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFractionFunctionLayout.h; sourceTree = "<group>"; };
3B69B67F19E493630028E608 /* MPFractionFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFractionFunctionLayout.m; sourceTree = "<group>"; };
3B69B68319E6E8B20028E608 /* MPExpressionTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionTree.h; sourceTree = "<group>"; };
3B69B68419E6E8B20028E608 /* MPExpressionTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionTree.m; sourceTree = "<group>"; };
3B69B68719E6E9280028E608 /* MPSummand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSummand.h; sourceTree = "<group>"; };
3B69B68819E6E9280028E608 /* MPSummand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSummand.m; sourceTree = "<group>"; };
3B69B68B19E6EB0D0028E608 /* MPProduct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPProduct.h; sourceTree = "<group>"; };
3B69B68C19E6EB0D0028E608 /* MPProduct.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPProduct.m; sourceTree = "<group>"; };
3B69B68F19E6ED6E0028E608 /* MPExpressionTreeElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionTreeElement.h; sourceTree = "<group>"; };
3B69B69519E6F0780028E608 /* MPValueGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPValueGroup.h; sourceTree = "<group>"; };
3B69B69619E6F0780028E608 /* MPValueGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPValueGroup.m; sourceTree = "<group>"; };
3B69B69B19E6F2110028E608 /* MPNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNumber.h; sourceTree = "<group>"; };
3B69B69C19E6F2110028E608 /* MPNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNumber.m; sourceTree = "<group>"; };
3B69B69F19E6F2420028E608 /* MPVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPVariable.h; sourceTree = "<group>"; };
3B69B6A019E6F2420028E608 /* MPVariable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPVariable.m; sourceTree = "<group>"; };
3B69B6A719E6F2AF0028E608 /* MPFunction+MPValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MPFunction+MPValue.h"; sourceTree = "<group>"; };
3B69B6A819E6F2AF0028E608 /* MPFunction+MPValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPFunction+MPValue.m"; sourceTree = "<group>"; };
3B69B6AF19E8175F0028E608 /* MPFactor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFactor.h; sourceTree = "<group>"; };
3B69B6B019E8175F0028E608 /* MPFactor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFactor.m; sourceTree = "<group>"; };
3B69B6B319E88E750028E608 /* MPUnexpectedSymbolValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUnexpectedSymbolValue.h; sourceTree = "<group>"; };
3B69B6B419E88E750028E608 /* MPUnexpectedSymbolValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUnexpectedSymbolValue.m; sourceTree = "<group>"; };
3B69B6B719E935E20028E608 /* MPSuffixFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSuffixFunction.h; sourceTree = "<group>"; };
3B69B6B819E935E20028E608 /* MPSuffixFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSuffixFunction.m; sourceTree = "<group>"; };
3B69B6BB19E948740028E608 /* MPFunctionValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunctionValue.h; sourceTree = "<group>"; };
3B69B6BC19E948740028E608 /* MPFunctionValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFunctionValue.m; sourceTree = "<group>"; };
3B69B6BF19E953590028E608 /* MPFactorial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFactorial.h; sourceTree = "<group>"; };
3B69B6C019E953590028E608 /* MPFactorial.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFactorial.m; sourceTree = "<group>"; };
3B69B6C319E95B250028E608 /* MPOperatorChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOperatorChain.h; sourceTree = "<group>"; };
3B69B6C419E95B250028E608 /* MPOperatorChain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOperatorChain.m; sourceTree = "<group>"; };
3B7172E819C7147000FEAA5B /* FunctionsButtonDisclosure@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "FunctionsButtonDisclosure@2x.png"; sourceTree = "<group>"; };
3B7172E919C7147000FEAA5B /* FunctionsButtonDisclosure.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FunctionsButtonDisclosure.png; sourceTree = "<group>"; };
3B7172EC19C9FA8E00FEAA5B /* MPParenthesisFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPParenthesisFunction.h; sourceTree = "<group>"; };
@@ -181,8 +239,6 @@
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>"; };
3B87E35F19009D5F00259938 /* MPFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFunction.m; sourceTree = "<group>"; };
3BAF938B19D6D508002C5EC6 /* MPTerm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTerm.h; sourceTree = "<group>"; };
3BAF938C19D6D508002C5EC6 /* MPTerm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTerm.m; sourceTree = "<group>"; };
3BB09EB01905DE500080A5ED /* MPExpressionStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MPExpressionStorage.h; path = ../MathPad/MPExpressionStorage.h; sourceTree = "<group>"; };
3BB09EB11905DE500080A5ED /* MPExpressionStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPExpressionStorage.m; path = ../MathPad/MPExpressionStorage.m; sourceTree = "<group>"; };
3BB09EC71906FD830080A5ED /* MPSumFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSumFunction.h; sourceTree = "<group>"; };
@@ -197,8 +253,6 @@
3BC4661319B245C60033F13A /* Fonts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Fonts; sourceTree = "<group>"; };
3BC4661519B365070033F13A /* MPArrayCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPArrayCache.h; sourceTree = "<group>"; };
3BC4661619B365070033F13A /* MPArrayCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPArrayCache.m; sourceTree = "<group>"; };
3BC46B4719B38C980033F13A /* MPExpressionEvaluator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionEvaluator.h; sourceTree = "<group>"; };
3BC46B4819B38C980033F13A /* MPExpressionEvaluator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionEvaluator.m; sourceTree = "<group>"; };
3BF59AFB19D80ECC00E54292 /* MPFunctionsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFunctionsViewController.h; sourceTree = "<group>"; };
3BF59AFC19D80ECC00E54292 /* MPFunctionsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFunctionsViewController.m; sourceTree = "<group>"; };
3BF59AFD19D80ECC00E54292 /* MPFunctionsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPFunctionsViewController.xib; sourceTree = "<group>"; };
@@ -271,6 +325,38 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
3B69B68219E6E8A50028E608 /* Expression Tree */ = {
isa = PBXGroup;
children = (
3B69B68F19E6ED6E0028E608 /* MPExpressionTreeElement.h */,
3B69B68319E6E8B20028E608 /* MPExpressionTree.h */,
3B69B68419E6E8B20028E608 /* MPExpressionTree.m */,
3B69B68719E6E9280028E608 /* MPSummand.h */,
3B69B68819E6E9280028E608 /* MPSummand.m */,
3B69B6C319E95B250028E608 /* MPOperatorChain.h */,
3B69B6C419E95B250028E608 /* MPOperatorChain.m */,
3B69B68B19E6EB0D0028E608 /* MPProduct.h */,
3B69B68C19E6EB0D0028E608 /* MPProduct.m */,
3B69B6AF19E8175F0028E608 /* MPFactor.h */,
3B69B6B019E8175F0028E608 /* MPFactor.m */,
3B69B69519E6F0780028E608 /* MPValueGroup.h */,
3B69B69619E6F0780028E608 /* MPValueGroup.m */,
3B69B69B19E6F2110028E608 /* MPNumber.h */,
3B69B69C19E6F2110028E608 /* MPNumber.m */,
3B69B69F19E6F2420028E608 /* MPVariable.h */,
3B69B6A019E6F2420028E608 /* MPVariable.m */,
3B69B6A719E6F2AF0028E608 /* MPFunction+MPValue.h */,
3B69B6A819E6F2AF0028E608 /* MPFunction+MPValue.m */,
3B69B6BB19E948740028E608 /* MPFunctionValue.h */,
3B69B6BC19E948740028E608 /* MPFunctionValue.m */,
3B69B6B319E88E750028E608 /* MPUnexpectedSymbolValue.h */,
3B69B6B419E88E750028E608 /* MPUnexpectedSymbolValue.m */,
3B69B6BF19E953590028E608 /* MPFactorial.h */,
3B69B6C019E953590028E608 /* MPFactorial.m */,
);
name = "Expression Tree";
sourceTree = "<group>";
};
3B7172E519C7112C00FEAA5B /* Resources */ = {
isa = PBXGroup;
children = (
@@ -356,21 +442,6 @@
name = Resources;
sourceTree = "<group>";
};
3BAF938F19D6D535002C5EC6 /* Tokenizer */ = {
isa = PBXGroup;
children = (
3B7B3A1619CC44E4005849E5 /* MPExpressionTokenizer.h */,
3B7B3A1719CC44E4005849E5 /* MPExpressionTokenizer.m */,
3B7B3A2A19CC467E005849E5 /* MPToken.h */,
3B7B3A2B19CC467E005849E5 /* MPToken.m */,
3B7B3A5219CC50B1005849E5 /* MPFunction+MPToken.h */,
3B7B3A5319CC50B1005849E5 /* MPFunction+MPToken.m */,
3BB18AA319CDB3A900986DA0 /* MPTokenStream.h */,
3BB18AA419CDB3A900986DA0 /* MPTokenStream.m */,
);
name = Tokenizer;
sourceTree = "<group>";
};
3BB09EBC1905EF210080A5ED /* Functions */ = {
isa = PBXGroup;
children = (
@@ -380,6 +451,8 @@
3B7172ED19C9FA8E00FEAA5B /* MPParenthesisFunction.m */,
3B5FF73919DB2FF500C8348A /* MPPowerFunction.h */,
3B5FF73A19DB2FF500C8348A /* MPPowerFunction.m */,
3B69B67A19E4915E0028E608 /* MPFractionFunction.h */,
3B69B67B19E4915E0028E608 /* MPFractionFunction.m */,
);
name = Functions;
sourceTree = "<group>";
@@ -413,6 +486,8 @@
3B7172F119C9FC6700FEAA5B /* MPParenthesisFunctionLayout.m */,
3B69B66A19DB41B90028E608 /* MPPowerFunctionLayout.h */,
3B69B66B19DB41B90028E608 /* MPPowerFunctionLayout.m */,
3B69B67E19E493630028E608 /* MPFractionFunctionLayout.h */,
3B69B67F19E493630028E608 /* MPFractionFunctionLayout.m */,
);
name = "Function Layouts";
sourceTree = "<group>";
@@ -434,6 +509,17 @@
3BFAC3961997B67400B3EF67 /* MPExpressionElement.h */,
3B87E35E19009D5F00259938 /* MPFunction.h */,
3B87E35F19009D5F00259938 /* MPFunction.m */,
3B69B6B719E935E20028E608 /* MPSuffixFunction.h */,
3B69B6B819E935E20028E608 /* MPSuffixFunction.m */,
3B7B3A1619CC44E4005849E5 /* MPExpressionTokenizer.h */,
3B7B3A1719CC44E4005849E5 /* MPExpressionTokenizer.m */,
3B7B3A2A19CC467E005849E5 /* MPToken.h */,
3B7B3A2B19CC467E005849E5 /* MPToken.m */,
3B7B3A5219CC50B1005849E5 /* MPFunction+MPToken.h */,
3B7B3A5319CC50B1005849E5 /* MPFunction+MPToken.m */,
3BB18AA319CDB3A900986DA0 /* MPTokenStream.h */,
3BB18AA419CDB3A900986DA0 /* MPTokenStream.m */,
3B69B68219E6E8A50028E608 /* Expression Tree */,
3BC46B4F19B506F20033F13A /* Evaluation */,
);
name = "Base Expression Classes";
@@ -466,15 +552,10 @@
3BC46B4F19B506F20033F13A /* Evaluation */ = {
isa = PBXGroup;
children = (
3BC46B4719B38C980033F13A /* MPExpressionEvaluator.h */,
3BC46B4819B38C980033F13A /* MPExpressionEvaluator.m */,
3B78C85219C2DA5300516335 /* MPEvaluationContext.h */,
3B78C85319C2DA5300516335 /* MPEvaluationContext.m */,
3B591BB919C58D000061D86B /* MPMathRules.h */,
3B591BBA19C58D000061D86B /* MPMathRules.m */,
3BAF938F19D6D535002C5EC6 /* Tokenizer */,
3BAF938B19D6D508002C5EC6 /* MPTerm.h */,
3BAF938C19D6D508002C5EC6 /* MPTerm.m */,
3B52CECE19BE509C00CEDCFC /* MPParseError.h */,
3B52CECF19BE509C00CEDCFC /* MPParseError.m */,
);
@@ -574,19 +655,27 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
3B69B6C519E95B250028E608 /* MPOperatorChain.h in Headers */,
3B85834C19BB661100D76A8D /* MathKit.h in Headers */,
3B85833819BB63BD00D76A8D /* MPExpression.h in Headers */,
3B85833919BB63C500D76A8D /* MPExpressionElement.h in Headers */,
3BAF938D19D6D508002C5EC6 /* MPTerm.h in Headers */,
3B69B68D19E6EB0D0028E608 /* MPProduct.h in Headers */,
3B69B6B919E935E20028E608 /* MPSuffixFunction.h in Headers */,
3B69B67C19E4915E0028E608 /* MPFractionFunction.h in Headers */,
3B78C85419C2DA5300516335 /* MPEvaluationContext.h in Headers */,
3B85834419BB654D00D76A8D /* NSString+MPExpressionElement.h in Headers */,
3B69B6B519E88E750028E608 /* MPUnexpectedSymbolValue.h in Headers */,
3B7172F219C9FC6700FEAA5B /* MPParenthesisFunctionLayout.h in Headers */,
3B52CEDC19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.h in Headers */,
3B85833A19BB63D400D76A8D /* MPFunction.h in Headers */,
3B69B6B119E8175F0028E608 /* MPFactor.h in Headers */,
3B69B66C19DB41B90028E608 /* MPPowerFunctionLayout.h in Headers */,
3B69B69719E6F0780028E608 /* MPValueGroup.h in Headers */,
3B85834319BB653700D76A8D /* MPSumFunction.h in Headers */,
3B85834119BB651E00D76A8D /* MPRangePath.h in Headers */,
3B69B6C119E953590028E608 /* MPFactorial.h in Headers */,
3B85834219BB652900D76A8D /* MPException.h in Headers */,
3B69B69D19E6F2110028E608 /* MPNumber.h in Headers */,
3B85834519BB655200D76A8D /* NSIndexPath+MPAdditions.h in Headers */,
3B5FF73B19DB2FF500C8348A /* MPPowerFunction.h in Headers */,
3B52CED019BE509C00CEDCFC /* MPParseError.h in Headers */,
@@ -596,13 +685,19 @@
3BB18AA519CDB3A900986DA0 /* MPTokenStream.h in Headers */,
3BF59AFE19D80ECC00E54292 /* MPFunctionsViewController.h in Headers */,
3B7B3A2C19CC467E005849E5 /* MPToken.h in Headers */,
3B69B68919E6E9280028E608 /* MPSummand.h in Headers */,
3B7B3A1819CC44E4005849E5 /* MPExpressionTokenizer.h in Headers */,
3B85833E19BB651400D76A8D /* MPExpressionEvaluator.h in Headers */,
3B69B69019E6ED6E0028E608 /* MPExpressionTreeElement.h in Headers */,
3BF59B0319D81EE600E54292 /* MPWhiteView.h in Headers */,
3B85834819BB65B600D76A8D /* MPLayout.h in Headers */,
3B69B6A919E6F2AF0028E608 /* MPFunction+MPValue.h in Headers */,
3B69B68519E6E8B20028E608 /* MPExpressionTree.h in Headers */,
3B85834919BB65B600D76A8D /* MPExpressionLayout.h in Headers */,
3B7B3A5419CC50B1005849E5 /* MPFunction+MPToken.h in Headers */,
3B69B6BD19E948740028E608 /* MPFunctionValue.h in Headers */,
3B591BBB19C58D000061D86B /* MPMathRules.h in Headers */,
3B69B68019E493630028E608 /* MPFractionFunctionLayout.h in Headers */,
3B69B6A119E6F2420028E608 /* MPVariable.h in Headers */,
3B85834A19BB65B600D76A8D /* MPFunctionLayout.h in Headers */,
3B85834B19BB65B600D76A8D /* MPSumFunctionLayout.h in Headers */,
);
@@ -776,23 +871,35 @@
3BBEA94219BB79A700133766 /* MPExpressionLayout.m in Sources */,
3B7B3A1919CC44E4005849E5 /* MPExpressionTokenizer.m in Sources */,
3B591BBC19C58D000061D86B /* MPMathRules.m in Sources */,
3B69B6BE19E948740028E608 /* MPFunctionValue.m in Sources */,
3B7172EF19C9FA8E00FEAA5B /* MPParenthesisFunction.m in Sources */,
3B7B3A5519CC50B1005849E5 /* MPFunction+MPToken.m in Sources */,
3BBEA94119BB79A700133766 /* MPLayout.m in Sources */,
3BAF938E19D6D508002C5EC6 /* MPTerm.m in Sources */,
3B69B6B219E8175F0028E608 /* MPFactor.m in Sources */,
3B69B6BA19E935E20028E608 /* MPSuffixFunction.m in Sources */,
3BBEA93D19BB79A700133766 /* NSString+MPExpressionElement.m in Sources */,
3B69B68119E493630028E608 /* MPFractionFunctionLayout.m in Sources */,
3B69B68619E6E8B20028E608 /* MPExpressionTree.m in Sources */,
3BF59B0419D81EE600E54292 /* MPWhiteView.m in Sources */,
3BBEA94019BB79A700133766 /* MPExpressionStorage.m in Sources */,
3BBEA93F19BB79A700133766 /* MPExpressionView.m in Sources */,
3B69B6AA19E6F2AF0028E608 /* MPFunction+MPValue.m in Sources */,
3B7B3A2D19CC467E005849E5 /* MPToken.m in Sources */,
3B69B6C619E95B250028E608 /* MPOperatorChain.m in Sources */,
3B78C85519C2DA5300516335 /* MPEvaluationContext.m in Sources */,
3B69B6A219E6F2420028E608 /* MPVariable.m in Sources */,
3B69B69819E6F0780028E608 /* MPValueGroup.m in Sources */,
3BBEA94419BB79A700133766 /* MPSumFunctionLayout.m in Sources */,
3B69B6C219E953590028E608 /* MPFactorial.m in Sources */,
3B69B69E19E6F2110028E608 /* MPNumber.m in Sources */,
3B7172F319C9FC6700FEAA5B /* MPParenthesisFunctionLayout.m in Sources */,
3BBEA93719BB79A700133766 /* MPExpressionEvaluator.m in Sources */,
3BBEA93A19BB79A700133766 /* MPSumFunction.m in Sources */,
3BBEA93E19BB79A700133766 /* NSIndexPath+MPAdditions.m in Sources */,
3B52CEDD19BEE63000CEDCFC /* NSRegularExpression+MPParsingAdditions.m in Sources */,
3B69B67D19E4915E0028E608 /* MPFractionFunction.m in Sources */,
3BBEA93C19BB79A700133766 /* MPException.m in Sources */,
3B69B68E19E6EB0D0028E608 /* MPProduct.m in Sources */,
3B69B6B619E88E750028E608 /* MPUnexpectedSymbolValue.m in Sources */,
3BF59AFF19D80ECC00E54292 /* MPFunctionsViewController.m in Sources */,
3B52CED119BE509C00CEDCFC /* MPParseError.m in Sources */,
3BB18AA619CDB3A900986DA0 /* MPTokenStream.m in Sources */,
@@ -800,6 +907,7 @@
3BBEA93619BB79A700133766 /* MPFunction.m in Sources */,
3BBEA93519BB79A700133766 /* MPExpression.m in Sources */,
3BBEA93B19BB79A700133766 /* MPRangePath.m in Sources */,
3B69B68A19E6E9280028E608 /* MPSummand.m in Sources */,
3BBEA94319BB79A700133766 /* MPFunctionLayout.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -8,6 +8,7 @@
@import Foundation;
#import "NSString+MPExpressionElement.h"
#import "MPExpressionTree.h"
#import "MPToken.h"
typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
@@ -77,6 +78,8 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
*/
- (instancetype)init;
- (instancetype)initWithExpressionTree:(MPExpressionTree *)expressionTree;
/*!
@method initWithElement:
@@ -358,6 +361,7 @@ typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
*/
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
- (MPExpressionTree *)parse;
#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

View File

@@ -14,7 +14,6 @@
#import "MPException.h"
#import "MPExpressionTokenizer.h"
#import "MPExpressionEvaluator.h"
#import "MPToken.h"
@@ -55,6 +54,11 @@
return [self initWithElements:@[]];
}
- (instancetype)initWithExpressionTree:(MPExpressionTree *)expressionTree
{
return [self initWithElements:expressionTree.expressionElements];
}
- (instancetype)initWithElement:(id<MPExpressionElement>)element
{
return [self initWithElements:@[element]];
@@ -518,13 +522,22 @@
#pragma mark Evaluating Expressions
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
{
MPExpressionEvaluator *evaluator = [[MPExpressionEvaluator alloc] initWithExpression:self];
MPTerm *term = [evaluator parseExpectingVariable:NO
error:error];
return [term evaluate];
MPExpressionTree *tree = [self parse];
if ([tree validate:error]) {
return [tree evaluate];
}
if (error) {
(*error).pathToExpression = self.indexPath;
}
return nil;
}
- (MPExpressionTree *)parse
{
MPTokenStream *tokenStream = [[MPTokenStream alloc] initWithTokens:self.tokens];
return [[MPExpressionTree alloc] initWithTokenStream:tokenStream];
}
#pragma mark Notifications

View File

@@ -1,26 +0,0 @@
//
// MPExpressionEvaluator.h
// MathPad
//
// Created by Kim Wittenburg on 31.08.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPExpression.h"
#import "MPExpressionTokenizer.h"
#import "MPTerm.h"
@class MPExpressionEvaluator, MPExpression, MPParsedElementOld;
@interface MPExpressionEvaluator : NSObject
- (instancetype)initWithExpression:(MPExpression *)expression;
@property (readonly, nonatomic, weak) MPExpression *expression;
#pragma mark Evaluating Expressions
@property (readonly, nonatomic, copy) NSString *definedVariable;
- (MPTerm *)parseExpectingVariable:(BOOL)flag error:(MPParseError *__autoreleasing *)error;
@end

View File

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

View File

@@ -11,6 +11,10 @@
#import "MPExpression.h"
#import "MPFunctionLayout.h"
#define kMPEmptyBoxWidth (self.usesSmallSize ? 2.0 : 3.0)
#define kMPEmptyBoxHeight (CTFontGetDescent((CTFontRef)self.font) + CTFontGetAscent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font))
#define kMPEmptyBoxYOrigin (-(CTFontGetDescent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font)))
@interface MPExpressionLayout : MPLayout
- (instancetype)initWithExpression:(MPExpression *)expression

View File

@@ -14,10 +14,6 @@
#import "NSString+MPExpressionElement.h"
#import "NSIndexPath+MPAdditions.h"
#define kMPEmptyBoxWidth (self.usesSmallSize ? 2.0 : 3.0)
#define kMPEmptyBoxHeight (CTFontGetDescent((CTFontRef)self.font) + CTFontGetAscent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font))
#define kMPEmptyBoxYOrigin (-(CTFontGetDescent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font)))
#define kMPEmptyBoxDrawingWidth kMPEmptyBoxWidth
#define kMPEmptyBoxDrawingHeight (CTFontGetDescent((CTFontRef)self.font) + CTFontGetAscent((CTFontRef)self.font))
#define kMPEmptyBoxDrawingYOrigin (-(CTFontGetDescent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font)/2))
@@ -60,6 +56,11 @@
}
#pragma mark Cache Methods
- (NSUInteger)numberOfChildren
{
return self.expression.countElements;
}
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
{
id cachedObject = [self cachableObjectForIndex:index generator:^id{
@@ -216,6 +217,11 @@
}
}
- (BOOL)drawsChildrenManually
{
return YES;
}
- (void)draw
{
// Get the current context

View File

@@ -42,16 +42,19 @@
NSString *decimalSeparator = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
NSString *regexStringFormat = @"\\A(?:"
@"(\\*)|"
@"([\\*∙⋅])|"
@"([+-](?:\\s*[+-])*)|"
@"((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))|"
@"(sin)|"
@"(cos)|"
@"(tan)|"
@"(asin)|"
@"(acos)|"
@"(atan)|"
@"([A-Za-z])|"
@"(!)|"
@"(=)|"
@"(\\s)"
@"(\\s+)"
@")";
NSString *regexString = [NSString stringWithFormat:regexStringFormat, decimalSeparator, decimalSeparator];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString
@@ -70,10 +73,13 @@
NSRange sinRange = [match rangeAtIndex:4];
NSRange cosRange = [match rangeAtIndex:5];
NSRange tanRange = [match rangeAtIndex:6];
NSRange variableRange = [match rangeAtIndex:7];
NSRange factorialRange = [match rangeAtIndex:8];
NSRange equalsRange = [match rangeAtIndex:9];
NSRange whitespaceRange = [match rangeAtIndex:10];
NSRange asinRange = [match rangeAtIndex:7];
NSRange acosRange = [match rangeAtIndex:8];
NSRange atanRange = [match rangeAtIndex:9];
NSRange variableRange = [match rangeAtIndex:10];
NSRange factorialRange = [match rangeAtIndex:11];
NSRange equalsRange = [match rangeAtIndex:12];
NSRange whitespaceRange = [match rangeAtIndex:13];
if (MPRangeExists(multiplicationSymbolRange)) {
range = multiplicationSymbolRange;
@@ -93,6 +99,15 @@
} else if (MPRangeExists(tanRange)) {
range = tanRange;
tokenType = MPTanToken;
} else if (MPRangeExists(asinRange)) {
range = asinRange;
tokenType = MPASinToken;
} else if (MPRangeExists(acosRange)) {
range = acosRange;
tokenType = MPACosToken;
} else if (MPRangeExists(atanRange)) {
range = atanRange;
tokenType = MPATanToken;
} else if (MPRangeExists(variableRange)) {
range = variableRange;
tokenType = MPVariableToken;

View File

@@ -0,0 +1,28 @@
//
// MPExpressionTree.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPSummand.h"
#import "MPExpressionTreeElement.h"
@interface MPExpressionTree : NSObject <MPExpressionTreeElement>
@property (nonatomic, copy) NSString *definedVariable;
- (NSArray *)summands;
- (void)appendSummand:(MPSummand *)summand;
- (void)insertSummand:(MPSummand *)summand
atIndex:(NSUInteger)index;
- (void)removeSummand:(MPSummand *)summand;
- (void)removeSummandAtIndex:(NSUInteger)index;
- (MPSummand *)summandAtIndex:(NSUInteger)index;
- (BOOL)validateExpectingVariableDefinition:(BOOL)flag
error:(MPParseError *__autoreleasing *)error;
@end

158
MathPad/MPExpressionTree.m Normal file
View File

@@ -0,0 +1,158 @@
//
// MPExpressionTree.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPExpressionTree.h"
@implementation MPExpressionTree {
NSRange _variableDefinitionRange;
NSMutableArray *_summands;
NSRange _range;
}
- (id)init
{
self = [super init];
if (self) {
_summands = [[NSMutableArray alloc] init];
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
MPTokenStreamRecordCurrentLocation(tokenStream);
[tokenStream beginIgnoringWhitespaceTokens];
_variableDefinitionRange = NSMakeRange(NSNotFound, 0);
self.definedVariable = nil;
if (tokenStream.currentToken.tokenType == MPVariableToken) {
if (tokenStream.peekNextToken.tokenType == MPEqualsToken) {
self.definedVariable = tokenStream.currentToken.stringValue;
NSRange variableRange = tokenStream.currentToken.range;
[tokenStream currentTokenConsumed];
NSRange equalsRange = tokenStream.currentToken.range;
[tokenStream currentTokenConsumed];
_variableDefinitionRange = NSUnionRange(variableRange, equalsRange);
}
}
while ([tokenStream hasMoreTokens]) {
[_summands addObject:[[MPSummand alloc] initWithTokenStream:tokenStream]];
}
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
_range = MPTokenStreamRecordedRange(tokenStream);
}
return self;
}
- (NSRange)range
{
return _range;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
return [self validateExpectingVariableDefinition:NO
error:error];
}
- (BOOL)validateExpectingVariableDefinition:(BOOL)flag
error:(MPParseError *__autoreleasing *)error
{
if (flag) {
if (!self.definedVariable) {
if (error) {
*error = MPParseError(NSMakeRange(self.range.location, 0), @"Expected Variable Definition.");
}
return NO;
}
} else {
if (self.definedVariable) {
if (error) {
*error = MPParseError(_variableDefinitionRange, @"Unexpected Variable Definition");
}
return NO;
}
}
if (_summands.count == 0) {
if (error) {
*error = MPParseError(self.range, @"Empty Expression.");
}
return NO;
}
for (MPSummand *summand in _summands) {
if (![summand validate:error]) {
return NO;
}
}
return YES;
}
- (NSDecimalNumber *)evaluate
{
NSDecimalNumber *value = [NSDecimalNumber zero];
for (MPSummand *summand in _summands) {
NSDecimalNumber *currentValue = [summand evaluate];
if ([currentValue isEqualToNumber:[NSDecimalNumber notANumber]]) {
value = currentValue;
break;
}
value = [value decimalNumberByAdding:currentValue];
}
return value;
}
- (NSArray *)expressionElements
{
NSMutableArray *elements = [[NSMutableArray alloc] init];
if (self.definedVariable) {
[elements addObject:[NSString stringWithFormat:@"%@=", self.definedVariable]];
}
for (MPSummand *summand in _summands) {
[elements addObjectsFromArray:summand.expressionElements];
}
return elements;
}
- (NSArray *)summands
{
return _summands;
}
- (void)appendSummand:(MPSummand *)summand
{
[_summands addObject:summand];
}
- (void)insertSummand:(MPSummand *)summand
atIndex:(NSUInteger)index
{
[_summands insertObject:summand
atIndex:index];
}
- (void)removeSummand:(MPSummand *)summand
{
[_summands removeObject:summand];
}
- (void)removeSummandAtIndex:(NSUInteger)index
{
[_summands removeObjectAtIndex:index];
}
- (MPSummand *)summandAtIndex:(NSUInteger)index
{
return [_summands objectAtIndex:index];
}
@end

View File

@@ -0,0 +1,30 @@
//
// MPExpressionTreeElement.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPTokenStream.h"
#import "MPParseError.h"
#import "MPTokenStream.h"
#define MPTokenStreamRecordCurrentLocation(tokenStream) NSUInteger __tokenStreamStart = tokenStream.currentToken.range.location
#define MPTokenStreamRecordedRange(tokenStream) NSMakeRange(__tokenStreamStart, tokenStream.currentToken.range.location - __tokenStreamStart)
@protocol MPExpressionTreeElement <NSObject>
@required
- (instancetype)init;
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream;
- (NSRange)range;
- (BOOL)validate:(MPParseError *__autoreleasing *)error;
- (NSDecimalNumber *)evaluate;
- (NSArray *)expressionElements; // Converts
@end

View File

@@ -582,6 +582,9 @@
[allowedCharacters addCharactersInString:[NSString stringWithFormat:@"+-*= !%@", decimalSeparator]];
if (characters.length == 1 && [characters stringByTrimmingCharactersInSet:allowedCharacters].length == 0) {
if ([characters isEqualToString:@"*"]) {
characters = @"⋅";
}
[self.expressionStorage replaceItemsInRangePath:self.selection
referenceFrame:MPSymbolReferenceFrame
withElements:@[characters]];

22
MathPad/MPFactor.h Normal file
View File

@@ -0,0 +1,22 @@
//
// MPFactor.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPExpressionTreeElement.h"
#import "MPValueGroup.h"
#import "MPOperatorChain.h"
@interface MPFactor : NSObject <MPExpressionTreeElement>
@property (nonatomic) BOOL hasMultiplicationSymbol;
@property (nonatomic, strong) MPOperatorChain *operatorChain;
@property (nonatomic, strong) id<MPValue> value;
- (NSRange)multiplicationSymbolRange;
@end

95
MathPad/MPFactor.m Normal file
View File

@@ -0,0 +1,95 @@
//
// MPFactor.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFactor.h"
#import "MPMathRules.h"
@implementation MPFactor {
NSRange _multiplicationSymbolRange;
}
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
MPToken *token = tokenStream.currentToken;
if (token.tokenType == MPMultiplicationSymbolToken) {
_multiplicationSymbolRange = token.range;
[tokenStream currentTokenConsumed];
} else {
_multiplicationSymbolRange = NSMakeRange(NSNotFound, 0);
}
if (tokenStream.currentToken.tokenType == MPOperatorListToken) {
_operatorChain = [[MPOperatorChain alloc] initWithTokenStream:tokenStream];
}
MPValueGroup *valueGroup = [[MPValueGroup alloc] initWithTokenStream:tokenStream];
_value = [tokenStream consumeSuffixesForValue:valueGroup];
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
if (_multiplicationSymbolRange.location == NSNotFound) {
return self.value.range;
}
return NSUnionRange(_multiplicationSymbolRange, self.value.range);
}
- (NSRange)multiplicationSymbolRange
{
return _multiplicationSymbolRange;
}
- (BOOL)hasMultiplicationSymbol
{
return _multiplicationSymbolRange.location != NSNotFound;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
if (self.operatorChain.numberOfOperators > [[MPMathRules sharedRules] maximumOperatorChainLengthInMultiplication]) {
if (error) {
*error = MPParseError(self.operatorChain.range, @"Too many operators in Multiplication");
}
return NO;
}
return [self.value validate:error];
}
- (NSDecimalNumber *)evaluate
{
NSDecimalNumber *value = [self.value evaluate];
if ([value isNotEqualTo:[NSDecimalNumber notANumber]] && self.operatorChain) {
value = [value decimalNumberByMultiplyingBy:[self.operatorChain evaluate]];
}
return value;
}
- (NSArray *)expressionElements
{
NSMutableArray *elements = [[NSMutableArray alloc] init];
if (self.hasMultiplicationSymbol) {
[elements addObject:@"*"];
}
[elements addObjectsFromArray:self.value.expressionElements];
return elements;
}
@end

16
MathPad/MPFactorial.h Normal file
View File

@@ -0,0 +1,16 @@
//
// MPFactorial.h
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "MPValueGroup.h"
@interface MPFactorial : NSObject <MPValue>
@property (nonatomic, strong) id<MPValue> value;
@end

58
MathPad/MPFactorial.m Normal file
View File

@@ -0,0 +1,58 @@
//
// MPFactorial.m
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFactorial.h"
@implementation MPFactorial
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
if (tokenStream.currentToken.tokenType != MPFactorialToken) {
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
return nil;
} else {
[tokenStream currentTokenConsumed];
}
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return NSMakeRange(0, 0);
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
return [self.value validate:error];
}
- (NSDecimalNumber *)evaluate
{
double value = [self.value evaluate].doubleValue;
return [[NSDecimalNumber alloc] initWithDouble:tgamma(value+1)];
}
- (NSArray *)expressionElements
{
return @[@"!"];
}
@end

View File

@@ -0,0 +1,16 @@
//
// MPFractionFunction.h
// MathPad
//
// Created by Kim Wittenburg on 07.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <MathKit/MathKit.h>
@interface MPFractionFunction : MPFunction
@property (nonatomic, strong) MPExpression *nominatorExpression;
@property (nonatomic, strong) MPExpression *denominatorExpression;
@end

View File

@@ -0,0 +1,36 @@
//
// MPFractionFunction.m
// MathPad
//
// Created by Kim Wittenburg on 07.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFractionFunction.h"
@implementation MPFractionFunction
MPFunctionAccessorImplementation(NominatorExpression, _nominatorExpression)
MPFunctionAccessorImplementation(DenominatorExpression, _denominatorExpression)
- (NSArray *)childrenAccessors
{
return @[@"nominatorExpression", @"denominatorExpression"];
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
return [[self.nominatorExpression parse] validate:error] && [[self.denominatorExpression parse] validate:error];
}
- (NSDecimalNumber *)evaluate
{
return [[[self.nominatorExpression parse] evaluate] decimalNumberByDividingBy:[[self.denominatorExpression parse] evaluate]];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ / %@", self.nominatorExpression, self.denominatorExpression];
}
@end

View File

@@ -0,0 +1,16 @@
//
// MPFractionFunctionLayout.h
// MathPad
//
// Created by Kim Wittenburg on 07.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFunctionLayout.h"
#import "MPFractionFunction.h"
@interface MPFractionFunctionLayout : MPFunctionLayout
- (MPFractionFunction *)fractionFunction;
@end

View File

@@ -0,0 +1,87 @@
//
// MPFractionFunctionLayout.m
// MathPad
//
// Created by Kim Wittenburg on 07.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFractionFunctionLayout.h"
#import "MPExpressionLayout.h"
#define kFractionFunctionLineWidth 2
#define kFractionFunctionHorizontalInset 2
#define kFractionFunctionNominatorOffset 0
#define kFractionFunctionDenominatorOffset 0
#define MPFractionMiddle (CTFontGetAscent((CTFontRef)self.font) / 2)
@implementation MPFractionFunctionLayout
- (MPFractionFunction *)fractionFunction
{
return (MPFractionFunction *)self.function;
}
- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index
{
return 1;
}
- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index
{
return 0;
}
- (NSIndexSet *)indexesOfRemainingChildren
{
return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 1)];
}
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
{
if (index == 0) {
CGFloat y = MPFractionMiddle + kFractionFunctionLineWidth / 2;
return NSMakePoint(0, y);
} else {
NSRect denominatorBounds = [self childLayoutAtIndex:1].bounds;
CGFloat y = CTFontGetAscent((CTFontRef)self.font) / 2 - kFractionFunctionLineWidth / 2;
y -= denominatorBounds.size.height - denominatorBounds.origin.y;
return NSMakePoint(0, y);
}
}
- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index
{
return YES;
}
- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point
{
if (point.x < self.bounds.size.width / 2) {
return [NSIndexPath indexPathWithIndex:0];
} else {
return [NSIndexPath indexPathWithIndex:1];
}
}
- (NSRect)generateBounds
{
NSRect nominatorBounds = [self childLayoutAtIndex:0].bounds;
NSRect denominatorBounds = [self childLayoutAtIndex:1].bounds;
NSRect bounds;
bounds.origin.x = 0;
CGFloat y = CTFontGetAscent((CTFontRef)self.font) / 2 - kFractionFunctionLineWidth / 2;
y -= denominatorBounds.size.height;
bounds.size.width = MAX(nominatorBounds.size.width, denominatorBounds.size.width);
bounds.size.height = nominatorBounds.size.height + denominatorBounds.size.height + kFractionFunctionLineWidth;
return bounds;
}
- (void)draw
{
CGFloat y = CTFontGetAscent((CTFontRef)self.font) / 2 - kFractionFunctionLineWidth / 2;
NSRectFill(NSMakeRect(0, y, self.bounds.size.width, kFractionFunctionLineWidth));
}
@end

View File

@@ -0,0 +1,15 @@
//
// MPFunction+MPValue.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <MathKit/MathKit.h>
#import "MPValueGroup.h"
#import "MPFunction+MPToken.h"
@interface MPFunction (MPValue) <MPValue>
@end

View File

@@ -0,0 +1,28 @@
//
// MPFunction+MPValue.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFunction+MPValue.h"
@implementation MPFunction (MPValue)
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
[tokenStream beginIgnoringWhitespaceTokens];
if (tokenStream.currentToken.tokenType != MPGenericFunctionToken) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Function" userInfo:nil];
}
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
return [self init];
}
- (NSArray *)expressionElements
{
return @[self];
}
@end

View File

@@ -9,7 +9,6 @@
@import Foundation;
#import "MPExpressionElement.h"
#import "MPParseError.h"
#import "MPTerm.h"
#define MPFunctionAccessorImplementation(Accessor, variableName) \
- (void)set##Accessor:(MPExpression *)value \
@@ -50,7 +49,8 @@
#pragma mark Evaluating Functions
- (MPTerm *)parseWithError:(MPParseError *__autoreleasing *)error; // Override
- (BOOL)validate:(MPParseError *__autoreleasing *)error; // Override
- (NSDecimalNumber *)evaluate; // Override
#pragma mark Messages
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath

View File

@@ -15,6 +15,8 @@
#import "MPParenthesisFunction.h"
#import "MPParenthesisFunctionLayout.h"
#import "MPPowerFunctionLayout.h"
#import "MPFractionFunctionLayout.h"
#import "MPFractionFunction.h"
#import "NSIndexPath+MPAdditions.h"
@@ -31,6 +33,8 @@
return [[MPParenthesisFunctionLayout alloc] initWithFunction:function parent:parent];
} else if (class == [MPPowerFunction class]) {
return [[MPPowerFunctionLayout alloc] initWithFunction:function parent:parent];
} else if (class == [MPFractionFunction class]) {
return [[MPFractionFunctionLayout alloc] initWithFunction:function parent:parent];
}
return [[self alloc] initWithFunction:function
parent:parent];
@@ -67,6 +71,11 @@
return [self cachableObjectForIndex:actualIndex generator:generator];
}
- (NSUInteger)numberOfChildren
{
return self.function.numberOfChildren;
}
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
{
return [self cachableObjectForIndex:index generator:^id{

19
MathPad/MPFunctionValue.h Normal file
View File

@@ -0,0 +1,19 @@
//
// MPFunctionValue.h
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "MPValueGroup.h"
@interface MPFunctionValue : NSObject <MPValue>
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream; // May return an MPFunctionValue or a powered function
@property (nonatomic, copy) NSString *functionName;
@property (nonatomic, strong) MPValueGroup *valueGroup;
@end

151
MathPad/MPFunctionValue.m Normal file
View File

@@ -0,0 +1,151 @@
//
// MPFunctionValue.m
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFunctionValue.h"
#import "MPMathRules.h"
double defaultFunction(double value) {return value;};
@implementation MPFunctionValue {
NSDecimalNumber *(^_function)(NSDecimalNumber *);
}
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
switch (tokenStream.currentToken.tokenType) {
case MPSinToken:
[tokenStream currentTokenConsumed];
self.functionName = @"sin";
return [self initWithTokenStream:tokenStream
function:&sin
takesArcValue:YES
returnsArcValue:NO];
case MPCosToken:
[tokenStream currentTokenConsumed];
self.functionName = @"cos";
return [self initWithTokenStream:tokenStream
function:&cos
takesArcValue:YES
returnsArcValue:NO];
case MPTanToken:
[tokenStream currentTokenConsumed];
self.functionName = @"tan";
return [self initWithTokenStream:tokenStream
function:&tan
takesArcValue:YES
returnsArcValue:NO];
case MPASinToken:
[tokenStream currentTokenConsumed];
self.functionName = @"asin";
return [self initWithTokenStream:tokenStream
function:&asin
takesArcValue:YES
returnsArcValue:NO];
case MPACosToken:
[tokenStream currentTokenConsumed];
self.functionName = @"acos";
return [self initWithTokenStream:tokenStream
function:&acos
takesArcValue:YES
returnsArcValue:NO];
case MPATanToken:
[tokenStream currentTokenConsumed];
self.functionName = @"atan";
return [self initWithTokenStream:tokenStream
function:&atan
takesArcValue:YES
returnsArcValue:NO];
default:
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Function" userInfo:nil];
break;
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
function:(double (*)(double))function
takesArcValue:(BOOL)takesArc
returnsArcValue:(BOOL)returnsArc
{
self = [self init];
if (self) {
_valueGroup = [[MPValueGroup alloc] initWithTokenStream:tokenStream];
id __weak weakSelf = self;
_function = ^(NSDecimalNumber *value){
if (takesArc) {
value = [weakSelf convertToRadiantsIfNecessary:value];
}
NSDecimalNumber *returnValue = [[NSDecimalNumber alloc] initWithDouble:function(value.doubleValue)];
if (returnsArc) {
returnValue = [weakSelf convertToDegreesIfNecessary:returnValue];
}
return returnValue;
};
}
return self;
}
- (NSDecimalNumber *)convertToRadiantsIfNecessary:(NSDecimalNumber *)degrees
{
if ([MPMathRules sharedRules].isUsingDegrees) {
// * M_PI / 180
return [[degrees decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithInteger:180]];
} else {
return degrees;
}
}
- (NSDecimalNumber *)convertToDegreesIfNecessary:(NSDecimalNumber *)radiants
{
if ([MPMathRules sharedRules].isUsingDegrees) {
// * 180 / M_PI
return [[radiants decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInteger:180]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]];
} else {
return radiants;
}
}
- (NSRange)range
{
return NSMakeRange(0, 0);
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
return [self.valueGroup validate:error];
}
- (NSDecimalNumber *)evaluate
{
return _function([self.valueGroup evaluate]);
}
- (NSArray *)expressionElements
{
NSMutableArray *elements = [[NSMutableArray alloc] init];
[elements addObject:self.functionName];
[elements addObjectsFromArray:self.valueGroup.expressionElements];
return elements;
}
@end

View File

@@ -13,6 +13,7 @@
#import "MPSumFunction.h"
#import "MPParenthesisFunction.h"
#import "MPPowerFunction.h"
#import "MPFractionFunction.h"
@class MPFunctionTemplateItem;
@@ -205,6 +206,7 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo
squareFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"2"];
MPPowerFunction *cubicFunction = [[MPPowerFunction alloc] init];
cubicFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"3"];
MPFractionFunction *fractionFunction = [[MPFractionFunction alloc] init];
self.functionPrototypes = @[
@{@"function": sumFunction,
@"name": NSLocalizedString(@"Sum", @"Sum Function Name")},
@@ -215,7 +217,9 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo
@{@"function": cubicFunction,
@"name": NSLocalizedString(@"Cubic", @"Cubic Function Name")},
@{@"function": powerFunction,
@"name": NSLocalizedString(@"Power", @"Power Function Name")}
@"name": NSLocalizedString(@"Power", @"Power Function Name")},
@{@"function": fractionFunction,
@"name": NSLocalizedString(@"Fraction", @"Fraction Function Name")}
];
[self.collectionView addObserver:self
forKeyPath:@"hoverItem"

View File

@@ -55,6 +55,8 @@
@end
@interface MPLayout (MPSubclassImplement)
- (NSUInteger)numberOfChildren;
- (BOOL)drawsChildrenManually;
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index; // To be implemented
- (NSRect)generateBounds; // To be implemented
- (NSRect)boundingRectForRange:(NSRange)range; // To be implemented, use rangePath instead, this one has wrong origin

View File

@@ -174,6 +174,11 @@
return bounds;
}
- (BOOL)drawsChildrenManually
{
return NO;
}
- (void)drawAtPoint:(NSPoint)point
{
NSAffineTransform *transform = [NSAffineTransform transform];
@@ -181,6 +186,13 @@
yBy:point.y];
[transform concat];
[self draw];
if (!self.drawsChildrenManually) {
for (NSUInteger index = 0; index < [self numberOfChildren]; index++) {
MPLayout *childLayout = [self childLayoutAtIndex:index];
NSPoint offset = [self offsetOfChildLayoutAtIndex:index];
[childLayout drawAtPoint:offset];
}
}
[transform invert];
[transform concat];
}

View File

@@ -8,10 +8,8 @@
#import <Foundation/Foundation.h>
FOUNDATION_EXPORT NSString *MPMathRulesAllowsImplicitMultiplicationKey;
FOUNDATION_EXPORT NSString *MPMathRulesMaximumOperatorChainLengthKey;
FOUNDATION_EXPORT NSString *MPMathRulesMaximumOperatorChainLengthInMultiplicationKey;
FOUNDATION_EXPORT NSString *MPMathRulesMaximumOperatorChainLengthInFunctionKey;
FOUNDATION_EXPORT NSString *MPMathRulesIsUsingDegreesKey;
@interface MPMathRules : NSObject
@@ -20,11 +18,9 @@ FOUNDATION_EXPORT NSString *MPMathRulesIsUsingDegreesKey;
@property (nonatomic, getter = isUsingUserDefaultValues) BOOL usingUserDefaultValues;
@property (nonatomic) BOOL allowsImplicitMultiplication; // wether 2 3 is equal to 6 or error
// Default value uses the key "..." in NSUserDefaults or ... if the key does not exist.
@property (nonatomic) NSUInteger maximumOperatorChainLength; // +--++-5 -> Chain length: 6, 2 default (sign of number and operator) (0 is invalid?)
@property (nonatomic) NSUInteger maximumOperatorChainLengthInMultiplication; // Default: 1, 0 means actually 0
@property (nonatomic) NSUInteger maximumOperatorChainLengthInFunction; // For sin, cos, tan. Default: 1
@property (nonatomic) BOOL isUsingDegrees;

View File

@@ -8,10 +8,8 @@
#import "MPMathRules.h"
NSString *MPMathRulesAllowsImplicitMultiplicationKey = @"MPMathRulesAllowsImplicitMultiplicationKey";
NSString *MPMathRulesMaximumOperatorChainLengthKey = @"MPMathRulesMaximumOperatorChainLengthKey";
NSString *MPMathRulesMaximumOperatorChainLengthInMultiplicationKey = @"MPMathRulesMaximumOperatorChainLengthInMultiplicationKey";
NSString *MPMathRulesMaximumOperatorChainLengthInFunctionKey = @"MPMathRulesMaximumOperatorChainLengthInFunctionKey";
NSString *MPMathRulesIsUsingDegreesKey = @"MPMathRulesIsUsingDegreesKey";
@implementation MPMathRules
@@ -35,16 +33,12 @@ static MPMathRules *sharedRules;
if (self) {
_usingUserDefaultValues = YES;
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSNumber *userDefaultsAllowImplicitMultiplication = [userDefaults objectForKey:MPMathRulesAllowsImplicitMultiplicationKey];
NSNumber *userDefaultsMaximumOperatorChainLength = [userDefaults objectForKey:MPMathRulesMaximumOperatorChainLengthKey];
NSNumber *userDefaultsMaximumOperatorChainLengthInMultiplication = [userDefaults objectForKey:MPMathRulesMaximumOperatorChainLengthInMultiplicationKey];
NSNumber *userDefaultsMaximumOperatorChainLengthInFunction = [userDefaults objectForKey:MPMathRulesMaximumOperatorChainLengthInFunctionKey];
NSNumber *userDefaultsIsUsingDegrees = [userDefaults objectForKey:MPMathRulesIsUsingDegreesKey];
_allowsImplicitMultiplication = userDefaultsAllowImplicitMultiplication.boolValue;
_maximumOperatorChainLength = userDefaultsMaximumOperatorChainLength != nil ? userDefaultsMaximumOperatorChainLength.unsignedIntegerValue : 2;
_maximumOperatorChainLengthInMultiplication = userDefaultsMaximumOperatorChainLengthInMultiplication != nil ? userDefaultsMaximumOperatorChainLengthInMultiplication.unsignedIntegerValue : 1;
_maximumOperatorChainLengthInFunction = userDefaultsMaximumOperatorChainLengthInFunction != nil ? userDefaultsMaximumOperatorChainLengthInFunction.unsignedIntegerValue : 1;
_isUsingDegrees = userDefaultsIsUsingDegrees.boolValue;
}
return self;
@@ -54,22 +48,11 @@ static MPMathRules *sharedRules;
{
_usingUserDefaultValues = usingUserDefaultValues;
// Save the current values
self.allowsImplicitMultiplication = self.allowsImplicitMultiplication;
self.maximumOperatorChainLength = self.maximumOperatorChainLength;
self.maximumOperatorChainLengthInMultiplication = self.maximumOperatorChainLengthInMultiplication;
self.maximumOperatorChainLengthInFunction = self.maximumOperatorChainLengthInFunction;
self.isUsingDegrees = self.isUsingDegrees;
}
- (void)setAllowsImplicitMultiplication:(BOOL)allowsImplicitMultiplication
{
_allowsImplicitMultiplication = allowsImplicitMultiplication;
if (self.isUsingUserDefaultValues) {
[[NSUserDefaults standardUserDefaults] setBool:allowsImplicitMultiplication
forKey:MPMathRulesAllowsImplicitMultiplicationKey];
}
}
- (void)setMaximumOperatorChainLength:(NSUInteger)maximumOperatorChainLength
{
_maximumOperatorChainLength = maximumOperatorChainLength;
@@ -88,15 +71,6 @@ static MPMathRules *sharedRules;
}
}
- (void)setMaximumOperatorChainLengthInFunction:(NSUInteger)maximumOperatorChainLengthInFunction
{
_maximumOperatorChainLengthInFunction = maximumOperatorChainLengthInFunction;
if (self.isUsingUserDefaultValues) {
[[NSUserDefaults standardUserDefaults] setObject:@(maximumOperatorChainLengthInFunction)
forKey:MPMathRulesMaximumOperatorChainLengthInFunctionKey];
}
}
- (void)setIsUsingDegrees:(BOOL)isUsingDegrees
{
_isUsingDegrees = isUsingDegrees;

16
MathPad/MPNumber.h Normal file
View File

@@ -0,0 +1,16 @@
//
// MPNumber.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPValueGroup.h"
@interface MPNumber : NSObject <MPValue>
@property (nonatomic, strong) NSDecimalNumber *number;
@end

61
MathPad/MPNumber.m Normal file
View File

@@ -0,0 +1,61 @@
//
// MPNumber.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPNumber.h"
@implementation MPNumber {
NSRange _range;
}
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
MPToken *token = tokenStream.currentToken;
if (token.tokenType == MPNumberToken) {
self.number = [NSDecimalNumber decimalNumberWithString:token.stringValue locale:[NSLocale currentLocale]];
_range = token.range;
} else {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Number" userInfo:nil];
}
[tokenStream currentTokenConsumed];
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return _range;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
return YES;
}
- (NSDecimalNumber *)evaluate
{
return self.number;
}
- (NSArray *)expressionElements
{
return @[[self.number descriptionWithLocale:[NSLocale currentLocale]]];
}
@end

17
MathPad/MPOperatorChain.h Normal file
View File

@@ -0,0 +1,17 @@
//
// MPOperatorChain.h
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "MPExpressionTreeElement.h"
@interface MPOperatorChain : NSObject <MPExpressionTreeElement>
@property (nonatomic) BOOL negating;
@property (nonatomic) NSUInteger numberOfOperators;
@end

75
MathPad/MPOperatorChain.m Normal file
View File

@@ -0,0 +1,75 @@
//
// MPOperatorChain.m
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPOperatorChain.h"
@implementation MPOperatorChain {
NSRange _range;
}
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
MPToken *currentToken = tokenStream.currentToken;
if (currentToken.tokenType != MPOperatorListToken) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Operators" userInfo:nil];
}
NSString *operatorString = currentToken.stringValue;
_range = currentToken.range;
operatorString = [[operatorString componentsSeparatedByString:@" "] componentsJoinedByString:@""];
_negating = NO;
_numberOfOperators = operatorString.length;
for (NSUInteger index = 0; index < _numberOfOperators; index++) {
if ([[operatorString substringWithRange:NSMakeRange(index, 1)] isEqualToString:@"-"]) {
_negating = !_negating;
}
}
[tokenStream currentTokenConsumed];
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return _range;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
return YES;
}
- (NSDecimalNumber *)evaluate
{
return self.negating ? [[NSDecimalNumber alloc] initWithInteger:-1] : [NSDecimalNumber one];
}
- (NSArray *)expressionElements
{
NSMutableString *text = [[NSMutableString alloc] init];
for (NSUInteger index = 1; index < self.numberOfOperators; index++) {
[text appendString:@"+"];
}
if (self.negating) {
[text appendString:@"-"];
}
return @[text.copy];
}
@end

View File

@@ -8,7 +8,6 @@
//
#import "MPParenthesisFunction.h"
#import "MPExpressionEvaluator.h"
@implementation MPParenthesisFunction
@@ -19,11 +18,14 @@ MPFunctionAccessorImplementation(Expression, _expression)
return @[@"expression"];
}
- (MPTerm *)parseWithError:(MPParseError *__autoreleasing *)error
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
MPExpressionEvaluator *evaluator = [[MPExpressionEvaluator alloc] initWithExpression:self.expression];
return [evaluator parseExpectingVariable:NO
error:error];
return [[self.expression parse] validate:error];
}
- (NSDecimalNumber *)evaluate
{
return [[self.expression parse] evaluate];
}
- (NSString *)description

View File

@@ -154,6 +154,12 @@
return bounds;
}
#warning Let the children be drawn automatically
- (BOOL)drawsChildrenManually
{
return YES;
}
- (void)draw
{
NSBezierPath *openingParens = self.transformedOpeningParens;

View File

@@ -7,10 +7,10 @@
//
#import <MathKit/MathKit.h>
#import "MPSuffixFunction.h"
@interface MPPowerFunction : MPFunction
@interface MPPowerFunction : MPSuffixFunction
@property (nonatomic, strong) MPTerm *baseTerm;
@property (nonatomic, strong) MPExpression *exponentExpression;
@end

View File

@@ -7,7 +7,7 @@
//
#import "MPPowerFunction.h"
#import "MPExpressionEvaluator.h"
#import "MPExpression.h"
@implementation MPPowerFunction
@@ -18,19 +18,24 @@ MPFunctionAccessorImplementation(ExponentExpression, _exponentExpression)
return @[@"exponentExpression"];
}
- (MPTerm *)parseWithError:(MPParseError *__autoreleasing *)error
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
MPExpressionEvaluator *exponent = [[MPExpressionEvaluator alloc] initWithExpression:self.exponentExpression];
MPTerm *exponentTerm = [exponent parseExpectingVariable:NO
error:error];
if (exponentTerm == nil) {
return nil;
if (!self.baseValue) {
if (error) {
*error = MPParseError(NSMakeRange([self.parent convertIndex:[self.parent indexOfElement:self]
fromReferenceFrame:MPElementReferenceFrame
toReferenceFrame:MPSymbolReferenceFrame], 0), @"No Base for Power");
}
return NO;
}
return [[MPTerm alloc] initWithBlock:^NSDecimalNumber *{
double power = pow([self.baseTerm evaluate].doubleValue, [exponentTerm evaluate].doubleValue);
return [[NSDecimalNumber alloc] initWithDouble:power];
}];
return [self.baseValue validate:error] && [[self.exponentExpression parse] validate:error];
}
- (NSDecimalNumber *)evaluate
{
NSDecimalNumber *base = [self.baseValue evaluate];
NSDecimalNumber *exponent = [[self.exponentExpression parse] evaluate];
return [[NSDecimalNumber alloc] initWithDouble:pow(base.doubleValue, exponent.doubleValue)];
}
- (NSString *)description

View File

@@ -7,9 +7,7 @@
//
#import "MPPowerFunctionLayout.h"
#define kMPEmptyBoxHeight (CTFontGetDescent((CTFontRef)self.font) + CTFontGetAscent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font))
#define kMPEmptyBoxYOrigin (-(CTFontGetDescent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font)))
#import "MPExpressionLayout.h"
#define kPowerFunctionExponentXOffset 1
#define kPowerFunctionTrailingOffset 2
@@ -36,7 +34,7 @@
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
{
CGFloat y = self.baseBounds.size.height / 2;
CGFloat y = (self.baseBounds.size.height + self.baseBounds.origin.y) / 2;
return NSMakePoint(kPowerFunctionExponentXOffset, y);
}
@@ -60,9 +58,6 @@
}
- (void)draw
{
MPLayout *exponentLayout = [self childLayoutAtIndex:0];
[exponentLayout drawAtPoint:[self offsetOfChildLayoutAtIndex:0]];
}
{}
@end

23
MathPad/MPProduct.h Normal file
View File

@@ -0,0 +1,23 @@
//
// MPProduct.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPExpressionTreeElement.h"
#import "MPFactor.h"
@interface MPProduct : NSObject <MPExpressionTreeElement>
- (NSArray *)factors;
- (void)appendFactor:(MPFactor *)factor;
- (void)insertFactor:(MPFactor *)factor
atIndex:(NSUInteger)index;
- (void)removeFactor:(MPFactor *)factor;
- (void)removeFactorAtIndex:(NSUInteger)index;
- (MPFactor *)factorAtIndex:(NSUInteger)index;
@end

125
MathPad/MPProduct.m Normal file
View File

@@ -0,0 +1,125 @@
//
// MPProduct.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPProduct.h"
#import "MPValueGroup.h"
@implementation MPProduct {
NSMutableArray *_factors;
NSRange _range;
}
- (id)init
{
self = [super init];
if (self) {
_factors = [[NSMutableArray alloc] init];
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
MPTokenStreamRecordCurrentLocation(tokenStream);
while (tokenStream.currentToken.tokenType != MPOperatorListToken && tokenStream.currentToken.tokenType != MPEOFToken) {
[_factors addObject:[[MPFactor alloc] initWithTokenStream:tokenStream]];
}
_range = MPTokenStreamRecordedRange(tokenStream);
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return _range;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
MPFactor *factor = _factors[0];
if (factor.hasMultiplicationSymbol) {
if (error) {
*error = MPParseError(factor.multiplicationSymbolRange, @"Unexpected Symbol.");
}
}
if (![factor.value validate:error]) {
return NO;
}
for (NSUInteger index = 1; index < _factors.count; index++) {
factor = _factors[index];
if (![factor validate:error]) {
return NO;
}
}
return YES;
}
- (NSDecimalNumber *)evaluate
{
NSDecimalNumber *value = [NSDecimalNumber one];
for (MPFactor *factor in _factors) {
NSDecimalNumber *currentValue = [factor evaluate];
if ([currentValue isEqualToNumber:[NSDecimalNumber notANumber]]) {
value = currentValue;
break;
}
value = [value decimalNumberByMultiplyingBy:currentValue];
if ([value compare:@(0)] == NSOrderedSame) {
break;
}
}
return value;
}
- (NSArray *)expressionElements
{
NSMutableArray *elements = [[NSMutableArray alloc] init];
for (MPFactor *factor in _factors) {
[elements addObjectsFromArray:factor.expressionElements];
}
return elements;
}
- (NSArray *)factors
{
return _factors;
}
- (void)appendFactor:(MPFactor *)factor
{
[_factors addObject:factor];
}
- (void)insertFactor:(MPFactor *)factor
atIndex:(NSUInteger)index
{
[_factors insertObject:factor
atIndex:index];
}
- (void)removeFactor:(MPFactor *)factor
{
[_factors removeObject:factor];
}
- (void)removeFactorAtIndex:(NSUInteger)index
{
[_factors removeObjectAtIndex:index];
}
- (MPFactor *)factorAtIndex:(NSUInteger)index
{
return [_factors objectAtIndex:index];
}
@end

View File

@@ -0,0 +1,15 @@
//
// MPSuffixFunction.h
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <MathKit/MathKit.h>
@interface MPSuffixFunction : MPFunction
@property (nonatomic, strong) id<MPValue> baseValue;
@end

View File

@@ -0,0 +1,13 @@
//
// MPSuffixFunction.m
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPSuffixFunction.h"
@implementation MPSuffixFunction
@end

View File

@@ -9,12 +9,8 @@
#import "MPSumFunction.h"
#import "MPExpression.h"
#import "MPExpressionEvaluator.h"
#import "MPEvaluationContext.h"
// TODO: Use this macro elsewhere
#define ReturnIfNil(test) if(test == nil) return nil
@implementation MPSumFunction
MPFunctionAccessorImplementation(StartExpression, _startExpression)
@@ -27,42 +23,47 @@ MPFunctionAccessorImplementation(SumExpression, _sumExpression)
}
#pragma mark Evaluating Functions
- (MPTerm *)parseWithError:(MPParseError *__autoreleasing *)error
{
MPExpressionEvaluator *startEvaluator = [[MPExpressionEvaluator alloc] initWithExpression:self.startExpression];
MPTerm *start = [startEvaluator parseExpectingVariable:YES
error:error];
ReturnIfNil(start);
MPExpressionEvaluator *targetEvaluator = [[MPExpressionEvaluator alloc] initWithExpression:self.targetExpression];
MPTerm *target = [targetEvaluator parseExpectingVariable:NO
error:error];
ReturnIfNil(target);
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
MPExpressionTree *startTree = [self.startExpression parse];
if (![startTree validateExpectingVariableDefinition:YES error:error]) {
return NO;
}
NSString *variable = startEvaluator.definedVariable.copy;
MPExpressionTree *targetTree = [self.targetExpression parse];
if (![targetTree validate:error]) {
return NO;
}
[[MPEvaluationContext sharedContext] push];
[[MPEvaluationContext sharedContext] defineVariable:variable withValue:[NSNull null]];
MPExpressionEvaluator *sumEvaluator = [[MPExpressionEvaluator alloc] initWithExpression:self.sumExpression];
MPTerm *sum = [sumEvaluator parseExpectingVariable:NO
error:error];
ReturnIfNil(sum);
[[MPEvaluationContext sharedContext] defineVariable:startTree.definedVariable withValue:[NSDecimalNumber notANumber]];
MPExpressionTree *sumTree = [self.sumExpression parse];
if (![sumTree validate:error]) {
return NO;
}
[[MPEvaluationContext sharedContext] pop];
return YES;
}
- (NSDecimalNumber *)evaluate
{
MPExpressionTree *startTree = [self.startExpression parse];
NSDecimalNumber *start = [startTree evaluate];
NSDecimalNumber *target = [[self.targetExpression parse] evaluate];
MPExpressionTree *sumTree = [self.sumExpression parse];
return [[MPTerm alloc] initWithBlock:^NSDecimalNumber *{
[[MPEvaluationContext sharedContext] push];
NSDecimalNumber *value = [NSDecimalNumber zero];
NSDecimalNumber *startValue = [start evaluate];
NSDecimalNumber *targetValue = [target evaluate];
for (NSDecimalNumber *iterator = startValue;
[iterator compare:targetValue] <= 0 ;
iterator = [iterator decimalNumberByAdding:[[NSDecimalNumber alloc] initWithInteger:1]]) {
[[MPEvaluationContext sharedContext] defineVariable:variable withValue:iterator];
value = [value decimalNumberByAdding:[sum evaluate]];
}
[[MPEvaluationContext sharedContext] pop];
return value;
}];
NSDecimalNumber *value = [NSDecimalNumber zero];
[[MPEvaluationContext sharedContext] push];
for (NSDecimalNumber *current = start;
[current compare:target] <= 0;
current = [current decimalNumberByAdding:[[NSDecimalNumber alloc] initWithInteger:1]]) {
[[MPEvaluationContext sharedContext] defineVariable:startTree.definedVariable withValue:current];
value = [value decimalNumberByAdding:[sumTree evaluate]];
}
[[MPEvaluationContext sharedContext] pop];
return value;
}
#pragma mark Working With Functions

View File

@@ -154,20 +154,7 @@
NSRect localLineBounds = [self localLineBounds];
CGContextSetTextPosition(context, localLineBounds.origin.x, 0);
CTLineDraw(line, context);
// Draw the start function
MPLayout *startExpressionLayout = [self childLayoutAtIndex:0];
NSPoint startExpressionLocation = [self offsetOfChildLayoutAtIndex:0];
[startExpressionLayout drawAtPoint:startExpressionLocation];
// Draw the target function
MPLayout *targetExpressionLayout = [self childLayoutAtIndex:1];
[targetExpressionLayout drawAtPoint:[self offsetOfChildLayoutAtIndex:1]];
// Draw the sum function
MPLayout *sumExpressionLayout = [self childLayoutAtIndex:2];
[sumExpressionLayout drawAtPoint:[self offsetOfChildLayoutAtIndex:2]];
CFRelease(line);
}

19
MathPad/MPSummand.h Normal file
View File

@@ -0,0 +1,19 @@
//
// MPSummand.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPExpressionTreeElement.h"
#import "MPProduct.h"
#import "MPOperatorChain.h"
@interface MPSummand : NSObject <MPExpressionTreeElement>
@property (nonatomic, strong) MPOperatorChain *operatorChain;
@property (nonatomic, strong) MPProduct *product;
@end

71
MathPad/MPSummand.m Normal file
View File

@@ -0,0 +1,71 @@
//
// MPSummand.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPSummand.h"
#import "MPMathRules.h"
@implementation MPSummand
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
if (tokenStream.currentToken.tokenType == MPOperatorListToken) {
_operatorChain = [[MPOperatorChain alloc] initWithTokenStream:tokenStream];
}
_product = [[MPProduct alloc] initWithTokenStream:tokenStream];
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return NSUnionRange(self.operatorChain.range, self.product.range);
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
if (self.operatorChain.numberOfOperators > [MPMathRules sharedRules].maximumOperatorChainLength) {
if (error) {
*error = MPParseError(self.operatorChain.range, @"Too many operators.");
}
return NO;
}
return [self.product validate:error];
}
- (NSDecimalNumber *)evaluate
{
NSDecimalNumber *value = [self.product evaluate];
if ([value isNotEqualTo:[NSDecimalNumber notANumber]] && self.operatorChain) {
value = [value decimalNumberByMultiplyingBy:[self.operatorChain evaluate]];
}
return value;
}
-(NSArray *)expressionElements
{
NSMutableArray *elements = [[NSMutableArray alloc] init];
if (self.operatorChain) {
[elements addObjectsFromArray:self.operatorChain.expressionElements];
}
[elements addObjectsFromArray:self.product.expressionElements];
return @[self.operatorChain.expressionElements,];
}
@end

View File

@@ -1,32 +0,0 @@
//
// MPTerm.h
// MathPad
//
// Created by Kim Wittenburg on 27.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
@import Foundation;
@interface MPTerm : NSObject
- (instancetype)initWithBlock:(NSDecimalNumber *(^)())block; // Designated Initializer
- (instancetype)initWithNumber:(NSDecimalNumber *)number;
- (instancetype)initWithSummands:(NSArray *)summands; // array of MPTerms
- (instancetype)initWithFactors:(NSArray *)factors; // array of MPTerms
- (instancetype)initWithVariable:(NSString *)variable;
- (instancetype)initWithFactorialOfTerm:(MPTerm *)term;
- (instancetype)initWithSinOfTerm:(MPTerm *)term;
- (instancetype)initWithCosOfTerm:(MPTerm *)term;
- (instancetype)initWithTanOfTerm:(MPTerm *)term;
- (instancetype)initWithInverseSinOfTerm:(MPTerm *)term;
- (instancetype)initWithInverseCosOfTerm:(MPTerm *)term;
- (instancetype)initWithInverseTanOfTerm:(MPTerm *)term;
- (NSDecimalNumber *)evaluate;
@end

View File

@@ -1,149 +0,0 @@
//
// MPTerm.m
// MathPad
//
// Created by Kim Wittenburg on 27.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPTerm.h"
#import "MPEvaluationContext.h"
#import "MPMathRules.h"
@interface MPTerm ()
@property (nonatomic, copy) NSDecimalNumber *(^block)();
@end
@implementation MPTerm
- (instancetype)initWithBlock:(NSDecimalNumber *(^)())block
{
self = [super init];
if (self) {
self.block = block;
}
return self;
}
- (instancetype)initWithNumber:(NSDecimalNumber *)number
{
return [self initWithBlock:^NSDecimalNumber *{
return number;
}];
}
- (instancetype)initWithSummands:(NSArray *)summands
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *value = [NSDecimalNumber zero];
for (MPTerm *term in summands) {
value = [value decimalNumberByAdding:[term evaluate]];
}
return value;
}];
}
- (instancetype)initWithFactors:(NSArray *)factors
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *value = [NSDecimalNumber one];
for (MPTerm *term in factors) {
value = [value decimalNumberByMultiplyingBy:[term evaluate]];
}
return value;
}];
}
- (instancetype)initWithVariable:(NSString *)variable
{
return [self initWithBlock:^NSDecimalNumber *{
return [[MPEvaluationContext sharedContext] valueForVariable:variable];
}];
}
- (instancetype)initWithFactorialOfTerm:(MPTerm *)term
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *termValue = [term evaluate];
return [[NSDecimalNumber alloc] initWithDouble:tgamma(termValue.doubleValue + 1)];
}];
}
- (instancetype)initWithSinOfTerm:(MPTerm *)term
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *termValue = [term evaluate];
if ([MPMathRules sharedRules].isUsingDegrees) {
termValue = [[termValue decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithInteger:180]];
}
return [[NSDecimalNumber alloc] initWithDouble:sin(termValue.doubleValue)];
}];
}
- (instancetype)initWithCosOfTerm:(MPTerm *)term
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *termValue = [term evaluate];
if ([MPMathRules sharedRules].isUsingDegrees) {
termValue = [[termValue decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithInteger:180]]; }
return [[NSDecimalNumber alloc] initWithDouble:cos(termValue.doubleValue)];
}];
}
- (instancetype)initWithTanOfTerm:(MPTerm *)term
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *termValue = [term evaluate];
if ([MPMathRules sharedRules].isUsingDegrees) {
termValue = [[termValue decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithInteger:180]]; }
return [[NSDecimalNumber alloc] initWithDouble:tan(termValue.doubleValue)];
}];
}
- (instancetype)initWithInverseSinOfTerm:(MPTerm *)term
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *termValue = [term evaluate];
NSDecimalNumber *result = [[NSDecimalNumber alloc] initWithDouble:asin(termValue.doubleValue)];
if ([MPMathRules sharedRules].isUsingDegrees) {
result = [[result decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInteger:180]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]];
}
return result;
}];
}
- (instancetype)initWithInverseCosOfTerm:(MPTerm *)term
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *termValue = [term evaluate];
NSDecimalNumber *result = [[NSDecimalNumber alloc] initWithDouble:acos(termValue.doubleValue)];
if ([MPMathRules sharedRules].isUsingDegrees) {
result = [[result decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInteger:180]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]];
}
return result; }];
}
- (instancetype)initWithInverseTanOfTerm:(MPTerm *)term
{
return [self initWithBlock:^NSDecimalNumber *{
NSDecimalNumber *termValue = [term evaluate];
NSDecimalNumber *result = [[NSDecimalNumber alloc] initWithDouble:atan(termValue.doubleValue)];
if ([MPMathRules sharedRules].isUsingDegrees) {
result = [[result decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInteger:180]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]];
}
return result; }];
}
- (NSDecimalNumber *)evaluate
{
@try {
return self.block();
}
@catch (NSException *exception) {
return [NSDecimalNumber notANumber];
}
}
@end

View File

@@ -15,6 +15,9 @@ typedef NS_ENUM(NSUInteger, MPTokenType) {
MPSinToken,
MPCosToken,
MPTanToken,
MPASinToken,
MPACosToken,
MPATanToken,
MPNumberToken,
MPVariableToken,
MPFactorialToken,
@@ -23,11 +26,8 @@ typedef NS_ENUM(NSUInteger, MPTokenType) {
MPWhitespaceToken,
MPUnidentifiedToken,
MPCompoundToken
};
@protocol MPToken <NSObject>
- (MPTokenType)tokenType;
@@ -41,22 +41,8 @@ typedef NS_ENUM(NSUInteger, MPTokenType) {
@interface MPToken : NSObject <MPToken>
- (instancetype)initEOFTokenAtLocation:(NSUInteger)eofLocation;
- (instancetype)initWithRange:(NSRange)range
stringValue:(NSString *)input;
- (instancetype)initWithTokenType:(MPTokenType)tokenType
range:(NSRange)range
stringValue:(NSString *)input;
@end
@interface MPToken (MPTokenExtension)
// Methods are only available for respective token type
- (NSUInteger)numberOfOperators;
- (NSDecimalNumber *)operatorValue;
- (NSDecimalNumber *)number;
- (NSString *)variable;
@end

View File

@@ -23,23 +23,14 @@
return self;
}
- (instancetype)initWithRange:(NSRange)range stringValue:(NSString *)input
- (instancetype)initWithTokenType:(MPTokenType)tokenType
range:(NSRange)range
stringValue:(NSString *)input
{
self = [super init];
if (self) {
_range = range;
_stringValue = input.copy;
}
return self;
}
- (instancetype)initWithTokenType:(MPTokenType)tokenType
range:(NSRange)range
stringValue:(NSString *)input
{
self = [self initWithRange:range
stringValue:input];
if (self) {
_tokenType = tokenType;
}
return self;
@@ -65,40 +56,4 @@
return self.stringValue;
}
@end
@implementation MPToken (MPTokenExtension)
- (NSUInteger)numberOfOperators
{
NSString *operatorString = [[self.stringValue componentsSeparatedByString:@" "] componentsJoinedByString:@""];
return operatorString.length;
}
- (NSDecimalNumber *)operatorValue
{
NSString *operatorString = [[self.stringValue componentsSeparatedByString:@" "] componentsJoinedByString:@""];
NSDecimalNumber *value = [NSDecimalNumber one];
for (NSUInteger charIndex = 0; charIndex < operatorString.length; charIndex++) {
NSString *operator = [operatorString substringWithRange:NSMakeRange(charIndex, 1)];
if ([operator isEqualToString:@"-"]) {
value = [value decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInteger:-1]];
}
}
return value;
}
- (NSDecimalNumber *)number
{
return [NSDecimalNumber decimalNumberWithString:self.stringValue
locale:[NSLocale currentLocale]];
}
- (NSString *)variable
{
return self.stringValue;
}
@end
@end

View File

@@ -14,14 +14,15 @@
- (instancetype)initWithTokens:(NSArray *)tokens;
@property (nonatomic, copy) NSArray *tokens;
@property (nonatomic, getter=isIgnoringWhitespaceTokens) BOOL ignoringWhitespaceTokens; // Default: YES
@property (nonatomic) NSUInteger currentTokenIndex;
- (void)beginIgnoringWhitespaceTokens;
- (void)beginAcceptingWhitespaceTokens;
- (void)endIgnoringOrAcceptingWhitespaceTokens;
- (void)reset;
- (BOOL)hasMoreTokens;
- (MPToken *)nextToken;
- (MPToken *)nextTokenOfType:(MPTokenType)type;
- (MPToken *)currentToken;
- (MPToken *)peekNextToken;
- (void)currentTokenConsumed;
@end

View File

@@ -9,7 +9,12 @@
#import "MPTokenStream.h"
@implementation MPTokenStream {
NSUInteger _currentTokenIndex;
NSUInteger eofLocation;
BOOL *whitespaceIgnores;
NSUInteger maxWhitespaceIgnores;
NSUInteger currentWhitespaceState;
}
- (instancetype)initWithTokens:(NSArray *)tokens
@@ -17,65 +22,96 @@
self = [super init];
if (self) {
self.tokens = tokens;
self.ignoringWhitespaceTokens = YES;
whitespaceIgnores = malloc(10 * sizeof(BOOL));
maxWhitespaceIgnores = 10;
currentWhitespaceState = 0;
[self beginAcceptingWhitespaceTokens];
_currentTokenIndex = 0;
if (tokens.count > 0) {
eofLocation = NSMaxRange([tokens.lastObject range]);
} else {
eofLocation = 0;
}
[self reset];
}
return self;
}
- (void)beginAcceptingWhitespaceTokens
{
[self pushWhitespaceState:YES];
}
- (void)beginIgnoringWhitespaceTokens
{
[self pushWhitespaceState:NO];
}
- (void)pushWhitespaceState:(BOOL)state
{
currentWhitespaceState++;
if (currentWhitespaceState >= maxWhitespaceIgnores) {
maxWhitespaceIgnores += 10;
BOOL *reallocatedWhitespaceIgnores = realloc(whitespaceIgnores, maxWhitespaceIgnores);
if (reallocatedWhitespaceIgnores) {
whitespaceIgnores = reallocatedWhitespaceIgnores;
} else {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Realloc Failed" userInfo:nil];
}
}
whitespaceIgnores[currentWhitespaceState] = state;
}
- (void)endIgnoringOrAcceptingWhitespaceTokens
{
currentWhitespaceState--;
}
- (void)skipWhitespaces
{
if (!self.isIgnoringWhitespaceTokens) {
if (whitespaceIgnores[currentWhitespaceState]) {
return;
}
while (self.currentTokenIndex < self.tokens.count) {
MPToken *token = self.tokens[self.currentTokenIndex];
while (_currentTokenIndex < self.tokens.count) {
MPToken *token = self.tokens[_currentTokenIndex];
if (token.tokenType != MPWhitespaceToken) {
return;
}
++self.currentTokenIndex;
[self currentTokenConsumed];
}
}
- (void)reset
{
self.currentTokenIndex = 0;
[self skipWhitespaces];
}
- (BOOL)hasMoreTokens
{
[self skipWhitespaces];
return self.currentTokenIndex < self.tokens.count;
return _currentTokenIndex < self.tokens.count;
}
- (MPToken *)nextToken
- (MPToken *)currentToken
{
[self skipWhitespaces];
if (self.currentTokenIndex >= self.tokens.count) {
if (_currentTokenIndex >= _tokens.count) {
return [[MPToken alloc] initEOFTokenAtLocation:eofLocation];
} else {
MPToken *token = self.tokens[self.currentTokenIndex++];
return token;
}
return _tokens[_currentTokenIndex];
}
- (MPToken *)nextTokenOfType:(MPTokenType)type
- (MPToken *)peekNextToken
{
[self skipWhitespaces];
if (self.currentTokenIndex >= self.tokens.count) {
return nil;
} else {
MPToken *token = self.tokens[self.currentTokenIndex];
if (token.tokenType != type) {
return nil;
}
++self.currentTokenIndex;
return token;
}
NSUInteger currentTokenIndex = _currentTokenIndex;
[self currentTokenConsumed]; // Pretend the current token has been consumed
MPToken *token = [self currentToken];
_currentTokenIndex = currentTokenIndex; // Undo the lookahead
return token;
}
- (void)currentTokenConsumed
{
++_currentTokenIndex;
}
- (void)dealloc
{
free(whitespaceIgnores);
}
@end

View File

@@ -0,0 +1,16 @@
//
// MPUnidentifiedSymbolValue.h
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "MPValueGroup.h"
@interface MPUnexpectedSymbolValue : NSObject <MPValue>
@property (nonatomic, copy) NSString *symbol;
@end

View File

@@ -0,0 +1,59 @@
//
// MPUnidentifiedSymbolValue.m
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPUnexpectedSymbolValue.h"
@implementation MPUnexpectedSymbolValue {
NSRange _range;
}
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
_range = tokenStream.currentToken.range;
_symbol = tokenStream.currentToken.stringValue;
[tokenStream currentTokenConsumed];
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return _range;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
if (error) {
*error = MPParseError(self.range, @"Unknown Symbol.");
}
return NO;
}
- (NSDecimalNumber *)evaluate
{
return [NSDecimalNumber notANumber];
}
- (NSArray *)expressionElements
{
return @[self.symbol];
}
@end

34
MathPad/MPValueGroup.h Normal file
View File

@@ -0,0 +1,34 @@
//
// MPValueGroup.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPExpressionTreeElement.h"
@protocol MPValue <MPExpressionTreeElement>
@end
@interface MPValueGroup : NSObject <MPValue>
@property (nonatomic, strong) NSArray *values;
- (void)appendValue:(id<MPValue>)value;
- (void)insertValue:(id<MPValue>)value
atIndex:(NSUInteger)index;
- (void)removeValue:(id<MPValue>)value;
- (void)removeValueAtIndex:(NSUInteger)index;
- (id<MPValue>)valueAtIndex:(NSUInteger)index;
@end
@interface MPTokenStream (MPValueSuffixes)
- (id<MPValue>)consumeSuffixesForValue:(id<MPValue>)value;
@end

197
MathPad/MPValueGroup.m Normal file
View File

@@ -0,0 +1,197 @@
//
// MPValueGroup.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPValueGroup.h"
#import "MPNumber.h"
#import "MPVariable.h"
#import "MPFunction+MPValue.h"
#import "MPUnexpectedSymbolValue.h"
#import "MPFunctionValue.h"
#import "MPFactorial.h"
#import "MPSuffixFunction.h"
@implementation MPValueGroup {
NSMutableArray *_values;
NSRange _range;
}
- (id)init
{
self = [super init];
if (self) {
_values = [[NSMutableArray alloc] init];
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
MPTokenStreamRecordCurrentLocation(tokenStream); // This will also skip leading whitespaces
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
[tokenStream beginAcceptingWhitespaceTokens];
BOOL checkMoreTokens = YES;
while (tokenStream.currentToken.tokenType != MPWhitespaceToken && checkMoreTokens) {
id<MPValue> currentValue;
switch (tokenStream.currentToken.tokenType) {
case MPNumberToken:
{
currentValue = [[MPNumber alloc] initWithTokenStream:tokenStream];
}
break;
case MPVariableToken:
{
currentValue = [[MPVariable alloc] initWithTokenStream:tokenStream];
}
break;
case MPGenericFunctionToken:
{
currentValue = (id<MPValue>)tokenStream.currentToken;
[tokenStream currentTokenConsumed];
}
break;
case MPSinToken:
case MPCosToken:
case MPTanToken:
case MPASinToken:
case MPACosToken:
case MPATanToken:
{
[tokenStream currentTokenConsumed];
currentValue = [[MPFunctionValue alloc] initWithTokenStream:tokenStream];
}
break;
case MPUnidentifiedToken:
case MPEqualsToken:
currentValue = [[MPUnexpectedSymbolValue alloc] initWithTokenStream:tokenStream];
break;
default:
checkMoreTokens = NO;
break;
}
if (checkMoreTokens) {
[_values addObject:[tokenStream consumeSuffixesForValue:currentValue]];
}
}
_range = MPTokenStreamRecordedRange(tokenStream);
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return _range;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
if (_values.count == 0) {
if (error) {
*error = MPParseError(self.range, @"Expected Value");
}
return NO;
}
for (id<MPValue> value in _values) {
if (![value validate:error]) {
return NO;
}
}
return YES;
}
- (NSDecimalNumber *)evaluate
{
NSDecimalNumber *result = [NSDecimalNumber one];
for (id<MPValue> value in _values) {
NSDecimalNumber *currentValue = [value evaluate];
if ([currentValue isEqualToNumber:[NSDecimalNumber notANumber]]) {
result = currentValue;
break;
}
result = [result decimalNumberByMultiplyingBy:currentValue];
if ([result compare:@(0)] == NSOrderedSame) {
break;
}
}
return result;
}
- (NSArray *)expressionElements
{
NSMutableArray *elements = [[NSMutableArray alloc] init];
for (id<MPValue> value in _values) {
[elements addObjectsFromArray:value.expressionElements];
}
return elements;
}
- (void)appendValue:(id<MPValue>)value
{
[_values addObject:value];
}
- (void)insertValue:(id<MPValue>)value
atIndex:(NSUInteger)index
{
[_values insertObject:value
atIndex:index];
}
- (void)removeValue:(id<MPValue>)value
{
[_values removeObject:value];
}
- (void)removeValueAtIndex:(NSUInteger)index
{
[_values removeObjectAtIndex:index];
}
- (id<MPValue>)valueAtIndex:(NSUInteger)index
{
return [_values objectAtIndex:index];
}
@end
@implementation MPTokenStream (MPValueSuffixes)
- (id<MPValue>)consumeSuffixesForValue:(id<MPValue>)value
{
BOOL repeat = YES;
while (repeat) {
if (self.currentToken.tokenType == MPFactorialToken) {
MPFactorial *factorial = [[MPFactorial alloc] init];
factorial.value = value;
value = factorial;
[self currentTokenConsumed];
} else if (self.currentToken.tokenType == MPGenericFunctionToken && [self.currentToken isKindOfClass:[MPSuffixFunction class]]) {
MPSuffixFunction *token = (MPSuffixFunction *)self.currentToken;
token.baseValue = value;
value = token;
[self currentTokenConsumed];
} else {
repeat = NO;
}
}
return value;
}
@end

16
MathPad/MPVariable.h Normal file
View File

@@ -0,0 +1,16 @@
//
// MPVariable.h
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPValueGroup.h"
@interface MPVariable : NSObject <MPValue>
@property (nonatomic, strong) NSString *variableName;
@end

68
MathPad/MPVariable.m Normal file
View File

@@ -0,0 +1,68 @@
//
// MPVariable.m
// MathPad
//
// Created by Kim Wittenburg on 09.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPVariable.h"
#import "MPEvaluationContext.h"
@implementation MPVariable {
NSRange _range;
}
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
self = [self init];
if (self) {
[tokenStream beginIgnoringWhitespaceTokens];
MPToken *token = tokenStream.currentToken;
if (token.tokenType == MPVariableToken) {
self.variableName = token.stringValue;
_range = token.range;
} else {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Expected Variable" userInfo:nil];
}
[tokenStream currentTokenConsumed];
[tokenStream endIgnoringOrAcceptingWhitespaceTokens];
}
return self;
}
- (NSRange)range
{
return _range;
}
- (BOOL)validate:(MPParseError *__autoreleasing *)error
{
if (![[MPEvaluationContext sharedContext] isVariableDefined:self.variableName]) {
if (error) {
*error = MPParseError(self.range, @"Undefined Variable");
}
return NO;
}
return YES;
}
- (NSDecimalNumber *)evaluate
{
return [[MPEvaluationContext sharedContext] valueForVariable:self.variableName];
}
- (NSArray *)expressionElements
{
return @[self.variableName];
}
@end