mirror of
https://github.com/morpheus65535/bazarr
synced 2024-12-30 11:35:50 +00:00
99 lines
3.9 KiB
Python
99 lines
3.9 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}')
|