Beispiel #1
0
def Literal(traverser, node):
    """
    Convert a literal node in the parse tree to its corresponding
    interpreted value.
    """
    value = node["value"]
    if isinstance(value, dict):
        return JSObject(traverser=traverser)
    return JSLiteral(value, traverser=traverser)
Beispiel #2
0
def _define_literal(traverser, node):
    """
    Convert a literal node in the parse tree to its corresponding
    interpreted value.
    """
    value = node['value']
    if isinstance(value, dict):
        return JSWrapper(JSObject(), traverser=traverser, dirty=True)

    wrapper = JSWrapper(value if value is not None else JSLiteral(None),
                        traverser=traverser)
    test_literal(traverser, wrapper)
    return wrapper
Beispiel #3
0
def UnaryExpression(traverser, node):
    operator = node["operator"]
    arg = traverser.traverse_node(node["argument"])
    if (isinstance(arg, JSGlobal) and "literal" in arg.global_data
            and not (operator == "typeof" and "undefined" in arg.global_data)):
        arg = JSLiteral(utils.evaluate_lambdas(traverser,
                                               arg.global_data["literal"]),
                        traverser=traverser)
    if operator in UNARY_OPERATORS:
        traverser._debug("Defined unary operator (%s)" % operator)
        return JSLiteral(UNARY_OPERATORS[node["operator"]](arg, traverser),
                         traverser=traverser)
    elif operator == "void":
        traverser._debug("Void unary operator")
        from predefinedentities import resolve_entity
        return JSGlobal(resolve_entity(traverser, "undefined"),
                        traverser=traverser)
    elif operator == "typeof":
        traverser._debug("Typeof unary operator")
        return JSLiteral(_expr_unary_typeof(arg))
    else:
        traverser._debug("Undefined unary operator")
        return JSObject(traverser=traverser)
Beispiel #4
0
def _call_create_pref(a, t, e):
    """
    Handler for pref() and user_pref() calls in defaults/preferences/*.js files
    to ensure that they don't touch preferences outside of the "extensions."
    branch.
    """

    # We really need to clean up the arguments passed to these functions.
    traverser = t.im_self

    if not traverser.filename.startswith('defaults/preferences/') or not a:
        return

    instanceactions.set_preference(
        JSWrapper(JSLiteral(None), traverser=traverser), a, traverser)

    value = _get_as_str(t(a[0]))
    return test_preference(value)
Beispiel #5
0
         },
         u"log": {
             "return": call_definitions.math_log
         },
         u"max": {
             "return": python_wrap(max, [("num", 0)], nargs=True)
         },
         u"min": {
             "return": python_wrap(min, [("num", 0)], nargs=True)
         },
         u"pow": {
             "return": python_wrap(math.pow, [("num", 0), ("num", 0)])
         },
         # Random always returns 0.5 in our fantasy land.
         u"random": {
             "return": lambda **kw: JSLiteral(0.5)
         },
         u"round": {
             "return": call_definitions.math_round
         },
         u"sin": {
             "return": python_wrap(math.sin, [("num", 0)])
         },
         u"sqrt": {
             "return": python_wrap(math.sqrt, [("num", 1)])
         },
         u"tan": {
             "return": python_wrap(math.tan, [("num", 0)])
         },
     },
 },
              u"acos": {"return": python_wrap(math.acos, [("num", 0)])},
              u"asin": {"return": python_wrap(math.asin, [("num", 0)])},
              u"atan": {"return": python_wrap(math.atan, [("num", 0)])},
              u"atan2": {"return": python_wrap(math.atan2, [("num", 0),
                                                            ("num", 1)])},
              u"ceil": {"return": python_wrap(math.ceil, [("num", 0)])},
              u"cos": {"return": python_wrap(math.cos, [("num", 0)])},
              u"exp": {"return": python_wrap(math.exp, [("num", 0)])},
              u"floor": {"return": python_wrap(math.floor, [("num", 0)])},
              u"log": {"return": call_definitions.math_log},
              u"max": {"return": python_wrap(max, [("num", 0)], nargs=True)},
              u"min": {"return": python_wrap(min, [("num", 0)], nargs=True)},
              u"pow": {"return": python_wrap(math.pow, [("num", 0),
                                                        ("num", 0)])},
              # Random always returns 0.5 in our fantasy land.
              u"random": {"return": lambda **kw: JSLiteral(0.5)},
              u"round": {"return": call_definitions.math_round},
              u"sin": {"return": python_wrap(math.sin, [("num", 0)])},
              u"sqrt": {"return": python_wrap(math.sqrt, [("num", 1)])},
              u"tan": {"return": python_wrap(math.tan, [("num", 0)])},
            },
        },

    u"XMLHttpRequest": entity('XMLHttpRequest'),

    # Global properties are inherently read-only, though this formalizes it.
    u"Infinity": get_global("Number", "POSITIVE_INFINITY"),
    u"NaN": READONLY,
    u"undefined": {"readonly": True, "undefined": True, "literal": None},

    u"opener": global_identity,
