You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.8 KiB
154 lines
5.8 KiB
2 years ago
|
from __future__ import print_function
|
||
|
|
||
|
from flow import translate_flow
|
||
|
from constants import remove_constants, recover_constants
|
||
|
from objects import remove_objects, remove_arrays, translate_object, translate_array, set_func_translator
|
||
|
from functions import remove_functions, reset_inline_count
|
||
|
from jsparser import inject_before_lval, indent, dbg
|
||
|
|
||
|
TOP_GLOBAL = '''from js2py.pyjs import *\nvar = Scope( JS_BUILTINS )\nset_global_object(var)\n'''
|
||
|
|
||
|
|
||
|
def translate_js(js, top=TOP_GLOBAL):
|
||
|
"""js has to be a javascript source code.
|
||
|
returns equivalent python code."""
|
||
|
# Remove constant literals
|
||
|
no_const, constants = remove_constants(js)
|
||
|
#print 'const count', len(constants)
|
||
|
# Remove object literals
|
||
|
no_obj, objects, obj_count = remove_objects(no_const)
|
||
|
#print 'obj count', len(objects)
|
||
|
# Remove arrays
|
||
|
no_arr, arrays, arr_count = remove_arrays(no_obj)
|
||
|
#print 'arr count', len(arrays)
|
||
|
# Here remove and replace functions
|
||
|
reset_inline_count()
|
||
|
no_func, hoisted, inline = remove_functions(no_arr)
|
||
|
|
||
|
#translate flow and expressions
|
||
|
py_seed, to_register = translate_flow(no_func)
|
||
|
|
||
|
# register variables and hoisted functions
|
||
|
#top += '# register variables\n'
|
||
|
top += 'var.registers(%s)\n' % str(to_register + hoisted.keys())
|
||
|
|
||
|
#Recover functions
|
||
|
# hoisted functions recovery
|
||
|
defs = ''
|
||
|
#defs += '# define hoisted functions\n'
|
||
|
#print len(hoisted) , 'HH'*40
|
||
|
for nested_name, nested_info in hoisted.iteritems():
|
||
|
nested_block, nested_args = nested_info
|
||
|
new_code = translate_func('PyJsLvalTempHoisted', nested_block,
|
||
|
nested_args)
|
||
|
new_code += 'PyJsLvalTempHoisted.func_name = %s\n' % repr(nested_name)
|
||
|
defs += new_code + '\nvar.put(%s, PyJsLvalTempHoisted)\n' % repr(
|
||
|
nested_name)
|
||
|
#defs += '# Everting ready!\n'
|
||
|
# inline functions recovery
|
||
|
for nested_name, nested_info in inline.iteritems():
|
||
|
nested_block, nested_args = nested_info
|
||
|
new_code = translate_func(nested_name, nested_block, nested_args)
|
||
|
py_seed = inject_before_lval(py_seed,
|
||
|
nested_name.split('@')[0], new_code)
|
||
|
# add hoisted definitiond - they have literals that have to be recovered
|
||
|
py_seed = defs + py_seed
|
||
|
|
||
|
#Recover arrays
|
||
|
for arr_lval, arr_code in arrays.iteritems():
|
||
|
translation, obj_count, arr_count = translate_array(
|
||
|
arr_code, arr_lval, obj_count, arr_count)
|
||
|
py_seed = inject_before_lval(py_seed, arr_lval, translation)
|
||
|
|
||
|
#Recover objects
|
||
|
for obj_lval, obj_code in objects.iteritems():
|
||
|
translation, obj_count, arr_count = translate_object(
|
||
|
obj_code, obj_lval, obj_count, arr_count)
|
||
|
py_seed = inject_before_lval(py_seed, obj_lval, translation)
|
||
|
|
||
|
#Recover constants
|
||
|
py_code = recover_constants(py_seed, constants)
|
||
|
|
||
|
return top + py_code
|
||
|
|
||
|
|
||
|
def translate_func(name, block, args):
|
||
|
"""Translates functions and all nested functions to Python code.
|
||
|
name - name of that function (global functions will be available under var while
|
||
|
inline will be available directly under this name )
|
||
|
block - code of the function (*with* brackets {} )
|
||
|
args - arguments that this function takes"""
|
||
|
inline = name.startswith('PyJsLvalInline')
|
||
|
real_name = ''
|
||
|
if inline:
|
||
|
name, real_name = name.split('@')
|
||
|
arglist = ', '.join(args) + ', ' if args else ''
|
||
|
code = '@Js\ndef %s(%sthis, arguments, var=var):\n' % (name, arglist)
|
||
|
# register local variables
|
||
|
scope = "'this':this, 'arguments':arguments" #it will be a simple dictionary
|
||
|
for arg in args:
|
||
|
scope += ', %s:%s' % (repr(arg), arg)
|
||
|
if real_name:
|
||
|
scope += ', %s:%s' % (repr(real_name), name)
|
||
|
code += indent('var = Scope({%s}, var)\n' % scope)
|
||
|
block, nested_hoisted, nested_inline = remove_functions(block)
|
||
|
py_code, to_register = translate_flow(block)
|
||
|
#register variables declared with var and names of hoisted functions.
|
||
|
to_register += nested_hoisted.keys()
|
||
|
if to_register:
|
||
|
code += indent('var.registers(%s)\n' % str(to_register))
|
||
|
for nested_name, info in nested_hoisted.iteritems():
|
||
|
nested_block, nested_args = info
|
||
|
new_code = translate_func('PyJsLvalTempHoisted', nested_block,
|
||
|
nested_args)
|
||
|
# Now put definition of hoisted function on the top
|
||
|
code += indent(new_code)
|
||
|
code += indent(
|
||
|
'PyJsLvalTempHoisted.func_name = %s\n' % repr(nested_name))
|
||
|
code += indent(
|
||
|
'var.put(%s, PyJsLvalTempHoisted)\n' % repr(nested_name))
|
||
|
for nested_name, info in nested_inline.iteritems():
|
||
|
nested_block, nested_args = info
|
||
|
new_code = translate_func(nested_name, nested_block, nested_args)
|
||
|
# Inject definitions of inline functions just before usage
|
||
|
# nested inline names have this format : LVAL_NAME@REAL_NAME
|
||
|
py_code = inject_before_lval(py_code,
|
||
|
nested_name.split('@')[0], new_code)
|
||
|
if py_code.strip():
|
||
|
code += indent(py_code)
|
||
|
return code
|
||
|
|
||
|
|
||
|
set_func_translator(translate_func)
|
||
|
|
||
|
#print inject_before_lval(' chuj\n moj\n lval\nelse\n', 'lval', 'siema\njestem piter\n')
|
||
|
import time
|
||
|
#print time.time()
|
||
|
#print translate_js('if (1) console.log("Hello, World!"); else if (5) console.log("Hello world?");')
|
||
|
#print time.time()
|
||
|
t = """
|
||
|
var x = [1,2,3,4,5,6];
|
||
|
for (var e in x) {console.log(e); delete x[3];}
|
||
|
console.log(5 in [1,2,3,4,5]);
|
||
|
|
||
|
"""
|
||
|
|
||
|
SANDBOX = '''
|
||
|
import traceback
|
||
|
try:
|
||
|
%s
|
||
|
except:
|
||
|
print traceback.format_exc()
|
||
|
print
|
||
|
raw_input('Press Enter to quit')
|
||
|
'''
|
||
|
if __name__ == '__main__':
|
||
|
# test with jq if works then it really works :)
|
||
|
#with open('jq.js', 'r') as f:
|
||
|
#jq = f.read()
|
||
|
|
||
|
#res = translate_js(jq)
|
||
|
res = translate_js(t)
|
||
|
dbg(SANDBOX % indent(res))
|
||
|
print('Done')
|