from __future__ import unicode_literals # Type Conversions. to_type. All must return PyJs subclass instance from .simplex import * def to_primitive(self, hint=None): if is_primitive(self): return self if hint is None and (self.Class == 'Number' or self.Class == 'Boolean'): # favour number for Class== Number or Boolean default = String hint = 'Number' return self.default_value(hint) def to_boolean(self): typ = Type(self) if typ == 'Boolean': # no need to convert return self elif typ == 'Null' or typ == 'Undefined': # they are both always false return False elif typ == 'Number': # false only for 0, and NaN return self and self == self # test for nan (nan -> flase) elif typ == 'String': return bool(self) else: # object - always True return True def to_number(self): typ = Type(self) if typ == 'Number': # or self.Class=='Number': # no need to convert return self elif typ == 'Null': # null is 0 return 0. elif typ == 'Undefined': # undefined is NaN return NaN elif typ == 'Boolean': # 1 for True 0 for false return float(self) elif typ == 'String': s = self.strip() # Strip white space if not s: # '' is simply 0 return 0. if 'x' in s or 'X' in s[:3]: # hex (positive only) try: # try to convert num = int(s, 16) except ValueError: # could not convert -> NaN return NaN return float(num) sign = 1 # get sign if s[0] in '+-': if s[0] == '-': sign = -1 s = s[1:] if s == 'Infinity': # Check for infinity keyword. 'NaN' will be NaN anyway. return sign * Infinity try: # decimal try num = sign * float(s) # Converted except ValueError: return NaN # could not convert to decimal > return NaN return float(num) else: # object - most likely it will be NaN. return to_number(to_primitive(self, 'Number')) def to_string(self): typ = Type(self) if typ == 'String': return self elif typ == 'Null': return 'null' elif typ == 'Undefined': return 'undefined' elif typ == 'Boolean': return 'true' if self else 'false' elif typ == 'Number': # or self.Class=='Number': return js_dtoa(self) else: # object return to_string(to_primitive(self, 'String')) def to_object(self, space): typ = Type(self) if typ == 'Object': return self elif typ == 'Boolean': # Unsure ... todo check here return space.Boolean.create((self, ), space) elif typ == 'Number': # ? return space.Number.create((self, ), space) elif typ == 'String': # ? return space.String.create((self, ), space) elif typ == 'Null' or typ == 'Undefined': raise MakeError('TypeError', 'undefined or null can\'t be converted to object') else: raise RuntimeError() def to_int32(self): num = to_number(self) if is_nan(num) or is_infinity(num): return 0 int32 = int(num) % 2**32 return int(int32 - 2**32 if int32 >= 2**31 else int32) def to_int(self): num = to_number(self) if is_nan(num): return 0 elif is_infinity(num): return 10**20 if num > 0 else -10**20 return int(num) def to_uint32(self): num = to_number(self) if is_nan(num) or is_infinity(num): return 0 return int(num) % 2**32 def to_uint16(self): num = to_number(self) if is_nan(num) or is_infinity(num): return 0 return int(num) % 2**16 def to_int16(self): num = to_number(self) if is_nan(num) or is_infinity(num): return 0 int16 = int(num) % 2**16 return int(int16 - 2**16 if int16 >= 2**15 else int16) def cok(self): """Check object coercible""" if type(self) in (UNDEFINED_TYPE, NULL_TYPE): raise MakeError('TypeError', 'undefined or null can\'t be converted to object')