Beispiel #7
0
def AssignmentExpression(traverser, node):
    traverser._debug("ASSIGNMENT_EXPRESSION")
    traverser.debug_level += 1

    traverser._debug("ASSIGNMENT>>PARSING RIGHT")
    right = traverser.traverse_node(node["right"])

    traverser._debug("ASSIGNMENT>>PARSING LEFT")
    orig_left = left = traverser.traverse_node(node["left"])

    operator = node["operator"]

    def set_lvalue(value):
        node_left = node["left"]
        traverser._debug("ASSIGNING:DIRECT(%s)" % node_left["type"])

        global_overwrite = False
        readonly_value = True
        if node_left["type"] == "Identifier":
            # Identifiers just need the ID name and a value to push.
            # Raise a global overwrite issue if the identifier is global.
            global_overwrite = traverser._is_global(node_left["name"])

            # Get the readonly attribute and store its value if is_global
            if global_overwrite:
                from predefinedentities import GLOBAL_ENTITIES
                global_dict = GLOBAL_ENTITIES[node_left["name"]]
                readonly_value = global_dict.get("readonly", False)

            traverser._declare_variable(node_left["name"], value, type_="glob")

        elif node_left["type"] == "MemberExpression":
            member_object = MemberExpression(traverser,
                                             node_left["object"],
                                             instantiate=True)
            member_property = _get_member_exp_property(traverser, node_left)
            traverser._debug("ASSIGNMENT:MEMBER_PROPERTY(%s)" %
                             member_property)

            if member_object is None:
                member_object = JSObject()

            member_object.set(member_property, value, traverser)

    # Treat direct assignment different than augmented assignment.
    if operator == "=":
        set_lvalue(right)
        return right

    elif operator not in ASSIGNMENT_OPERATORS:
        # We don't support that operator. (yet?)
        traverser._debug("ASSIGNMENT>>OPERATOR NOT FOUND", 1)
        return left

    if left.const:
        traverser.err.warning(
            err_id=("js", "AssignmentExpression", "aug_const_overwrite"),
            warning="Overwritten constant value",
            description="A variable declared as constant has been "
            "overwritten in some JS code by an augmented "
            "assignment.",
            filename=traverser.filename,
            line=traverser.line,
            column=traverser.position,
            context=traverser.context)
        return JSObject(traverser=traverser)

    traverser._debug("ASSIGNMENT>>DONE PARSING LEFT")
    traverser.debug_level -= 1

    # If we're modifying a non-numeric type with a numeric operator, return
    # NaN.
    if (operator in NUMERIC_OPERATORS and not isinstance(
            left.get_literal_value(traverser) or 0, NUMERIC_TYPES)):
        set_lvalue(utils.get_NaN(traverser))
        return left

    gleft, gright = utils.get_as_num(left), utils.get_as_num(right)

    traverser._debug("ASSIGNMENT>>OPERATION:%s" % operator)
    if operator in ("<<=", ">>=", ">>>=") and gright < 0:
        # The user is doing weird bitshifting that will return 0 in JS but
        # not in Python.
        set_lvalue(JSLiteral(0, traverser=traverser))
        return left
    elif (operator in ("<<=", ">>=", ">>>=", "|=", "^=", "&=")
          and (abs(gleft) == float('inf') or abs(gright) == float('inf'))):
        # Don't bother handling infinity for integer-converted operations.
        set_lvalue(utils.get_NaN(traverser))
        return left

    if operator == '+=':
        lit_left = left.get_literal_value(traverser)
        lit_right = right.get_literal_value(traverser)
        # Don't perform an operation on None. Python freaks out.
        if lit_left is None:
            lit_left = 0
        if lit_right is None:
            lit_right = 0

        # If either side of the assignment operator is a string, both sides
        # need to be cast to strings first.
        if (isinstance(lit_left, types.StringTypes)
                or isinstance(lit_right, types.StringTypes)):
            left = utils.get_as_str(lit_left)
            right = utils.get_as_str(lit_right)
        else:
            left, right = lit_left, lit_right

    output = ASSIGNMENT_OPERATORS[operator](left, right, gleft, gright)

    # Cap the length of analyzed strings.
    if isinstance(output, types.StringTypes) and len(output) > MAX_STR_SIZE:
        output = output[:MAX_STR_SIZE]

    traverser._debug("ASSIGNMENT::New value >> %s" % output, 1)
    set_lvalue(JSLiteral(output, traverser=traverser))
    return orig_left
