Cleaned Code
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6245" systemVersion="14A389" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6245"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPDocument">
|
||||
<connections>
|
||||
<outlet property="expressionView" destination="lcd-Ip-jjR" id="Vww-eh-hP7"/>
|
||||
<outlet property="resultLabel" destination="Cdb-3b-4iC" id="7O2-I6-gqP"/>
|
||||
<outlet property="expressionView" destination="bhV-kp-c0I" id="VkG-iX-blr"/>
|
||||
<outlet property="resultLabel" destination="4B1-d4-7wd" id="kgz-yK-Ud3"/>
|
||||
<outlet property="window" destination="xOd-HO-29H" id="JIz-fz-R2o"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@@ -16,17 +16,18 @@
|
||||
<window title="MathPad" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="xOd-HO-29H" userLabel="Window">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<rect key="contentRect" x="525" y="411" width="432" height="181"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
|
||||
<value key="minSize" type="size" width="432" height="181"/>
|
||||
<view key="contentView" id="gIp-Ho-8D9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="432" height="181"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="lcd-Ip-jjR" customClass="MPExpressionView">
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="bhV-kp-c0I" customClass="MPExpressionView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="432" height="181"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Cdb-3b-4iC">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="4B1-d4-7wd">
|
||||
<rect key="frame" x="410" y="20" width="4" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" id="I9X-Yv-EiR">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" id="53e-7L-BTd">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -34,22 +35,22 @@
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="Cdb-3b-4iC" secondAttribute="bottom" constant="20" id="3T9-HB-OrZ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Cdb-3b-4iC" secondAttribute="trailing" constant="20" id="toz-uq-kuq"/>
|
||||
<constraint firstAttribute="bottom" secondItem="4B1-d4-7wd" secondAttribute="bottom" constant="20" symbolic="YES" id="Gnf-6p-lx6"/>
|
||||
<constraint firstAttribute="trailing" secondItem="4B1-d4-7wd" secondAttribute="trailing" constant="20" symbolic="YES" id="paI-1L-J2e"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="lcd-Ip-jjR" firstAttribute="leading" secondItem="gIp-Ho-8D9" secondAttribute="leading" id="5G8-rw-mds"/>
|
||||
<constraint firstAttribute="bottom" secondItem="lcd-Ip-jjR" secondAttribute="bottom" id="JAt-GL-atf"/>
|
||||
<constraint firstAttribute="trailing" secondItem="lcd-Ip-jjR" secondAttribute="trailing" id="Wi2-6P-2Li"/>
|
||||
<constraint firstItem="lcd-Ip-jjR" firstAttribute="top" secondItem="gIp-Ho-8D9" secondAttribute="top" id="hvP-0r-1OZ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="bhV-kp-c0I" secondAttribute="bottom" id="VRz-hN-lFY"/>
|
||||
<constraint firstItem="bhV-kp-c0I" firstAttribute="leading" secondItem="gIp-Ho-8D9" secondAttribute="leading" id="WbH-hd-lvs"/>
|
||||
<constraint firstAttribute="trailing" secondItem="bhV-kp-c0I" secondAttribute="trailing" id="nYd-dS-gsv"/>
|
||||
<constraint firstItem="bhV-kp-c0I" firstAttribute="top" secondItem="gIp-Ho-8D9" secondAttribute="top" id="png-CY-BRy"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="0bl-1N-x8E"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="102" y="112.5"/>
|
||||
<point key="canvasLocation" x="-147" y="119.5"/>
|
||||
</window>
|
||||
<collectionViewItem id="J9S-PW-LCL">
|
||||
<connections>
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 854 KiB After Width: | Height: | Size: 74 KiB |
@@ -308,10 +308,7 @@
|
||||
break;
|
||||
|
||||
case MPTokenReferenceFrame:
|
||||
[_elements enumerateObjectsUsingBlock:^(id<MPToken> obj, NSUInteger idx, BOOL *stop) {
|
||||
symbolIndex = NSMaxRange(obj.range);
|
||||
*stop = idx >= index - 1;
|
||||
}];
|
||||
symbolIndex = [self.tokens[index] range].location;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -345,14 +342,13 @@
|
||||
|
||||
case MPTokenReferenceFrame:
|
||||
{
|
||||
NSUInteger totalLength = 0;
|
||||
NSUInteger tokenIndex = 0;
|
||||
id<MPToken> token;
|
||||
while (totalLength < symbolIndex) {
|
||||
token = self.tokens[tokenIndex++];
|
||||
totalLength = NSMaxRange(token.range);
|
||||
while (true) {
|
||||
id<MPToken> token = self.tokens[tokenIndex++];
|
||||
if (NSMaxRange(token.range) < symbolIndex || token.range.location > symbolIndex) {
|
||||
continue;
|
||||
}
|
||||
NSUInteger offsetInToken = token.range.length - totalLength + symbolIndex;
|
||||
NSUInteger offsetInToken = index - token.range.location;
|
||||
if (offsetInToken == token.range.length) {
|
||||
offsetInToken = 0;
|
||||
tokenIndex++;
|
||||
@@ -362,6 +358,9 @@
|
||||
}
|
||||
return tokenIndex;
|
||||
}
|
||||
// Should never get here
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,15 +524,10 @@
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
MPExpressionTree *tree = [self parse];
|
||||
if ([tree validate:error]) {
|
||||
return [tree evaluate];
|
||||
}
|
||||
if (error) {
|
||||
(*error).pathToExpression = self.indexPath;
|
||||
}
|
||||
return nil;
|
||||
return [tree validate:error] ? [tree evaluate] : nil;
|
||||
}
|
||||
|
||||
|
||||
- (MPExpressionTree *)parse
|
||||
{
|
||||
MPTokenStream *tokenStream = [[MPTokenStream alloc] initWithTokens:self.tokens];
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#import "MPFunctionLayout.h"
|
||||
|
||||
#import "MPPowerFunction.h"
|
||||
#import "MPFractionFunction.h"
|
||||
|
||||
#import "MPRangePath.h"
|
||||
|
||||
@@ -91,11 +92,9 @@
|
||||
|
||||
- (void)restartCaretTimer
|
||||
{
|
||||
if (self.caretTimer) {
|
||||
if ([self.caretTimer isValid]) {
|
||||
if (self.caretTimer && [self.caretTimer isValid]) {
|
||||
[self.caretTimer invalidate];
|
||||
}
|
||||
}
|
||||
self.caretTimer = [NSTimer scheduledTimerWithTimeInterval:self.caretBlinkRate/2 target:self selector:@selector(updateCaret:) userInfo:nil repeats:YES];
|
||||
self.caretVisible = NO;
|
||||
[self updateCaret:self.caretTimer];
|
||||
@@ -104,7 +103,11 @@
|
||||
- (void)updateCaret:(NSTimer *)timer
|
||||
{
|
||||
self.caretVisible = !self.caretVisible;
|
||||
self.needsDisplay = YES;
|
||||
NSRect updatedRect = self.selectionRect;
|
||||
NSPoint expressionOrigin = self.expressionOrigin;
|
||||
updatedRect.origin.x += expressionOrigin.x;
|
||||
updatedRect.origin.y += expressionOrigin.y;
|
||||
[self setNeedsDisplayInRect:updatedRect];
|
||||
}
|
||||
|
||||
- (NSRect)selectionRect
|
||||
@@ -576,6 +579,10 @@
|
||||
[self insertPowerFunction];
|
||||
return;
|
||||
}
|
||||
if ([characters isEqualToString:@"/"]) {
|
||||
[self insertFractionFunction];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *decimalSeparator = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
|
||||
NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet];
|
||||
@@ -630,6 +637,23 @@
|
||||
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:0] indexPathByAddingIndex:0], self.selection.length);
|
||||
}
|
||||
|
||||
- (void)insertFractionFunction
|
||||
{
|
||||
MPExpression *selectedElementsExpression = [self.expressionStorage subexpressionWithRangePath:self.selection
|
||||
referenceFrame:MPSymbolReferenceFrame];
|
||||
MPFractionFunction *function = [[MPFractionFunction alloc] init];
|
||||
function.nominatorExpression = selectedElementsExpression;
|
||||
[self.expressionStorage replaceItemsInRangePath:self.selection
|
||||
referenceFrame:MPSymbolReferenceFrame
|
||||
withElements:@[function]];
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||
NSUInteger functionElementIndex = [targetExpression convertIndex:self.selection.location.lastIndex
|
||||
fromReferenceFrame:MPSymbolReferenceFrame
|
||||
toReferenceFrame:MPElementReferenceFrame];
|
||||
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:functionElementIndex];
|
||||
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:1] indexPathByAddingIndex:0], 0);
|
||||
}
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if (self.target && self.action) {
|
||||
@@ -900,22 +924,22 @@
|
||||
[transform concat];
|
||||
|
||||
// Draw the error
|
||||
if (self.error) {
|
||||
[[NSColor redColor] set];
|
||||
NSRect rect = [self.expressionStorage.rootLayout boundingRectForRangePath:self.error.rangePath];
|
||||
if (self.error.rangePath.length == 0) {
|
||||
NSBezierPath *bezierPath = [NSBezierPath bezierPath];
|
||||
[bezierPath moveToPoint:rect.origin];
|
||||
[bezierPath lineToPoint:NSMakePoint(rect.origin.x - 5, rect.origin.y - 5)];
|
||||
[bezierPath moveToPoint:rect.origin];
|
||||
[bezierPath lineToPoint:NSMakePoint(rect.origin.x + 5, rect.origin.y - 5)];
|
||||
bezierPath.lineWidth = 2.0;
|
||||
[bezierPath stroke];
|
||||
} else {
|
||||
NSRect underlineRect = NSMakeRect(rect.origin.x, rect.origin.y + 2, rect.size.width, 2);
|
||||
NSRectFill(underlineRect);
|
||||
}
|
||||
}
|
||||
// if (self.error) {
|
||||
// [[NSColor redColor] set];
|
||||
// NSRect rect = [self.expressionStorage.rootLayout boundingRectForRangePath:self.error.rangePath];
|
||||
// if (self.error.rangePath.length == 0) {
|
||||
// NSBezierPath *bezierPath = [NSBezierPath bezierPath];
|
||||
// [bezierPath moveToPoint:rect.origin];
|
||||
// [bezierPath lineToPoint:NSMakePoint(rect.origin.x - 5, rect.origin.y - 5)];
|
||||
// [bezierPath moveToPoint:rect.origin];
|
||||
// [bezierPath lineToPoint:NSMakePoint(rect.origin.x + 5, rect.origin.y - 5)];
|
||||
// bezierPath.lineWidth = 2.0;
|
||||
// [bezierPath stroke];
|
||||
// } else {
|
||||
// NSRect underlineRect = NSMakeRect(rect.origin.x, rect.origin.y + 2, rect.size.width, 2);
|
||||
// NSRectFill(underlineRect);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Draw the selection
|
||||
if (self.caretVisible || self.selection.length > 0) {
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
#import "MPFractionFunctionLayout.h"
|
||||
#import "MPExpressionLayout.h"
|
||||
|
||||
#define kFractionFunctionLineWidth 2
|
||||
#define kFractionFunctionHorizontalInset 2
|
||||
#define kFractionFunctionLineWidth 1.0
|
||||
#define kFractionFunctionHorizontalInset 2.0
|
||||
#define kFractionFunctionNominatorOffset 0
|
||||
#define kFractionFunctionDenominatorOffset 0
|
||||
|
||||
#define MPFractionMiddle (CTFontGetAscent((CTFontRef)self.font) / 2)
|
||||
#define MPFractionMiddle (CTFontGetCapHeight((CTFontRef)self.font) / 2)
|
||||
|
||||
@implementation MPFractionFunctionLayout
|
||||
|
||||
@@ -41,13 +41,14 @@
|
||||
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
|
||||
{
|
||||
if (index == 0) {
|
||||
CGFloat y = MPFractionMiddle + kFractionFunctionLineWidth / 2;
|
||||
return NSMakePoint(0, y);
|
||||
NSRect nominatorBounds = [self childLayoutAtIndex:0].bounds;
|
||||
CGFloat y = MPFractionMiddle + kFractionFunctionLineWidth / 2 - nominatorBounds.origin.y;
|
||||
return NSMakePoint(kFractionFunctionHorizontalInset, 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);
|
||||
CGFloat y = MPFractionMiddle - kFractionFunctionLineWidth / 2;
|
||||
y -= denominatorBounds.size.height + denominatorBounds.origin.y;
|
||||
return NSMakePoint(kFractionFunctionHorizontalInset, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,16 +72,15 @@
|
||||
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.origin.y = MPFractionMiddle - kFractionFunctionLineWidth / 2 - denominatorBounds.size.height;
|
||||
bounds.size.width = MAX(nominatorBounds.size.width, denominatorBounds.size.width) + 2 * kFractionFunctionHorizontalInset;
|
||||
bounds.size.height = nominatorBounds.size.height + denominatorBounds.size.height + kFractionFunctionLineWidth;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (void)draw
|
||||
{
|
||||
CGFloat y = CTFontGetAscent((CTFontRef)self.font) / 2 - kFractionFunctionLineWidth / 2;
|
||||
CGFloat y = MPFractionMiddle - kFractionFunctionLineWidth / 2;
|
||||
NSRectFill(NSMakeRect(0, y, self.bounds.size.width, kFractionFunctionLineWidth));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
@import Cocoa;
|
||||
#import "MPExpressionStorage.h"
|
||||
|
||||
#define MPNull [NSNull null]
|
||||
|
||||
@interface MPLayout : NSObject
|
||||
|
||||
#pragma mark Creation Methods
|
||||
@@ -42,6 +40,7 @@
|
||||
|
||||
#pragma mark Calculation and Drawing Methods
|
||||
- (CTLineRef)createLineForString:(NSString *)aString;
|
||||
- (CTLineRef)createLineForString:(NSString *)aString emphasize:(BOOL)emphasize;
|
||||
- (CTLineRef)createLineForString:(NSString *)aString usingFont:(NSFont *)font;
|
||||
|
||||
@property (nonatomic, getter = isFlipped) BOOL flipped;
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
if (index >= _cache.count) {
|
||||
return NO;
|
||||
}
|
||||
return _cache[index] != MPNull;
|
||||
return _cache[index] != [NSNull null];
|
||||
}
|
||||
|
||||
- (id)cachableObjectForIndex:(NSUInteger)index
|
||||
@@ -102,7 +102,7 @@
|
||||
- (void)ensureCacheSizeForIndex:(NSUInteger)index
|
||||
{
|
||||
while (index >= _cache.count) {
|
||||
[_cache addObject:MPNull];
|
||||
[_cache addObject:[NSNull null]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
{
|
||||
NSMutableArray *placeholders = [[NSMutableArray alloc] initWithCapacity:replacementLength];
|
||||
while (placeholders.count < replacementLength) {
|
||||
[placeholders addObject:MPNull];
|
||||
[placeholders addObject:[NSNull null]];
|
||||
}
|
||||
[_cache replaceObjectsInRange:range
|
||||
withObjectsFromArray:placeholders];
|
||||
@@ -141,6 +141,12 @@
|
||||
usingFont:self.font];
|
||||
}
|
||||
|
||||
- (CTLineRef)createLineForString:(NSString *)aString emphasize:(BOOL)emphasize
|
||||
{
|
||||
return [self createLineForString:aString
|
||||
usingFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
|
||||
}
|
||||
|
||||
- (CTLineRef)createLineForString:(NSString *)aString
|
||||
usingFont:(NSFont *)font
|
||||
{
|
||||
|
||||
@@ -102,16 +102,22 @@
|
||||
|
||||
- (NSAffineTransform *)parenthesisTransform
|
||||
{
|
||||
NSRect parensBounds = self.openingParens.bounds;
|
||||
NSRect expressionBounds = [self childLayoutAtIndex:0].bounds;
|
||||
NSAffineTransform *transform = [NSAffineTransform transform];
|
||||
if (expressionBounds.size.height >= parensBounds.size.height) {
|
||||
[transform scaleXBy:1
|
||||
yBy:self.scaleFactor];
|
||||
return transform;
|
||||
}
|
||||
CGFloat scaleFactor = expressionBounds.size.height / parensBounds.size.height;
|
||||
[transform scaleXBy:1
|
||||
yBy:scaleFactor];
|
||||
return transform;
|
||||
|
||||
- (CGFloat)scaleFactor
|
||||
{
|
||||
NSRect parensBounds = self.openingParens.bounds;
|
||||
NSRect expressionBounds = [self childLayoutAtIndex:0].bounds;
|
||||
CGFloat parensHeight = parensBounds.size.height;
|
||||
CGFloat expressionHeight = expressionBounds.size.height;
|
||||
if (expressionHeight <= parensHeight) {
|
||||
return 1.0;
|
||||
}
|
||||
return expressionHeight / parensHeight;
|
||||
}
|
||||
|
||||
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
|
||||
@@ -154,24 +160,18 @@
|
||||
return bounds;
|
||||
}
|
||||
|
||||
#warning Let the children be drawn automatically
|
||||
- (BOOL)drawsChildrenManually
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)draw
|
||||
{
|
||||
NSBezierPath *openingParens = self.transformedOpeningParens;
|
||||
MPLayout *expressionLayout = [self childLayoutAtIndex:0];
|
||||
NSBezierPath *closingParens = self.transformedClosingParens;
|
||||
|
||||
|
||||
CGFloat x = 0;
|
||||
|
||||
[openingParens fill];
|
||||
x += openingParens.bounds.size.width;
|
||||
x += MPParenthesisFunctionOpeningParensOffset;
|
||||
[expressionLayout drawAtPoint:NSMakePoint(x, 0)];
|
||||
x += expressionLayout.bounds.size.width;
|
||||
x += MPParenthesisFunctionClosingParensOffset;
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ MPFunctionAccessorImplementation(ExponentExpression, _exponentExpression)
|
||||
{
|
||||
NSDecimalNumber *base = [self.baseValue evaluate];
|
||||
NSDecimalNumber *exponent = [[self.exponentExpression parse] evaluate];
|
||||
if ([base isEqualToNumber:@(0)] && [exponent isEqualToNumber:@(0)]) {
|
||||
// The C pow function returns 1 for pow(0, 0). Mathematically this should be undefined.
|
||||
return [NSDecimalNumber notANumber];
|
||||
}
|
||||
return [[NSDecimalNumber alloc] initWithDouble:pow(base.doubleValue, exponent.doubleValue)];
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,18 @@
|
||||
|
||||
- (BOOL)validate:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
if (_factors.count == 0) {
|
||||
if (error) {
|
||||
*error = MPParseError(_range, @"Expected Value");
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
MPFactor *factor = _factors[0];
|
||||
if (factor.hasMultiplicationSymbol) {
|
||||
if (error) {
|
||||
*error = MPParseError(factor.multiplicationSymbolRange, @"Unexpected Symbol.");
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
if (![factor.value validate:error]) {
|
||||
return NO;
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
case MPACosToken:
|
||||
case MPATanToken:
|
||||
{
|
||||
[tokenStream currentTokenConsumed];
|
||||
currentValue = [[MPFunctionValue alloc] initWithTokenStream:tokenStream];
|
||||
}
|
||||
break;
|
||||
|
||||