From 53f8eff4858041b45c1dcb2030bb1d62f2717419 Mon Sep 17 00:00:00 2001 From: sulyi Date: Fri, 1 Jun 2018 01:45:35 +0200 Subject: [PATCH] [jsbuilt_ins] Fixing circular imports --- test/jstests/__init__.py | 5 ++- test/jstests/stringprototype.py | 12 +++++ youtube_dl/jsinterp/jsbuilt_ins/__init__.py | 6 +-- youtube_dl/jsinterp/jsbuilt_ins/base.py | 44 ++---------------- youtube_dl/jsinterp/jsbuilt_ins/internals.py | 33 +++++++++++--- youtube_dl/jsinterp/jsbuilt_ins/jsarray.py | 3 +- youtube_dl/jsinterp/jsbuilt_ins/jsboolean.py | 7 ++- youtube_dl/jsinterp/jsbuilt_ins/jsfunction.py | 5 ++- youtube_dl/jsinterp/jsbuilt_ins/jsnumber.py | 2 +- youtube_dl/jsinterp/jsbuilt_ins/jsobject.py | 11 ++--- youtube_dl/jsinterp/jsbuilt_ins/utils.py | 45 +++++++++++++++++++ 11 files changed, 109 insertions(+), 64 deletions(-) create mode 100644 test/jstests/stringprototype.py create mode 100644 youtube_dl/jsinterp/jsbuilt_ins/utils.py diff --git a/test/jstests/__init__.py b/test/jstests/__init__.py index 21c6e673b..5c670287b 100644 --- a/test/jstests/__init__.py +++ b/test/jstests/__init__.py @@ -26,13 +26,14 @@ from . import ( try_statement, with_statement, debug, - unshift + unshift, + stringprototype ) modules = [basic, calc, empty_return, morespace, strange_chars, operators, unary, array_access, parens, assignments, comments, precedence, call, getfield, branch, switch, for_loop, for_empty, for_in, do_loop, while_loop, - label, func_expr, object_literal, try_statement, with_statement, debug, unshift] + label, func_expr, object_literal, try_statement, with_statement, debug, unshift, stringprototype] def gettestcases(): diff --git a/test/jstests/stringprototype.py b/test/jstests/stringprototype.py new file mode 100644 index 000000000..531fcc211 --- /dev/null +++ b/test/jstests/stringprototype.py @@ -0,0 +1,12 @@ +from __future__ import unicode_literals + +skip = {'parse': 'Ast not yet implemented'} + +tests = [ + { + 'code': '"hello".split("");', + 'globals': {}, + 'asserts': [{'value': ['h', 'e', 'l', 'l', 'o']}], + 'ast': [] + } +] diff --git a/youtube_dl/jsinterp/jsbuilt_ins/__init__.py b/youtube_dl/jsinterp/jsbuilt_ins/__init__.py index a6a07f11e..b87d1a03d 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/__init__.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/__init__.py @@ -8,10 +8,8 @@ from . import jsboolean from . import jsstring from . import jsnumber -undefined = base.JSBase('undefined') -null = base.JSBase('null') -true = jsboolean.JSBooleanPrototype(True) -false = jsboolean.JSBooleanPrototype(False) +from .base import null, undefined +from .jsboolean import false, true def _eval(code): diff --git a/youtube_dl/jsinterp/jsbuilt_ins/base.py b/youtube_dl/jsinterp/jsbuilt_ins/base.py index a787da150..2e63a958d 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/base.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/base.py @@ -3,13 +3,6 @@ from __future__ import unicode_literals from types import FunctionType from ...compat import compat_str -from . import undefined -from .jsobject import JSObjectPrototype -from .jsfunction import JSFunctionPrototype -from .jsarray import JSArrayPrototype -from .jsboolean import JSBooleanPrototype -from .jsstring import JSStringPrototype -from .jsnumber import JSNumberPrototype class JSBase(object): @@ -21,6 +14,10 @@ class JSBase(object): own = {} +undefined = JSBase('undefined') +null = JSBase('null') + + class JSProtoBase(JSBase): def __init__(self): @@ -60,39 +57,6 @@ class JSProtoBase(JSBase): jsclass = '' -def _get_formal_args(func): - return func.__code__.co_varnames[func.__code__.co_argcount - len((func.__defaults__))] - - -def to_js(o, name=None): - if isinstance(o, JSProtoBase): - return o - elif o is None: - return undefined - elif isinstance(o, native_bool): - return JSBooleanPrototype(o) - elif isinstance(o, native_string): - return JSStringPrototype(o) - elif isinstance(o, native_number): - return JSNumberPrototype(o) - elif isinstance(o, native_object): - return JSObjectPrototype(o) - elif isinstance(o, native_function): - return JSFunctionPrototype(name, o, _get_formal_args(o)) - elif isinstance(o, JSBase) and hasattr(o, 'call'): - return JSFunctionPrototype(o.name, o, _get_formal_args(o.call)) - elif isinstance(o, native_array): - return JSArrayPrototype(o) - else: - raise Exception('Not allowed conversion %s to js' % type(o)) - - -def js(func): - def wrapper(*args, **kwargs): - return to_js(*func(*args, **kwargs)) - return wrapper - - native_bool = bool native_string = compat_str native_number = (int, float) diff --git a/youtube_dl/jsinterp/jsbuilt_ins/internals.py b/youtube_dl/jsinterp/jsbuilt_ins/internals.py index 18544e04e..e822d87fc 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/internals.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/internals.py @@ -4,12 +4,8 @@ import re from math import isnan, isinf, log10 from sys import float_info -from . import undefined, null, true, false -from .base import to_js, native_bool, native_string, native_number, native_object -from .jsobject import JSObjectPrototype -from .jsboolean import JSBooleanPrototype -from .jsstring import JSStringPrototype -from .jsnumber import JSNumberPrototype +from .base import native_bool, native_string, native_number, native_object +from .utils import to_js from ..jsgrammar import __HEXADECIMAL_RE undefined_type = object() @@ -21,6 +17,9 @@ object_type = object() def jstype(o): + from .base import null, undefined + from .jsboolean import true, false + if o is undefined: return undefined_type elif o is None or o is null: @@ -42,6 +41,12 @@ def to_primitive(o, hint=None): def to_boolean(o): + from .base import undefined, null + from .jsobject import JSObjectPrototype + from .jsboolean import JSBooleanPrototype, false, true + from .jsstring import JSStringPrototype + from .jsnumber import JSNumberPrototype + if o is undefined or o is null: return false elif isinstance(o, JSBooleanPrototype): @@ -57,6 +62,11 @@ def to_boolean(o): def to_number(o): + from .base import null, undefined + from .jsobject import JSObjectPrototype + from .jsboolean import JSBooleanPrototype, false, true + from .jsstring import JSStringPrototype + if o is undefined: return float('nan') elif o is null or isinstance(o, JSBooleanPrototype) and o.value is false: @@ -129,6 +139,11 @@ def to_uint16(o): def to_string(o): + from .base import null, undefined + from .jsobject import JSObjectPrototype + from .jsboolean import JSBooleanPrototype, false, true + from .jsnumber import JSNumberPrototype + if o is undefined: return 'undefined' elif o is null: @@ -184,6 +199,12 @@ def to_string(o): def to_object(o): + from .base import null, undefined + from .jsobject import JSObjectPrototype + from .jsboolean import JSBooleanPrototype + from .jsstring import JSStringPrototype + from .jsnumber import JSNumberPrototype + if o is undefined or o is null: raise Exception('TypeError: Cannot convert undefined or null to object') elif isinstance(o, JSBooleanPrototype): diff --git a/youtube_dl/jsinterp/jsbuilt_ins/jsarray.py b/youtube_dl/jsinterp/jsbuilt_ins/jsarray.py index 6920ca2ed..f6c329f3f 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/jsarray.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/jsarray.py @@ -1,7 +1,6 @@ from __future__ import unicode_literals -from . import undefined -from .base import native_number +from .base import native_number, undefined from .jsobject import JSObject, JSObjectPrototype from .jsnumber import JSNumberPrototype diff --git a/youtube_dl/jsinterp/jsbuilt_ins/jsboolean.py b/youtube_dl/jsinterp/jsbuilt_ins/jsboolean.py index be82fd24a..ad3895815 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/jsboolean.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/jsboolean.py @@ -1,8 +1,7 @@ from __future__ import unicode_literals -from . import true from .internals import jstype, boolean_type, object_type, to_boolean -from .base import to_js +from .utils import to_js from .jsobject import JSObject, JSObjectPrototype @@ -42,6 +41,10 @@ class JSBooleanPrototype(JSObjectPrototype): } +true = JSBooleanPrototype(True) +false = JSBooleanPrototype(False) + + class JSBoolean(JSObject): @staticmethod diff --git a/youtube_dl/jsinterp/jsbuilt_ins/jsfunction.py b/youtube_dl/jsinterp/jsbuilt_ins/jsfunction.py index 5802d2625..6deb6f4b5 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/jsfunction.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/jsfunction.py @@ -1,8 +1,9 @@ from __future__ import unicode_literals -from . import undefined, null +from .base import undefined, null from .internals import to_string, throw_type_error -from .base import to_js, native_function, JSBase +from .base import native_function, JSBase +from .utils import to_js from .jsobject import JSObject, JSObjectPrototype diff --git a/youtube_dl/jsinterp/jsbuilt_ins/jsnumber.py b/youtube_dl/jsinterp/jsbuilt_ins/jsnumber.py index e571f8350..e2f195c92 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/jsnumber.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/jsnumber.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals from .internals import jstype, number_type, to_number -from .base import to_js +from .utils import to_js from .jsobject import JSObject, JSObjectPrototype diff --git a/youtube_dl/jsinterp/jsbuilt_ins/jsobject.py b/youtube_dl/jsinterp/jsbuilt_ins/jsobject.py index da85bd91a..08f0f437f 100644 --- a/youtube_dl/jsinterp/jsbuilt_ins/jsobject.py +++ b/youtube_dl/jsinterp/jsbuilt_ins/jsobject.py @@ -1,11 +1,8 @@ from __future__ import unicode_literals -from . import null, undefined -from .base import JSProtoBase, to_js, js, JSBase +from .base import JSProtoBase, JSBase, null, undefined +from .utils import to_js, js from .internals import to_object -from .jsboolean import JSBooleanPrototype -from .jsnumber import JSNumberPrototype -from .jsstring import JSStringPrototype class JSObjectPrototype(JSProtoBase): @@ -63,6 +60,10 @@ class JSObject(JSBase): @staticmethod def construct(value=None): + from .jsboolean import JSBooleanPrototype + from .jsnumber import JSNumberPrototype + from .jsstring import JSStringPrototype + value = to_js(value) # TODO set [[Prototype]], [[Class]], [[Extensible]], internal methods if value is undefined or value is null: diff --git a/youtube_dl/jsinterp/jsbuilt_ins/utils.py b/youtube_dl/jsinterp/jsbuilt_ins/utils.py new file mode 100644 index 000000000..65338cc1a --- /dev/null +++ b/youtube_dl/jsinterp/jsbuilt_ins/utils.py @@ -0,0 +1,45 @@ +from .base import ( + JSProtoBase, native_bool, native_string, native_number, native_object, native_function, JSBase, native_array +) + + +def _get_formal_args(func): + return func.__code__.co_varnames[func.__code__.co_argcount - len((func.__defaults__))] + + +def to_js(o, name=None): + from .base import undefined + + from .jsarray import JSArrayPrototype + from .jsboolean import JSBooleanPrototype + from .jsfunction import JSFunctionPrototype + from .jsnumber import JSNumberPrototype + from .jsobject import JSObjectPrototype + from .jsstring import JSStringPrototype + + if isinstance(o, JSProtoBase): + return o + elif o is None: + return undefined + elif isinstance(o, native_bool): + return JSBooleanPrototype(o) + elif isinstance(o, native_string): + return JSStringPrototype(o) + elif isinstance(o, native_number): + return JSNumberPrototype(o) + elif isinstance(o, native_object): + return JSObjectPrototype(o) + elif isinstance(o, native_function): + return JSFunctionPrototype(name, o, _get_formal_args(o)) + elif isinstance(o, JSBase) and hasattr(o, 'call'): + return JSFunctionPrototype(o.name, o, _get_formal_args(o.call)) + elif isinstance(o, native_array): + return JSArrayPrototype(o) + else: + raise Exception('Not allowed conversion %s to js' % type(o)) + + +def js(func): + def wrapper(*args, **kwargs): + return to_js(*func(*args, **kwargs)) + return wrapper