Tue, 09 Jul 2013 19:30:56 +0200
Added a JavaScript parser to the file browser in order to show the structure of JavaScript files
# # Jasy - Web Tooling Framework # Copyright 2010-2012 Zynga Inc. # # # License: MPL 1.1/GPL 2.0/LGPL 2.1 # Authors: # - Brendan Eich <brendan@mozilla.org> (Original JavaScript) (2004) # - Sebastian Werner <info@sebastian-werner.net> (Refactoring Python) (2010) # 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=[]): list.__init__(self) 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 else: 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: self.append(arg) def getUnrelatedChildren(self): """Collects all unrelated children""" collection = [] for child in self: if not hasattr(child, "rel"): collection.append(child) 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.remove(kid) 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"): kid.parent.remove(kid) # 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 return list.append(self, kid) def replace(self, kid, repl): """Replaces the given kid with a replacement kid""" if repl in self: self.remove(repl) 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) else: result = Node(type=self.type) # Copy children for child in self: if child is None: list.append(result, None) else: # 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: pass 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