Sat, 14 Dec 2013 23:44:25 +0100

T.Rzepka <>
Sat, 14 Dec 2013 23:44:25 +0100
Py2 comp.
changeset 3145
parent 2847
child 5843

# __IGNORE_WARNING__ added/ removed.

# Jasy - Web Tooling Framework
# Copyright 2010-2012 Zynga Inc.

# License: MPL 1.1/GPL 2.0/LGPL 2.1
# Authors: 
#   - Brendan Eich <> (Original JavaScript) (2004)
#   - Sebastian Werner <> (Refactoring Python) (2010)

from __future__ import unicode_literals

import copy

class Node(list):
    __slots__ = [
        # core data
        "line", "type", "tokenizer", "start", "end", "rel", "parent", 
        # dynamic added data by other modules
        "comments", "scope", 
        # node type specific
        "value", "expression", "body", "functionForm", "parenthesized", "fileId",
        "params", "name", "readOnly", "initializer", "condition", "isLoop", "isEach",
        "object", "assignOp", "iterator", "thenPart", "exception", "elsePart", "setup",
        "postfix", "update", "tryBlock", "block", "defaultIndex", "discriminant", "label",
        "statements", "finallyBlock", "statement", "variables", "names", "guard", "for",
        "tail", "expressionClosure"
    def __init__(self, tokenizer=None, type=None, args=[]):
        self.start = 0
        self.end = 0
        self.line = None
        if tokenizer:
            token = getattr(tokenizer, "token", None)
            if token:
                # We may define a custom type but use the same positioning as another
                # token, e.g. transform curlys in block nodes, etc.
                self.type = type if type else getattr(token, "type", None)
                self.line = token.line
                # Start & end are file positions for error handling.
                self.start = token.start
                self.end = token.end
                self.type = type
                self.line = tokenizer.line
                self.start = None
                self.end = None

            self.tokenizer = tokenizer
        elif type:
            self.type = type

        for arg in args:
    def getUnrelatedChildren(self):
        """Collects all unrelated children"""
        collection = []
        for child in self:
            if not hasattr(child, "rel"):
        return collection
    def getChildrenLength(self, filter=True):
        """Number of (per default unrelated) children"""
        count = 0
        for child in self:
            if not filter or not hasattr(child, "rel"):
                count += 1
        return count
    def remove(self, kid):
        """Removes the given kid"""
        if not kid in self:
            raise Exception("Given node is no child!")
        if hasattr(kid, "rel"):
            delattr(self, kid.rel)
            del kid.rel
            del kid.parent
        list.remove(self, kid)
    def insert(self, index, kid):
        """Inserts the given kid at the given index"""
        if index is None:
            return self.append(kid)
        if hasattr(kid, "parent"):
        kid.parent = self

        return list.insert(self, index, kid)
    def append(self, kid, rel=None):
        """Appends the given kid with an optional relation hint"""
        # kid can be null e.g. [1, , 2].
        if kid:
            if hasattr(kid, "parent"):
            # Debug
            if not isinstance(kid, Node):
                raise Exception("Invalid kid: %s" % kid)
            if hasattr(kid, "tokenizer"):
                if hasattr(kid, "start"):
                    if not hasattr(self, "start") or \
                       self.start == None or \
                       kid.start < self.start:
                        self.start = kid.start

                if hasattr(kid, "end"):
                    if not hasattr(self, "end") or \
                       self.end == None or \
                       self.end < kid.end:
                        self.end = kid.end
            kid.parent = self
            # alias for function
            if rel != None:
                setattr(self, rel, kid)
                setattr(kid, "rel", rel)

        # Block None kids when they should be related
        if not kid and rel:
        return list.append(self, kid)
    def replace(self, kid, repl):
        """Replaces the given kid with a replacement kid"""
        if repl in self:
        self[self.index(kid)] = repl
        if hasattr(kid, "rel"):
            repl.rel = kid.rel
            setattr(self, kid.rel, repl)
            # cleanup old kid
            delattr(kid, "rel")
        elif hasattr(repl, "rel"):
            # delete old relation on new child
            delattr(repl, "rel")

        delattr(kid, "parent")
        repl.parent = self
        return kid
    def __deepcopy__(self, memo):
        """Used by deepcopy function to clone Node instances"""
        # Create copy
        if hasattr(self, "tokenizer"):
            result = Node(tokenizer=self.tokenizer)
            result = Node(type=self.type)
        # Copy children
        for child in self:
            if child is None:
                list.append(result, None)
                # Using simple list appends for better performance
                childCopy = copy.deepcopy(child, memo)
                childCopy.parent = result
                list.append(result, childCopy)
        # Sync attributes
        # Note: "parent" attribute is handled by append() already
        for name in self.__slots__:
            if hasattr(self, name) and not name in ("parent", "tokenizer"):
                value = getattr(self, name)
                if value is None:
                elif type(value) in (bool, int, float, str):
                    setattr(result, name, value)
                elif type(value) in (list, set, dict, Node):
                    setattr(result, name, copy.deepcopy(value, memo))
                # Scope can be assigned (will be re-created when needed for the
                # copied node)
                elif name == "scope":
                    result.scope = self.scope

        return result
    def __eq__(self, other):
        return self is other

    def __bool__(self): 
        return True

eric ide