docs: public static AbstractExpression evaluateExpression(AbstractExpression expr) {
          if (expr == null) {
              return null;
          }
  
          // Evaluate children first
          expr.setLeft(evaluateExpression(expr.getLeft()));
          expr.setRight(evaluateExpression(expr.getRight()));
  
          // Evaluate self
          if (ExpressionType.CONJUNCTION_AND == expr.getExpressionType()) {
              if (ExpressionType.VALUE_CONSTANT == expr.getLeft().getExpressionType()) {
                  if (ConstantValueExpression.isBooleanTrue(expr.getLeft())) {
                      return expr.getRight();
                  } else {
                      return expr.getLeft();
                  }
              }
              if (ExpressionType.VALUE_CONSTANT == expr.getRight().getExpressionType()) {
                  if (ConstantValueExpression.isBooleanTrue(expr.getRight())) {
                      return expr.getLeft();
                  } else {
                      return expr.getRight();
                  }
              }
          } else if (ExpressionType.CONJUNCTION_OR == expr.getExpressionType()) {
              if (ExpressionType.VALUE_CONSTANT == expr.getLeft().getExpressionType()) {
                  if (ConstantValueExpression.isBooleanTrue(expr.getLeft())) {
                      return expr.getLeft();
                  } else {
                      return expr.getRight();
                  }
              }
              if (ExpressionType.VALUE_CONSTANT == expr.getRight().getExpressionType()) {
                  if (ConstantValueExpression.isBooleanTrue(expr.getRight())) {
                      return expr.getRight();
                  } else {
                      return expr.getLeft();
                  }
              }
          } else if (ExpressionType.OPERATOR_NOT == expr.getExpressionType()) {
              AbstractExpression leftExpr = expr.getLeft();
              // function expressions can also return boolean. So the left child expression
              // can be expression which are not constant value expressions, so don't
              // evaluate every left child expr as constant value expression
              if ((VoltType.BOOLEAN == leftExpr.getValueType()) &&
                      (leftExpr instanceof ConstantValueExpression)) {
                  if (ConstantValueExpression.isBooleanTrue(leftExpr)) {
                      return ConstantValueExpression.getFalse();
                  } else {
                      return ConstantValueExpression.getTrue();
                  }
              } else if (ExpressionType.OPERATOR_NOT == leftExpr.getExpressionType()) {
                  return leftExpr.getLeft();
              } else if (ExpressionType.CONJUNCTION_OR == leftExpr.getExpressionType()) {
                  // NOT (.. OR .. OR ..) => NOT(..) AND NOT(..) AND NOT(..)
                  AbstractExpression l = new OperatorExpression(ExpressionType.OPERATOR_NOT, leftExpr.getLeft(), null);
                  AbstractExpression r = new OperatorExpression(ExpressionType.OPERATOR_NOT, leftExpr.getRight(), null);
                  leftExpr = new OperatorExpression(ExpressionType.CONJUNCTION_AND, l, r);
                  return evaluateExpression(leftExpr);
              }
              // NOT (expr1 AND expr2) => (NOT expr1) || (NOT expr2)
              // The above case is probably not interesting to do for short circuit purpose
          }
          return expr;
      }