Revert "Test - CF per XBOX"

This reverts commit ef822e749d.
This commit is contained in:
Alhaziel
2019-12-03 18:47:48 +01:00
parent ef822e749d
commit 917f1a2c4b
208 changed files with 78 additions and 115980 deletions
+1 -2
View File
@@ -409,8 +409,7 @@ def downloadpage(url, **opt):
"""
load_cookies()
import requests
if ('Linux' in os.name and 'ANDROID_STORAGE' not in os.environ and config.get_platform(True)['num_version'] > 18.2) \
or ('nt' in os.name and 'ProfileDrive' in os.environ and 'LogDrive' in os.environ):
if 'Linux' in os.name and 'ANDROID_STORAGE' not in os.environ and config.get_platform(True)['num_version'] > 18.2:
from lib.cloudscraper import cloudscraper
else:
from lib.cloudscraper import cloudscraper_mod as cloudscraper
@@ -1,6 +1,6 @@
from __future__ import absolute_import
from js2py import js2py
import js2py
import logging
import base64
@@ -1,6 +1,6 @@
from __future__ import absolute_import
from js2py import js2py_old as js2py
import js2py
import logging
import base64
+75
View File
@@ -0,0 +1,75 @@
# 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
""" This module allows you to translate and execute Javascript in pure python.
Basically its implementation of ECMAScript 5.1 in pure python.
Use eval_js method to execute javascript code and get resulting python object (builtin if possible).
EXAMPLE:
>>> import js2py
>>> add = js2py.eval_js('function add(a, b) {return a + b}')
>>> add(1, 2) + 3
6
>>> add('1', 2, 3)
u'12'
>>> add.constructor
function Function() { [python code] }
Or use EvalJs to execute many javascript code fragments under same context - you would be able to get any
variable from the context!
>>> js = js2py.EvalJs()
>>> js.execute('var a = 10; function f(x) {return x*x};')
>>> js.f(9)
81
>>> js.a
10
Also you can use its console method to play with interactive javascript console.
Use parse_js to parse (syntax tree is just like in esprima.js) and translate_js to trasnlate JavaScript.
Finally, you can use pyimport statement from inside JS code to import and use python libraries.
>>> js2py.eval_js('pyimport urllib; urllib.urlopen("https://www.google.com")')
NOTE: This module is still not fully finished:
Date and JSON builtin objects are not implemented
Array prototype is not fully finished (will be soon)
Other than that everything should work fine.
"""
__author__ = 'Piotr Dabkowski'
__all__ = [
'EvalJs', 'translate_js', 'import_js', 'eval_js', 'parse_js',
'translate_file', 'run_file', 'disable_pyimport', 'eval_js6',
'translate_js6', 'PyJsException', 'get_file_contents',
'write_file_contents', 'require'
]
from .base import PyJsException
from .evaljs import *
from .translators import parse as parse_js
from .node_import import require
-75
View File
@@ -1,75 +0,0 @@
# 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
""" This module allows you to translate and execute Javascript in pure python.
Basically its implementation of ECMAScript 5.1 in pure python.
Use eval_js method to execute javascript code and get resulting python object (builtin if possible).
EXAMPLE:
>>> import js2py
>>> add = js2py.eval_js('function add(a, b) {return a + b}')
>>> add(1, 2) + 3
6
>>> add('1', 2, 3)
u'12'
>>> add.constructor
function Function() { [python code] }
Or use EvalJs to execute many javascript code fragments under same context - you would be able to get any
variable from the context!
>>> js = js2py.EvalJs()
>>> js.execute('var a = 10; function f(x) {return x*x};')
>>> js.f(9)
81
>>> js.a
10
Also you can use its console method to play with interactive javascript console.
Use parse_js to parse (syntax tree is just like in esprima.js) and translate_js to trasnlate JavaScript.
Finally, you can use pyimport statement from inside JS code to import and use python libraries.
>>> js2py.eval_js('pyimport urllib; urllib.urlopen("https://www.google.com")')
NOTE: This module is still not fully finished:
Date and JSON builtin objects are not implemented
Array prototype is not fully finished (will be soon)
Other than that everything should work fine.
"""
__author__ = 'Piotr Dabkowski'
__all__ = [
'EvalJs', 'translate_js', 'import_js', 'eval_js', 'parse_js',
'translate_file', 'run_file', 'disable_pyimport', 'eval_js6',
'translate_js6', 'PyJsException', 'get_file_contents',
'write_file_contents', 'require'
]
from .base import PyJsException
from .evaljs import *
from .translators import parse as parse_js
from .node_import import require
File diff suppressed because it is too large Load Diff
-281
View File
@@ -1,281 +0,0 @@
# coding=utf-8
from .translators import translate_js, DEFAULT_HEADER
from .es6 import js6_to_js5
import sys
import time
import json
import six
import os
import hashlib
import codecs
__all__ = [
'EvalJs', 'translate_js', 'import_js', 'eval_js', 'translate_file',
'eval_js6', 'translate_js6', 'run_file', 'disable_pyimport',
'get_file_contents', 'write_file_contents'
]
DEBUG = False
def disable_pyimport():
import pyjsparser.parser
pyjsparser.parser.ENABLE_PYIMPORT = False
def path_as_local(path):
if os.path.isabs(path):
return path
# relative to cwd
return os.path.join(os.getcwd(), path)
def import_js(path, lib_name, globals):
"""Imports from javascript source file.
globals is your globals()"""
with codecs.open(path_as_local(path), "r", "utf-8") as f:
js = f.read()
e = EvalJs()
e.execute(js)
var = e.context['var']
globals[lib_name] = var.to_python()
def get_file_contents(path_or_file):
if hasattr(path_or_file, 'read'):
js = path_or_file.read()
else:
with codecs.open(path_as_local(path_or_file), "r", "utf-8") as f:
js = f.read()
return js
def write_file_contents(path_or_file, contents):
if hasattr(path_or_file, 'write'):
path_or_file.write(contents)
else:
with open(path_as_local(path_or_file), 'w') as f:
f.write(contents)
def translate_file(input_path, output_path):
'''
Translates input JS file to python and saves the it to the output path.
It appends some convenience code at the end so that it is easy to import JS objects.
For example we have a file 'example.js' with: var a = function(x) {return x}
translate_file('example.js', 'example.py')
Now example.py can be easily importend and used:
>>> from example import example
>>> example.a(30)
30
'''
js = get_file_contents(input_path)
py_code = translate_js(js)
lib_name = os.path.basename(output_path).split('.')[0]
head = '__all__ = [%s]\n\n# Don\'t look below, you will not understand this Python code :) I don\'t.\n\n' % repr(
lib_name)
tail = '\n\n# Add lib to the module scope\n%s = var.to_python()' % lib_name
out = head + py_code + tail
write_file_contents(output_path, out)
def run_file(path_or_file, context=None):
''' Context must be EvalJS object. Runs given path as a JS program. Returns (eval_value, context).
'''
if context is None:
context = EvalJs()
if not isinstance(context, EvalJs):
raise TypeError('context must be the instance of EvalJs')
eval_value = context.eval(get_file_contents(path_or_file))
return eval_value, context
def eval_js(js):
"""Just like javascript eval. Translates javascript to python,
executes and returns python object.
js is javascript source code
EXAMPLE:
>>> import js2py
>>> add = js2py.eval_js('function add(a, b) {return a + b}')
>>> add(1, 2) + 3
6
>>> add('1', 2, 3)
u'12'
>>> add.constructor
function Function() { [python code] }
NOTE: For Js Number, String, Boolean and other base types returns appropriate python BUILTIN type.
For Js functions and objects, returns Python wrapper - basically behaves like normal python object.
If you really want to convert object to python dict you can use to_dict method.
"""
e = EvalJs()
return e.eval(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.
>>> ctx = EvalJs()
>>> ctx.execute('var a = 10;function f(x) {return x*x};')
>>> ctx.f(9)
81
>>> ctx.a
10
context is a python dict or object that contains python variables that should be available to JavaScript
For example:
>>> 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={}, 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__
except:
raise TypeError(
'context has to be either a dict or have __dict__ attr')
for k, v in six.iteritems(context):
setattr(self._var, k, v)
def execute(self, js=None, use_compilation_plan=False):
"""executes javascript js in current context
During initial execute() the converted js is cached for re-use. That means next time you
run the same javascript snippet you save many instructions needed to parse and convert the
js code to python code.
This cache causes minor overhead (a cache dicts is updated) but the Js=>Py conversion process
is typically expensive compared to actually running the generated python code.
Note that the cache is just a dict, it has no expiration or cleanup so when running this
in automated situations with vast amounts of snippets it might increase memory usage.
"""
try:
cache = self.__dict__['cache']
except KeyError:
cache = self.__dict__['cache'] = {}
hashkey = hashlib.md5(js.encode('utf-8')).digest()
try:
compiled = cache[hashkey]
except KeyError:
code = translate_js(
js, '', use_compilation_plan=use_compilation_plan)
compiled = cache[hashkey] = compile(code, '<EvalJS snippet>',
'exec')
exec (compiled, self._context)
def eval(self, expression, use_compilation_plan=False):
"""evaluates expression in current context and returns its value"""
code = 'PyJsEvalResult = eval(%s)' % json.dumps(expression)
self.execute(code, use_compilation_plan=use_compilation_plan)
return self['PyJsEvalResult']
def execute_debug(self, js):
"""executes javascript js in current context
as opposed to the (faster) self.execute method, you can use your regular debugger
to set breakpoints and inspect the generated python code
"""
code = translate_js(js, '')
# make sure you have a temp folder:
filename = 'temp' + os.sep + '_' + hashlib.md5(
code.encode("utf-8")).hexdigest() + '.py'
try:
with open(filename, mode='w') as f:
f.write(code)
with open(filename, "r") as f:
pyCode = compile(f.read(), filename, 'exec')
exec(pyCode, self._context)
except Exception as err:
raise err
finally:
os.remove(filename)
try:
os.remove(filename + 'c')
except:
pass
def eval_debug(self, expression):
"""evaluates expression in current context and returns its value
as opposed to the (faster) self.execute method, you can use your regular debugger
to set breakpoints and inspect the generated python code
"""
code = 'PyJsEvalResult = eval(%s)' % json.dumps(expression)
self.execute_debug(code)
return self['PyJsEvalResult']
def __getattr__(self, var):
return getattr(self._var, var)
def __getitem__(self, var):
return getattr(self._var, var)
def __setattr__(self, var, val):
return setattr(self._var, var, val)
def __setitem__(self, var, val):
return setattr(self._var, var, val)
def console(self):
"""starts to interact (starts interactive console) Something like code.InteractiveConsole"""
while True:
if six.PY2:
code = raw_input('>>> ')
else:
code = input('>>>')
try:
print(self.eval(code))
except KeyboardInterrupt:
break
except Exception as e:
import traceback
if DEBUG:
sys.stderr.write(traceback.format_exc())
else:
sys.stderr.write('EXCEPTION: ' + str(e) + '\n')
time.sleep(0.01)
#print x
if __name__ == '__main__':
#with open('C:\Users\Piotrek\Desktop\esprima.js', 'rb') as f:
# x = f.read()
e = EvalJs()
e.execute('square(x)')
#e.execute(x)
e.console()
@@ -1,76 +0,0 @@
from ..base import *
from ..conversions import *
from ..func_utils import *
from pyjsparser import parse
from ..byte_trans import ByteCodeGenerator, Code
def Function(this, args):
# convert arguments to python list of strings
a = map(to_string, tuple(args))
_body = u';'
_args = ()
if len(a):
_body = u'%s;' % a[-1]
_args = a[:-1]
return executable_function(_body, _args, args.space, global_context=True)
def executable_function(_body, _args, space, global_context=True):
func_str = u'(function (%s) { ; %s ; });' % (u', '.join(_args), _body)
co = executable_code(
code_str=func_str, space=space, global_context=global_context)
return co()
# you can use this one lovely piece of function to compile and execute code on the fly! Watch out though as it may generate lots of code.
# todo tape cleanup? we dont know which pieces are needed and which are not so rather impossible without smarter machinery something like GC,
# a one solution would be to have a separate tape for functions
def executable_code(code_str, space, global_context=True):
# parse first to check if any SyntaxErrors
parsed = parse(code_str)
old_tape_len = len(space.byte_generator.exe.tape)
space.byte_generator.record_state()
start = space.byte_generator.exe.get_new_label()
skip = space.byte_generator.exe.get_new_label()
space.byte_generator.emit('JUMP', skip)
space.byte_generator.emit('LABEL', start)
space.byte_generator.emit(parsed)
space.byte_generator.emit('NOP')
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!
ctx = space.GlobalObj if global_context else space.exe.current_ctx
def ex_code():
ret, status, token = space.byte_generator.exe.execute_fragment_under_context(
ctx, start, skip)
# todo Clean up the tape!
# this is NOT a way to do that because the fragment may contain the executable code! We dont want to remove it
#del space.byte_generator.exe.tape[old_tape_len:]
if status == 0:
return ret
elif status == 3:
raise token
else:
raise RuntimeError(
'Unexpected return status during JIT execution: %d' % status)
return ex_code
def _eval(this, args):
code_str = to_string(get_arg(args, 0))
return executable_code(code_str, args.space, global_context=True)()
def log(this, args):
print(' '.join(map(to_string, args)))
return undefined
@@ -1,323 +0,0 @@
from __future__ import unicode_literals
# -*- coding: utf-8 -*-
import re
from ..conversions import *
from ..func_utils import *
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"
def replacement_template(rep, source, span, npar):
"""Takes the replacement template and some info about the match and returns filled template
"""
n = 0
res = ''
while n < len(rep) - 1:
char = rep[n]
if char == '$':
if rep[n + 1] == '$':
res += '$'
n += 2
continue
elif rep[n + 1] == '`':
# replace with string that is BEFORE match
res += source[:span[0]]
n += 2
continue
elif rep[n + 1] == '\'':
# replace with string that is AFTER match
res += source[span[1]:]
n += 2
continue
elif rep[n + 1] in DIGS:
dig = rep[n + 1]
if n + 2 < len(rep) and rep[n + 2] in DIGS:
dig += rep[n + 2]
num = int(dig)
# we will not do any replacements if we dont have this npar or dig is 0
if not num or num > len(npar):
res += '$' + dig
else:
# None - undefined has to be replaced with ''
res += npar[num - 1] if npar[num - 1] else ''
n += 1 + len(dig)
continue
res += char
n += 1
if n < len(rep):
res += rep[-1]
return res
###################################################
class StringPrototype:
def toString(this, args):
if GetClass(this) != 'String':
raise MakeError('TypeError',
'String.prototype.toString is not generic')
if type(this) == unicode:
return this
assert type(this.value) == unicode
return this.value
def valueOf(this, args):
if GetClass(this) != 'String':
raise MakeError('TypeError',
'String.prototype.valueOf is not generic')
if type(this) == unicode:
return this
assert type(this.value) == unicode
return this.value
def charAt(this, args):
cok(this)
pos = to_int(get_arg(args, 0))
s = to_string(this)
if 0 <= pos < len(s):
return s[pos]
return u''
def charCodeAt(this, args):
cok(this)
pos = to_int(get_arg(args, 0))
s = to_string(this)
if 0 <= pos < len(s):
return float(ord(s[pos]))
return NaN
def concat(this, args):
cok(this)
return to_string(this) + u''.join(map(to_string, args))
def indexOf(this, args):
cok(this)
search = to_string(get_arg(args, 0))
pos = to_int(get_arg(args, 1))
s = to_string(this)
return float(s.find(search, min(max(pos, 0), len(s))))
def lastIndexOf(this, args):
cok(this)
search = to_string(get_arg(args, 0))
pos = get_arg(args, 1)
s = to_string(this)
pos = 10**12 if is_nan(pos) else to_int(pos)
return float(s.rfind(search, 0, min(max(pos, 0) + 1, len(s))))
def localeCompare(this, args):
cok(this)
s = to_string(this)
that = to_string(get_arg(args, 0))
if s < that:
return -1.
elif s > that:
return 1.
return 0.
def match(this, args):
cok(this)
s = to_string(this)
regexp = get_arg(args, 0)
r = args.space.NewRegExp(
regexp, '') if GetClass(regexp) != 'RegExp' else regexp
if not r.glob:
return RegExpExec(r, s, space=args.space)
r.put('lastIndex', float(0))
found = []
previous_last_index = 0
last_match = True
while last_match:
result = RegExpExec(r, s, space=args.space)
if is_null(result):
last_match = False
else:
this_index = r.get('lastIndex')
if this_index == previous_last_index:
r.put('lastIndex', float(this_index + 1))
previous_last_index += 1
else:
previous_last_index = this_index
matchStr = result.get('0')
found.append(matchStr)
if not found:
return null
return args.space.ConstructArray(found)
def replace(this, args):
# VERY COMPLICATED. to check again.
cok(this)
s = to_string(this)
searchValue = get_arg(args, 0)
replaceValue = get_arg(args, 1)
res = ''
if not is_callable(replaceValue):
replaceValue = to_string(replaceValue)
func = False
else:
func = True
# Replace all ( global )
if GetClass(searchValue) == 'RegExp' and searchValue.glob:
last = 0
for e in re.finditer(searchValue.pat, s):
res += s[last:e.span()[0]]
if func:
# prepare arguments for custom func (replaceValue)
call_args = (e.group(), ) + e.groups() + (e.span()[1], s)
# convert all types to JS before Js bytecode call...
res += to_string(
replaceValue.call(
this, ensure_js_types(call_args,
space=args.space)))
else:
res += replacement_template(replaceValue, s, e.span(),
e.groups())
last = e.span()[1]
res += s[last:]
return res
elif GetClass(searchValue) == 'RegExp':
e = re.search(searchValue.pat, s)
if e is None:
return s
span = e.span()
pars = e.groups()
match = e.group()
else:
match = to_string(searchValue)
ind = s.find(match)
if ind == -1:
return s
span = ind, ind + len(match)
pars = ()
res = s[:span[0]]
if func:
call_args = (match, ) + pars + (span[1], s)
# convert all types to JS before Js bytecode call...
res += to_string(
replaceValue.call(this,
ensure_js_types(call_args,
space=args.space)))
else:
res += replacement_template(replaceValue, s, span, pars)
res += s[span[1]:]
return res
def search(this, args):
cok(this)
string = to_string(this)
regexp = get_arg(args, 0)
if GetClass(regexp) == 'RegExp':
rx = regexp
else:
rx = args.space.NewRegExp(regexp, '')
res = re.search(rx.pat, string)
if res is not None:
return float(res.span()[0])
return -1.
def slice(this, args):
cok(this)
s = to_string(this)
start = to_int(get_arg(args, 0))
length = len(s)
end = get_arg(args, 1)
end = length if is_undefined(end) else to_int(end)
#From = max(length+start, 0) if start<0 else min(length, start)
#To = max(length+end, 0) if end<0 else min(length, end)
return s[start:end]
def split(this, args):
# its a bit different from re.split!
cok(this)
s = to_string(this)
separator = get_arg(args, 0)
limit = get_arg(args, 1)
lim = 2**32 - 1 if is_undefined(limit) else to_uint32(limit)
if not lim:
return args.space.ConstructArray([])
if is_undefined(separator):
return args.space.ConstructArray([s])
len_s = len(s)
res = []
R = separator if GetClass(separator) == 'RegExp' else to_string(
separator)
if not len_s:
if SplitMatch(s, 0, R) is None:
return args.space.ConstructArray([s])
return args.space.ConstructArray([])
p = q = 0
while q != len_s:
e, cap = SplitMatch(s, q, R)
if e is None or e == p:
q += 1
continue
res.append(s[p:q])
p = q = e
if len(res) == lim:
return args.space.ConstructArray(res)
for element in cap:
res.append(element)
if len(res) == lim:
return args.space.ConstructArray(res)
res.append(s[p:])
return args.space.ConstructArray(res)
def substring(this, args):
cok(this)
s = to_string(this)
start = to_int(get_arg(args, 0))
length = len(s)
end = get_arg(args, 1)
end = length if is_undefined(end) else to_int(end)
fstart = min(max(start, 0), length)
fend = min(max(end, 0), length)
return s[min(fstart, fend):max(fstart, fend)]
def substr(this, args):
cok(this)
#I hate this function and its description in specification
r1 = to_string(this)
r2 = to_int(get_arg(args, 0))
length = get_arg(args, 1)
r3 = 10**20 if is_undefined(length) else to_int(length)
r4 = len(r1)
r5 = r2 if r2 >= 0 else max(0, r2 + r4)
r6 = min(max(r3, 0), r4 - r5)
if r6 <= 0:
return ''
return r1[r5:r5 + r6]
def toLowerCase(this, args):
cok(this)
return to_string(this).lower()
def toLocaleLowerCase(this, args):
cok(this)
return to_string(this).lower()
def toUpperCase(this, args):
cok(this)
return to_string(this).upper()
def toLocaleUpperCase(this, args):
cok(this)
return to_string(this).upper()
def trim(this, args):
cok(this)
return to_string(this).strip(WHITE)
def SplitMatch(s, q, R):
# s is Py String to match, q is the py int match start and R is Js RegExp or String.
if GetClass(R) == 'RegExp':
res = R.match(s, q)
return (None, ()) if res is None else (res.span()[1], res.groups())
# R is just a string
if s[q:].startswith(R):
return q + len(R), ()
return None, ()
-145
View File
@@ -1,145 +0,0 @@
__all__ = ['require']
import subprocess, os, codecs, glob
from .evaljs import translate_js, DEFAULT_HEADER
import six
DID_INIT = False
DIRNAME = os.path.dirname(os.path.abspath(__file__))
PY_NODE_MODULES_PATH = os.path.join(DIRNAME, 'py_node_modules')
def _init():
global DID_INIT
if DID_INIT:
return
assert subprocess.call(
'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 browserify-shim'
% repr(DIRNAME),
shell=True,
cwd=DIRNAME) == 0, 'Could not link required node_modules'
DID_INIT = True
ADD_TO_GLOBALS_FUNC = '''
;function addToGlobals(name, obj) {
if (!Object.prototype.hasOwnProperty('_fake_exports')) {
Object.prototype._fake_exports = {};
}
Object.prototype._fake_exports[name] = obj;
};
'''
# subprocess.call("""node -e 'require("browserify")'""", shell=True)
GET_FROM_GLOBALS_FUNC = '''
;function getFromGlobals(name) {
if (!Object.prototype.hasOwnProperty('_fake_exports')) {
throw Error("Could not find any value named "+name);
}
if (Object.prototype._fake_exports.hasOwnProperty(name)) {
return Object.prototype._fake_exports[name];
} else {
throw Error("Could not find any value named "+name);
}
};
'''
def _get_module_py_name(module_name):
return module_name.replace('-', '_')
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 = _get_module_py_name(module_name)
module_filename = '%s.py' % py_name
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()
in_file_name = 'tmp0in439341018923js2py.js'
out_file_name = 'tmp0out439341018923js2py.js'
code = ADD_TO_GLOBALS_FUNC
if include_polyfill:
code += "\n;require('babel-polyfill');\n"
code += """
var module_temp_love_python = require(%s);
addToGlobals(%s, module_temp_love_python);
""" % (repr(module_name), repr(module_name))
with open(os.path.join(DIRNAME, in_file_name), 'wb') as f:
f.write(code.encode('utf-8') if six.PY3 else code)
pkg_name = module_name.partition('/')[0]
# make sure the module is installed
assert subprocess.call(
'cd %s;npm install %s' % (repr(DIRNAME), pkg_name),
shell=True,
cwd=DIRNAME
) == 0, 'Could not install the required module: ' + pkg_name
# convert the module
assert subprocess.call(
'''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,
) == 0, 'Error when converting module to the js bundle'
os.remove(os.path.join(DIRNAME, in_file_name))
with codecs.open(os.path.join(DIRNAME, out_file_name), "r",
"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)
print('Please wait, translating...')
py_code = translate_js(js_code)
dirname = os.path.dirname(
os.path.join(PY_NODE_MODULES_PATH, module_filename))
if not os.path.isdir(dirname):
os.makedirs(dirname)
with open(os.path.join(PY_NODE_MODULES_PATH, module_filename),
'wb') as f:
f.write(py_code.encode('utf-8') if six.PY3 else py_code)
else:
with codecs.open(
os.path.join(PY_NODE_MODULES_PATH, module_filename), "r",
"utf-8") as f:
py_code = f.read()
return py_code
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'][_get_module_var_name(module_name)].to_py()
-51
View File
@@ -1,51 +0,0 @@
# python 3 support
import six
if six.PY3:
basestring = str
long = int
xrange = range
unicode = str
class FunctionPrototype:
def toString():
if not this.is_callable():
raise TypeError('toString is not generic!')
args = ', '.join(this.code.__code__.co_varnames[:this.argcount])
return 'function %s(%s) ' % (this.func_name, args) + this.source
def call():
arguments_ = arguments
if not len(arguments):
obj = this.Js(None)
else:
obj = arguments[0]
if len(arguments) <= 1:
args = ()
else:
args = tuple([arguments_[e] for e in xrange(1, len(arguments_))])
return this.call(obj, args)
def apply():
if not len(arguments):
obj = this.Js(None)
else:
obj = arguments[0]
if len(arguments) <= 1:
args = ()
else:
appl = arguments[1]
args = tuple([appl[e] for e in xrange(len(appl))])
return this.call(obj, args)
def bind(thisArg):
arguments_ = arguments
target = this
if not target.is_callable():
raise this.MakeError(
'Object must be callable in order to be used with bind method')
if len(arguments) <= 1:
args = ()
else:
args = tuple([arguments_[e] for e in xrange(1, len(arguments_))])
return this.PyJsBoundFunction(target, thisArg, args)
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,697 +0,0 @@
from __future__ import unicode_literals
from pyjsparser.pyjsparserdata import *
from .friendly_nodes import *
import random
import six
if six.PY3:
from functools import reduce
xrange = range
unicode = str
# number of characters above which expression will be split to multiple lines in order to avoid python parser stack overflow
# still experimental so I suggest to set it to 400 in order to avoid common errors
# set it to smaller value only if you have problems with parser stack overflow
LINE_LEN_LIMIT = 400 # 200 # or any other value - the larger the smaller probability of errors :)
class ForController:
def __init__(self):
self.inside = [False]
self.update = ''
def enter_for(self, update):
self.inside.append(True)
self.update = update
def leave_for(self):
self.inside.pop()
def enter_other(self):
self.inside.append(False)
def leave_other(self):
self.inside.pop()
def is_inside(self):
return self.inside[-1]
class InlineStack:
NAME = 'PyJs_%s_%d_'
def __init__(self):
self.reps = {}
self.names = []
def inject_inlines(self, source):
for lval in self.names: # first in first out! Its important by the way
source = inject_before_lval(source, lval, self.reps[lval])
return source
def require(self, typ):
name = self.NAME % (typ, len(self.names))
self.names.append(name)
return name
def define(self, name, val):
self.reps[name] = val
def reset(self):
self.rel = {}
self.names = []
class ContextStack:
def __init__(self):
self.to_register = set([])
self.to_define = {}
def reset(self):
self.to_register = set([])
self.to_define = {}
def register(self, var):
self.to_register.add(var)
def define(self, name, code):
self.to_define[name] = code
self.register(name)
def get_code(self):
code = 'var.registers([%s])\n' % ', '.join(
repr(e) for e in self.to_register)
for name, func_code in six.iteritems(self.to_define):
code += func_code
return code
def clean_stacks():
global Context, inline_stack
Context = ContextStack()
inline_stack = InlineStack()
def to_key(literal_or_identifier):
''' returns string representation of this object'''
if literal_or_identifier['type'] == 'Identifier':
return literal_or_identifier['name']
elif literal_or_identifier['type'] == 'Literal':
k = literal_or_identifier['value']
if isinstance(k, float):
return unicode(float_repr(k))
elif 'regex' in literal_or_identifier:
return compose_regex(k)
elif isinstance(k, bool):
return 'true' if k else 'false'
elif k is None:
return 'null'
else:
return unicode(k)
def trans(ele, standard=False):
"""Translates esprima syntax tree to python by delegating to appropriate translating node"""
try:
node = globals().get(ele['type'])
if not node:
raise NotImplementedError('%s is not supported!' % ele['type'])
if standard:
node = node.__dict__[
'standard'] if 'standard' in node.__dict__ else node
return node(**ele)
except:
#print ele
raise
def limited(func):
'''Decorator limiting resulting line length in order to avoid python parser stack overflow -
If expression longer than LINE_LEN_LIMIT characters then it will be moved to upper line
USE ONLY ON EXPRESSIONS!!! '''
def f(standard=False, **args):
insert_pos = len(
inline_stack.names
) # in case line is longer than limit we will have to insert the lval at current position
# this is because calling func will change inline_stack.
# we cant use inline_stack.require here because we dont know whether line overflows yet
res = func(**args)
if len(res) > LINE_LEN_LIMIT:
name = inline_stack.require('LONG')
inline_stack.names.pop()
inline_stack.names.insert(insert_pos, name)
res = 'def %s(var=var):\n return %s\n' % (name, res)
inline_stack.define(name, res)
return name + '()'
else:
return res
f.__dict__['standard'] = func
return f
# ==== IDENTIFIERS AND LITERALS =======
inf = float('inf')
def Literal(type, value, raw, regex=None):
if regex: # regex
return 'JsRegExp(%s)' % repr(compose_regex(value))
elif value is None: # null
return 'var.get(u"null")'
# Todo template
# String, Bool, Float
return 'Js(%s)' % repr(value) if value != inf else 'Js(float("inf"))'
def Identifier(type, name):
return 'var.get(%s)' % repr(name)
@limited
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
if property['type'] == 'Literal':
prop = repr(to_key(property))
else: # worst case
prop = trans(property)
else: # always the same since not computed (obj.prop accessor)
prop = repr(to_key(property))
return far_left + '.get(%s)' % prop
def ThisExpression(type):
return 'var.get(u"this")'
@limited
def CallExpression(type, callee, arguments):
arguments = [trans(e) for e in arguments]
if callee['type'] == 'MemberExpression':
far_left = trans(callee['object'])
if callee['computed']: # obj[prop] type accessor
# may be literal which is the same in every case so we can save some time on conversion
if callee['property']['type'] == 'Literal':
prop = repr(to_key(callee['property']))
else: # worst case
prop = trans(
callee['property']) # its not a string literal! so no repr
else: # always the same since not computed (obj.prop accessor)
prop = repr(to_key(callee['property']))
arguments.insert(0, prop)
return far_left + '.callprop(%s)' % ', '.join(arguments)
else: # standard call
return trans(callee) + '(%s)' % ', '.join(arguments)
# ========== ARRAYS ============
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):
name = None
elems = []
after = ''
for p in properties:
if p['kind'] == 'init':
elems.append('%s:%s' % Property(**p))
else:
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):
if shorthand or computed:
raise NotImplementedError(
'Shorthand and Computed properties not implemented!')
k = to_key(key)
if k is None:
raise SyntaxError('Invalid key in dictionary! Or bug in Js2Py')
v = trans(value)
return repr(k), v
# ========== EXPRESSIONS ============
@limited
def UnaryExpression(type, operator, argument, prefix):
a = trans(
argument, standard=True
) # unary involve some complex operations so we cant use line shorteners here
if operator == 'delete':
if argument['type'] in ('Identifier', 'MemberExpression'):
# means that operation is valid
return js_delete(a)
return 'PyJsComma(%s, Js(True))' % a # otherwise not valid, just perform expression and return true.
elif operator == 'typeof':
return js_typeof(a)
return UNARY[operator](a)
@limited
def BinaryExpression(type, operator, left, right):
a = trans(left)
b = trans(right)
# delegate to our friends
return BINARY[operator](a, b)
@limited
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
return js_postfix(a, operator == '++', not prefix)
@limited
def AssignmentExpression(type, operator, left, right):
operator = operator[:-1]
if left['type'] == 'Identifier':
if operator:
return 'var.put(%s, %s, %s)' % (repr(to_key(left)), trans(right),
repr(operator))
else:
return 'var.put(%s, %s)' % (repr(to_key(left)), trans(right))
elif left['type'] == 'MemberExpression':
far_left = trans(left['object'])
if left['computed']: # obj[prop] type accessor
# may be literal which is the same in every case so we can save some time on conversion
if left['property']['type'] == 'Literal':
prop = repr(to_key(left['property']))
else: # worst case
prop = trans(
left['property']) # its not a string literal! so no repr
else: # always the same since not computed (obj.prop accessor)
prop = repr(to_key(left['property']))
if operator:
return far_left + '.put(%s, %s, %s)' % (prop, trans(right),
repr(operator))
else:
return far_left + '.put(%s, %s)' % (prop, trans(right))
else:
raise SyntaxError('Invalid left hand side in assignment!')
six
@limited
def SequenceExpression(type, expressions):
return reduce(js_comma, (trans(e) for e in expressions))
@limited
def NewExpression(type, callee, arguments):
return trans(callee) + '.create(%s)' % ', '.join(
trans(e) for e in arguments)
@limited
def ConditionalExpression(
type, test, consequent,
alternate): # caused plenty of problems in my home-made translator :)
return '(%s if %s else %s)' % (trans(consequent), trans(test),
trans(alternate))
# =========== STATEMENTS =============
def BlockStatement(type, body):
return StatementList(
body) # never returns empty string! In the worst case returns pass\n
def ExpressionStatement(type, expression):
return trans(expression) + '\n' # end expression space with new line
def BreakStatement(type, label):
if label:
return 'raise %s("Breaked")\n' % (get_break_label(label['name']))
else:
return 'break\n'
def ContinueStatement(type, label):
if label:
return 'raise %s("Continued")\n' % (get_continue_label(label['name']))
else:
return 'continue\n'
def ReturnStatement(type, argument):
return 'return %s\n' % (trans(argument)
if argument else "var.get('undefined')")
def EmptyStatement(type):
return 'pass\n'
def DebuggerStatement(type):
return 'pass\n'
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):
update = indent(trans(update)) if update else ''
init = trans(init) if init else ''
if not init.endswith('\n'):
init += '\n'
test = trans(test) if test else '1'
if not update:
result = '#for JS loop\n%swhile %s:\n%s%s\n' % (
init, test, indent(trans(body)), update)
else:
result = '#for JS loop\n%swhile %s:\n' % (init, test)
body = 'try:\n%sfinally:\n %s\n' % (indent(trans(body)), update)
result += indent(body)
return result
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
if addon != 'pass\n':
res = addon + res # we have to execute this expression :(
# now extract the name
try:
name = left['declarations'][0]['id']['name']
except:
raise RuntimeError('Unusual ForIn loop')
elif left['type'] == 'Identifier':
name = left['name']
else:
raise RuntimeError('Unusual ForIn loop')
res += indent('var.put(%s, PyJsTemp)\n' % repr(name) + trans(body))
return res
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))
if not alternate:
return IF
ELSE = 'else:\n' + indent(trans(alternate))
return IF + ELSE
def LabeledStatement(type, label, body):
# todo consider using smarter approach!
inside = trans(body)
defs = ''
if inside.startswith('while ') or inside.startswith(
'for ') or inside.startswith('#for'):
# we have to add contine label as well...
# 3 or 1 since #for loop type has more lines before real for.
sep = 1 if not inside.startswith('#for') else 3
cont_label = get_continue_label(label['name'])
temp = inside.split('\n')
injected = 'try:\n' + '\n'.join(temp[sep:])
injected += 'except %s:\n pass\n' % cont_label
inside = '\n'.join(temp[:sep]) + '\n' + indent(injected)
defs += 'class %s(Exception): pass\n' % cont_label
break_label = get_break_label(label['name'])
inside = 'try:\n%sexcept %s:\n pass\n' % (indent(inside), break_label)
defs += 'class %s(Exception): pass\n' % break_label
return defs + inside
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'
else:
return 'pass\n'
def PyimportStatement(type, imp):
lib = imp['name']
jlib = 'PyImport_%s' % lib
code = 'import %s as %s\n' % (lib, jlib)
#check whether valid lib name...
try:
compile(code, '', 'exec')
except:
raise SyntaxError(
'Invalid Python module name (%s) in pyimport statement' % lib)
# var.pyimport will handle module conversion to PyJs object
code += 'var.pyimport(%s, %s)\n' % (repr(lib), jlib)
return code
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)
for case in cases:
case_code = None
if case['test']: # case (x):
case_code = 'if SWITCHED or PyJsStrictEq(CONDITION, %s):\n' % (
trans(case['test']))
else: # default:
case_code = 'if True:\n'
case_code += indent('SWITCHED = True\n')
case_code += indent(StatementList(case['consequent']))
# one more indent for whole
code += indent(case_code)
# prevent infinite loop and sort out nested switch...
code += indent('SWITCHED = True\nbreak\n')
return code
def ThrowStatement(type, argument):
return 'PyJsTempException = JsToPyException(%s)\nraise PyJsTempException\n' % trans(
argument)
def TryStatement(type, block, handler, handlers, guardedHandlers, finalizer):
result = 'try:\n%s' % indent(trans(block))
# complicated catch statement...
if handler:
identifier = handler['param']['name']
holder = 'PyJsHolder_%s_%d' % (to_hex(identifier),
random.randrange(1e8))
identifier = repr(identifier)
result += 'except PyJsException as PyJsTempException:\n'
# fill in except ( catch ) block and remember to recover holder variable to its previous state
result += indent(
TRY_CATCH.replace('HOLDER',
holder).replace('NAME', identifier).replace(
'BLOCK', indent(trans(handler['body']))))
# translate finally statement if present
if finalizer:
result += 'finally:\n%s' % indent(trans(finalizer))
return result
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):
name = id['name']
# register the name if not already registered
Context.register(name)
if init:
return 'var.put(%s, %s)\n' % (repr(name), trans(init))
return ''
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):
result = 'while %s:\n' % trans(test) + indent(trans(body))
return result
def WithStatement(type, object, body):
raise NotImplementedError('With statement not implemented!')
def Program(type, body):
inline_stack.reset()
code = ''.join(trans(e) for e in body)
# here add hoisted elements (register variables and define functions)
code = Context.get_code() + code
# replace all inline variables
code = inline_stack.inject_inlines(code)
return code
# ======== FUNCTIONS ============
def FunctionDeclaration(type, id, params, defaults, body, generator,
expression):
if generator:
raise NotImplementedError('Generators not supported')
if defaults:
raise NotImplementedError('Defaults not supported')
if not id:
return FunctionExpression(type, id, params, defaults, body, generator,
expression) + '\n'
JsName = id['name']
PyName = 'PyJsHoisted_%s_' % JsName
PyName = PyName if is_valid_py_name(PyName) else 'PyJsHoistedNonPyName'
# this is quite complicated
global Context
previous_context = Context
# change context to the context of this function
Context = ContextStack()
# translate body within current context
code = trans(body)
# get arg names
vars = [v['name'] for v in params]
# args are automaticaly registered variables
Context.to_register.update(vars)
# add all hoisted elements inside function
code = Context.get_code() + code
# check whether args are valid python names:
used_vars = []
for v in vars:
if is_valid_py_name(v):
used_vars.append(v)
else: # invalid arg in python, for example $, replace with alternatice arg
used_vars.append('PyJsArg_%s_' % to_hex(v))
header = '@Js\n'
header += 'def %s(%sthis, arguments, var=var):\n' % (
PyName, ', '.join(used_vars) + (', ' if vars else ''))
# transfer names from Py scope to Js scope
arg_map = dict(zip(vars, used_vars))
arg_map.update({'this': 'this', 'arguments': 'arguments'})
arg_conv = 'var = Scope({%s}, var)\n' % ', '.join(
repr(k) + ':' + v for k, v in six.iteritems(arg_map))
# and finally set the name of the function to its real name:
footer = '%s.func_name = %s\n' % (PyName, repr(JsName))
footer += 'var.put(%s, %s)\n' % (repr(JsName), PyName)
whole_code = header + indent(arg_conv + code) + footer
# restore context
Context = previous_context
# define in upper context
Context.define(JsName, whole_code)
return 'pass\n'
def FunctionExpression(type, id, params, defaults, body, generator,
expression):
if generator:
raise NotImplementedError('Generators not supported')
if defaults:
raise NotImplementedError('Defaults not supported')
JsName = id['name'] if id else 'anonymous'
if not is_valid_py_name(JsName):
ScriptName = 'InlineNonPyName'
else:
ScriptName = JsName
PyName = inline_stack.require(ScriptName) # this is unique
# again quite complicated
global Context
previous_context = Context
# change context to the context of this function
Context = ContextStack()
# translate body within current context
code = trans(body)
# get arg names
vars = [v['name'] for v in params]
# args are automaticaly registered variables
Context.to_register.update(vars)
# add all hoisted elements inside function
code = Context.get_code() + code
# check whether args are valid python names:
used_vars = []
for v in vars:
if is_valid_py_name(v):
used_vars.append(v)
else: # invalid arg in python, for example $, replace with alternatice arg
used_vars.append('PyJsArg_%s_' % to_hex(v))
header = '@Js\n'
header += 'def %s(%sthis, arguments, var=var):\n' % (
PyName, ', '.join(used_vars) + (', ' if vars else ''))
# transfer names from Py scope to Js scope
arg_map = dict(zip(vars, used_vars))
arg_map.update({'this': 'this', 'arguments': 'arguments'})
if id: # make self available from inside...
if id['name'] not in arg_map:
arg_map[id['name']] = PyName
arg_conv = 'var = Scope({%s}, var)\n' % ', '.join(
repr(k) + ':' + v for k, v in six.iteritems(arg_map))
# and finally set the name of the function to its real name:
footer = '%s._set_name(%s)\n' % (PyName, repr(JsName))
whole_code = header + indent(arg_conv + code) + footer
# restore context
Context = previous_context
# define in upper context
inline_stack.define(PyName, whole_code)
return PyName
LogicalExpression = BinaryExpression
PostfixExpression = UpdateExpression
clean_stacks()
if __name__ == '__main__':
import codecs
import time
import pyjsparser
c = None #'''`ijfdij`'''
if not c:
with codecs.open("esp.js", "r", "utf-8") as f:
c = f.read()
print('Started')
t = time.time()
res = trans(pyjsparser.PyJsParser().parse(c))
dt = time.time() - t + 0.000000001
print('Translated everyting in', round(dt, 5), 'seconds.')
print('Thats %d characters per second' % int(len(c) / dt))
with open('res.py', 'w') as f:
f.write(res)
-244
View File
@@ -1,244 +0,0 @@
__all__ = ['fix_js_args']
import types
from collections import namedtuple
import opcode
import six
import sys
import dis
if six.PY3:
xrange = range
chr = lambda x: x
# Opcode constants used for comparison and replacecment
LOAD_FAST = opcode.opmap['LOAD_FAST']
LOAD_GLOBAL = opcode.opmap['LOAD_GLOBAL']
STORE_FAST = opcode.opmap['STORE_FAST']
def fix_js_args(func):
'''Use this function when unsure whether func takes this and arguments as its last 2 args.
It will append 2 args if it does not.'''
fcode = six.get_function_code(func)
fargs = fcode.co_varnames[fcode.co_argcount - 2:fcode.co_argcount]
if fargs == ('this', 'arguments') or fargs == ('arguments', 'var'):
return func
code = append_arguments(six.get_function_code(func), ('this', 'arguments'))
return types.FunctionType(
code,
six.get_function_globals(func),
func.__name__,
closure=six.get_function_closure(func))
def append_arguments(code_obj, new_locals):
co_varnames = code_obj.co_varnames # Old locals
co_names = code_obj.co_names # Old globals
co_names += tuple(e for e in new_locals if e not in co_names)
co_argcount = code_obj.co_argcount # Argument count
co_code = code_obj.co_code # The actual bytecode as a string
# Make one pass over the bytecode to identify names that should be
# left in code_obj.co_names.
not_removed = set(opcode.hasname) - set([LOAD_GLOBAL])
saved_names = set()
for inst in instructions(code_obj):
if inst[0] in not_removed:
saved_names.add(co_names[inst[1]])
# Build co_names for the new code object. This should consist of
# globals that were only accessed via LOAD_GLOBAL
names = tuple(
name for name in co_names if name not in set(new_locals) - saved_names)
# Build a dictionary that maps the indices of the entries in co_names
# to their entry in the new co_names
name_translations = dict(
(co_names.index(name), i) for i, name in enumerate(names))
# Build co_varnames for the new code object. This should consist of
# the entirety of co_varnames with new_locals spliced in after the
# arguments
new_locals_len = len(new_locals)
varnames = (
co_varnames[:co_argcount] + new_locals + co_varnames[co_argcount:])
# Build the dictionary that maps indices of entries in the old co_varnames
# to their indices in the new co_varnames
range1, range2 = xrange(co_argcount), xrange(co_argcount, len(co_varnames))
varname_translations = dict((i, i) for i in range1)
varname_translations.update((i, i + new_locals_len) for i in range2)
# Build the dictionary that maps indices of deleted entries of co_names
# to their indices in the new co_varnames
names_to_varnames = dict(
(co_names.index(name), varnames.index(name)) for name in new_locals)
# Now we modify the actual bytecode
modified = []
for inst in instructions(code_obj):
op, arg = inst.opcode, inst.arg
# If the instruction is a LOAD_GLOBAL, we have to check to see if
# it's one of the globals that we are replacing. Either way,
# update its arg using the appropriate dict.
if inst.opcode == LOAD_GLOBAL:
if inst.arg in names_to_varnames:
op = LOAD_FAST
arg = names_to_varnames[inst.arg]
elif inst.arg in name_translations:
arg = name_translations[inst.arg]
else:
raise ValueError("a name was lost in translation")
# If it accesses co_varnames or co_names then update its argument.
elif inst.opcode in opcode.haslocal:
arg = varname_translations[inst.arg]
elif inst.opcode in opcode.hasname:
arg = name_translations[inst.arg]
modified.extend(write_instruction(op, arg))
if six.PY2:
code = ''.join(modified)
args = (co_argcount + new_locals_len,
code_obj.co_nlocals + new_locals_len, code_obj.co_stacksize,
code_obj.co_flags, code, code_obj.co_consts, names, varnames,
code_obj.co_filename, code_obj.co_name,
code_obj.co_firstlineno, code_obj.co_lnotab,
code_obj.co_freevars, code_obj.co_cellvars)
else:
code = bytes(modified)
args = (co_argcount + new_locals_len, 0,
code_obj.co_nlocals + new_locals_len, code_obj.co_stacksize,
code_obj.co_flags, code, code_obj.co_consts, names, varnames,
code_obj.co_filename, code_obj.co_name,
code_obj.co_firstlineno, code_obj.co_lnotab,
code_obj.co_freevars, code_obj.co_cellvars)
# Done modifying codestring - make the code object
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):
# easy for python 3.4+
if sys.version_info >= (3, 4):
for inst in dis.Bytecode(code_obj):
yield inst
else:
# otherwise we have to manually parse
code = code_obj.co_code
NewInstruction = namedtuple('Instruction', ('opcode', 'arg'))
if six.PY2:
code = map(ord, code)
i, L = 0, len(code)
extended_arg = 0
while i < L:
op = code[i]
i += 1
if op < opcode.HAVE_ARGUMENT:
yield NewInstruction(op, None)
continue
oparg = code[i] + (code[i + 1] << 8) + extended_arg
extended_arg = 0
i += 2
if op == opcode.EXTENDED_ARG:
extended_arg = oparg << 16
continue
yield NewInstruction(op, oparg)
def write_instruction(op, arg):
if sys.version_info < (3, 6):
if arg is None:
return [chr(op)]
elif arg <= 65536:
return [chr(op), chr(arg & 255), chr((arg >> 8) & 255)]
elif arg <= 4294967296:
return [
chr(opcode.EXTENDED_ARG),
chr((arg >> 16) & 255),
chr((arg >> 24) & 255),
chr(op),
chr(arg & 255),
chr((arg >> 8) & 255)
]
else:
raise ValueError("Invalid oparg: {0} is too large".format(oparg))
else: # python 3.6+ uses wordcode instead of bytecode and they already supply all the EXTENDEND_ARG ops :)
if arg is None:
return [chr(op), 0]
return [chr(op), arg & 255]
# the code below is for case when extended args are to be determined automatically
# if op == opcode.EXTENDED_ARG:
# return [] # this will be added automatically
# elif arg < 1 << 8:
# return [chr(op), arg]
# elif arg < 1 << 32:
# subs = [1<<24, 1<<16, 1<<8] # allowed op extension sizes
# for sub in subs:
# if arg >= sub:
# fit = int(arg / sub)
# return [chr(opcode.EXTENDED_ARG), fit] + write_instruction(op, arg - fit * sub)
# else:
# raise ValueError("Invalid oparg: {0} is too large".format(oparg))
def check(code_obj):
old_bytecode = code_obj.co_code
insts = list(instructions(code_obj))
pos_to_inst = {}
bytelist = []
for inst in insts:
pos_to_inst[len(bytelist)] = inst
bytelist.extend(write_instruction(inst.opcode, inst.arg))
if six.PY2:
new_bytecode = ''.join(bytelist)
else:
new_bytecode = bytes(bytelist)
if new_bytecode != old_bytecode:
print(new_bytecode)
print(old_bytecode)
for i in range(min(len(new_bytecode), len(old_bytecode))):
if old_bytecode[i] != new_bytecode[i]:
while 1:
if i in pos_to_inst:
print(pos_to_inst[i])
print(pos_to_inst[i - 2])
print(list(map(chr, old_bytecode))[i - 4:i + 8])
print(bytelist[i - 4:i + 8])
break
raise RuntimeError(
'Your python version made changes to the bytecode')
check(six.get_function_code(check))
if __name__ == '__main__':
x = 'Wrong'
dick = 3000
def func(a):
print(x, y, z, a)
print(dick)
d = (x, )
for e in (e for e in x):
print(e)
return x, y, z
func2 = types.FunctionType(
append_arguments(six.get_function_code(func), ('x', 'y', 'z')),
six.get_function_globals(func),
func.__name__,
closure=six.get_function_closure(func))
args = (2, 2, 3, 4), 3, 4
assert func2(1, *args) == args
-75
View File
@@ -1,75 +0,0 @@
# 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
""" This module allows you to translate and execute Javascript in pure python.
Basically its implementation of ECMAScript 5.1 in pure python.
Use eval_js method to execute javascript code and get resulting python object (builtin if possible).
EXAMPLE:
>>> import js2py
>>> add = js2py.eval_js('function add(a, b) {return a + b}')
>>> add(1, 2) + 3
6
>>> add('1', 2, 3)
u'12'
>>> add.constructor
function Function() { [python code] }
Or use EvalJs to execute many javascript code fragments under same context - you would be able to get any
variable from the context!
>>> js = js2py.EvalJs()
>>> js.execute('var a = 10; function f(x) {return x*x};')
>>> js.f(9)
81
>>> js.a
10
Also you can use its console method to play with interactive javascript console.
Use parse_js to parse (syntax tree is just like in esprima.js) and translate_js to trasnlate JavaScript.
Finally, you can use pyimport statement from inside JS code to import and use python libraries.
>>> js2py.eval_js('pyimport urllib; urllib.urlopen("https://www.google.com")')
NOTE: This module is still not fully finished:
Date and JSON builtin objects are not implemented
Array prototype is not fully finished (will be soon)
Other than that everything should work fine.
"""
__author__ = 'Piotr Dabkowski'
__all__ = [
'EvalJs', 'translate_js', 'import_js', 'eval_js', 'parse_js',
'translate_file', 'run_file', 'disable_pyimport', 'eval_js6',
'translate_js6', 'PyJsException', 'get_file_contents',
'write_file_contents', 'require'
]
from .base import PyJsException
from .evaljs import *
from .translators import parse as parse_js
from .node_import import require
@@ -1 +0,0 @@
__author__ = 'Piotr Dabkowski'
@@ -1,48 +0,0 @@
from ..base import *
@Js
def Array():
if len(arguments) == 0 or len(arguments) > 1:
return arguments.to_list()
a = arguments[0]
if isinstance(a, PyJsNumber):
length = a.to_uint32()
if length != a.value:
raise MakeError('RangeError', 'Invalid array length')
temp = Js([])
temp.put('length', a)
return temp
return [a]
Array.create = Array
Array.own['length']['value'] = Js(1)
@Js
def isArray(arg):
return arg.Class == 'Array'
Array.define_own_property('isArray', {
'value': isArray,
'enumerable': False,
'writable': True,
'configurable': True
})
Array.define_own_property(
'prototype', {
'value': ArrayPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
ArrayPrototype.define_own_property('constructor', {
'value': Array,
'enumerable': False,
'writable': True,
'configurable': True
})
@@ -1,41 +0,0 @@
# this is based on jsarray.py
# todo check everything :)
from ..base import *
try:
import numpy
except:
pass
@Js
def ArrayBuffer():
a = arguments[0]
if isinstance(a, PyJsNumber):
length = a.to_uint32()
if length != a.value:
raise MakeError('RangeError', 'Invalid array length')
temp = Js(bytearray([0] * length))
return temp
return Js(bytearray([0]))
ArrayBuffer.create = ArrayBuffer
ArrayBuffer.own['length']['value'] = Js(None)
ArrayBuffer.define_own_property(
'prototype', {
'value': ArrayBufferPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
ArrayBufferPrototype.define_own_property(
'constructor', {
'value': ArrayBuffer,
'enumerable': False,
'writable': False,
'configurable': True
})
@@ -1,16 +0,0 @@
from ..base import *
BooleanPrototype.define_own_property('constructor', {
'value': Boolean,
'enumerable': False,
'writable': True,
'configurable': True
})
Boolean.define_own_property(
'prototype', {
'value': BooleanPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
-405
View File
@@ -1,405 +0,0 @@
from ..base import *
from .time_helpers import *
TZ_OFFSET = (time.altzone // 3600)
ABS_OFFSET = abs(TZ_OFFSET)
TZ_NAME = time.tzname[1]
ISO_FORMAT = '%s-%s-%sT%s:%s:%s.%sZ'
@Js
def Date(year, month, date, hours, minutes, seconds, ms):
return now().to_string()
Date.Class = 'Date'
def now():
return PyJsDate(int(time.time() * 1000), prototype=DatePrototype)
@Js
def UTC(year, month, date, hours, minutes, seconds, ms): # todo complete this
args = arguments
y = args[0].to_number()
m = args[1].to_number()
l = len(args)
dt = args[2].to_number() if l > 2 else Js(1)
h = args[3].to_number() if l > 3 else Js(0)
mi = args[4].to_number() if l > 4 else Js(0)
sec = args[5].to_number() if l > 5 else Js(0)
mili = args[6].to_number() if l > 6 else Js(0)
if not y.is_nan() and 0 <= y.value <= 99:
y = y + Js(1900)
t = TimeClip(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili)))
return PyJsDate(t, prototype=DatePrototype)
@Js
def parse(string):
return PyJsDate(
TimeClip(parse_date(string.to_string().value)),
prototype=DatePrototype)
Date.define_own_property('now', {
'value': Js(now),
'enumerable': False,
'writable': True,
'configurable': True
})
Date.define_own_property('parse', {
'value': parse,
'enumerable': False,
'writable': True,
'configurable': True
})
Date.define_own_property('UTC', {
'value': UTC,
'enumerable': False,
'writable': True,
'configurable': True
})
class PyJsDate(PyJs):
Class = 'Date'
extensible = True
def __init__(self, value, prototype=None):
self.value = value
self.own = {}
self.prototype = prototype
# todo fix this problematic datetime part
def to_local_dt(self):
return datetime.datetime.utcfromtimestamp(
UTCToLocal(self.value) // 1000)
def to_utc_dt(self):
return datetime.datetime.utcfromtimestamp(self.value // 1000)
def local_strftime(self, pattern):
if self.value is NaN:
return 'Invalid Date'
try:
dt = self.to_local_dt()
except:
raise MakeError(
'TypeError',
'unsupported date range. Will fix in future versions')
try:
return dt.strftime(pattern)
except:
raise MakeError(
'TypeError',
'Could not generate date string from this date (limitations of python.datetime)'
)
def utc_strftime(self, pattern):
if self.value is NaN:
return 'Invalid Date'
try:
dt = self.to_utc_dt()
except:
raise MakeError(
'TypeError',
'unsupported date range. Will fix in future versions')
try:
return dt.strftime(pattern)
except:
raise MakeError(
'TypeError',
'Could not generate date string from this date (limitations of python.datetime)'
)
def parse_date(py_string): # todo support all date string formats
try:
try:
dt = datetime.datetime.strptime(py_string, "%Y-%m-%dT%H:%M:%S.%fZ")
except:
dt = datetime.datetime.strptime(py_string, "%Y-%m-%dT%H:%M:%SZ")
return MakeDate(
MakeDay(Js(dt.year), Js(dt.month - 1), Js(dt.day)),
MakeTime(
Js(dt.hour), Js(dt.minute), Js(dt.second),
Js(dt.microsecond // 1000)))
except:
raise MakeError(
'TypeError',
'Could not parse date %s - unsupported date format. Currently only supported format is RFC3339 utc. Sorry!'
% py_string)
def date_constructor(*args):
if len(args) >= 2:
return date_constructor2(*args)
elif len(args) == 1:
return date_constructor1(args[0])
else:
return date_constructor0()
def date_constructor0():
return now()
def date_constructor1(value):
v = value.to_primitive()
if v._type() == 'String':
v = parse_date(v.value)
else:
v = v.to_int()
return PyJsDate(TimeClip(v), prototype=DatePrototype)
def date_constructor2(*args):
y = args[0].to_number()
m = args[1].to_number()
l = len(args)
dt = args[2].to_number() if l > 2 else Js(1)
h = args[3].to_number() if l > 3 else Js(0)
mi = args[4].to_number() if l > 4 else Js(0)
sec = args[5].to_number() if l > 5 else Js(0)
mili = args[6].to_number() if l > 6 else Js(0)
if not y.is_nan() and 0 <= y.value <= 99:
y = y + Js(1900)
t = TimeClip(
LocalToUTC(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili))))
return PyJsDate(t, prototype=DatePrototype)
Date.create = date_constructor
DatePrototype = PyJsDate(float('nan'), prototype=ObjectPrototype)
def check_date(obj):
if obj.Class != 'Date':
raise MakeError('TypeError', 'this is not a Date object')
class DateProto:
def toString():
check_date(this)
if this.value is NaN:
return 'Invalid Date'
offset = (UTCToLocal(this.value) - this.value) // msPerHour
return this.local_strftime(
'%a %b %d %Y %H:%M:%S GMT') + '%s00 (%s)' % (pad(
offset, 2, True), GetTimeZoneName(this.value))
def toDateString():
check_date(this)
return this.local_strftime('%d %B %Y')
def toTimeString():
check_date(this)
return this.local_strftime('%H:%M:%S')
def toLocaleString():
check_date(this)
return this.local_strftime('%d %B %Y %H:%M:%S')
def toLocaleDateString():
check_date(this)
return this.local_strftime('%d %B %Y')
def toLocaleTimeString():
check_date(this)
return this.local_strftime('%H:%M:%S')
def valueOf():
check_date(this)
return this.value
def getTime():
check_date(this)
return this.value
def getFullYear():
check_date(this)
if this.value is NaN:
return NaN
return YearFromTime(UTCToLocal(this.value))
def getUTCFullYear():
check_date(this)
if this.value is NaN:
return NaN
return YearFromTime(this.value)
def getMonth():
check_date(this)
if this.value is NaN:
return NaN
return MonthFromTime(UTCToLocal(this.value))
def getDate():
check_date(this)
if this.value is NaN:
return NaN
return DateFromTime(UTCToLocal(this.value))
def getUTCMonth():
check_date(this)
if this.value is NaN:
return NaN
return MonthFromTime(this.value)
def getUTCDate():
check_date(this)
if this.value is NaN:
return NaN
return DateFromTime(this.value)
def getDay():
check_date(this)
if this.value is NaN:
return NaN
return WeekDay(UTCToLocal(this.value))
def getUTCDay():
check_date(this)
if this.value is NaN:
return NaN
return WeekDay(this.value)
def getHours():
check_date(this)
if this.value is NaN:
return NaN
return HourFromTime(UTCToLocal(this.value))
def getUTCHours():
check_date(this)
if this.value is NaN:
return NaN
return HourFromTime(this.value)
def getMinutes():
check_date(this)
if this.value is NaN:
return NaN
return MinFromTime(UTCToLocal(this.value))
def getUTCMinutes():
check_date(this)
if this.value is NaN:
return NaN
return MinFromTime(this.value)
def getSeconds():
check_date(this)
if this.value is NaN:
return NaN
return SecFromTime(UTCToLocal(this.value))
def getUTCSeconds():
check_date(this)
if this.value is NaN:
return NaN
return SecFromTime(this.value)
def getMilliseconds():
check_date(this)
if this.value is NaN:
return NaN
return msFromTime(UTCToLocal(this.value))
def getUTCMilliseconds():
check_date(this)
if this.value is NaN:
return NaN
return msFromTime(this.value)
def getTimezoneOffset():
check_date(this)
if this.value is NaN:
return NaN
return (this.value - UTCToLocal(this.value)) // 60000
def setTime(time):
check_date(this)
this.value = TimeClip(time.to_number().to_int())
return this.value
def setMilliseconds(ms):
check_date(this)
t = UTCToLocal(this.value)
tim = MakeTime(
HourFromTime(t), MinFromTime(t), SecFromTime(t), ms.to_int())
u = TimeClip(LocalToUTC(MakeDate(Day(t), tim)))
this.value = u
return u
def setUTCMilliseconds(ms):
check_date(this)
t = this.value
tim = MakeTime(
HourFromTime(t), MinFromTime(t), SecFromTime(t), ms.to_int())
u = TimeClip(MakeDate(Day(t), tim))
this.value = u
return u
# todo Complete all setters!
def toUTCString():
check_date(this)
return this.utc_strftime('%d %B %Y %H:%M:%S')
def toISOString():
check_date(this)
t = this.value
year = YearFromTime(t)
month, day, hour, minute, second, milli = pad(
MonthFromTime(t) + 1), pad(DateFromTime(t)), pad(
HourFromTime(t)), pad(MinFromTime(t)), pad(
SecFromTime(t)), pad(msFromTime(t))
return ISO_FORMAT % (unicode(year) if 0 <= year <= 9999 else pad(
year, 6, True), month, day, hour, minute, second, milli)
def toJSON(key):
o = this.to_object()
tv = o.to_primitive('Number')
if tv.Class == 'Number' and not tv.is_finite():
return this.null
toISO = o.get('toISOString')
if not toISO.is_callable():
raise this.MakeError('TypeError', 'toISOString is not callable')
return toISO.call(o, ())
def pad(num, n=2, sign=False):
'''returns n digit string representation of the num'''
s = unicode(abs(num))
if len(s) < n:
s = '0' * (n - len(s)) + s
if not sign:
return s
if num >= 0:
return '+' + s
else:
return '-' + s
fill_prototype(DatePrototype, DateProto, default_attrs)
Date.define_own_property(
'prototype', {
'value': DatePrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
DatePrototype.define_own_property('constructor', {
'value': Date,
'enumerable': False,
'writable': True,
'configurable': True
})
@@ -1,87 +0,0 @@
# this is based on jsarray.py
from ..base import *
try:
import numpy
except:
pass
@Js
def Float32Array():
TypedArray = (PyJsInt8Array, PyJsUint8Array, PyJsUint8ClampedArray,
PyJsInt16Array, PyJsUint16Array, PyJsInt32Array,
PyJsUint32Array, PyJsFloat32Array, PyJsFloat64Array)
a = arguments[0]
if isinstance(a, PyJsNumber): # length
length = a.to_uint32()
if length != a.value:
raise MakeError('RangeError', 'Invalid array length')
temp = Js(numpy.full(length, 0, dtype=numpy.float32))
temp.put('length', a)
return temp
elif isinstance(a, PyJsString): # object (string)
temp = Js(numpy.array(list(a.value), dtype=numpy.float32))
temp.put('length', Js(len(list(a.value))))
return temp
elif isinstance(a, PyJsArray) or isinstance(a, TypedArray) or isinstance(
a, PyJsArrayBuffer): # object (Array, TypedArray)
array = a.to_list()
array = [(int(item.value) if item.value != None else 0)
for item in array]
temp = Js(numpy.array(array, dtype=numpy.float32))
temp.put('length', Js(len(array)))
return temp
elif isinstance(a, PyObjectWrapper): # object (ArrayBuffer, etc)
if len(a.obj) % 4 != 0:
raise MakeError(
'RangeError',
'Byte length of Float32Array should be a multiple of 4')
if len(arguments) > 1:
offset = int(arguments[1].value)
if offset % 4 != 0:
raise MakeError(
'RangeError',
'Start offset of Float32Array should be a multiple of 4')
else:
offset = 0
if len(arguments) > 2:
length = int(arguments[2].value)
else:
length = int((len(a.obj) - offset) / 4)
array = numpy.frombuffer(
a.obj, dtype=numpy.float32, count=length, offset=offset)
temp = Js(array)
temp.put('length', Js(length))
temp.buff = array
return temp
temp = Js(numpy.full(0, 0, dtype=numpy.float32))
temp.put('length', Js(0))
return temp
Float32Array.create = Float32Array
Float32Array.own['length']['value'] = Js(3)
Float32Array.define_own_property(
'prototype', {
'value': Float32ArrayPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
Float32ArrayPrototype.define_own_property(
'constructor', {
'value': Float32Array,
'enumerable': False,
'writable': True,
'configurable': True
})
Float32ArrayPrototype.define_own_property('BYTES_PER_ELEMENT', {
'value': Js(4),
'enumerable': False,
'writable': False,
'configurable': False
})
@@ -1,87 +0,0 @@
# this is based on jsarray.py
from ..base import *
try:
import numpy
except:
pass
@Js
def Float64Array():
TypedArray = (PyJsInt8Array, PyJsUint8Array, PyJsUint8ClampedArray,
PyJsInt16Array, PyJsUint16Array, PyJsInt32Array,
PyJsUint32Array, PyJsFloat32Array, PyJsFloat64Array)
a = arguments[0]
if isinstance(a, PyJsNumber): # length
length = a.to_uint32()
if length != a.value:
raise MakeError('RangeError', 'Invalid array length')
temp = Js(numpy.full(length, 0, dtype=numpy.float64))
temp.put('length', a)
return temp
elif isinstance(a, PyJsString): # object (string)
temp = Js(numpy.array(list(a.value), dtype=numpy.float64))
temp.put('length', Js(len(list(a.value))))
return temp
elif isinstance(a, PyJsArray) or isinstance(a, TypedArray) or isinstance(
a, PyJsArrayBuffer): # object (Array, TypedArray)
array = a.to_list()
array = [(int(item.value) if item.value != None else 0)
for item in array]
temp = Js(numpy.array(array, dtype=numpy.float64))
temp.put('length', Js(len(array)))
return temp
elif isinstance(a, PyObjectWrapper): # object (ArrayBuffer, etc)
if len(a.obj) % 8 != 0:
raise MakeError(
'RangeError',
'Byte length of Float64Array should be a multiple of 8')
if len(arguments) > 1:
offset = int(arguments[1].value)
if offset % 8 != 0:
raise MakeError(
'RangeError',
'Start offset of Float64Array should be a multiple of 8')
else:
offset = 0
if len(arguments) > 2:
length = int(arguments[2].value)
else:
length = int((len(a.obj) - offset) / 8)
array = numpy.frombuffer(
a.obj, dtype=numpy.float64, count=length, offset=offset)
temp = Js(array)
temp.put('length', Js(length))
temp.buff = array
return temp
temp = Js(numpy.full(0, 0, dtype=numpy.float64))
temp.put('length', Js(0))
return temp
Float64Array.create = Float64Array
Float64Array.own['length']['value'] = Js(3)
Float64Array.define_own_property(
'prototype', {
'value': Float64ArrayPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
Float64ArrayPrototype.define_own_property(
'constructor', {
'value': Float64Array,
'enumerable': False,
'writable': True,
'configurable': True
})
Float64ArrayPrototype.define_own_property('BYTES_PER_ELEMENT', {
'value': Js(8),
'enumerable': False,
'writable': False,
'configurable': False
})
@@ -1,52 +0,0 @@
from ..base import *
try:
from ..translators.translator import translate_js
except:
pass
@Js
def Function():
# convert arguments to python list of strings
a = [e.to_string().value for e in arguments.to_list()]
body = ';'
args = ()
if len(a):
body = '%s;' % a[-1]
args = a[:-1]
# translate this function to js inline function
js_func = '(function (%s) {%s})' % (','.join(args), body)
# now translate js inline to python function
py_func = translate_js(js_func, '')
# add set func scope to global scope
# a but messy solution but works :)
globals()['var'] = PyJs.GlobalObject
# define py function and return it
temp = executor(py_func, globals())
temp.source = '{%s}' % body
temp.func_name = 'anonymous'
return temp
def executor(f, glob):
exec (f, globals())
return globals()['PyJs_anonymous_0_']
#new statement simply calls Function
Function.create = Function
#set constructor property inside FunctionPrototype
fill_in_props(FunctionPrototype, {'constructor': Function}, default_attrs)
#attach prototype to Function constructor
Function.define_own_property(
'prototype', {
'value': FunctionPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
#Fix Function length (its 0 and should be 1)
Function.own['length']['value'] = Js(1)
@@ -1,87 +0,0 @@
# this is based on jsarray.py
from ..base import *
try:
import numpy
except:
pass
@Js
def Int16Array():
TypedArray = (PyJsInt8Array, PyJsUint8Array, PyJsUint8ClampedArray,
PyJsInt16Array, PyJsUint16Array, PyJsInt32Array,
PyJsUint32Array, PyJsFloat32Array, PyJsFloat64Array)
a = arguments[0]
if isinstance(a, PyJsNumber): # length
length = a.to_uint32()
if length != a.value:
raise MakeError('RangeError', 'Invalid array length')
temp = Js(numpy.full(length, 0, dtype=numpy.int16))
temp.put('length', a)
return temp
elif isinstance(a, PyJsString): # object (string)
temp = Js(numpy.array(list(a.value), dtype=numpy.int16))
temp.put('length', Js(len(list(a.value))))
return temp
elif isinstance(a, PyJsArray) or isinstance(a, TypedArray) or isinstance(
a, PyJsArrayBuffer): # object (Array, TypedArray)
array = a.to_list()
array = [(int(item.value) if item.value != None else 0)
for item in array]
temp = Js(numpy.array(array, dtype=numpy.int16))
temp.put('length', Js(len(array)))
return temp
elif isinstance(a, PyObjectWrapper): # object (ArrayBuffer, etc)
if len(a.obj) % 2 != 0:
raise MakeError(
'RangeError',
'Byte length of Int16Array should be a multiple of 2')
if len(arguments) > 1:
offset = int(arguments[1].value)
if offset % 2 != 0:
raise MakeError(
'RangeError',
'Start offset of Int16Array should be a multiple of 2')
else:
offset = 0
if len(arguments) > 2:
length = int(arguments[2].value)
else:
length = int((len(a.obj) - offset) / 2)
array = numpy.frombuffer(
a.obj, dtype=numpy.int16, count=length, offset=offset)
temp = Js(array)
temp.put('length', Js(length))
temp.buff = array
return temp
temp = Js(numpy.full(0, 0, dtype=numpy.int16))
temp.put('length', Js(0))
return temp
Int16Array.create = Int16Array
Int16Array.own['length']['value'] = Js(3)
Int16Array.define_own_property(
'prototype', {
'value': Int16ArrayPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
Int16ArrayPrototype.define_own_property(
'constructor', {
'value': Int16Array,
'enumerable': False,
'writable': True,
'configurable': True
})
Int16ArrayPrototype.define_own_property('BYTES_PER_ELEMENT', {
'value': Js(2),
'enumerable': False,
'writable': False,
'configurable': False
})
@@ -1,87 +0,0 @@
# this is based on jsarray.py
from ..base import *
try:
import numpy
except:
pass
@Js
def Int32Array():
TypedArray = (PyJsInt8Array, PyJsUint8Array, PyJsUint8ClampedArray,
PyJsInt16Array, PyJsUint16Array, PyJsInt32Array,
PyJsUint32Array, PyJsFloat32Array, PyJsFloat64Array)
a = arguments[0]
if isinstance(a, PyJsNumber): # length
length = a.to_uint32()
if length != a.value:
raise MakeError('RangeError', 'Invalid array length')
temp = Js(numpy.full(length, 0, dtype=numpy.int32))
temp.put('length', a)
return temp
elif isinstance(a, PyJsString): # object (string)
temp = Js(numpy.array(list(a.value), dtype=numpy.int32))
temp.put('length', Js(len(list(a.value))))
return temp
elif isinstance(a, PyJsArray) or isinstance(a, TypedArray) or isinstance(
a, PyJsArrayBuffer): # object (Array, TypedArray)
array = a.to_list()
array = [(int(item.value) if item.value != None else 0)
for item in array]
temp = Js(numpy.array(array, dtype=numpy.int32))
temp.put('length', Js(len(array)))
return temp
elif isinstance(a, PyObjectWrapper): # object (ArrayBuffer, etc)
if len(a.obj) % 4 != 0:
raise MakeError(
'RangeError',
'Byte length of Int32Array should be a multiple of 4')
if len(arguments) > 1:
offset = int(arguments[1].value)
if offset % 4 != 0:
raise MakeError(
'RangeError',
'Start offset of Int32Array should be a multiple of 4')
else:
offset = 0
if len(arguments) > 2:
length = int(arguments[2].value)
else:
length = int((len(a.obj) - offset) / 4)
array = numpy.frombuffer(
a.obj, dtype=numpy.int32, count=length, offset=offset)
temp = Js(array)
temp.put('length', Js(length))
temp.buff = array
return temp
temp = Js(numpy.full(0, 0, dtype=numpy.int32))
temp.put('length', Js(0))
return temp
Int32Array.create = Int32Array
Int32Array.own['length']['value'] = Js(3)
Int32Array.define_own_property(
'prototype', {
'value': Int32ArrayPrototype,
'enumerable': False,
'writable': False,
'configurable': False
})
Int32ArrayPrototype.define_own_property(
'constructor', {
'value': Int32Array,
'enumerable': False,
'writable': True,
'configurable': True
})
Int32ArrayPrototype.define_own_property('BYTES_PER_ELEMENT', {
'value': Js(4),
'enumerable': False,
'writable': False,
'configurable': False
})

Some files were not shown because too many files have changed in this diff Show More