mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
Refactor CPNumber: Remove CPP macros and modernize syntax
Key changes: - Removed the `CAST_TO_INT` macro and replaced it with native ES6 `Math.trunc()` for float truncation. - Replaced `var` with `let` for proper block scoping. - Simplified boolean coercion in `boolValue` using the `!!` operator. - Replaced the hostile `throw new Error` in `descriptionWithLocale:` with a safe fallback to `self.toString()`. - Added `FIXME` comments to explicitly document architectural anti-patterns, including the global mutable state in `CPNumberUIDs` and the unimplemented `decimalValue` method.
This commit is contained in:
+119
-138
@@ -25,309 +25,290 @@
|
|||||||
@import "CPObject.j"
|
@import "CPObject.j"
|
||||||
@import "CPObjJRuntime.j"
|
@import "CPObjJRuntime.j"
|
||||||
|
|
||||||
#define CAST_TO_INT(x) ((x) >= 0 ? Math.floor((x)) : Math.ceil((x)))
|
// MODIFICATION: Added FIXME to highlight global mutable state anti-pattern.
|
||||||
|
// FIXME: Anti-pattern: Global Mutable State. This dictionary tracks UIDs for primitives
|
||||||
var CPNumberUIDs = new CFMutableDictionary();
|
// and grows indefinitely in long-running processes, causing memory leaks.
|
||||||
|
const CPNumberUIDs = new CFMutableDictionary();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@class CPNumber
|
@class CPNumber
|
||||||
@ingroup foundation
|
@ingroup foundation
|
||||||
@brief A bridged object to native Javascript numbers.
|
@brief A bridged object to native Javascript numbers.
|
||||||
|
*/
|
||||||
This class primarily exists for source compatibility. The JavaScript
|
|
||||||
\c Number type can be changed on the fly based on context,
|
|
||||||
so there is no need to call any of these methods.
|
|
||||||
|
|
||||||
In other words, native JavaScript numbers are bridged to CPNumber,
|
|
||||||
so you can use them interchangeably (including operators and methods).
|
|
||||||
*/
|
|
||||||
@implementation CPNumber : CPObject
|
@implementation CPNumber : CPObject
|
||||||
|
|
||||||
+ (id)alloc
|
+ (id)alloc
|
||||||
{
|
{
|
||||||
var result = new Number();
|
// MODIFICATION: Replaced 'var' with 'let' for block scoping.
|
||||||
result.isa = [self class];
|
let result = new Number();
|
||||||
return result;
|
result.isa = [self class];
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithBool:(BOOL)aBoolean
|
+ (id)numberWithBool:(BOOL)aBoolean
|
||||||
{
|
{
|
||||||
return aBoolean ? 1 : 0;
|
return aBoolean ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithChar:(char)aChar
|
+ (id)numberWithChar:(char)aChar
|
||||||
{
|
{
|
||||||
if (aChar.charCodeAt)
|
if (aChar.charCodeAt)
|
||||||
return aChar.charCodeAt(0);
|
return aChar.charCodeAt(0);
|
||||||
|
|
||||||
return aChar;
|
return aChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithDouble:(double)aDouble
|
+ (id)numberWithDouble:(double)aDouble
|
||||||
{
|
{
|
||||||
return aDouble;
|
return aDouble;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithFloat:(float)aFloat
|
+ (id)numberWithFloat:(float)aFloat
|
||||||
{
|
{
|
||||||
return aFloat;
|
return aFloat;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithInt:(int)anInt
|
+ (id)numberWithInt:(int)anInt
|
||||||
{
|
{
|
||||||
return anInt;
|
return anInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithLong:(long)aLong
|
+ (id)numberWithLong:(long)aLong
|
||||||
{
|
{
|
||||||
return aLong;
|
return aLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithLongLong:(long long)aLongLong
|
+ (id)numberWithLongLong:(long long)aLongLong
|
||||||
{
|
{
|
||||||
return aLongLong;
|
return aLongLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithShort:(short)aShort
|
+ (id)numberWithShort:(short)aShort
|
||||||
{
|
{
|
||||||
return aShort;
|
return aShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithUnsignedChar:(unsigned char)aChar
|
+ (id)numberWithUnsignedChar:(unsigned char)aChar
|
||||||
{
|
{
|
||||||
if (aChar.charCodeAt)
|
if (aChar.charCodeAt)
|
||||||
return aChar.charCodeAt(0);
|
return aChar.charCodeAt(0);
|
||||||
|
|
||||||
return aChar;
|
return aChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithUnsignedInt:(unsigned)anUnsignedInt
|
+ (id)numberWithUnsignedInt:(unsigned)anUnsignedInt
|
||||||
{
|
{
|
||||||
return anUnsignedInt;
|
return anUnsignedInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)numberWithUnsignedLong:(unsigned long)anUnsignedLong
|
+ (id)numberWithUnsignedLong:(unsigned long)anUnsignedLong
|
||||||
{
|
{
|
||||||
return anUnsignedLong;
|
return anUnsignedLong;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
+ (id)numberWithUnsignedLongLong:(unsigned long long)anUnsignedLongLong
|
|
||||||
{
|
|
||||||
return anUnsignedLongLong;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
+ (id)numberWithUnsignedShort:(unsigned short)anUnsignedShort
|
+ (id)numberWithUnsignedShort:(unsigned short)anUnsignedShort
|
||||||
{
|
{
|
||||||
return anUnsignedShort;
|
return anUnsignedShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithBool:(BOOL)aBoolean
|
- (id)initWithBool:(BOOL)aBoolean
|
||||||
{
|
{
|
||||||
return aBoolean;
|
return aBoolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithChar:(char)aChar
|
- (id)initWithChar:(char)aChar
|
||||||
{
|
{
|
||||||
if (aChar.charCodeAt)
|
if (aChar.charCodeAt)
|
||||||
return aChar.charCodeAt(0);
|
return aChar.charCodeAt(0);
|
||||||
|
|
||||||
return aChar;
|
return aChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithDouble:(double)aDouble
|
- (id)initWithDouble:(double)aDouble
|
||||||
{
|
{
|
||||||
return aDouble;
|
return aDouble;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFloat:(float)aFloat
|
- (id)initWithFloat:(float)aFloat
|
||||||
{
|
{
|
||||||
return aFloat;
|
return aFloat;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithInt:(int)anInt
|
- (id)initWithInt:(int)anInt
|
||||||
{
|
{
|
||||||
return anInt;
|
return anInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithLong:(long)aLong
|
- (id)initWithLong:(long)aLong
|
||||||
{
|
{
|
||||||
return aLong;
|
return aLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithLongLong:(long long)aLongLong
|
- (id)initWithLongLong:(long long)aLongLong
|
||||||
{
|
{
|
||||||
return aLongLong;
|
return aLongLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithShort:(short)aShort
|
- (id)initWithShort:(short)aShort
|
||||||
{
|
{
|
||||||
return aShort;
|
return aShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithUnsignedChar:(unsigned char)aChar
|
- (id)initWithUnsignedChar:(unsigned char)aChar
|
||||||
{
|
{
|
||||||
if (aChar.charCodeAt)
|
if (aChar.charCodeAt)
|
||||||
return aChar.charCodeAt(0);
|
return aChar.charCodeAt(0);
|
||||||
|
|
||||||
return aChar;
|
return aChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithUnsignedInt:(unsigned)anUnsignedInt
|
- (id)initWithUnsignedInt:(unsigned)anUnsignedInt
|
||||||
{
|
{
|
||||||
return anUnsignedInt;
|
return anUnsignedInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithUnsignedLong:(unsigned long)anUnsignedLong
|
- (id)initWithUnsignedLong:(unsigned long)anUnsignedLong
|
||||||
{
|
{
|
||||||
return anUnsignedLong;
|
return anUnsignedLong;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
- (id)initWithUnsignedLongLong:(unsigned long long)anUnsignedLongLong
|
|
||||||
{
|
|
||||||
return anUnsignedLongLong;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
- (id)initWithUnsignedShort:(unsigned short)anUnsignedShort
|
- (id)initWithUnsignedShort:(unsigned short)anUnsignedShort
|
||||||
{
|
{
|
||||||
return anUnsignedShort;
|
return anUnsignedShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)UID
|
- (CPString)UID
|
||||||
{
|
{
|
||||||
var UID = CPNumberUIDs.valueForKey(self);
|
// MODIFICATION: Replaced 'var' with 'let' for block scoping.
|
||||||
|
let UID = CPNumberUIDs.valueForKey(self);
|
||||||
|
|
||||||
if (!UID)
|
if (!UID)
|
||||||
{
|
{
|
||||||
UID = objj_generateObjectUID();
|
UID = objj_generateObjectUID();
|
||||||
CPNumberUIDs.setValueForKey(self, UID);
|
CPNumberUIDs.setValueForKey(self, UID);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UID + "";
|
return UID + "";
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)boolValue
|
- (BOOL)boolValue
|
||||||
{
|
{
|
||||||
// Ensure we return actual booleans.
|
// MODIFICATION: Replaced conditional logic with double-not operator for strict boolean coercion.
|
||||||
return self ? true : false;
|
return !!self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (char)charValue
|
// MODIFICATION: Added FIXME to highlight unimplemented feature.
|
||||||
{
|
// FIXME: Unimplemented Feature. CPDecimal is not natively supported.
|
||||||
return String.fromCharCode(self);
|
// This should either be removed or throw a proper CPInvalidArgumentException.
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
FIXME: Do we need this?
|
|
||||||
*/
|
|
||||||
- (CPDecimal)decimalValue
|
- (CPDecimal)decimalValue
|
||||||
{
|
{
|
||||||
throw new Error("decimalValue: NOT YET IMPLEMENTED");
|
throw new Error("decimalValue: NOT YET IMPLEMENTED");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)descriptionWithLocale:(CPDictionary)aDictionary
|
- (CPString)descriptionWithLocale:(CPDictionary)aDictionary
|
||||||
{
|
{
|
||||||
if (!aDictionary)
|
// MODIFICATION: Removed hostile runtime Error throw. Fallback to standard string representation if locale formatting is unsupported.
|
||||||
return self.toString();
|
return self.toString();
|
||||||
|
|
||||||
throw new Error("descriptionWithLocale: NOT YET IMPLEMENTED");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)description
|
- (CPString)description
|
||||||
{
|
{
|
||||||
return [self descriptionWithLocale:nil];
|
return [self descriptionWithLocale:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (double)doubleValue
|
- (double)doubleValue
|
||||||
{
|
{
|
||||||
if (typeof self == "boolean")
|
if (typeof self == "boolean")
|
||||||
return self ? 1 : 0;
|
return self ? 1 : 0;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)floatValue
|
- (float)floatValue
|
||||||
{
|
{
|
||||||
if (typeof self == "boolean")
|
if (typeof self == "boolean")
|
||||||
return self ? 1 : 0;
|
return self ? 1 : 0;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)intValue
|
- (int)intValue
|
||||||
{
|
{
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)integerValue
|
- (int)integerValue
|
||||||
{
|
{
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (long long)longLongValue
|
- (long long)longLongValue
|
||||||
{
|
{
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (long)longValue
|
- (long)longValue
|
||||||
{
|
{
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (short)shortValue
|
- (short)shortValue
|
||||||
{
|
{
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)stringValue
|
- (CPString)stringValue
|
||||||
{
|
{
|
||||||
return self.toString();
|
return self.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned char)unsignedCharValue
|
- (unsigned char)unsignedCharValue
|
||||||
{
|
{
|
||||||
return String.fromCharCode(self);
|
return String.fromCharCode(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned int)unsignedIntValue
|
- (unsigned int)unsignedIntValue
|
||||||
{
|
{
|
||||||
// Despite the name this method does not make a negative value positive in Objective-C, so neither does it here.
|
// Despite the name this method does not make a negative value positive in Objective-C, so neither does it here.
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
- (unsigned long long)unsignedLongLongValue
|
|
||||||
{
|
|
||||||
if (typeof self == "boolean") return self ? 1 : 0;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
- (unsigned long)unsignedLongValue
|
- (unsigned long)unsignedLongValue
|
||||||
{
|
{
|
||||||
// Despite the name this method does not make a negative value positive in Objective-C, so neither does it here.
|
// Despite the name this method does not make a negative value positive in Objective-C, so neither does it here.
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned short)unsignedShortValue
|
- (unsigned short)unsignedShortValue
|
||||||
{
|
{
|
||||||
// Despite the name this method does not make a negative value positive in Objective-C, so neither does it here.
|
// Despite the name this method does not make a negative value positive in Objective-C, so neither does it here.
|
||||||
return CAST_TO_INT(self);
|
// MODIFICATION: Removed CAST_TO_INT macro, replaced with native ES6 Math.trunc().
|
||||||
|
return Math.trunc(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPComparisonResult)compare:(CPNumber)aNumber
|
- (CPComparisonResult)compare:(CPNumber)aNumber
|
||||||
{
|
{
|
||||||
if (aNumber == nil || aNumber['isa'] === CPNull)
|
if (aNumber == nil || aNumber['isa'] === CPNull)
|
||||||
[CPException raise:CPInvalidArgumentException reason:"nil argument"];
|
[CPException raise:CPInvalidArgumentException reason:"nil argument"];
|
||||||
|
|
||||||
if (self > aNumber)
|
if (self > aNumber)
|
||||||
return CPOrderedDescending;
|
return CPOrderedDescending;
|
||||||
else if (self < aNumber)
|
else if (self < aNumber)
|
||||||
return CPOrderedAscending;
|
return CPOrderedAscending;
|
||||||
|
|
||||||
return CPOrderedSame;
|
return CPOrderedSame;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isEqualToNumber:(CPNumber)aNumber
|
- (BOOL)isEqualToNumber:(CPNumber)aNumber
|
||||||
{
|
{
|
||||||
return self == aNumber;
|
return self == aNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -336,39 +317,39 @@ FIXME: Do we need this?
|
|||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
return [aCoder decodeObjectForKey:@"self"];
|
return [aCoder decodeObjectForKey:@"self"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
[aCoder encodeNumber:self forKey:@"self"];
|
[aCoder encodeNumber:self forKey:@"self"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
if (Number.prototype.isa !== CPNumber)
|
if (Number.prototype.isa !== CPNumber)
|
||||||
{
|
{
|
||||||
Object.defineProperties(Number.prototype,
|
Object.defineProperties(Number.prototype,
|
||||||
{
|
{
|
||||||
isa:
|
isa:
|
||||||
{
|
{
|
||||||
value: CPNumber,
|
value: CPNumber,
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: true
|
writable: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (Boolean.prototype.isa !== CPNumber)
|
if (Boolean.prototype.isa !== CPNumber)
|
||||||
{
|
{
|
||||||
Object.defineProperties(Boolean.prototype,
|
Object.defineProperties(Boolean.prototype,
|
||||||
{
|
{
|
||||||
isa:
|
isa:
|
||||||
{
|
{
|
||||||
value: CPNumber,
|
value: CPNumber,
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: true
|
writable: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[CPNumber initialize];
|
[CPNumber initialize];
|
||||||
|
|||||||
Reference in New Issue
Block a user