Beispiel #8
0
def BinaryExpression(traverser, node):
    traverser.debug_level += 1

    # Select the proper operator.
    operator = node["operator"]
    traverser._debug("BIN_OPERATOR>>%s" % operator)

    # Traverse the left half of the binary expression.
    traverser._debug("BIN_EXP>>l-value")
    traverser.debug_level += 1

    if (node["left"]["type"] == "BinaryExpression"
            and "__traversal" not in node["left"]):
        # Process the left branch of the binary expression directly. This keeps
        # the recursion cap in line and speeds up processing of large chains
        # of binary expressions.
        left = BinaryExpression(traverser, node["left"])
        node["left"]["__traversal"] = left
    else:
        left = traverser.traverse_node(node["left"])

    # Traverse the right half of the binary expression.
    traverser._debug("BIN_EXP>>r-value", -1)

    if (operator == "instanceof" and node["right"]["type"] == "Identifier"
            and node["right"]["name"] == "Function"):
        # We make an exception for instanceof's r-value if it's a dangerous
        # global, specifically Function.
        traverser.debug_level -= 1
        return JSLiteral(True, traverser=traverser)
    else:
        right = traverser.traverse_node(node["right"])

    traverser.debug_level -= 1

    # Binary expressions are only executed on literals.
    left = left.get_literal_value(traverser)
    right_wrap = right
    right = right.get_literal_value(traverser)

    # Coerce the literals to numbers for numeric operations.
    gleft = utils.get_as_num(left)
    gright = utils.get_as_num(right)

    if operator in (">>", "<<", ">>>"):
        if left is None or right is None or gright < 0:
            return JSLiteral(False, traverser=traverser)
        elif abs(gleft) == float('inf') or abs(gright) == float('inf'):
            return utils.get_NaN(traverser)

    output = None
    if operator in BINARY_OPERATORS:
        # Concatenation can be silly, so always turn undefineds into empty
        # strings and if there are strings, make everything strings.
        if operator == "+":
            if left is None:
                left = ""
            if right is None:
                right = ""
            if (isinstance(left, types.StringTypes)
                    or isinstance(right, types.StringTypes)):
                left = utils.get_as_str(left)
                right = utils.get_as_str(right)

        output = BINARY_OPERATORS[operator](left, right, gleft, gright)
    elif operator == "in":
        return JSLiteral(right_wrap.has_var(left, traverser=traverser),
                         traverser=traverser)
    #TODO: `delete` operator

    # Cap the length of analyzed strings.
    if isinstance(output, types.StringTypes) and len(output) > MAX_STR_SIZE:
        output = output[:MAX_STR_SIZE]

    return JSLiteral(output, traverser=traverser)