src/eric7/ThirdParty/Jasy/jasy/script/output/Compressor.py

branch
eric7
changeset 9955
aa02420279fe
parent 9954
7c5fa3eef082
child 9956
5b138f996a1e
--- a/src/eric7/ThirdParty/Jasy/jasy/script/output/Compressor.py	Fri Mar 31 13:39:51 2023 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,564 +0,0 @@
-#
-# Jasy - Web Tooling Framework
-# Copyright 2010-2012 Zynga Inc.
-# Copyright 2013-2014 Sebastian Werner
-#
-
-from __future__ import unicode_literals
-
-import re, sys, json
-
-from jasy.script.tokenize.Lang import keywords
-from jasy.script.parse.Lang import expressions, futureReserved
-
-high_unicode = re.compile(r"\\u[2-9A-Fa-f][0-9A-Fa-f]{3}")
-ascii_encoder = json.JSONEncoder(ensure_ascii=True)
-unicode_encoder = json.JSONEncoder(ensure_ascii=False)
-
-#
-# Class
-#
-
-class Compressor:
-    __semicolonSymbol = ";"
-    __commaSymbol = ","
-
-
-    def __init__(self, format=None):
-        if format:
-            if format.has("semicolon"):
-                self.__semicolonSymbol = ";\n"
-
-            if format.has("comma"):
-                self.__commaSymbol = ",\n"
-
-        self.__forcedSemicolon = False
-
-
-
-    #
-    # Main
-    #
-
-    def compress(self, node):
-        type = node.type
-        result = None
-
-        if type in self.__simple:
-            result = type
-        elif type in self.__prefixes:
-            if getattr(node, "postfix", False):
-                result = self.compress(node[0]) + self.__prefixes[node.type]
-            else:
-                result = self.__prefixes[node.type] + self.compress(node[0])
-
-        elif type in self.__dividers:
-            first = self.compress(node[0])
-            second = self.compress(node[1])
-            divider = self.__dividers[node.type]
-
-            # Fast path
-            if node.type not in ("plus", "minus"):
-                result = "%s%s%s" % (first, divider, second)
-
-            # Special code for dealing with situations like x + ++y and y-- - x
-            else:
-                result = first
-                if first.endswith(divider):
-                    result += " "
-
-                result += divider
-
-                if second.startswith(divider):
-                    result += " "
-
-                result += second
-
-        else:
-            try:
-                result = getattr(self, "type_%s" % type)(node)
-            except AttributeError:
-                raise Exception("Script compressor does not support type '%s' from line %s in file %s" % (type, node.line, node.getFileName()))
-
-        if getattr(node, "parenthesized", None):
-            return "(%s)" % result
-        else:
-            return result
-
-
-
-    #
-    # Helpers
-    #
-
-    def __statements(self, node):
-        result = []
-        for child in node:
-            result.append(self.compress(child))
-
-        return "".join(result)
-
-    def __handleForcedSemicolon(self, node):
-        if node.type == "semicolon" and not hasattr(node, "expression"):
-            self.__forcedSemicolon = True
-
-    def __addSemicolon(self, result):
-        if not result.endswith(self.__semicolonSymbol):
-            if self.__forcedSemicolon:
-                self.__forcedSemicolon = False
-
-            return result + self.__semicolonSymbol
-
-        else:
-            return result
-
-    def __removeSemicolon(self, result):
-        if self.__forcedSemicolon:
-            self.__forcedSemicolon = False
-            return result
-
-        if result.endswith(self.__semicolonSymbol):
-            return result[:-len(self.__semicolonSymbol)]
-        else:
-            return result
-
-
-    #
-    # Data
-    #
-
-    __simple_property = re.compile(r"^[a-zA-Z_$][a-zA-Z0-9_$]*$")
-    __number_property = re.compile(r"^[0-9]+$")
-
-    __simple = ["true", "false", "null", "this", "debugger"]
-
-    __dividers = {
-        "plus"        : '+',
-        "minus"       : '-',
-        "mul"         : '*',
-        "div"         : '/',
-        "mod"         : '%',
-        "dot"         : '.',
-        "or"          : "||",
-        "and"         : "&&",
-        "strict_eq"   : '===',
-        "eq"          : '==',
-        "strict_ne"   : '!==',
-        "ne"          : '!=',
-        "lsh"         : '<<',
-        "le"          : '<=',
-        "lt"          : '<',
-        "ursh"        : '>>>',
-        "rsh"         : '>>',
-        "ge"          : '>=',
-        "gt"          : '>',
-        "bitwise_or"  : '|',
-        "bitwise_xor" : '^',
-        "bitwise_and" : '&'
-    }
-
-    __prefixes = {
-        "increment"   : "++",
-        "decrement"   : "--",
-        "bitwise_not" : '~',
-        "not"         : "!",
-        "unary_plus"  : "+",
-        "unary_minus" : "-",
-        "delete"      : "delete ",
-        "new"         : "new ",
-        "typeof"      : "typeof ",
-        "void"        : "void "
-    }
-
-
-
-    #
-    # Script Scope
-    #
-
-    def type_script(self, node):
-        return self.__statements(node)
-
-
-
-    #
-    # Expressions
-    #
-
-    def type_comma(self, node):
-        return self.__commaSymbol.join(map(self.compress, node))
-
-    def type_object_init(self, node):
-        return "{%s}" % self.__commaSymbol.join(map(self.compress, node))
-
-    def type_property_init(self, node):
-        key = self.compress(node[0])
-        value = self.compress(node[1])
-
-        if type(key) in (int, float):
-            pass
-
-        elif self.__number_property.match(key):
-            pass
-
-        # Protect keywords and special characters
-        elif key in keywords or key in futureReserved or not self.__simple_property.match(key):
-            key = self.type_string(node[0])
-
-        return "%s:%s" % (key, value)
-
-    def type_array_init(self, node):
-        def helper(child):
-            return self.compress(child) if child != None else ""
-
-        return "[%s]" % ",".join(map(helper, node))
-
-    def type_array_comp(self, node):
-        return "[%s %s]" % (self.compress(node.expression), self.compress(node.tail))
-
-    def type_string(self, node):
-        # Omit writing real high unicode character which are not supported well by browsers
-        ascii = ascii_encoder.encode(node.value)
-
-        if high_unicode.search(ascii):
-            return ascii
-        else:
-            return unicode_encoder.encode(node.value)
-
-    def type_number(self, node):
-        value = node.value
-
-        # Special handling for protected float/exponential
-        if type(value) == str:
-            # Convert zero-prefix
-            if value.startswith("0.") and len(value) > 2:
-                value = value[1:]
-
-            # Convert zero postfix
-            elif value.endswith(".0"):
-                value = value[:-2]
-
-        elif int(value) == value and node.parent.type != "dot":
-            value = int(value)
-
-        return "%s" % value
-
-    def type_regexp(self, node):
-        return node.value
-
-    def type_identifier(self, node):
-        return node.value
-
-    def type_list(self, node):
-        return ",".join(map(self.compress, node))
-
-    def type_index(self, node):
-        return "%s[%s]" % (self.compress(node[0]), self.compress(node[1]))
-
-    def type_declaration(self, node):
-        names = getattr(node, "names", None)
-        if names:
-            result = self.compress(names)
-        else:
-            result = node.name
-
-        initializer = getattr(node, "initializer", None)
-        if initializer:
-            result += "=%s" % self.compress(node.initializer)
-
-        return result
-
-    def type_assign(self, node):
-        assignOp = getattr(node, "assignOp", None)
-        operator = "=" if not assignOp else self.__dividers[assignOp] + "="
-
-        return self.compress(node[0]) + operator + self.compress(node[1])
-
-    def type_call(self, node):
-        return "%s(%s)" % (self.compress(node[0]), self.compress(node[1]))
-
-    def type_new_with_args(self, node):
-        result = "new %s" % self.compress(node[0])
-
-        # Compress new Object(); => new Object;
-        if len(node[1]) > 0:
-            result += "(%s)" % self.compress(node[1])
-        else:
-            parent = getattr(node, "parent", None)
-            if parent and parent.type == "dot":
-                result += "()"
-
-        return result
-
-    def type_exception(self, node):
-        return node.value
-
-    def type_generator(self, node):
-        """ Generator Expression """
-        result = self.compress(getattr(node, "expression"))
-        tail = getattr(node, "tail", None)
-        if tail:
-            result += " %s" % self.compress(tail)
-
-        return result
-
-    def type_comp_tail(self, node):
-        """  Comprehensions Tails """
-        result = self.compress(getattr(node, "for"))
-        guard = getattr(node, "guard", None)
-        if guard:
-            result += "if(%s)" % self.compress(guard)
-
-        return result
-
-    def type_in(self, node):
-        first = self.compress(node[0])
-        second = self.compress(node[1])
-
-        if first.endswith("'") or first.endswith('"'):
-            pattern = "%sin %s"
-        else:
-            pattern = "%s in %s"
-
-        return pattern % (first, second)
-
-    def type_instanceof(self, node):
-        first = self.compress(node[0])
-        second = self.compress(node[1])
-
-        return "%s instanceof %s" % (first, second)
-
-
-
-    #
-    # Statements :: Core
-    #
-
-    def type_block(self, node):
-        return "{%s}" % self.__removeSemicolon(self.__statements(node))
-
-    def type_let_block(self, node):
-        begin = "let(%s)" % ",".join(map(self.compress, node.variables))
-        if hasattr(node, "block"):
-            end = self.compress(node.block)
-        elif hasattr(node, "expression"):
-            end = self.compress(node.expression)
-
-        return begin + end
-
-    def type_const(self, node):
-        return self.__addSemicolon("const %s" % self.type_list(node))
-
-    def type_var(self, node):
-        return self.__addSemicolon("var %s" % self.type_list(node))
-
-    def type_let(self, node):
-        return self.__addSemicolon("let %s" % self.type_list(node))
-
-    def type_semicolon(self, node):
-        expression = getattr(node, "expression", None)
-        return self.__addSemicolon(self.compress(expression) if expression else "")
-
-    def type_label(self, node):
-        return self.__addSemicolon("%s:%s" % (node.label, self.compress(node.statement)))
-
-    def type_break(self, node):
-        return self.__addSemicolon("break" if not hasattr(node, "label") else "break %s" % node.label)
-
-    def type_continue(self, node):
-        return self.__addSemicolon("continue" if not hasattr(node, "label") else "continue %s" % node.label)
-
-
-    #
-    # Statements :: Functions
-    #
-
-    def type_function(self, node):
-        if node.type == "setter":
-            result = "set"
-        elif node.type == "getter":
-            result = "get"
-        else:
-            result = "function"
-
-        name = getattr(node, "name", None)
-        if name:
-            result += " %s" % name
-
-        params = getattr(node, "params", None)
-        result += "(%s)" % self.compress(params) if params else "()"
-
-        # keep expression closure format (may be micro-optimized for other code, too)
-        if getattr(node, "expressionClosure", False):
-            result += self.compress(node.body)
-        else:
-            result += "{%s}" % self.__removeSemicolon(self.compress(node.body))
-
-        return result
-
-    def type_getter(self, node):
-        return self.type_function(node)
-
-    def type_setter(self, node):
-        return self.type_function(node)
-
-    def type_return(self, node):
-        result = "return"
-        if hasattr(node, "value"):
-            valueCode = self.compress(node.value)
-
-            # Micro optimization: Don't need a space when a block/map/array/group/strings are returned
-            if not valueCode.startswith(("(","[","{","'",'"',"!","-","/")):
-                result += " "
-
-            result += valueCode
-
-        return self.__addSemicolon(result)
-
-
-
-    #
-    # Statements :: Exception Handling
-    #
-
-    def type_throw(self, node):
-        return self.__addSemicolon("throw %s" % self.compress(node.exception))
-
-    def type_try(self, node):
-        result = "try%s" % self.compress(node.tryBlock)
-
-        for catch in node:
-            if catch.type == "catch":
-                if hasattr(catch, "guard"):
-                    result += "catch(%s if %s)%s" % (self.compress(catch.exception), self.compress(catch.guard), self.compress(catch.block))
-                else:
-                    result += "catch(%s)%s" % (self.compress(catch.exception), self.compress(catch.block))
-
-        if hasattr(node, "finallyBlock"):
-            result += "finally%s" % self.compress(node.finallyBlock)
-
-        return result
-
-
-
-    #
-    # Statements :: Loops
-    #
-
-    def type_while(self, node):
-        result = "while(%s)%s" % (self.compress(node.condition), self.compress(node.body))
-        self.__handleForcedSemicolon(node.body)
-        return result
-
-
-    def type_do(self, node):
-        # block unwrapping don't help to reduce size on this loop type
-        # but if it happens (don't like to modify a global function to fix a local issue), we
-        # need to fix the body and re-add braces around the statement
-        body = self.compress(node.body)
-        if not body.startswith("{"):
-            body = "{%s}" % body
-
-        return self.__addSemicolon("do%swhile(%s)" % (body, self.compress(node.condition)))
-
-
-    def type_for_in(self, node):
-        # Optional variable declarations
-        varDecl = getattr(node, "varDecl", None)
-
-        # Body is optional - at least in comprehensions tails
-        body = getattr(node, "body", None)
-        if body:
-            body = self.compress(body)
-        else:
-            body = ""
-
-        result = "for"
-        if node.isEach:
-            result += " each"
-
-        result += "(%s in %s)%s" % (self.__removeSemicolon(self.compress(node.iterator)), self.compress(node.object), body)
-
-        if body:
-            self.__handleForcedSemicolon(node.body)
-
-        return result
-
-
-    def type_for(self, node):
-        setup = getattr(node, "setup", None)
-        condition = getattr(node, "condition", None)
-        update = getattr(node, "update", None)
-
-        result = "for("
-        result += self.__addSemicolon(self.compress(setup) if setup else "")
-        result += self.__addSemicolon(self.compress(condition) if condition else "")
-        result += self.compress(update) if update else ""
-        result += ")%s" % self.compress(node.body)
-
-        self.__handleForcedSemicolon(node.body)
-        return result
-
-
-
-    #
-    # Statements :: Conditionals
-    #
-
-    def type_hook(self, node):
-        """aka ternary operator"""
-        condition = node.condition
-        thenPart = node.thenPart
-        elsePart = node.elsePart
-
-        if condition.type == "not":
-            [thenPart,elsePart] = [elsePart,thenPart]
-            condition = condition[0]
-
-        return "%s?%s:%s" % (self.compress(condition), self.compress(thenPart), self.compress(elsePart))
-
-
-    def type_if(self, node):
-        result = "if(%s)%s" % (self.compress(node.condition), self.compress(node.thenPart))
-
-        elsePart = getattr(node, "elsePart", None)
-        if elsePart:
-            result += "else"
-
-            elseCode = self.compress(elsePart)
-
-            # Micro optimization: Don't need a space when the child is a block
-            # At this time the brace could not be part of a map declaration (would be a syntax error)
-            if not elseCode.startswith(("{", "(", ";")):
-                result += " "
-
-            result += elseCode
-
-            self.__handleForcedSemicolon(elsePart)
-
-        return result
-
-
-    def type_switch(self, node):
-        result = "switch(%s){" % self.compress(node.discriminant)
-        for case in node:
-            if case.type == "case":
-                labelCode = self.compress(case.label)
-                if labelCode.startswith('"'):
-                    result += "case%s:" % labelCode
-                else:
-                    result += "case %s:" % labelCode
-            elif case.type == "default":
-                result += "default:"
-            else:
-                continue
-
-            for statement in case.statements:
-                temp = self.compress(statement)
-                if len(temp) > 0:
-                    result += self.__addSemicolon(temp)
-
-        return "%s}" % self.__removeSemicolon(result)
-
-
-

eric ide

mercurial