[jsinterp] Fixing types and operators
- Adds `jsbuilt_ins.nan` and `jsbuilt_ins.infinity` - Adds arithmetic operator overload to `jsbuilt_ins.jsnumber.JSNumberPrototype` - Adds equality operator overload to `jsinterp.Reference` - Adds better strict equality and typeof operator in `tstream`
This commit is contained in:
parent
a33b47e485
commit
93c0bb53a6
@ -10,6 +10,7 @@ from . import jsnumber
|
||||
|
||||
from .base import null, undefined
|
||||
from .jsboolean import false, true
|
||||
from .jsnumber import infinity, nan
|
||||
|
||||
|
||||
def _eval(code):
|
||||
|
@ -16,6 +16,34 @@ class JSNumberPrototype(JSObjectPrototype):
|
||||
self.value = value
|
||||
self.own = {}
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, JSNumberPrototype):
|
||||
other = other.value
|
||||
return JSNumberPrototype(self.value + other)
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, JSNumberPrototype):
|
||||
other = other.value
|
||||
return JSNumberPrototype(self.value - other)
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, JSNumberPrototype):
|
||||
other = other.value
|
||||
return JSNumberPrototype(self.value * other)
|
||||
|
||||
def __div__(self, other):
|
||||
if isinstance(other, JSNumberPrototype):
|
||||
other = other.value
|
||||
return JSNumberPrototype(self.value / other)
|
||||
|
||||
def __neg__(self):
|
||||
return JSNumberPrototype(-self.value)
|
||||
|
||||
def __pos__(self):
|
||||
return JSNumberPrototype(+self.value)
|
||||
|
||||
# __invert__?
|
||||
|
||||
@staticmethod
|
||||
def _constructor(value=None):
|
||||
return JSNumber.construct(value)
|
||||
@ -53,6 +81,10 @@ class JSNumberPrototype(JSObjectPrototype):
|
||||
}
|
||||
|
||||
|
||||
nan = JSNumberPrototype(float('nan'))
|
||||
infinity = JSNumberPrototype(float('inf'))
|
||||
|
||||
|
||||
class JSNumber(JSObject):
|
||||
@staticmethod
|
||||
def call(value=None):
|
||||
@ -68,7 +100,7 @@ class JSNumber(JSObject):
|
||||
'prototype': JSNumberPrototype(),
|
||||
'MAX_VALUE': 1.7976931348623157 * 10 ** 308,
|
||||
'MIN_VALUE': 5 * 10 ** (-324),
|
||||
'NAN': float('nan'),
|
||||
'NEGATIVE_INFINITY': float('-inf'),
|
||||
'POSITIVE_INFINITY': float('inf'),
|
||||
'NAN': nan,
|
||||
'NEGATIVE_INFINITY': infinity * -1,
|
||||
'POSITIVE_INFINITY': infinity,
|
||||
}
|
||||
|
@ -25,10 +25,13 @@ class Context(object):
|
||||
|
||||
|
||||
class Reference(object):
|
||||
def __init__(self, value, parent=None):
|
||||
def __init__(self, value, parent_key=None):
|
||||
super(Reference, self).__init__()
|
||||
self._value = value
|
||||
self._parent = parent
|
||||
if parent_key is not None:
|
||||
self._parent, self._name = parent_key
|
||||
else:
|
||||
self._parent = self._name = None
|
||||
|
||||
def getvalue(self, deep=False):
|
||||
value = self._value
|
||||
@ -46,10 +49,9 @@ class Reference(object):
|
||||
def putvalue(self, value):
|
||||
if self._parent is None:
|
||||
raise ExtractorError('Trying to set a read-only reference')
|
||||
parent, key = self._parent
|
||||
if not hasattr(parent, '__setitem__'):
|
||||
if not hasattr(self._parent, '__setitem__'):
|
||||
raise ExtractorError('Unknown reference')
|
||||
parent.__setitem__(key, Reference(value, (parent, key)))
|
||||
self._parent.__setitem__(self._name, Reference(value, (self._parent, self._name)))
|
||||
self._value = value
|
||||
return value
|
||||
|
||||
@ -60,6 +62,14 @@ class Reference(object):
|
||||
str(self._value), parent.__class__.__name__, id(parent), key)
|
||||
return '<Reference value: %s, parent: %s>' % (self._value, None)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Reference):
|
||||
return self._parent is other._parent and self._name == other._name
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class JSInterpreter(object):
|
||||
# TODO support json
|
||||
|
@ -16,6 +16,35 @@ from .jsgrammar import (
|
||||
UNARY_OPERATORS_RE,
|
||||
TokenTypes
|
||||
)
|
||||
from .jsbuilt_ins import false, true, nan
|
||||
from .jsbuilt_ins.internals import jstype, undefined_type, null_type, number_type, boolean_type, string_type
|
||||
|
||||
|
||||
def convert_to_unary(token_value):
|
||||
return {TokenTypes.ADD: _UNARY_OPERATORS['+'], TokenTypes.SUB: _UNARY_OPERATORS['-']}[token_value[0]]
|
||||
|
||||
|
||||
def strict_equal(x, y):
|
||||
from .jsinterp import Reference
|
||||
|
||||
if jstype(x) != jstype(y):
|
||||
return False
|
||||
if jstype(x) in (undefined_type, null_type):
|
||||
return True
|
||||
if jstype(x) is number_type:
|
||||
if x is nan or y is nan:
|
||||
return False
|
||||
if x.value == y.value:
|
||||
return True
|
||||
return False
|
||||
if jstype(x):
|
||||
return x.value == y.value
|
||||
if jstype(x) is boolean_type:
|
||||
return (x is true and y is true) or (x is false and y is false)
|
||||
if isinstance(x, Reference):
|
||||
return isinstance(y, Reference) and x == y
|
||||
return False
|
||||
|
||||
|
||||
_PUNCTUATIONS = {
|
||||
'{': TokenTypes.COPEN,
|
||||
@ -35,8 +64,8 @@ _LOGICAL_OPERATORS = {
|
||||
'||': (TokenTypes.OR, lambda cur, right: cur or right)
|
||||
}
|
||||
_UNARY_OPERATORS = {
|
||||
'+': (TokenTypes.PLUS, lambda cur: cur),
|
||||
'-': (TokenTypes.NEG, lambda cur: cur * -1),
|
||||
'+': (TokenTypes.PLUS, operator.pos),
|
||||
'-': (TokenTypes.NEG, operator.neg),
|
||||
'++': (TokenTypes.INC, lambda cur: cur + 1),
|
||||
'--': (TokenTypes.DEC, lambda cur: cur - 1),
|
||||
'!': (TokenTypes.NOT, operator.not_),
|
||||
@ -44,7 +73,7 @@ _UNARY_OPERATORS = {
|
||||
# XXX define these operators
|
||||
'delete': (TokenTypes.DEL, None),
|
||||
'void': (TokenTypes.VOID, None),
|
||||
'typeof': (TokenTypes.TYPE, lambda cur: type(cur))
|
||||
'typeof': (TokenTypes.TYPE, lambda cur: _type_strings[jstype(cur)])
|
||||
}
|
||||
_RELATIONS = {
|
||||
'<': (TokenTypes.LT, operator.lt),
|
||||
@ -54,8 +83,8 @@ _RELATIONS = {
|
||||
# XXX check python and JavaScript equality difference
|
||||
'==': (TokenTypes.EQ, operator.eq),
|
||||
'!=': (TokenTypes.NE, operator.ne),
|
||||
'===': (TokenTypes.SEQ, lambda cur, right: cur == right and type(cur) == type(right)),
|
||||
'!==': (TokenTypes.SNE, lambda cur, right: not cur == right or not type(cur) == type(right)),
|
||||
'===': (TokenTypes.SEQ, strict_equal),
|
||||
'!==': (TokenTypes.SNE, lambda cur, right: not strict_equal(cur, right)),
|
||||
'in': (TokenTypes.IN, operator.contains),
|
||||
'instanceof': (TokenTypes.INSTANCEOF, lambda cur, right: isinstance(cur, right))
|
||||
}
|
||||
@ -100,9 +129,13 @@ _input_element = re.compile(r'\s*(?:%(comment)s|%(token)s|%(lop)s|%(uop)s|%(aop)
|
||||
|
||||
_line_terminator = re.compile(LINETERMINATORSEQ_RE)
|
||||
|
||||
|
||||
def convert_to_unary(token_value):
|
||||
return {TokenTypes.ADD: _UNARY_OPERATORS['+'], TokenTypes.SUB: _UNARY_OPERATORS['-']}[token_value[0]]
|
||||
_type_strings = {
|
||||
undefined_type: 'undefinied',
|
||||
null_type: 'null',
|
||||
boolean_type: 'boolean',
|
||||
number_type: 'number',
|
||||
string_type: 'string'
|
||||
}
|
||||
|
||||
|
||||
class Token(object):
|
||||
|
Loading…
x
Reference in New Issue
Block a user