mylar/lib/js2py/legecy_translators/functions.py

84 lines
3.6 KiB
Python

"""This module removes JS functions from source code"""
from jsparser import *
from utils import *
INLINE_NAME = 'PyJsLvalInline%d_'
INLINE_COUNT = 0
PRE_EXP_STARTS = {'return', 'new', 'void', 'throw', 'typeof', 'in', 'instanceof'}
PRE_ALLOWED = IDENTIFIER_PART.union({';', '{', '}', ']', ')', ':'})
INCREMENTS = {'++', '--'}
def reset_inline_count():
global INLINE_COUNT
INLINE_COUNT = 0
def remove_functions(source, all_inline=False):
"""removes functions and returns new source, and 2 dicts.
first dict with removed hoisted(global) functions and second with replaced inline functions"""
global INLINE_COUNT
inline = {}
hoisted = {}
n = 0
limit = len(source) - 9 # 8 is length of 'function'
res = ''
last = 0
while n < limit:
if n and source[n-1] in IDENTIFIER_PART:
n+=1
continue
if source[n:n+8] == 'function' and source[n+8] not in IDENTIFIER_PART:
if source[:n].rstrip().endswith('.'): # allow function as a property name :)
n+=1
continue
if source[n+8:].lstrip().startswith(':'): # allow functions inside objects...
n+=1
continue
entered = n
res += source[last:n]
name = ''
n = pass_white(source, n+8)
if source[n] in IDENTIFIER_START: # hoisted function
name, n= parse_identifier(source, n)
args, n = pass_bracket(source, n, '()')
if not args:
raise SyntaxError('Function misses bracket with argnames ()')
args = args.strip('() \n')
args = tuple(parse_identifier(e, 0)[0] for e in argsplit(args)) if args else ()
if len(args) - len(set(args)):
# I know its legal in JS but python does not allow duplicate argnames
# I will not work around it
raise SyntaxError('Function has duplicate argument names. Its not legal in this implementation. Sorry.')
block, n = pass_bracket(source, n, '{}')
if not block:
raise SyntaxError('Function does not have any code block to execute')
mixed = False # named function expression flag
if name and not all_inline:
# Here I will distinguish between named function expression (mixed) and a function statement
before = source[:entered].rstrip()
if any(endswith_keyword(before, e) for e in PRE_EXP_STARTS):
#print 'Ended ith keyword'
mixed = True
elif before and before[-1] not in PRE_ALLOWED and not before[-2:] in INCREMENTS:
#print 'Ended with'+repr(before[-1]), before[-1]=='}'
mixed = True
else:
#print 'FUNCTION STATEMENT'
#its a function statement.
# todo remove fucking label if present!
hoisted[name] = block, args
if not name or mixed or all_inline: # its a function expression (can be both named and not named)
#print 'FUNCTION EXPRESSION'
INLINE_COUNT += 1
iname = INLINE_NAME%INLINE_COUNT # inline name
res += ' '+ iname
inline['%s@%s' %(iname, name)] = block, args #here added real name at the end because it has to be added to the func scope
last = n
else:
n+=1
res += source[last:]
return res, hoisted, inline
if __name__=='__main__':
print remove_functions('5+5 function n (functiona ,functionaj) {dsd s, dsdd}')