possibilities.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from node import TYPE_OPERATOR
  2. # Each rule will append its hint message to the following dictionary. The
  3. # function pointer to the apply function of the rule is used as key. The
  4. # corresponding value is a string, which will be used to produce the hint
  5. # message. The string will be processed using string.format().
  6. MESSAGES = {}
  7. class Possibility(object):
  8. def __init__(self, root, handler, args=()):
  9. self.root = root
  10. self.handler = handler
  11. self.args = args
  12. def __str__(self):
  13. if self.handler in MESSAGES:
  14. return MESSAGES[self.handler].format(self.root, *self.args)
  15. return repr(self)
  16. def __repr__(self):
  17. return '<Possibility root="%s" handler=%s args=%s>' \
  18. % (self.root, self.handler.func_name, self.args)
  19. def __eq__(self, other):
  20. return self.handler == other.handler \
  21. and hash(self.root) == hash(other.root) \
  22. and self.args == other.args
  23. def filter_duplicates(possibilities):
  24. """
  25. Filter duplicated possibilities. Duplicated possibilities occur in n-ary
  26. nodes, the root-level node and a lower-level node will both recognize a
  27. rewrite possibility within their scope, whereas only the root-level one
  28. matters.
  29. Example: 1 + 2 + 3
  30. The addition of 1 and 2 is recognized by n-ary additions "1 + 2" and
  31. "1 + 2 + 3". The "1 + 2" addition should be removed by this function.
  32. """
  33. features = []
  34. unique = []
  35. for p in reversed(possibilities):
  36. feature = (p.handler, p.args)
  37. if feature not in features:
  38. features.append(feature)
  39. unique.insert(0, p)
  40. return unique
  41. def find_parent_node(root, child):
  42. nodes = [root]
  43. while nodes:
  44. node = nodes.pop()
  45. while node:
  46. if node.type != TYPE_OPERATOR:
  47. break
  48. if child in node:
  49. return node
  50. if len(node) > 1:
  51. nodes.append(node[1])
  52. node = node[0]
  53. def apply_suggestion(root, suggestion):
  54. # TODO: clone the root node before modifying. After deep copying the root
  55. # node, the subtree_map cannot be used since the hash() of each node in the
  56. # deep copied root node has changed.
  57. #root_clone = root.clone()
  58. subtree = suggestion.handler(suggestion.root, suggestion.args)
  59. parent_node = find_parent_node(root, suggestion.root)
  60. # There is either a parent node or the subtree is the root node.
  61. # FIXME: FAIL: test_diagnostic_test_application in tests/test_b1_ch08.py
  62. #try:
  63. # assert bool(parent_node) != (subtree == root)
  64. #except:
  65. # print 'parent_node: %s' % (str(parent_node))
  66. # print 'subtree: %s == %s' % (str(subtree), str(root))
  67. # raise
  68. if parent_node:
  69. parent_node.substitute(suggestion.root, subtree)
  70. return root
  71. return subtree