Ejemplo n.º 1
0
def translate_object(obj, lval, obj_count=1, arr_count=1):
    obj = obj[1:-1]  # remove {} from both ends
    obj, obj_rep, obj_count = remove_objects(obj, obj_count)
    obj, arr_rep, arr_count = remove_arrays(obj, arr_count)
    # functions can be defined inside objects. exp translator cant translate them.
    # we have to remove them and translate with func translator
    # its better explained in translate_array function
    obj, hoisted, inline = functions.remove_functions(obj, all_inline=True)
    assert not hoisted
    gsetters_after = ''
    keys = argsplit(obj)
    res = []
    for i, e in enumerate(keys, 1):
        e = e.strip()
        if e.startswith('set '):
            gsetters_after += translate_setter(lval, e)
        elif e.startswith('get '):
            gsetters_after += translate_getter(lval, e)
        elif ':' not in e:
            if i < len(keys
                       ):  # can happen legally only in the last element {3:2,}
                raise SyntaxError('Unexpected "," in Object literal')
            break
        else:  #Not getter, setter or elision
            spl = argsplit(e, ':')
            if len(spl) < 2:
                raise SyntaxError('Invalid Object literal: ' + e)
            try:
                key, value = spl
            except:  #len(spl)> 2
                print 'Unusual case ' + repr(e)
                key = spl[0]
                value = ':'.join(spl[1:])
            key = key.strip()
            if is_internal(key):
                key = '%s.to_string().value' % key
            else:
                key = repr(key)

            value = exp_translator(value)
            if not value:
                raise SyntaxError('Missing value in Object literal')
            res.append('%s:%s' % (key, value))
    res = '%s = Js({%s})\n' % (lval, ','.join(res)) + gsetters_after
    # translate all the nested objects (including removed earlier functions)
    for nested_name, nested_info in inline.iteritems():  # functions
        nested_block, nested_args = nested_info
        new_def = FUNC_TRANSLATOR(nested_name, nested_block, nested_args)
        res = new_def + res
    for lval, obj in obj_rep.iteritems():  #objects
        new_def, obj_count, arr_count = translate_object(
            obj, lval, obj_count, arr_count)
        # add object definition BEFORE array definition
        res = new_def + res
    for lval, obj in arr_rep.iteritems():  # arrays
        new_def, obj_count, arr_count = translate_array(
            obj, lval, obj_count, arr_count)
        # add object definition BEFORE array definition
        res = new_def + res
    return res, obj_count, arr_count
Ejemplo n.º 2
0
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_getter(lval, getter):
    func = 'function' + getter[3:]
    try:
        _, data, _ = functions.remove_functions(func)
        if not data or len(data)>1:
            raise Exception()
    except:
        raise SyntaxError('Could not parse getter: '+getter)
    prop = data.keys()[0]
    body, args = data[prop]
    if len(args)!=0:  #setter must have exactly 0 argument
        raise SyntaxError('Invalid getter. It must take exactly 0 argument.')
    # now messy part
    res = FUNC_TRANSLATOR('getter', body, args)
    res += "%s.define_own_property(%s, {'get': setter})\n"%(lval, repr(prop))
    return res
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
def translate_array(array, lval, obj_count=1, arr_count=1):
    """array has to be any js array for example [1,2,3]
       lval has to be name of this array.
       Returns python code that adds lval to the PY scope it should be put before lval"""
    array = array[1:-1]
    array, obj_rep, obj_count = remove_objects(array, obj_count)
    array, arr_rep, arr_count = remove_arrays(array, arr_count)
    #functions can be also defined in arrays, this caused many problems since in Python
    # functions cant be defined inside literal
    # remove functions (they dont contain arrays or objects so can be translated easily)
    # hoisted functions are treated like inline
    array, hoisted, inline = functions.remove_functions(array, all_inline=True)
    assert not hoisted
    arr = []
    # separate elements in array
    for e in argsplit(array, ','):
        # translate expressions in array PyJsLvalInline will not be translated!
        e = exp_translator(e.replace('\n', ''))
        arr.append(e if e else 'None')
    arr = '%s = Js([%s])\n' % (lval, ','.join(arr))
    #But we can have more code to add to define arrays/objects/functions defined inside this array
    # translate nested objects:
    # functions:
    for nested_name, nested_info in inline.iteritems():
        nested_block, nested_args = nested_info
        new_def = FUNC_TRANSLATOR(nested_name, nested_block, nested_args)
        arr = new_def + arr
    for lval, obj in obj_rep.iteritems():
        new_def, obj_count, arr_count = translate_object(
            obj, lval, obj_count, arr_count)
        # add object definition BEFORE array definition
        arr = new_def + arr
    for lval, obj in arr_rep.iteritems():
        new_def, obj_count, arr_count = translate_array(
            obj, lval, obj_count, arr_count)
        # add object definition BEFORE array definition
        arr = new_def + arr
    return arr, obj_count, arr_count
Ejemplo n.º 7
0
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