text: """A set of objects that can create logical expressions via
  combining logical operators and Smarts Primitives.
  """
  class NotMatch:
      def __init__(self, child):
          self.child = child
      def __eq__(self, obj):
          return not self.child == obj
      def __str__(self):
          return "not (%s)" % (self.child,)
  
  class AndMatch:
      def __init__(self, left, right):
          self.left = left
          self.right = right
      def __eq__(self, obj):
          return self.left == obj and self.right == obj
      def __str__(self):
          return "AND(%s, %s)" % (self.left, self.right)
      
  class OrMatch:
      def __init__(self, left, right):
          self.left = left
          self.right = right
      def __eq__(self, obj):
          return (self.left == obj) or (self.right == obj)
      def __str__(self):
          return "OR(%s, %s)" % (self.left, self.right)
  
  bool_unary_not = 76
  bool_strong_and = 77
  bool_or = 78
  bool_weak_and = 79
  binary_operators = [bool_strong_and, bool_or, bool_weak_and]
  boolean_operators = binary_operators + [bool_unary_not]
  text_to_bool = {
      "&": bool_strong_and,
      ",": bool_or,
      ";": bool_weak_and,
      "!": bool_unary_not,
      }
  
  class ExpressionList:
      def __init__(self):
          self.matchers = []
          
      def __nonzero__(self):
          return len(self.matchers) != 0
      
      def add_matcher(self, obj):
          # see if the matcher is not in the boolean list
          if self.matchers:
              target = self.matchers[-1]
              for _matcher in boolean_operators:
                  if target is _matcher:
                      break
              else:
                  self.matchers.append(bool_strong_and)
          #if self.matchers and self.matchers[-1] not in boolean_operators:
          #    self.matchers.append(bool_strong_and)
          self.matchers.append(obj)
          
      def add_operator(self, op):
          assert op in binary_operators or op == bool_unary_not
          if __debug__:
              if self.matchers:
                  if op in binary_operators:
                      s = self.matchers[-1]
                      for _matcher in binary_operators:
                          assert s is not _matcher
              else:
                  for _matcher in binary_operators:
                      assert op is not _matcher
  
          self.matchers.append(op)
  
      def make_matcher(self):
          matchers = self.matchers[:]
          i = 0
          while i < len(matchers):
              if matchers[i] is bool_unary_not:
                  matchers[i:i+2] = [NotMatch(matchers[i+1])]
              else:
                  i = i + 1
          i = 1
          while i < len(matchers):
              if matchers[i] is bool_strong_and:
                  matchers[i-1:i+2] = [AndMatch(matchers[i-1], matchers[i+1])]
              else:
                  i = i + 1
          i = 1
          while i < len(matchers):
              if matchers[i] is bool_or:
                  matchers[i-1:i+2] = [OrMatch(matchers[i-1], matchers[i+1])]
              else:
                  i = i + 1
          i = 1
          while i < len(matchers):
              if matchers[i] is bool_weak_and:
                  matchers[i-1:i+2] = [AndMatch(matchers[i-1], matchers[i+1])]
              else:
                  i = i + 1
          assert len(matchers) == 1, matchers
          return matchers[0]
  
  class AtomExpression(ExpressionList):
      pass
  
  class BondExpression(ExpressionList):
      pass
          
  
  