docs: public boolean match() {
          if (m_expr1 == null || m_expr2 == null) {
              return m_expr1 == m_expr2;
          } else if (m_expr1.getExpressionType() != m_expr2.getExpressionType()) {
              // Exception to the rule:
              // 1. CVE and PVE need to be translated before compared.
              // 2. Comparisons could be reversed, e.g. "a >= b" and "b <= a" are the same relation
              return valueConstantsMatch(m_expr1, m_expr2) || revComparisonsMatch(m_expr1, m_expr2);
          } else if (m_expr1 instanceof ConstantValueExpression) {
              return m_expr1.equals(m_expr2);
          } else if (m_expr1 instanceof TupleValueExpression) {
              return tvesMatch((TupleValueExpression) m_expr1, (TupleValueExpression) m_expr2);
          } else if (m_expr1 instanceof VectorValueExpression) {      // VVE does not have left/right.
              return vectorsMatch((VectorValueExpression) m_expr1, (VectorValueExpression) m_expr2);
          } else if(EXCHANGEABLE_EXPRESSIONS.contains(m_expr1.getExpressionType())) {
              return (argsMatch(m_expr1, m_expr2) && childrenMatch(m_expr1, m_expr2)) ||
                      (new FilterMatcher(m_expr1.getLeft(), m_expr2.getRight()).match() &&
                              new FilterMatcher(m_expr1.getRight(), m_expr2.getLeft()).match());
          } else {
              return argsMatch(m_expr1, m_expr2) && childrenMatch(m_expr1, m_expr2);
          }
      }