rimessa libreria pyjsparser e aggiornata js2py
This commit is contained in:
@@ -5,6 +5,7 @@ import re
|
||||
from .translators.friendly_nodes import REGEXP_CONVERTER
|
||||
from .utils.injector import fix_js_args
|
||||
from types import FunctionType, ModuleType, GeneratorType, BuiltinFunctionType, MethodType, BuiltinMethodType
|
||||
from math import floor, log10
|
||||
import traceback
|
||||
try:
|
||||
import numpy
|
||||
@@ -603,15 +604,7 @@ class PyJs(object):
|
||||
elif typ == 'Boolean':
|
||||
return Js('true') if self.value else Js('false')
|
||||
elif typ == 'Number': #or self.Class=='Number':
|
||||
if self.is_nan():
|
||||
return Js('NaN')
|
||||
elif self.is_infinity():
|
||||
sign = '-' if self.value < 0 else ''
|
||||
return Js(sign + 'Infinity')
|
||||
elif isinstance(self.value,
|
||||
long) or self.value.is_integer(): # dont print .0
|
||||
return Js(unicode(int(self.value)))
|
||||
return Js(unicode(self.value)) # accurate enough
|
||||
return Js(unicode(js_dtoa(self.value)))
|
||||
elif typ == 'String':
|
||||
return self
|
||||
else: #object
|
||||
@@ -1046,7 +1039,7 @@ def PyJsComma(a, b):
|
||||
return b
|
||||
|
||||
|
||||
from .internals.simplex import JsException as PyJsException
|
||||
from .internals.simplex import JsException as PyJsException, js_dtoa
|
||||
import pyjsparser
|
||||
pyjsparser.parser.ENABLE_JS2PY_ERRORS = lambda msg: MakeError('SyntaxError', msg)
|
||||
|
||||
|
||||
@@ -116,36 +116,52 @@ def eval_js(js):
|
||||
|
||||
|
||||
def eval_js6(js):
|
||||
"""Just like eval_js but with experimental support for js6 via babel."""
|
||||
return eval_js(js6_to_js5(js))
|
||||
|
||||
|
||||
def translate_js6(js):
|
||||
"""Just like translate_js but with experimental support for js6 via babel."""
|
||||
return translate_js(js6_to_js5(js))
|
||||
|
||||
|
||||
class EvalJs(object):
|
||||
"""This class supports continuous execution of javascript under same context.
|
||||
|
||||
>>> js = EvalJs()
|
||||
>>> js.execute('var a = 10;function f(x) {return x*x};')
|
||||
>>> js.f(9)
|
||||
>>> ctx = EvalJs()
|
||||
>>> ctx.execute('var a = 10;function f(x) {return x*x};')
|
||||
>>> ctx.f(9)
|
||||
81
|
||||
>>> js.a
|
||||
>>> ctx.a
|
||||
10
|
||||
|
||||
context is a python dict or object that contains python variables that should be available to JavaScript
|
||||
For example:
|
||||
>>> js = EvalJs({'a': 30})
|
||||
>>> js.execute('var x = a')
|
||||
>>> js.x
|
||||
>>> ctx = EvalJs({'a': 30})
|
||||
>>> ctx.execute('var x = a')
|
||||
>>> ctx.x
|
||||
30
|
||||
|
||||
You can enable JS require function via enable_require. With this feature enabled you can use js modules
|
||||
from npm, for example:
|
||||
>>> ctx = EvalJs(enable_require=True)
|
||||
>>> ctx.execute("var esprima = require('esprima');")
|
||||
>>> ctx.execute("esprima.parse('var a = 1')")
|
||||
|
||||
You can run interactive javascript console with console method!"""
|
||||
|
||||
def __init__(self, context={}):
|
||||
def __init__(self, context={}, enable_require=False):
|
||||
self.__dict__['_context'] = {}
|
||||
exec (DEFAULT_HEADER, self._context)
|
||||
self.__dict__['_var'] = self._context['var'].to_python()
|
||||
|
||||
if enable_require:
|
||||
def _js_require_impl(npm_module_name):
|
||||
from .node_import import require
|
||||
from .base import to_python
|
||||
return require(to_python(npm_module_name), context=self._context)
|
||||
setattr(self._var, 'require', _js_require_impl)
|
||||
|
||||
if not isinstance(context, dict):
|
||||
try:
|
||||
context = context.__dict__
|
||||
|
||||
@@ -7,7 +7,7 @@ from ..byte_trans import ByteCodeGenerator, Code
|
||||
|
||||
def Function(this, args):
|
||||
# convert arguments to python list of strings
|
||||
a = map(to_string, tuple(args))
|
||||
a = list(map(to_string, tuple(args)))
|
||||
_body = u';'
|
||||
_args = ()
|
||||
if len(a):
|
||||
@@ -42,6 +42,7 @@ def executable_code(code_str, space, global_context=True):
|
||||
space.byte_generator.emit('LABEL', skip)
|
||||
space.byte_generator.emit('NOP')
|
||||
space.byte_generator.restore_state()
|
||||
|
||||
space.byte_generator.exe.compile(
|
||||
start_loc=old_tape_len
|
||||
) # dont read the code from the beginning, dont be stupid!
|
||||
@@ -71,5 +72,5 @@ def _eval(this, args):
|
||||
|
||||
|
||||
def log(this, args):
|
||||
print ' '.join(map(to_string, args))
|
||||
print(' '.join(map(to_string, args)))
|
||||
return undefined
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
|
||||
import re
|
||||
from ..conversions import *
|
||||
from ..func_utils import *
|
||||
from jsregexp import RegExpExec
|
||||
from .jsregexp import RegExpExec
|
||||
|
||||
DIGS = set(u'0123456789')
|
||||
WHITE = u"\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
__all__ = ['require']
|
||||
import subprocess, os, codecs, glob
|
||||
from .evaljs import translate_js
|
||||
from .evaljs import translate_js, DEFAULT_HEADER
|
||||
import six
|
||||
DID_INIT = False
|
||||
DIRNAME = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -15,7 +15,7 @@ def _init():
|
||||
'node -v', shell=True, cwd=DIRNAME
|
||||
) == 0, 'You must have node installed! run: brew install node'
|
||||
assert subprocess.call(
|
||||
'cd %s;npm install babel-core babel-cli babel-preset-es2015 babel-polyfill babelify browserify'
|
||||
'cd %s;npm install babel-core babel-cli babel-preset-es2015 babel-polyfill babelify browserify browserify-shim'
|
||||
% repr(DIRNAME),
|
||||
shell=True,
|
||||
cwd=DIRNAME) == 0, 'Could not link required node_modules'
|
||||
@@ -46,12 +46,18 @@ GET_FROM_GLOBALS_FUNC = '''
|
||||
|
||||
'''
|
||||
|
||||
def _get_module_py_name(module_name):
|
||||
return module_name.replace('-', '_')
|
||||
|
||||
def require(module_name, include_polyfill=False, update=False):
|
||||
def _get_module_var_name(module_name):
|
||||
return _get_module_py_name(module_name).rpartition('/')[-1]
|
||||
|
||||
|
||||
def _get_and_translate_npm_module(module_name, include_polyfill=False, update=False):
|
||||
assert isinstance(module_name, str), 'module_name must be a string!'
|
||||
py_name = module_name.replace('-', '_')
|
||||
py_name = _get_module_py_name(module_name)
|
||||
module_filename = '%s.py' % py_name
|
||||
var_name = py_name.rpartition('/')[-1]
|
||||
var_name = _get_module_var_name(module_name)
|
||||
if not os.path.exists(os.path.join(PY_NODE_MODULES_PATH,
|
||||
module_filename)) or update:
|
||||
_init()
|
||||
@@ -77,7 +83,7 @@ def require(module_name, include_polyfill=False, update=False):
|
||||
|
||||
# convert the module
|
||||
assert subprocess.call(
|
||||
'''node -e "(require('browserify')('./%s').bundle(function (err,data) {fs.writeFile('%s', require('babel-core').transform(data, {'presets': require('babel-preset-es2015')}).code, ()=>{});}))"'''
|
||||
'''node -e "(require('browserify')('./%s').bundle(function (err,data) {if (err) {console.log(err);throw new Error(err);};fs.writeFile('%s', require('babel-core').transform(data, {'presets': require('babel-preset-es2015')}).code, ()=>{});}))"'''
|
||||
% (in_file_name, out_file_name),
|
||||
shell=True,
|
||||
cwd=DIRNAME,
|
||||
@@ -88,7 +94,8 @@ def require(module_name, include_polyfill=False, update=False):
|
||||
"utf-8") as f:
|
||||
js_code = f.read()
|
||||
os.remove(os.path.join(DIRNAME, out_file_name))
|
||||
|
||||
if len(js_code) < 50:
|
||||
raise RuntimeError("Candidate JS bundle too short - likely browserify issue.")
|
||||
js_code += GET_FROM_GLOBALS_FUNC
|
||||
js_code += ';var %s = getFromGlobals(%s);%s' % (
|
||||
var_name, repr(module_name), var_name)
|
||||
@@ -107,7 +114,32 @@ def require(module_name, include_polyfill=False, update=False):
|
||||
os.path.join(PY_NODE_MODULES_PATH, module_filename), "r",
|
||||
"utf-8") as f:
|
||||
py_code = f.read()
|
||||
return py_code
|
||||
|
||||
context = {}
|
||||
|
||||
def require(module_name, include_polyfill=False, update=False, context=None):
|
||||
"""
|
||||
Installs the provided npm module, exports a js bundle via browserify, converts to ECMA 5.1 via babel and
|
||||
finally translates the generated JS bundle to Python via Js2Py.
|
||||
Returns a pure python object that behaves like the installed module. Nice!
|
||||
|
||||
:param module_name: Name of the npm module to require. For example 'esprima'.
|
||||
:param include_polyfill: Whether the babel-polyfill should be included as part of the translation. May be needed
|
||||
for some modules that use unsupported features.
|
||||
:param update: Whether to force update the translation. Otherwise uses a cached version if exists.
|
||||
:param context: Optional context in which the translated module should be executed in. If provided, the
|
||||
header (js2py imports) will be skipped as it is assumed that the context already has all the necessary imports.
|
||||
:return: The JsObjectWrapper containing the translated module object. Can be used like a standard python object.
|
||||
"""
|
||||
py_code = _get_and_translate_npm_module(module_name, include_polyfill=include_polyfill, update=update)
|
||||
# this is a bit hacky but we need to strip the default header from the generated code...
|
||||
if context is not None:
|
||||
if not py_code.startswith(DEFAULT_HEADER):
|
||||
# new header version? retranslate...
|
||||
assert not update, "Unexpected header."
|
||||
py_code = _get_and_translate_npm_module(module_name, include_polyfill=include_polyfill, update=True)
|
||||
assert py_code.startswith(DEFAULT_HEADER), "Unexpected header."
|
||||
py_code = py_code[len(DEFAULT_HEADER):]
|
||||
context = {} if context is None else context
|
||||
exec (py_code, context)
|
||||
return context['var'][var_name].to_py()
|
||||
return context['var'][_get_module_var_name(module_name)].to_py()
|
||||
|
||||
@@ -6,8 +6,6 @@ if six.PY3:
|
||||
xrange = range
|
||||
unicode = str
|
||||
|
||||
# todo fix apply and bind
|
||||
|
||||
|
||||
class FunctionPrototype:
|
||||
def toString():
|
||||
@@ -41,6 +39,7 @@ class FunctionPrototype:
|
||||
return this.call(obj, args)
|
||||
|
||||
def bind(thisArg):
|
||||
arguments_ = arguments
|
||||
target = this
|
||||
if not target.is_callable():
|
||||
raise this.MakeError(
|
||||
@@ -48,5 +47,5 @@ class FunctionPrototype:
|
||||
if len(arguments) <= 1:
|
||||
args = ()
|
||||
else:
|
||||
args = tuple([arguments[e] for e in xrange(1, len(arguments))])
|
||||
args = tuple([arguments_[e] for e in xrange(1, len(arguments_))])
|
||||
return this.PyJsBoundFunction(target, thisArg, args)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
from internals import byte_trans
|
||||
from internals import seval
|
||||
import pyjsparser
|
||||
|
||||
x = r'''
|
||||
function g() {var h123 = 11; return [function g1() {return h123}, new Function('return h123')]}
|
||||
g()[1]()
|
||||
'''
|
||||
print seval.eval_js_vm(x)
|
||||
@@ -155,7 +155,7 @@ def limited(func):
|
||||
inf = float('inf')
|
||||
|
||||
|
||||
def Literal(type, value, raw, regex=None, comments=None):
|
||||
def Literal(type, value, raw, regex=None):
|
||||
if regex: # regex
|
||||
return 'JsRegExp(%s)' % repr(compose_regex(value))
|
||||
elif value is None: # null
|
||||
@@ -165,12 +165,12 @@ def Literal(type, value, raw, regex=None, comments=None):
|
||||
return 'Js(%s)' % repr(value) if value != inf else 'Js(float("inf"))'
|
||||
|
||||
|
||||
def Identifier(type, name, comments=None):
|
||||
def Identifier(type, name):
|
||||
return 'var.get(%s)' % repr(name)
|
||||
|
||||
|
||||
@limited
|
||||
def MemberExpression(type, computed, object, property, comments=None):
|
||||
def MemberExpression(type, computed, object, property):
|
||||
far_left = trans(object)
|
||||
if computed: # obj[prop] type accessor
|
||||
# may be literal which is the same in every case so we can save some time on conversion
|
||||
@@ -183,12 +183,12 @@ def MemberExpression(type, computed, object, property, comments=None):
|
||||
return far_left + '.get(%s)' % prop
|
||||
|
||||
|
||||
def ThisExpression(type, comments=None):
|
||||
def ThisExpression(type):
|
||||
return 'var.get(u"this")'
|
||||
|
||||
|
||||
@limited
|
||||
def CallExpression(type, callee, arguments, comments=None):
|
||||
def CallExpression(type, callee, arguments):
|
||||
arguments = [trans(e) for e in arguments]
|
||||
if callee['type'] == 'MemberExpression':
|
||||
far_left = trans(callee['object'])
|
||||
@@ -210,38 +210,47 @@ def CallExpression(type, callee, arguments, comments=None):
|
||||
# ========== ARRAYS ============
|
||||
|
||||
|
||||
def ArrayExpression(type, elements, comments=None): # todo fix null inside problem
|
||||
def ArrayExpression(type, elements): # todo fix null inside problem
|
||||
return 'Js([%s])' % ', '.join(trans(e) if e else 'None' for e in elements)
|
||||
|
||||
|
||||
# ========== OBJECTS =============
|
||||
|
||||
|
||||
def ObjectExpression(type, properties, comments=None):
|
||||
name = inline_stack.require('Object')
|
||||
def ObjectExpression(type, properties):
|
||||
name = None
|
||||
elems = []
|
||||
after = ''
|
||||
for p in properties:
|
||||
if p['kind'] == 'init':
|
||||
elems.append('%s:%s' % Property(**p))
|
||||
elif p['kind'] == 'set':
|
||||
k, setter = Property(
|
||||
**p
|
||||
) # setter is just a lval referring to that function, it will be defined in InlineStack automatically
|
||||
after += '%s.define_own_property(%s, {"set":%s, "configurable":True, "enumerable":True})\n' % (
|
||||
name, k, setter)
|
||||
elif p['kind'] == 'get':
|
||||
k, getter = Property(**p)
|
||||
after += '%s.define_own_property(%s, {"get":%s, "configurable":True, "enumerable":True})\n' % (
|
||||
name, k, getter)
|
||||
else:
|
||||
raise RuntimeError('Unexpected object propery kind')
|
||||
obj = '%s = Js({%s})\n' % (name, ','.join(elems))
|
||||
inline_stack.define(name, obj + after)
|
||||
return name
|
||||
if name is None:
|
||||
name = inline_stack.require('Object')
|
||||
if p['kind'] == 'set':
|
||||
k, setter = Property(
|
||||
**p
|
||||
) # setter is just a lval referring to that function, it will be defined in InlineStack automatically
|
||||
after += '%s.define_own_property(%s, {"set":%s, "configurable":True, "enumerable":True})\n' % (
|
||||
name, k, setter)
|
||||
elif p['kind'] == 'get':
|
||||
k, getter = Property(**p)
|
||||
after += '%s.define_own_property(%s, {"get":%s, "configurable":True, "enumerable":True})\n' % (
|
||||
name, k, getter)
|
||||
else:
|
||||
raise RuntimeError('Unexpected object propery kind')
|
||||
definition = 'Js({%s})' % ','.join(elems)
|
||||
if name is None:
|
||||
return definition
|
||||
body = '%s = %s\n' % (name, definition)
|
||||
body += after
|
||||
body += 'return %s\n' % name
|
||||
code = 'def %s():\n%s' % (name, indent(body))
|
||||
inline_stack.define(name, code)
|
||||
return name + '()'
|
||||
|
||||
|
||||
def Property(type, kind, key, computed, value, method, shorthand, comments=None):
|
||||
def Property(type, kind, key, computed, value, method, shorthand):
|
||||
if shorthand or computed:
|
||||
raise NotImplementedError(
|
||||
'Shorthand and Computed properties not implemented!')
|
||||
@@ -256,7 +265,7 @@ def Property(type, kind, key, computed, value, method, shorthand, comments=None)
|
||||
|
||||
|
||||
@limited
|
||||
def UnaryExpression(type, operator, argument, prefix, comments=None):
|
||||
def UnaryExpression(type, operator, argument, prefix):
|
||||
a = trans(
|
||||
argument, standard=True
|
||||
) # unary involve some complex operations so we cant use line shorteners here
|
||||
@@ -271,7 +280,7 @@ def UnaryExpression(type, operator, argument, prefix, comments=None):
|
||||
|
||||
|
||||
@limited
|
||||
def BinaryExpression(type, operator, left, right, comments=None):
|
||||
def BinaryExpression(type, operator, left, right):
|
||||
a = trans(left)
|
||||
b = trans(right)
|
||||
# delegate to our friends
|
||||
@@ -279,7 +288,7 @@ def BinaryExpression(type, operator, left, right, comments=None):
|
||||
|
||||
|
||||
@limited
|
||||
def UpdateExpression(type, operator, argument, prefix, comments=None):
|
||||
def UpdateExpression(type, operator, argument, prefix):
|
||||
a = trans(
|
||||
argument, standard=True
|
||||
) # also complex operation involving parsing of the result so no line length reducing here
|
||||
@@ -287,7 +296,7 @@ def UpdateExpression(type, operator, argument, prefix, comments=None):
|
||||
|
||||
|
||||
@limited
|
||||
def AssignmentExpression(type, operator, left, right, comments=None):
|
||||
def AssignmentExpression(type, operator, left, right):
|
||||
operator = operator[:-1]
|
||||
if left['type'] == 'Identifier':
|
||||
if operator:
|
||||
@@ -319,12 +328,12 @@ six
|
||||
|
||||
|
||||
@limited
|
||||
def SequenceExpression(type, expressions, comments=None):
|
||||
def SequenceExpression(type, expressions):
|
||||
return reduce(js_comma, (trans(e) for e in expressions))
|
||||
|
||||
|
||||
@limited
|
||||
def NewExpression(type, callee, arguments, comments=None):
|
||||
def NewExpression(type, callee, arguments):
|
||||
return trans(callee) + '.create(%s)' % ', '.join(
|
||||
trans(e) for e in arguments)
|
||||
|
||||
@@ -332,7 +341,7 @@ def NewExpression(type, callee, arguments, comments=None):
|
||||
@limited
|
||||
def ConditionalExpression(
|
||||
type, test, consequent,
|
||||
alternate, comments=None): # caused plenty of problems in my home-made translator :)
|
||||
alternate): # caused plenty of problems in my home-made translator :)
|
||||
return '(%s if %s else %s)' % (trans(consequent), trans(test),
|
||||
trans(alternate))
|
||||
|
||||
@@ -340,49 +349,49 @@ def ConditionalExpression(
|
||||
# =========== STATEMENTS =============
|
||||
|
||||
|
||||
def BlockStatement(type, body, comments=None):
|
||||
def BlockStatement(type, body):
|
||||
return StatementList(
|
||||
body) # never returns empty string! In the worst case returns pass\n
|
||||
|
||||
|
||||
def ExpressionStatement(type, expression, comments=None):
|
||||
def ExpressionStatement(type, expression):
|
||||
return trans(expression) + '\n' # end expression space with new line
|
||||
|
||||
|
||||
def BreakStatement(type, label, comments=None):
|
||||
def BreakStatement(type, label):
|
||||
if label:
|
||||
return 'raise %s("Breaked")\n' % (get_break_label(label['name']))
|
||||
else:
|
||||
return 'break\n'
|
||||
|
||||
|
||||
def ContinueStatement(type, label, comments=None):
|
||||
def ContinueStatement(type, label):
|
||||
if label:
|
||||
return 'raise %s("Continued")\n' % (get_continue_label(label['name']))
|
||||
else:
|
||||
return 'continue\n'
|
||||
|
||||
|
||||
def ReturnStatement(type, argument, comments=None):
|
||||
def ReturnStatement(type, argument):
|
||||
return 'return %s\n' % (trans(argument)
|
||||
if argument else "var.get('undefined')")
|
||||
|
||||
|
||||
def EmptyStatement(type, comments=None):
|
||||
def EmptyStatement(type):
|
||||
return 'pass\n'
|
||||
|
||||
|
||||
def DebuggerStatement(type, comments=None):
|
||||
def DebuggerStatement(type):
|
||||
return 'pass\n'
|
||||
|
||||
|
||||
def DoWhileStatement(type, body, test, comments=None):
|
||||
def DoWhileStatement(type, body, test):
|
||||
inside = trans(body) + 'if not %s:\n' % trans(test) + indent('break\n')
|
||||
result = 'while 1:\n' + indent(inside)
|
||||
return result
|
||||
|
||||
|
||||
def ForStatement(type, init, test, update, body, comments=None):
|
||||
def ForStatement(type, init, test, update, body):
|
||||
update = indent(trans(update)) if update else ''
|
||||
init = trans(init) if init else ''
|
||||
if not init.endswith('\n'):
|
||||
@@ -398,7 +407,7 @@ def ForStatement(type, init, test, update, body, comments=None):
|
||||
return result
|
||||
|
||||
|
||||
def ForInStatement(type, left, right, body, each, comments=None):
|
||||
def ForInStatement(type, left, right, body, each):
|
||||
res = 'for PyJsTemp in %s:\n' % trans(right)
|
||||
if left['type'] == "VariableDeclaration":
|
||||
addon = trans(left) # make sure variable is registered
|
||||
@@ -417,7 +426,7 @@ def ForInStatement(type, left, right, body, each, comments=None):
|
||||
return res
|
||||
|
||||
|
||||
def IfStatement(type, test, consequent, alternate, comments=None):
|
||||
def IfStatement(type, test, consequent, alternate):
|
||||
# NOTE we cannot do elif because function definition inside elif statement would not be possible!
|
||||
IF = 'if %s:\n' % trans(test)
|
||||
IF += indent(trans(consequent))
|
||||
@@ -427,7 +436,7 @@ def IfStatement(type, test, consequent, alternate, comments=None):
|
||||
return IF + ELSE
|
||||
|
||||
|
||||
def LabeledStatement(type, label, body, comments=None):
|
||||
def LabeledStatement(type, label, body):
|
||||
# todo consider using smarter approach!
|
||||
inside = trans(body)
|
||||
defs = ''
|
||||
@@ -448,7 +457,7 @@ def LabeledStatement(type, label, body, comments=None):
|
||||
return defs + inside
|
||||
|
||||
|
||||
def StatementList(lis, comments=None):
|
||||
def StatementList(lis):
|
||||
if lis: # ensure we don't return empty string because it may ruin indentation!
|
||||
code = ''.join(trans(e) for e in lis)
|
||||
return code if code else 'pass\n'
|
||||
@@ -456,7 +465,7 @@ def StatementList(lis, comments=None):
|
||||
return 'pass\n'
|
||||
|
||||
|
||||
def PyimportStatement(type, imp, comments=None):
|
||||
def PyimportStatement(type, imp):
|
||||
lib = imp['name']
|
||||
jlib = 'PyImport_%s' % lib
|
||||
code = 'import %s as %s\n' % (lib, jlib)
|
||||
@@ -471,7 +480,7 @@ def PyimportStatement(type, imp, comments=None):
|
||||
return code
|
||||
|
||||
|
||||
def SwitchStatement(type, discriminant, cases, comments=None):
|
||||
def SwitchStatement(type, discriminant, cases):
|
||||
#TODO there will be a problem with continue in a switch statement.... FIX IT
|
||||
code = 'while 1:\n' + indent('SWITCHED = False\nCONDITION = (%s)\n')
|
||||
code = code % trans(discriminant)
|
||||
@@ -491,12 +500,12 @@ def SwitchStatement(type, discriminant, cases, comments=None):
|
||||
return code
|
||||
|
||||
|
||||
def ThrowStatement(type, argument, comments=None):
|
||||
def ThrowStatement(type, argument):
|
||||
return 'PyJsTempException = JsToPyException(%s)\nraise PyJsTempException\n' % trans(
|
||||
argument)
|
||||
|
||||
|
||||
def TryStatement(type, block, handler, handlers, guardedHandlers, finalizer, comments=None):
|
||||
def TryStatement(type, block, handler, handlers, guardedHandlers, finalizer):
|
||||
result = 'try:\n%s' % indent(trans(block))
|
||||
# complicated catch statement...
|
||||
if handler:
|
||||
@@ -516,13 +525,13 @@ def TryStatement(type, block, handler, handlers, guardedHandlers, finalizer, com
|
||||
return result
|
||||
|
||||
|
||||
def LexicalDeclaration(type, declarations, kind, comments=None):
|
||||
def LexicalDeclaration(type, declarations, kind):
|
||||
raise NotImplementedError(
|
||||
'let and const not implemented yet but they will be soon! Check github for updates.'
|
||||
)
|
||||
|
||||
|
||||
def VariableDeclarator(type, id, init, comments=None):
|
||||
def VariableDeclarator(type, id, init):
|
||||
name = id['name']
|
||||
# register the name if not already registered
|
||||
Context.register(name)
|
||||
@@ -531,21 +540,21 @@ def VariableDeclarator(type, id, init, comments=None):
|
||||
return ''
|
||||
|
||||
|
||||
def VariableDeclaration(type, declarations, kind, comments=None):
|
||||
def VariableDeclaration(type, declarations, kind):
|
||||
code = ''.join(trans(d) for d in declarations)
|
||||
return code if code else 'pass\n'
|
||||
|
||||
|
||||
def WhileStatement(type, test, body, comments=None):
|
||||
def WhileStatement(type, test, body):
|
||||
result = 'while %s:\n' % trans(test) + indent(trans(body))
|
||||
return result
|
||||
|
||||
|
||||
def WithStatement(type, object, body, comments=None):
|
||||
def WithStatement(type, object, body):
|
||||
raise NotImplementedError('With statement not implemented!')
|
||||
|
||||
|
||||
def Program(type, body, comments=None):
|
||||
def Program(type, body):
|
||||
inline_stack.reset()
|
||||
code = ''.join(trans(e) for e in body)
|
||||
# here add hoisted elements (register variables and define functions)
|
||||
@@ -559,7 +568,7 @@ def Program(type, body, comments=None):
|
||||
|
||||
|
||||
def FunctionDeclaration(type, id, params, defaults, body, generator,
|
||||
expression, comments=None):
|
||||
expression):
|
||||
if generator:
|
||||
raise NotImplementedError('Generators not supported')
|
||||
if defaults:
|
||||
@@ -610,7 +619,7 @@ def FunctionDeclaration(type, id, params, defaults, body, generator,
|
||||
|
||||
|
||||
def FunctionExpression(type, id, params, defaults, body, generator,
|
||||
expression, comments=None):
|
||||
expression):
|
||||
if generator:
|
||||
raise NotImplementedError('Generators not supported')
|
||||
if defaults:
|
||||
|
||||
@@ -115,7 +115,16 @@ def append_arguments(code_obj, new_locals):
|
||||
code_obj.co_freevars, code_obj.co_cellvars)
|
||||
|
||||
# Done modifying codestring - make the code object
|
||||
return types.CodeType(*args)
|
||||
if hasattr(code_obj, "replace"):
|
||||
# Python 3.8+
|
||||
return code_obj.replace(
|
||||
co_argcount=co_argcount + new_locals_len,
|
||||
co_nlocals=code_obj.co_nlocals + new_locals_len,
|
||||
co_code=code,
|
||||
co_names=names,
|
||||
co_varnames=varnames)
|
||||
else:
|
||||
return types.CodeType(*args)
|
||||
|
||||
|
||||
def instructions(code_obj):
|
||||
|
||||
5
lib/pyjsparser/__init__.py
Normal file
5
lib/pyjsparser/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
__all__ = ['PyJsParser', 'parse', 'JsSyntaxError', 'pyjsparserdata']
|
||||
__author__ = 'Piotr Dabkowski'
|
||||
__version__ = '2.2.0'
|
||||
from .parser import PyJsParser, parse, JsSyntaxError
|
||||
from . import pyjsparserdata
|
||||
3041
lib/pyjsparser/parser.py
Normal file
3041
lib/pyjsparser/parser.py
Normal file
File diff suppressed because it is too large
Load Diff
407
lib/pyjsparser/pyjsparserdata.py
Normal file
407
lib/pyjsparser/pyjsparserdata.py
Normal file
@@ -0,0 +1,407 @@
|
||||
# The MIT License
|
||||
#
|
||||
# Copyright 2014, 2015 Piotr Dabkowski
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the 'Software'),
|
||||
# to deal in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so, subject
|
||||
# to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all copies or
|
||||
# substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import unicodedata
|
||||
from collections import defaultdict
|
||||
|
||||
PY3 = sys.version_info >= (3, 0)
|
||||
|
||||
if PY3:
|
||||
unichr = chr
|
||||
xrange = range
|
||||
unicode = str
|
||||
|
||||
token = {
|
||||
'BooleanLiteral': 1,
|
||||
'EOF': 2,
|
||||
'Identifier': 3,
|
||||
'Keyword': 4,
|
||||
'NullLiteral': 5,
|
||||
'NumericLiteral': 6,
|
||||
'Punctuator': 7,
|
||||
'StringLiteral': 8,
|
||||
'RegularExpression': 9,
|
||||
'Template': 10
|
||||
}
|
||||
|
||||
TokenName = dict((v, k) for k, v in token.items())
|
||||
|
||||
FnExprTokens = [
|
||||
'(',
|
||||
'{',
|
||||
'[',
|
||||
'in',
|
||||
'typeof',
|
||||
'instanceof',
|
||||
'new',
|
||||
'return',
|
||||
'case',
|
||||
'delete',
|
||||
'throw',
|
||||
'void',
|
||||
# assignment operators
|
||||
'=',
|
||||
'+=',
|
||||
'-=',
|
||||
'*=',
|
||||
'/=',
|
||||
'%=',
|
||||
'<<=',
|
||||
'>>=',
|
||||
'>>>=',
|
||||
'&=',
|
||||
'|=',
|
||||
'^=',
|
||||
',',
|
||||
# binary/unary operators
|
||||
'+',
|
||||
'-',
|
||||
'*',
|
||||
'/',
|
||||
'%',
|
||||
'++',
|
||||
'--',
|
||||
'<<',
|
||||
'>>',
|
||||
'>>>',
|
||||
'&',
|
||||
'|',
|
||||
'^',
|
||||
'!',
|
||||
'~',
|
||||
'&&',
|
||||
'||',
|
||||
'?',
|
||||
':',
|
||||
'===',
|
||||
'==',
|
||||
'>=',
|
||||
'<=',
|
||||
'<',
|
||||
'>',
|
||||
'!=',
|
||||
'!=='
|
||||
]
|
||||
|
||||
syntax = set(
|
||||
('AssignmentExpression', 'AssignmentPattern', 'ArrayExpression',
|
||||
'ArrayPattern', 'ArrowFunctionExpression', 'BlockStatement',
|
||||
'BinaryExpression', 'BreakStatement', 'CallExpression', 'CatchClause',
|
||||
'ClassBody', 'ClassDeclaration', 'ClassExpression',
|
||||
'ConditionalExpression', 'ContinueStatement', 'DoWhileStatement',
|
||||
'DebuggerStatement', 'EmptyStatement', 'ExportAllDeclaration',
|
||||
'ExportDefaultDeclaration', 'ExportNamedDeclaration', 'ExportSpecifier',
|
||||
'ExpressionStatement', 'ForStatement', 'ForInStatement',
|
||||
'FunctionDeclaration', 'FunctionExpression', 'Identifier', 'IfStatement',
|
||||
'ImportDeclaration', 'ImportDefaultSpecifier', 'ImportNamespaceSpecifier',
|
||||
'ImportSpecifier', 'Literal', 'LabeledStatement', 'LogicalExpression',
|
||||
'MemberExpression', 'MethodDefinition', 'NewExpression',
|
||||
'ObjectExpression', 'ObjectPattern', 'Program', 'Property', 'RestElement',
|
||||
'ReturnStatement', 'SequenceExpression', 'SpreadElement', 'Super',
|
||||
'SwitchCase', 'SwitchStatement', 'TaggedTemplateExpression',
|
||||
'TemplateElement', 'TemplateLiteral', 'ThisExpression', 'ThrowStatement',
|
||||
'TryStatement', 'UnaryExpression', 'UpdateExpression',
|
||||
'VariableDeclaration', 'VariableDeclarator', 'WhileStatement',
|
||||
'WithStatement'))
|
||||
|
||||
supported_syntax = set(
|
||||
('AssignmentExpression', 'ArrayExpression', 'BlockStatement',
|
||||
'BinaryExpression', 'BreakStatement', 'CallExpression', 'CatchClause',
|
||||
'ConditionalExpression', 'ContinueStatement', 'DoWhileStatement',
|
||||
'DebuggerStatement', 'EmptyStatement', 'ExpressionStatement',
|
||||
'ForStatement', 'ForInStatement', 'FunctionDeclaration',
|
||||
'FunctionExpression', 'Identifier', 'IfStatement', 'Literal',
|
||||
'LabeledStatement', 'LogicalExpression', 'MemberExpression',
|
||||
'MethodDefinition', 'NewExpression', 'ObjectExpression', 'Program',
|
||||
'Property', 'ReturnStatement', 'SequenceExpression', 'SwitchCase',
|
||||
'SwitchStatement', 'ThisExpression', 'ThrowStatement', 'TryStatement',
|
||||
'UnaryExpression', 'UpdateExpression', 'VariableDeclaration',
|
||||
'VariableDeclarator', 'WhileStatement', 'WithStatement'))
|
||||
|
||||
# Error messages should be identical to V8.
|
||||
messages = {
|
||||
'UnexpectedToken':
|
||||
'Unexpected token %s',
|
||||
'UnexpectedNumber':
|
||||
'Unexpected number',
|
||||
'UnexpectedString':
|
||||
'Unexpected string',
|
||||
'UnexpectedIdentifier':
|
||||
'Unexpected identifier',
|
||||
'UnexpectedReserved':
|
||||
'Unexpected reserved word',
|
||||
'UnexpectedTemplate':
|
||||
'Unexpected quasi %s',
|
||||
'UnexpectedEOS':
|
||||
'Unexpected end of input',
|
||||
'NewlineAfterThrow':
|
||||
'Illegal newline after throw',
|
||||
'InvalidRegExp':
|
||||
'Invalid regular expression',
|
||||
'UnterminatedRegExp':
|
||||
'Invalid regular expression: missing /',
|
||||
'InvalidLHSInAssignment':
|
||||
'Invalid left-hand side in assignment',
|
||||
'InvalidLHSInForIn':
|
||||
'Invalid left-hand side in for-in',
|
||||
'MultipleDefaultsInSwitch':
|
||||
'More than one default clause in switch statement',
|
||||
'NoCatchOrFinally':
|
||||
'Missing catch or finally after try',
|
||||
'UnknownLabel':
|
||||
'Undefined label \'%s\'',
|
||||
'Redeclaration':
|
||||
'%s \'%s\' has already been declared',
|
||||
'IllegalContinue':
|
||||
'Illegal continue statement',
|
||||
'IllegalBreak':
|
||||
'Illegal break statement',
|
||||
'IllegalReturn':
|
||||
'Illegal return statement',
|
||||
'StrictModeWith':
|
||||
'Strict mode code may not include a with statement',
|
||||
'StrictCatchVariable':
|
||||
'Catch variable may not be eval or arguments in strict mode',
|
||||
'StrictVarName':
|
||||
'Variable name may not be eval or arguments in strict mode',
|
||||
'StrictParamName':
|
||||
'Parameter name eval or arguments is not allowed in strict mode',
|
||||
'StrictParamDupe':
|
||||
'Strict mode function may not have duplicate parameter names',
|
||||
'StrictFunctionName':
|
||||
'Function name may not be eval or arguments in strict mode',
|
||||
'StrictOctalLiteral':
|
||||
'Octal literals are not allowed in strict mode.',
|
||||
'StrictDelete':
|
||||
'Delete of an unqualified identifier in strict mode.',
|
||||
'StrictLHSAssignment':
|
||||
'Assignment to eval or arguments is not allowed in strict mode',
|
||||
'StrictLHSPostfix':
|
||||
'Postfix increment/decrement may not have eval or arguments operand in strict mode',
|
||||
'StrictLHSPrefix':
|
||||
'Prefix increment/decrement may not have eval or arguments operand in strict mode',
|
||||
'StrictReservedWord':
|
||||
'Use of future reserved word in strict mode',
|
||||
'TemplateOctalLiteral':
|
||||
'Octal literals are not allowed in template strings.',
|
||||
'ParameterAfterRestParameter':
|
||||
'Rest parameter must be last formal parameter',
|
||||
'DefaultRestParameter':
|
||||
'Unexpected token =',
|
||||
'ObjectPatternAsRestParameter':
|
||||
'Unexpected token {',
|
||||
'DuplicateProtoProperty':
|
||||
'Duplicate __proto__ fields are not allowed in object literals',
|
||||
'ConstructorSpecialMethod':
|
||||
'Class constructor may not be an accessor',
|
||||
'DuplicateConstructor':
|
||||
'A class may only have one constructor',
|
||||
'StaticPrototype':
|
||||
'Classes may not have static property named prototype',
|
||||
'MissingFromClause':
|
||||
'Unexpected token',
|
||||
'NoAsAfterImportNamespace':
|
||||
'Unexpected token',
|
||||
'InvalidModuleSpecifier':
|
||||
'Unexpected token',
|
||||
'IllegalImportDeclaration':
|
||||
'Unexpected token',
|
||||
'IllegalExportDeclaration':
|
||||
'Unexpected token'
|
||||
}
|
||||
|
||||
PRECEDENCE = {
|
||||
'||': 1,
|
||||
'&&': 2,
|
||||
'|': 3,
|
||||
'^': 4,
|
||||
'&': 5,
|
||||
'==': 6,
|
||||
'!=': 6,
|
||||
'===': 6,
|
||||
'!==': 6,
|
||||
'<': 7,
|
||||
'>': 7,
|
||||
'<=': 7,
|
||||
'>=': 7,
|
||||
'instanceof': 7,
|
||||
'in': 7,
|
||||
'<<': 8,
|
||||
'>>': 8,
|
||||
'>>>': 8,
|
||||
'+': 9,
|
||||
'-': 9,
|
||||
'*': 11,
|
||||
'/': 11,
|
||||
'%': 11
|
||||
}
|
||||
|
||||
|
||||
class Token:
|
||||
pass
|
||||
|
||||
|
||||
class Syntax:
|
||||
pass
|
||||
|
||||
|
||||
class Messages:
|
||||
pass
|
||||
|
||||
|
||||
class PlaceHolders:
|
||||
ArrowParameterPlaceHolder = 'ArrowParameterPlaceHolder'
|
||||
|
||||
|
||||
for k, v in token.items():
|
||||
setattr(Token, k, v)
|
||||
|
||||
for e in syntax:
|
||||
setattr(Syntax, e, e)
|
||||
|
||||
for k, v in messages.items():
|
||||
setattr(Messages, k, v)
|
||||
|
||||
#http://stackoverflow.com/questions/14245893/efficiently-list-all-characters-in-a-given-unicode-category
|
||||
BOM = u'\uFEFF'
|
||||
ZWJ = u'\u200D'
|
||||
ZWNJ = u'\u200C'
|
||||
TAB = u'\u0009'
|
||||
VT = u'\u000B'
|
||||
FF = u'\u000C'
|
||||
SP = u'\u0020'
|
||||
NBSP = u'\u00A0'
|
||||
LF = u'\u000A'
|
||||
CR = u'\u000D'
|
||||
LS = u'\u2028'
|
||||
PS = u'\u2029'
|
||||
|
||||
|
||||
LETTER_CATEGORIES = set(['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl'])
|
||||
|
||||
COMBINING_MARK_CATEGORIES = set(['Mn', 'Mc'])
|
||||
DIGIT_CATEGORIES = set(['Nd'])
|
||||
CONNECTOR_PUNCTUATION_CATEGORIES = set(['Pc'])
|
||||
IDENTIFIER_START_CATEGORIES = LETTER_CATEGORIES.copy() # and some fucking unicode escape sequence
|
||||
IDENTIFIER_PART_CATEGORIES = IDENTIFIER_START_CATEGORIES.union(COMBINING_MARK_CATEGORIES).union(DIGIT_CATEGORIES)\
|
||||
.union(CONNECTOR_PUNCTUATION_CATEGORIES)
|
||||
|
||||
EXTRA_IDENTIFIER_START_CHARS = set(('$','_', '\\'))
|
||||
EXTRA_IDENTIFIER_PART_CHARS = EXTRA_IDENTIFIER_START_CHARS.union(set((ZWJ, ZWNJ)))
|
||||
|
||||
WHITE_SPACE = set((0x20, 0x09, 0x0B, 0x0C, 0xA0, 0x1680, 0x180E, 0x2000,
|
||||
0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
|
||||
0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF))
|
||||
|
||||
LINE_TERMINATORS = set((0x0A, 0x0D, 0x2028, 0x2029))
|
||||
|
||||
|
||||
def isIdentifierStart(ch):
|
||||
uch = (ch if isinstance(ch, unicode) else unichr(ch))
|
||||
return unicodedata.category(uch) in IDENTIFIER_START_CATEGORIES or uch in EXTRA_IDENTIFIER_START_CHARS
|
||||
|
||||
|
||||
def isIdentifierPart(ch):
|
||||
uch = (ch if isinstance(ch, unicode) else unichr(ch))
|
||||
return unicodedata.category(uch) in IDENTIFIER_PART_CATEGORIES or uch in EXTRA_IDENTIFIER_PART_CHARS
|
||||
|
||||
|
||||
def isValidIdentifier(name):
|
||||
if not name or isKeyword(name):
|
||||
return False
|
||||
check = isIdentifierStart
|
||||
for e in name:
|
||||
if not check(e):
|
||||
return False
|
||||
check = isIdentifierPart
|
||||
return True
|
||||
|
||||
|
||||
def isWhiteSpace(ch):
|
||||
return (ord(ch) if isinstance(ch, unicode) else ch) in WHITE_SPACE
|
||||
|
||||
|
||||
def isLineTerminator(ch):
|
||||
return (ord(ch) if isinstance(ch, unicode) else ch) in LINE_TERMINATORS
|
||||
|
||||
|
||||
OCTAL = set(('0', '1', '2', '3', '4', '5', '6', '7'))
|
||||
DEC = set(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'))
|
||||
HEX = set('0123456789abcdefABCDEF')
|
||||
HEX_CONV = dict(('0123456789abcdef' [n], n) for n in xrange(16))
|
||||
for i, e in enumerate('ABCDEF', 10):
|
||||
HEX_CONV[e] = i
|
||||
|
||||
|
||||
def isDecimalDigit(ch):
|
||||
return (ch if isinstance(ch, unicode) else unichr(ch)) in DEC
|
||||
|
||||
|
||||
def isHexDigit(ch):
|
||||
return (ch if isinstance(ch, unicode) else unichr(ch)) in HEX
|
||||
|
||||
|
||||
def isOctalDigit(ch):
|
||||
return (ch if isinstance(ch, unicode) else unichr(ch)) in OCTAL
|
||||
|
||||
|
||||
def isFutureReservedWord(w):
|
||||
return w in ('enum', 'export', 'import', 'super')
|
||||
|
||||
|
||||
RESERVED_WORD = set(('implements', 'interface', 'package', 'private',
|
||||
'protected', 'public', 'static', 'yield', 'let'))
|
||||
|
||||
|
||||
def isStrictModeReservedWord(w):
|
||||
return w in RESERVED_WORD
|
||||
|
||||
|
||||
def isRestrictedWord(w):
|
||||
return w in ('eval', 'arguments')
|
||||
|
||||
|
||||
KEYWORDS = set(
|
||||
('if', 'in', 'do', 'var', 'for', 'new', 'try', 'let', 'this', 'else',
|
||||
'case', 'void', 'with', 'enum', 'while', 'break', 'catch', 'throw',
|
||||
'const', 'yield', 'class', 'super', 'return', 'typeof', 'delete',
|
||||
'switch', 'export', 'import', 'default', 'finally', 'extends', 'function',
|
||||
'continue', 'debugger', 'instanceof', 'pyimport'))
|
||||
|
||||
|
||||
def isKeyword(w):
|
||||
# 'const' is specialized as Keyword in V8.
|
||||
# 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next.
|
||||
# Some others are from future reserved words.
|
||||
return w in KEYWORDS
|
||||
|
||||
|
||||
class JsSyntaxError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
assert isLineTerminator('\n')
|
||||
assert isLineTerminator(0x0A)
|
||||
assert isIdentifierStart('$')
|
||||
assert isIdentifierStart(100)
|
||||
assert isWhiteSpace(' ')
|
||||
371
lib/pyjsparser/std_nodes.py
Normal file
371
lib/pyjsparser/std_nodes.py
Normal file
@@ -0,0 +1,371 @@
|
||||
from .pyjsparserdata import *
|
||||
|
||||
|
||||
class Ecma51NotSupported(Exception):
|
||||
def __init__(self, feature):
|
||||
super(Ecma51NotSupported,
|
||||
self).__init__("%s is not supported by ECMA 5.1." % feature)
|
||||
self.feature = feature
|
||||
|
||||
def get_feature(self):
|
||||
return self.feature
|
||||
|
||||
|
||||
class BaseNode:
|
||||
def finish(self):
|
||||
pass
|
||||
|
||||
def finishArrayExpression(self, elements):
|
||||
self.type = Syntax.ArrayExpression
|
||||
self.elements = elements
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishArrayPattern(self, elements):
|
||||
self.type = Syntax.ArrayPattern
|
||||
self.elements = elements
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishAssignmentExpression(self, operator, left, right):
|
||||
self.type = Syntax.AssignmentExpression
|
||||
self.operator = operator
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishAssignmentPattern(self, left, right):
|
||||
self.type = Syntax.AssignmentPattern
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishBinaryExpression(self, operator, left, right):
|
||||
self.type = Syntax.LogicalExpression if (
|
||||
operator == '||' or operator == '&&') else Syntax.BinaryExpression
|
||||
self.operator = operator
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishBlockStatement(self, body):
|
||||
self.type = Syntax.BlockStatement
|
||||
self.body = body
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishBreakStatement(self, label):
|
||||
self.type = Syntax.BreakStatement
|
||||
self.label = label
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishCallExpression(self, callee, args):
|
||||
self.type = Syntax.CallExpression
|
||||
self.callee = callee
|
||||
self.arguments = args
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishCatchClause(self, param, body):
|
||||
self.type = Syntax.CatchClause
|
||||
self.param = param
|
||||
self.body = body
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishConditionalExpression(self, test, consequent, alternate):
|
||||
self.type = Syntax.ConditionalExpression
|
||||
self.test = test
|
||||
self.consequent = consequent
|
||||
self.alternate = alternate
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishContinueStatement(self, label):
|
||||
self.type = Syntax.ContinueStatement
|
||||
self.label = label
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishDebuggerStatement(self, ):
|
||||
self.type = Syntax.DebuggerStatement
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishDoWhileStatement(self, body, test):
|
||||
self.type = Syntax.DoWhileStatement
|
||||
self.body = body
|
||||
self.test = test
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishEmptyStatement(self, ):
|
||||
self.type = Syntax.EmptyStatement
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishExpressionStatement(self, expression):
|
||||
self.type = Syntax.ExpressionStatement
|
||||
self.expression = expression
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishForStatement(self, init, test, update, body):
|
||||
self.type = Syntax.ForStatement
|
||||
self.init = init
|
||||
self.test = test
|
||||
self.update = update
|
||||
self.body = body
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishForInStatement(self, left, right, body):
|
||||
self.type = Syntax.ForInStatement
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.body = body
|
||||
self.each = False
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishFunctionDeclaration(self, id, params, defaults, body):
|
||||
self.type = Syntax.FunctionDeclaration
|
||||
self.id = id
|
||||
self.params = params
|
||||
self.defaults = defaults
|
||||
self.body = body
|
||||
self.generator = False
|
||||
self.expression = False
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishFunctionExpression(self, id, params, defaults, body):
|
||||
self.type = Syntax.FunctionExpression
|
||||
self.id = id
|
||||
self.params = params
|
||||
self.defaults = defaults
|
||||
self.body = body
|
||||
self.generator = False
|
||||
self.expression = False
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishIdentifier(self, name):
|
||||
self.type = Syntax.Identifier
|
||||
self.name = name
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishIfStatement(self, test, consequent, alternate):
|
||||
self.type = Syntax.IfStatement
|
||||
self.test = test
|
||||
self.consequent = consequent
|
||||
self.alternate = alternate
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishLabeledStatement(self, label, body):
|
||||
self.type = Syntax.LabeledStatement
|
||||
self.label = label
|
||||
self.body = body
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishLiteral(self, token):
|
||||
self.type = Syntax.Literal
|
||||
self.value = token['value']
|
||||
self.raw = token['raw']
|
||||
if token.get('regex'):
|
||||
self.regex = token['regex']
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishMemberExpression(self, accessor, object, property):
|
||||
self.type = Syntax.MemberExpression
|
||||
self.computed = accessor == '['
|
||||
self.object = object
|
||||
self.property = property
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishNewExpression(self, callee, args):
|
||||
self.type = Syntax.NewExpression
|
||||
self.callee = callee
|
||||
self.arguments = args
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishObjectExpression(self, properties):
|
||||
self.type = Syntax.ObjectExpression
|
||||
self.properties = properties
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishObjectPattern(self, properties):
|
||||
self.type = Syntax.ObjectPattern
|
||||
self.properties = properties
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishPostfixExpression(self, operator, argument):
|
||||
self.type = Syntax.UpdateExpression
|
||||
self.operator = operator
|
||||
self.argument = argument
|
||||
self.prefix = False
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishProgram(self, body):
|
||||
self.type = Syntax.Program
|
||||
self.body = body
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishPyimport(self, imp):
|
||||
self.type = 'PyimportStatement'
|
||||
self.imp = imp
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishProperty(self, kind, key, computed, value, method, shorthand):
|
||||
self.type = Syntax.Property
|
||||
self.key = key
|
||||
self.computed = computed
|
||||
self.value = value
|
||||
self.kind = kind
|
||||
self.method = method
|
||||
self.shorthand = shorthand
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishReturnStatement(self, argument):
|
||||
self.type = Syntax.ReturnStatement
|
||||
self.argument = argument
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishSequenceExpression(self, expressions):
|
||||
self.type = Syntax.SequenceExpression
|
||||
self.expressions = expressions
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishSwitchCase(self, test, consequent):
|
||||
self.type = Syntax.SwitchCase
|
||||
self.test = test
|
||||
self.consequent = consequent
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishSwitchStatement(self, discriminant, cases):
|
||||
self.type = Syntax.SwitchStatement
|
||||
self.discriminant = discriminant
|
||||
self.cases = cases
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishThisExpression(self, ):
|
||||
self.type = Syntax.ThisExpression
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishThrowStatement(self, argument):
|
||||
self.type = Syntax.ThrowStatement
|
||||
self.argument = argument
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishTryStatement(self, block, handler, finalizer):
|
||||
self.type = Syntax.TryStatement
|
||||
self.block = block
|
||||
self.guardedHandlers = []
|
||||
self.handlers = [handler] if handler else []
|
||||
self.handler = handler
|
||||
self.finalizer = finalizer
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishUnaryExpression(self, operator, argument):
|
||||
self.type = Syntax.UpdateExpression if (
|
||||
operator == '++' or operator == '--') else Syntax.UnaryExpression
|
||||
self.operator = operator
|
||||
self.argument = argument
|
||||
self.prefix = True
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishVariableDeclaration(self, declarations):
|
||||
self.type = Syntax.VariableDeclaration
|
||||
self.declarations = declarations
|
||||
self.kind = 'var'
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishLexicalDeclaration(self, declarations, kind):
|
||||
self.type = Syntax.VariableDeclaration
|
||||
self.declarations = declarations
|
||||
self.kind = kind
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishVariableDeclarator(self, id, init):
|
||||
self.type = Syntax.VariableDeclarator
|
||||
self.id = id
|
||||
self.init = init
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishWhileStatement(self, test, body):
|
||||
self.type = Syntax.WhileStatement
|
||||
self.test = test
|
||||
self.body = body
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def finishWithStatement(self, object, body):
|
||||
self.type = Syntax.WithStatement
|
||||
self.object = object
|
||||
self.body = body
|
||||
self.finish()
|
||||
return self
|
||||
|
||||
def __getattr__(self, item):
|
||||
if item in self.__dict__:
|
||||
return self.__dict__[item]
|
||||
if item.startswith('finish'):
|
||||
feature = item[6:]
|
||||
raise Ecma51NotSupported(feature)
|
||||
else:
|
||||
raise AttributeError(item)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return getattr(self, item)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
setattr(self, key, value)
|
||||
|
||||
def to_dict(self):
|
||||
return node_to_dict(self)
|
||||
|
||||
|
||||
class Node(BaseNode):
|
||||
pass
|
||||
|
||||
|
||||
class WrappingNode(BaseNode):
|
||||
def __init__(self, startToken=None):
|
||||
pass
|
||||
|
||||
|
||||
def node_to_dict(node): # extremely important for translation speed
|
||||
if isinstance(node, list):
|
||||
return [node_to_dict(e) for e in node]
|
||||
elif isinstance(node, dict):
|
||||
return dict((k, node_to_dict(v)) for k, v in node.items())
|
||||
elif not isinstance(node, BaseNode):
|
||||
return node
|
||||
return dict((k, node_to_dict(v)) for k, v in node.__dict__.items())
|
||||
Reference in New Issue
Block a user