[jsinterp] Implementing String split
This commit is contained in:
parent
327bb2dd86
commit
f9f030a005
@ -39,8 +39,6 @@ tests = [
|
||||
])
|
||||
]
|
||||
}, {
|
||||
# FIXME built-in functions are not yet implemented
|
||||
'exclude': ('jsinterp2',),
|
||||
'code': 'function x(a) { return a.split(""); }',
|
||||
'asserts': [{'value': ["a", "b", "c"], 'call': ('x', "abc")}],
|
||||
'ast': [
|
||||
|
@ -2,7 +2,6 @@ from __future__ import unicode_literals
|
||||
|
||||
skip = {
|
||||
'jsinterp': 'String literals are not supported',
|
||||
'interpret': 'Builtins are not yet implemented',
|
||||
'parse': 'Test is not yet implemented: missing ast'
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ __doc__ = """see: `js2tests`"""
|
||||
defs = gettestcases()
|
||||
# set level to logging.DEBUG to see messages about missing assertions
|
||||
# set level to logging.DEBUG to see messages about code tests are running
|
||||
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
||||
logging.basicConfig(stream=sys.stderr, level=logging.WARNING)
|
||||
log = logging.getLogger('TestJSInterpreter')
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ __doc__ = """see: `js2tests`"""
|
||||
defs = gettestcases()
|
||||
# set level to logging.DEBUG to see messages about missing assertions
|
||||
# set level to logging.DEBUG to see messages about code tests are running
|
||||
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
||||
logging.basicConfig(stream=sys.stderr, level=logging.WARNING)
|
||||
log = logging.getLogger('TestJSInterpreter2')
|
||||
|
||||
|
||||
|
@ -53,5 +53,9 @@ global_obj = jsobject.JSObject.construct(
|
||||
'Array': jsarray.JSArray(),
|
||||
'Function': jsfunction.JSFunction(),
|
||||
'String': jsstring.JSString(),
|
||||
'Number': jsnumber.JSNumber()
|
||||
'Number': jsnumber.JSNumber(),
|
||||
'false': jsboolean.false,
|
||||
'true': jsboolean.true,
|
||||
'null': base.null,
|
||||
'undefined': base.undefined
|
||||
})
|
||||
|
@ -24,10 +24,10 @@ class JSProtoBase(JSBase):
|
||||
super(JSProtoBase, self).__init__('')
|
||||
cls = self.__class__
|
||||
while cls.__base__ is not JSProtoBase:
|
||||
cls = cls.__base__
|
||||
props = cls.own.copy()
|
||||
props.update(self.props)
|
||||
self.props = props
|
||||
cls = cls.__base__
|
||||
self.value = {}
|
||||
|
||||
def get_prop(self, prop):
|
||||
@ -63,3 +63,8 @@ native_number = (int, float)
|
||||
native_object = dict
|
||||
native_array = (list, tuple)
|
||||
native_function = FunctionType
|
||||
|
||||
|
||||
def isprimitive(value):
|
||||
return (isinstance(value, (native_bool, native_string, native_number, native_object, native_array, native_function))
|
||||
or value is None)
|
||||
|
@ -60,7 +60,9 @@ class JSStringPrototype(JSObjectPrototype):
|
||||
return 'string slice'
|
||||
|
||||
def _split(self, sep):
|
||||
return 'string split'
|
||||
if sep == '':
|
||||
return list(self.value)
|
||||
return self.value.split(sep)
|
||||
|
||||
def _substring(self, start, end):
|
||||
return 'string substring'
|
||||
|
@ -6,6 +6,10 @@ from ..compat import compat_str
|
||||
from ..utils import ExtractorError
|
||||
from .jsparser import Parser
|
||||
from .jsgrammar import Token, token_keys
|
||||
from .jsbuilt_ins import global_obj
|
||||
from .jsbuilt_ins.base import isprimitive
|
||||
from .jsbuilt_ins.internals import to_string
|
||||
from .jsbuilt_ins.utils import to_js
|
||||
|
||||
|
||||
class Context(object):
|
||||
@ -31,7 +35,7 @@ class Reference(object):
|
||||
if deep:
|
||||
if isinstance(self._value, (list, tuple)):
|
||||
# TODO test nested arrays
|
||||
value = [elem.getvalue() for elem in self._value]
|
||||
value = [elem if isprimitive(elem) else elem.getvalue() for elem in self._value]
|
||||
elif isinstance(self._value, dict):
|
||||
value = {}
|
||||
for key, prop in self._value.items():
|
||||
@ -60,8 +64,6 @@ class Reference(object):
|
||||
class JSInterpreter(object):
|
||||
# TODO support json
|
||||
|
||||
undefined = object()
|
||||
|
||||
def __init__(self, code, variables=None):
|
||||
super(JSInterpreter, self).__init__()
|
||||
self.code = code
|
||||
@ -116,7 +118,8 @@ class JSInterpreter(object):
|
||||
ref = s.getvalue()
|
||||
elif name is Token.VAR:
|
||||
for name, value in stmt[1]:
|
||||
value = self.interpret_expression(value).getvalue() if value is not None else self.undefined
|
||||
value = (self.interpret_expression(value).getvalue() if value is not None else
|
||||
global_obj.get_prop('undefined'))
|
||||
self.this[name] = Reference(value, (self.this, name))
|
||||
elif name is Token.EXPR:
|
||||
for expr in stmt[1]:
|
||||
@ -158,7 +161,7 @@ class JSInterpreter(object):
|
||||
if lid[0] is Token.ID and args is None and tail is None:
|
||||
key = lid[1]
|
||||
if key is not None:
|
||||
u = Reference(self.undefined, (self.this, key))
|
||||
u = Reference(global_obj.get_prop('undefined'), (self.this, key))
|
||||
leftref = self.this[key] = u
|
||||
else:
|
||||
raise ExtractorError('Invalid left-hand side in assignment')
|
||||
@ -209,16 +212,31 @@ class JSInterpreter(object):
|
||||
if args is not None:
|
||||
# TODO interpret NewExpression
|
||||
pass
|
||||
source = None
|
||||
while tail is not None:
|
||||
tail_name, tail_value, tail = tail
|
||||
if tail_name is Token.FIELD:
|
||||
target = target.getvalue()[tail_value]
|
||||
source = to_js(target.getvalue())
|
||||
target = source.get_prop(tail_value)
|
||||
elif tail_name is Token.ELEM:
|
||||
index = self.interpret_expression(tail_value).getvalue()
|
||||
target = target.getvalue()[index]
|
||||
prop = self.interpret_expression(tail_value).getvalue()
|
||||
target = to_js(target.getvalue()).get_prop(to_string(to_js(prop)))
|
||||
elif tail_name is Token.CALL:
|
||||
args = (self.interpret_expression(arg).getvalue() for arg in tail_value)
|
||||
target = Reference(target.getvalue()(*args))
|
||||
if isprimitive(target):
|
||||
if source is None:
|
||||
target = target(*args)
|
||||
else:
|
||||
target = target(source, *args)
|
||||
else:
|
||||
if source is None:
|
||||
target = target.getvalue()(*args)
|
||||
else:
|
||||
target = target.getvalue()(source, *args)
|
||||
if isprimitive(target):
|
||||
target = Reference(target)
|
||||
else:
|
||||
target = Reference(target.getvalue())
|
||||
ref = target
|
||||
|
||||
elif name is Token.ID:
|
||||
|
@ -440,7 +440,7 @@ class Parser(object):
|
||||
# Rhino has check for args length
|
||||
# Rhino has experimental syntax allowing an object literal to follow a new expression
|
||||
else:
|
||||
target = self._primary_expression(stack_top)
|
||||
target = self._primary_expression(stack_top - 1)
|
||||
args = None
|
||||
|
||||
return (Token.MEMBER, target, args, self._member_tail(stack_top - 1))
|
||||
|
Loading…
x
Reference in New Issue
Block a user