Source code for jasy.script.optimize.LocalVariables

#
# Jasy - Web Tooling Framework
# Copyright 2010-2012 Zynga Inc.
# Copyright 2013-2014 Sebastian Werner
#

import string
import jasy.script.tokenize.Lang



#
# Public API
#


[docs]class Error(Exception): def __init__(self, name, line): self.__name = name self.__line = line def __str__(self): return "Unallowed private field access to %s at line %s!" % (self.__name, self.__line)
[docs]def optimize(node): """Node to optimize with the global variables to ignore as names.""" blocked = set(node.scope.shared.keys()) blocked.update(node.scope.modified) __patch(node, blocked)
# # Implementation # def __baseEncode(num, alphabet=string.ascii_letters): if (num == 0): return alphabet[0] arr = [] base = len(alphabet) while num: rem = num % base num = num // base arr.append(alphabet[rem]) arr.reverse() return "".join(arr) def __patch(node, blocked=None, enable=False, translate=None): # Start with first level scopes (global scope should not be affected) if node.type == "script" and hasattr(node, "parent"): enable = True # # GENERATE TRANSLATION TABLE # if enable: scope = getattr(node, "scope", None) if scope: declared = scope.declared params = scope.params if declared or params: usedRepl = set() if not translate: translate = {} else: # copy only the interesting ones from the shared set newTranslate = {} for name in scope.shared: if name in translate: newTranslate[name] = translate[name] usedRepl.add(translate[name]) translate = newTranslate # Merge in usage data into declaration map to have # the possibilities to sort translation priority to # the usage number. Pretty cool. names = set() if params: names.update(params) if declared: names.update(declared) # We have to sort the set() before to support both Python 3.2 and # Python 3.3 with identical results. namesSorted = list(reversed(sorted(sorted(names), key=lambda x: scope.accessed[x] if x in scope.accessed else 0))) # Extend translation map by new replacements for locally # declared variables. Automatically ignores keywords. Only # blocks usage of replacements where the original variable from # outer scope is used. This way variable names may be re-used more # often than in the original code. pos = 0 for name in namesSorted: while True: repl = __baseEncode(pos) pos += 1 if not repl in usedRepl and not repl in jasy.script.tokenize.Lang.keywords and not repl in blocked: break # print("Translate: %s => %s" % (name, repl)) translate[name] = repl # # APPLY TRANSLATION # if translate: # Update param names in outer function block if node.type == "script" and hasattr(node, "parent"): function = node.parent if function.type == "function" and hasattr(function, "params"): for identifier in function.params: if identifier.value in translate: identifier.value = translate[identifier.value] # Update names of exception objects elif node.type == "exception" and node.value in translate: node.value = translate[node.value] # Update function name elif node.type == "function" and hasattr(node, "name") and node.name in translate: node.name = translate[node.name] # Update identifiers elif node.type == "identifier": # Ignore param blocks from inner functions if node.parent.type == "list" and getattr(node.parent, "rel", None) == "params": pass # Ignore keyword in property initialization names elif node.parent.type == "property_init" and node.parent[0] == node: pass # Update all identifiers which are # a) not part of a dot operator # b) first in a dot operator elif node.parent.type != "dot" or node.parent.index(node) == 0: if node.value in translate: node.value = translate[node.value] # Update declarations (as part of a var statement) elif node.type == "declaration": varName = getattr(node, "name", None) if varName is not None: if varName in translate: node.name = varName = translate[varName] else: # JS 1.7 Destructing Expression for identifier in node.names: if identifier.value in translate: identifier.value = translate[identifier.value] # # PROCESS CHILDREN # for child in node: # None children are allowed sometimes e.g. during array_init like [1,2,,,7,8] if child is not None: __patch(child, blocked, enable, translate)