docs: def p_expression_boolop(self, p):
          """
          expression : expression GT expression
                    | expression LT expression
                    | expression GE expression
                    | expression LE expression
                    | expression EQ expression
                    | expression NE expression
                    | expression AND expression
                    | expression OR expression
          """
          _LOGGER.debug("expresion -> expresion %s expression" % p[2])
          if self._autodefine_vars:
              self._init_vars(p[1], p[3])
  
          if p[1].type != p[3].type: raise TypeError()
  
          if p[1].type == TypedClass.LIST:
              raise TypeError("operator not defined for lists")
          if p[1].type == TypedClass.STRING:
              if p[2] == '==':
                  p[0] = TypedClass(p[1].value == p[3].value, TypedClass.BOOLEAN)
              elif p[2] == '!=':
                  p[0] = TypedClass(p[1].value != p[3].value, TypedClass.BOOLEAN)
              else:
                  raise TypeError("operator not defined for strings")
  
          if p[2] == '>':
              p[0] = TypedClass(p[1].value > p[3].value, TypedClass.BOOLEAN)
          elif p[2] == '<':
              p[0] = TypedClass(p[1].value < p[3].value, TypedClass.BOOLEAN)
          elif p[2] == '>=':
              p[0] = TypedClass(p[1].value >= p[3].value, TypedClass.BOOLEAN)
          elif p[2] == '<=':
              p[0] = TypedClass(p[1].value <= p[3].value, TypedClass.BOOLEAN)
          elif p[2] == '==':
              p[0] = TypedClass(p[1].value == p[3].value, TypedClass.BOOLEAN)
          elif p[2] == '!=':
              p[0] = TypedClass(p[1].value != p[3].value, TypedClass.BOOLEAN)
          elif p[2] == '&&':
              p[0] = TypedClass(p[1].value and p[3].value, TypedClass.BOOLEAN)
          elif p[2] == '||':
              p[0] = TypedClass(p[1].value or p[3].value, TypedClass.BOOLEAN)