"Fossies" - the Fresh Open Source Software Archive

Member "eric6-20.8/eric/eric6/ThirdParty/Jasy/jasy/parse/AbstractNode.py" (3 Oct 2019, 11471 Bytes) of package /linux/misc/eric6-20.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 #
    2 # Jasy - Web Tooling Framework
    3 # Copyright 2013-2014 Sebastian Werner
    4 #
    5 
    6 import json, copy
    7 
    8 class AbstractNode(list):
    9 
   10     __slots__ = [
   11         # core data
   12         "line", "type", "tokenizer", "start", "end", "rel", "parent",
   13 
   14         # dynamic added data by other modules
   15         "comments", "scope", "values",
   16 
   17         # node type specific
   18         "value", "parenthesized", "fileId", "params",
   19         "name", "initializer", "condition", "assignOp",
   20         "thenPart", "elsePart", "statements",
   21         "statement", "variables", "names", "postfix"
   22     ]
   23 
   24 
   25     def __init__(self, tokenizer=None, type=None, args=[]):
   26         list.__init__(self)
   27 
   28         self.start = 0
   29         self.end = 0
   30         self.line = None
   31 
   32         if tokenizer:
   33             token = getattr(tokenizer, "token", None)
   34             if token:
   35                 # We may define a custom type but use the same positioning as another token
   36                 # e.g. transform curlys in block nodes, etc.
   37                 self.type = type if type else getattr(token, "type", None)
   38                 self.line = token.line
   39 
   40                 # Start & end are file positions for error handling.
   41                 self.start = token.start
   42                 self.end = token.end
   43 
   44             else:
   45                 self.type = type
   46                 self.line = tokenizer.line
   47                 self.start = None
   48                 self.end = None
   49 
   50             self.tokenizer = tokenizer
   51 
   52         elif type:
   53             self.type = type
   54 
   55         for arg in args:
   56             self.append(arg)
   57 
   58 
   59     def getFileName(self):
   60         """
   61         Traverses up the tree to find a node with a fileId and returns it
   62         """
   63 
   64         node = self
   65         while node:
   66             fileId = getattr(node, "fileId", None)
   67             if fileId is not None:
   68                 return fileId
   69 
   70             node = getattr(node, "parent", None)
   71 
   72 
   73     def getUnrelatedChildren(self):
   74         """Collects all unrelated children"""
   75 
   76         collection = []
   77         for child in self:
   78             if not hasattr(child, "rel"):
   79                 collection.append(child)
   80 
   81         return collection
   82 
   83 
   84     def getChildrenLength(self, filter=True):
   85         """Number of (per default unrelated) children"""
   86 
   87         count = 0
   88         for child in self:
   89             if not filter or not hasattr(child, "rel"):
   90                 count += 1
   91         return count
   92 
   93 
   94     def remove(self, kid):
   95         """Removes the given kid"""
   96 
   97         if not kid in self:
   98             raise Exception("Given node is no child!")
   99 
  100         if hasattr(kid, "rel"):
  101             delattr(self, kid.rel)
  102             del kid.rel
  103             del kid.parent
  104 
  105         list.remove(self, kid)
  106 
  107 
  108     def insert(self, index, kid):
  109         """Inserts the given kid at the given index"""
  110 
  111         if index is None:
  112             return self.append(kid)
  113 
  114         if hasattr(kid, "parent"):
  115             kid.parent.remove(kid)
  116 
  117         kid.parent = self
  118 
  119         return list.insert(self, index, kid)
  120 
  121 
  122     def insertAll(self, index, kids):
  123         """Inserts all kids starting with the given index"""
  124 
  125         if index is None:
  126             for kid in list(kids):
  127                 self.append(kid)
  128         else:
  129             for pos, kid in enumerate(list(kids)):
  130                 self.insert(index+pos, kid)
  131 
  132 
  133     def insertAllReplace(self, orig, kids):
  134         """Inserts all kids at the same position as the original node (which is removed afterwards)"""
  135 
  136         index = self.index(orig)
  137         for pos, kid in enumerate(list(kids)):
  138             self.insert(index+pos, kid)
  139 
  140         self.remove(orig)
  141 
  142 
  143     def append(self, kid, rel=None):
  144         """Appends the given kid with an optional relation hint"""
  145 
  146         # kid can be null e.g. [1, , 2].
  147         if kid:
  148             if hasattr(kid, "parent"):
  149                 kid.parent.remove(kid)
  150 
  151             # Debug
  152             if not isinstance(kid, AbstractNode):
  153                 raise Exception("Invalid kid: %s" % kid)
  154 
  155             if hasattr(kid, "tokenizer"):
  156                 if hasattr(kid, "start"):
  157                     if not hasattr(self, "start") or self.start == None or kid.start < self.start:
  158                         self.start = kid.start
  159 
  160                 if hasattr(kid, "end"):
  161                     if not hasattr(self, "end") or self.end == None or self.end < kid.end:
  162                         self.end = kid.end
  163 
  164             kid.parent = self
  165 
  166             # alias for function
  167             if rel != None:
  168                 setattr(self, rel, kid)
  169                 setattr(kid, "rel", rel)
  170 
  171         # Block None kids when they should be related
  172         if not kid and rel:
  173             return
  174 
  175         return list.append(self, kid)
  176 
  177 
  178     def replace(self, kid, repl):
  179         """Replaces the given kid with a replacement kid"""
  180 
  181         if repl in self:
  182             self.remove(repl)
  183 
  184         self[self.index(kid)] = repl
  185 
  186         if hasattr(kid, "rel"):
  187             repl.rel = kid.rel
  188             setattr(self, kid.rel, repl)
  189 
  190             # cleanup old kid
  191             delattr(kid, "rel")
  192 
  193         elif hasattr(repl, "rel"):
  194             # delete old relation on new child
  195             delattr(repl, "rel")
  196 
  197         delattr(kid, "parent")
  198         repl.parent = self
  199 
  200         return kid
  201 
  202 
  203     def toXml(self, format=True, indent=0, tab="  "):
  204         """Converts the node to XML"""
  205 
  206         lead = tab * indent if format else ""
  207         innerLead = tab * (indent+1) if format else ""
  208         lineBreak = "\n" if format else ""
  209 
  210         relatedChildren = []
  211         attrsCollection = []
  212 
  213         for name in self.__slots__:
  214             # "type" is used as node name - no need to repeat it as an attribute
  215             # "parent" is a relation to the parent node - for serialization we ignore these at the moment
  216             # "rel" is used internally to keep the relation to the parent - used by nodes which need to keep track of specific children
  217             # "start" and "end" are for debugging only
  218             if hasattr(self, name) and name not in ("type", "parent", "comments", "selector", "rel", "start", "end") and name[0] != "_":
  219                 value = getattr(self, name)
  220                 if isinstance(value, AbstractNode):
  221                     if hasattr(value, "rel"):
  222                         relatedChildren.append(value)
  223 
  224                 elif type(value) in (bool, int, float, str, list, set, dict):
  225                     if type(value) == bool:
  226                         value = "true" if value else "false"
  227                     elif type(value) in (int, float):
  228                         value = str(value)
  229                     elif type(value) in (list, set, dict):
  230                         if type(value) == dict:
  231                             value = value.keys()
  232                         if len(value) == 0:
  233                             continue
  234                         try:
  235                             value = ",".join(value)
  236                         except TypeError as ex:
  237                             raise Exception("Invalid attribute list child at: %s: %s" % (name, ex))
  238 
  239                     attrsCollection.append('%s=%s' % (name, json.dumps(value)))
  240 
  241         attrs = (" " + " ".join(attrsCollection)) if len(attrsCollection) > 0 else ""
  242 
  243         comments = getattr(self, "comments", None)
  244         scope = getattr(self, "scope", None)
  245         selector = getattr(self, "selector", None)
  246 
  247         if len(self) == 0 and len(relatedChildren) == 0 and (not comments or len(comments) == 0) and not scope and not selector:
  248             result = "%s<%s%s/>%s" % (lead, self.type, attrs, lineBreak)
  249 
  250         else:
  251             result = "%s<%s%s>%s" % (lead, self.type, attrs, lineBreak)
  252 
  253             if comments:
  254                 for comment in comments:
  255                     result += '%s<comment context="%s" variant="%s">%s</comment>%s' % (innerLead, comment.context, comment.variant, comment.text, lineBreak)
  256 
  257             if scope:
  258                 for statKey in scope:
  259                     statValue = scope[statKey]
  260                     if statValue != None and len(statValue) > 0:
  261                         if type(statValue) is set:
  262                             statValue = ",".join(statValue)
  263                         elif type(statValue) is dict:
  264                             statValue = ",".join(statValue.keys())
  265 
  266                         result += '%s<stat name="%s">%s</stat>%s' % (innerLead, statKey, statValue, lineBreak)
  267 
  268             if selector:
  269                 for entry in selector:
  270                     result += '%s<selector>%s</selector>%s' % (innerLead, entry, lineBreak)
  271 
  272             for child in self:
  273                 if not child:
  274                     result += "%s<none/>%s" % (innerLead, lineBreak)
  275                 elif not hasattr(child, "rel"):
  276                     result += child.toXml(format, indent+1)
  277                 elif not child in relatedChildren:
  278                     raise Exception("Oops, irritated by non related: %s in %s - child says it is related as %s" % (child.type, self.type, child.rel))
  279 
  280             for child in relatedChildren:
  281                 result += "%s<%s>%s" % (innerLead, child.rel, lineBreak)
  282                 result += child.toXml(format, indent+2)
  283                 result += "%s</%s>%s" % (innerLead, child.rel, lineBreak)
  284 
  285             result += "%s</%s>%s" % (lead, self.type, lineBreak)
  286 
  287         return result
  288 
  289 
  290     def __deepcopy__(self, memo):
  291         """Used by deepcopy function to clone AbstractNode instances"""
  292 
  293         CurrentClass = self.__class__
  294 
  295         # Create copy
  296         if hasattr(self, "tokenizer"):
  297             result = CurrentClass(tokenizer=self.tokenizer)
  298         else:
  299             result = CurrentClass(type=self.type)
  300 
  301         # Copy children
  302         for child in self:
  303             if child is None:
  304                 list.append(result, None)
  305             else:
  306                 # Using simple list appends for better performance
  307                 childCopy = copy.deepcopy(child, memo)
  308                 childCopy.parent = result
  309                 list.append(result, childCopy)
  310 
  311         # Sync attributes
  312         # Note: "parent" attribute is handled by append() already
  313         for name in self.__slots__:
  314             if hasattr(self, name) and not name in ("parent", "tokenizer"):
  315                 value = getattr(self, name)
  316                 if value is None:
  317                     pass
  318                 elif type(value) in (bool, int, float, str):
  319                     setattr(result, name, value)
  320                 elif type(value) in (list, set, dict, CurrentClass):
  321                     setattr(result, name, copy.deepcopy(value, memo))
  322                 # Scope can be assigned (will be re-created when needed for the copied node)
  323                 elif name == "scope":
  324                     result.scope = self.scope
  325 
  326         return result
  327 
  328 
  329     def getSource(self):
  330         """Returns the source code of the node"""
  331 
  332         if not self.tokenizer:
  333             raise Exception("Could not find source for node '%s'" % self.type)
  334 
  335         if getattr(self, "start", None) is not None:
  336             if getattr(self, "end", None) is not None:
  337                 return self.tokenizer.source[self.start:self.end]
  338             return self.tokenizer.source[self.start:]
  339 
  340         if getattr(self, "end", None) is not None:
  341             return self.tokenizer.source[:self.end]
  342 
  343         return self.tokenizer.source[:]
  344 
  345 
  346     # Map Python built-ins
  347     __repr__ = toXml
  348     __str__ = toXml
  349 
  350 
  351     def __eq__(self, other):
  352         return self is other
  353 
  354     def __bool__(self):
  355         return True