node.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. """
  2. Generic module for wrapping parse targets.
  3. Written April 2004 by David McNab <david@freenet.org.nz>
  4. Copyright (c) 2004 by David McNab, all rights reserved.
  5. Released under the GNU General Public License, a copy of which should appear in
  6. this distribution in the file called 'COPYING'. If this file is missing, then
  7. you can obtain a copy of the GPL license document from the GNU website at
  8. http://www.gnu.org.
  9. This software is released with no warranty whatsoever. Use it at your own
  10. risk.
  11. If you wish to use this software in a commercial application, and wish to
  12. depart from the GPL licensing requirements, please contact the author and apply
  13. for a commercial license.
  14. """
  15. import xml
  16. class BisonNode:
  17. """
  18. Generic class for wrapping parse targets.
  19. Arguments:
  20. - targetname - the name of the parse target being wrapped.
  21. - items - optional - a list of items comprising a clause
  22. in the target rule - typically this will only be used
  23. by the PyBison callback mechanism.
  24. Keywords:
  25. - any keywords you want (except 'items'), with any type of value.
  26. keywords will be stored as attributes in the constructed object.
  27. """
  28. def __init__(self, **kw):
  29. self.__dict__.update(kw)
  30. # ensure some default attribs
  31. self.target = kw.get('target', 'UnnamedTarget')
  32. self.names = kw.get('names', [])
  33. self.values = kw.get('values', [])
  34. self.option = kw.get('option', 0)
  35. # mirror this dict to simplify dumping
  36. self.kw = kw
  37. def __str__(self):
  38. return '<BisonNode:%s>' % self.target
  39. def __repr__(self):
  40. return str(self)
  41. def __getitem__(self, item):
  42. """
  43. Retrieves the ith value from this node, or child nodes
  44. If the subscript is a single number, it will be used as an
  45. index into this node's children list.
  46. If the subscript is a list or tuple, we recursively fetch
  47. the item by using the first element as an index into this
  48. node's children, the second element as an index into that
  49. child node's children, and so on
  50. """
  51. if type(item) in [type(0), type(0L)]:
  52. return self.values[item]
  53. elif type(item) in [type(()), type([])]:
  54. if len(item) == 0:
  55. return self
  56. return self.values[item[0]][item[1:]]
  57. else:
  58. raise TypeError('Can only index %s objects with an int or a'
  59. ' list/tuple' % self.__class.__name__)
  60. def __len__(self):
  61. return len(self.values)
  62. def __getslice__(self, fromidx, toidx):
  63. return self.values[fromidx:toidx]
  64. def __iter__(self):
  65. return iter(self.values)
  66. def dump(self, indent=0):
  67. """
  68. For debugging - prints a recursive dump of a parse tree node and its children
  69. """
  70. specialAttribs = ['option', 'target', 'names', 'values']
  71. indents = ' ' * indent * 2
  72. #print "%s%s: %s %s" % (indents, self.target, self.option, self.names)
  73. print '%s%s:' % (indents, self.target)
  74. for name, val in self.kw.items() + zip(self.names, self.values):
  75. if name in specialAttribs or name.startswith('_'):
  76. continue
  77. if isinstance(val, BisonNode):
  78. val.dump(indent + 1)
  79. else:
  80. print indents + ' %s=%s' % (name, val)
  81. def toxml(self):
  82. """
  83. Returns an xml serialisation of this node and its children, as a raw string
  84. Called on the toplevel node, the xml is a representation of the
  85. entire parse tree.
  86. """
  87. return self.toxmldoc().toxml()
  88. def toprettyxml(self, indent=' ', newl='\n', encoding=None):
  89. """
  90. Returns a human-readable xml serialisation of this node and its
  91. children.
  92. """
  93. return self.toxmldoc().toprettyxml(indent=indent,
  94. newl=newl,
  95. encoding=encoding)
  96. def toxmldoc(self):
  97. """
  98. Returns the node and its children as an xml.dom.minidom.Document
  99. object.
  100. """
  101. d = xml.dom.minidom.Document()
  102. d.appendChild(self.toxmlelem(d))
  103. return d
  104. def toxmlelem(self, docobj):
  105. """
  106. Returns a DOM Element object of this node and its children.
  107. """
  108. specialAttribs = ['option', 'target', 'names', 'values']
  109. # generate an xml element obj for this node
  110. x = docobj.createElement(self.target)
  111. # set attribs
  112. for name, val in self.kw.items():
  113. if name in ['names', 'values'] or name.startswith('_'):
  114. continue
  115. x.setAttribute(name, str(val))
  116. #x.setAttribute('target', self.target)
  117. #x.setAttribute('option', self.option)
  118. # and add the children
  119. for name, val in zip(self.names, self.values):
  120. if name in specialAttribs or name.startswith('_'):
  121. continue
  122. if isinstance(val, BisonNode):
  123. x.appendChild(val.toxmlelem(docobj))
  124. else:
  125. sn = docobj.createElement(name)
  126. sn.setAttribute('target', name)
  127. tn = docobj.createTextNode(val)
  128. sn.appendChild(tn)
  129. x.appendChild(sn)
  130. # done
  131. return x