<commit_before>#
# Jasy - Web Tooling Framework
# Copyright 2010-2011 <NAME>
#

import string, logging
from jasy.tokenizer.Tokenizer import keywords

__all__ = ["optimize", "Error"]



#
# Public API
#


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)


def optimize(node):
    """
    Node to optimize with the global variables to ignore as names
    """
    
    logging.debug(">>> Renaming local variables...")
    
    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:
        stats = getattr(node, "stats", None)
        
        if stats:
            declared = stats.declared
            params = stats.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 stats.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)
                
                namesSorted = list(reversed(sorted(names, key=lambda x: stats.accessed[x] if x in stats.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 keywords and not repl in blocked:
                            break
                
                    # print("Translate: %s => %s" % (name, repl))
                    translate[name] = repl


    #
    # APPLY TRANSLATION
    #<commit_msg>Fixed test<commit_after>#
# Jasy - Web Tooling Framework
# Copyright 2010-2011 <NAME>
#

import string, logging
from jasy.tokenizer.Tokenizer import keywords

__all__ = ["optimize", "Error"]



#
# Public API
#


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)


def optimize(node):
    """
    Node to optimize with the global variables to ignore as names
    """
    
    logging.debug(">>> Renaming local variables...")
    
    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)
                
                namesSorted = list(reversed(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 keywords and not repl in blocked:
                            break
                
                    # print("Translate: %s => %s" % (name, repl))
                    translate[name] = repl


    #
    # APPLY TRANSLATION
    #
{'fraction_non_alphanumeric': 0.07784166298098187, 'fraction_numerical': 0.003833112192245319, 'mean_word_length': 1.4297994269340975, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7041642', 'n_tokens_mistral': 1782, 'n_tokens_neox': 1655, 'n_words': 563}