ExpressionPtr UnaryOpExpression::postOptimize(AnalysisResultPtr ar) {
  bool insideScalarArray = ar->getInsideScalarArray();

  if (m_op == T_ARRAY &&
      (getContext() & (RefValue|LValue)) == 0) {
    if (m_exp) {
      ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
      if (pairs && pairs->isScalarArrayPairs()) {
        m_arrayId = ar->registerScalarArray(m_exp);
        ar->setInsideScalarArray(true);
      }
    } else {
      m_arrayId = ar->registerScalarArray(m_exp); // empty array
    }
  }

  ar->postOptimize(m_exp);
  if (m_op == T_PRINT && m_exp->is(KindOfEncapsListExpression) &&
      !m_exp->hasEffect()) {
    EncapsListExpressionPtr e = static_pointer_cast<EncapsListExpression>
      (m_exp);
    e->stripConcat();
  }

  ar->setInsideScalarArray(insideScalarArray);

  if (m_op == T_UNSET_CAST && !hasEffect()) {
    return CONSTANT("null");
  } else if (m_op == T_UNSET && m_exp->is(KindOfExpressionList) &&
             !static_pointer_cast<ExpressionList>(m_exp)->getCount()) {
    return CONSTANT("null");
  }

  return ExpressionPtr();
}
ExpressionPtr UnaryOpExpression::postOptimize(AnalysisResultPtr ar) {
    bool insideScalarArray = ar->getInsideScalarArray();

    if (m_op == T_ARRAY &&
            (getContext() & (RefValue|LValue)) == 0) {
        if (m_exp) {
            ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
            if (pairs && pairs->isScalarArrayPairs()) {
                m_arrayId = ar->registerScalarArray(m_exp);
                ar->setInsideScalarArray(true);
            }
        } else {
            m_arrayId = ar->registerScalarArray(m_exp); // empty array
        }
    }

    ar->postOptimize(m_exp);

    ar->setInsideScalarArray(insideScalarArray);
    return ExpressionPtr();
}
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  if ((m_op == T_INC || m_op == T_DEC) && outputCPPImplOpEqual(cg, ar)) {
    return;
  }
  if (m_op == T_ARRAY &&
      (getContext() & (RefValue|LValue)) == 0 &&
      !ar->getInsideScalarArray()) {
    int id = -1;
    int hash = -1;
    int index = -1;
    string text;
    if (m_exp) {
      ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
      Variant v;
      if (pairs && pairs->isScalarArrayPairs() && pairs->getScalarValue(v)) {
        id = ar->registerScalarArray(getFileScope(), m_exp, hash, index, text);
      }
    } else {
      id = ar->registerScalarArray(getFileScope(), m_exp,
                                   hash, index, text); // empty array
    }
    if (id != -1) {
      if (Option::UseNamedScalarArray &&
          cg.getContext() == CodeGenerator::CppParameterDefaultValueDecl) {
        getFileScope()->addUsedDefaultValueScalarArray(text);
      }
      ar->outputCPPScalarArrayId(cg, id, hash, index);
      return;
    }
  }

  if ((m_op == T_ISSET || m_op == T_EMPTY || m_op == T_UNSET) && m_exp) {
    if (m_exp->is(Expression::KindOfExpressionList)) {
      ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
      if (exps->getListKind() == ExpressionList::ListKindParam) {
        int count = exps->getCount();
        if (count > 1) {
          cg_printf("(");
        }
        for (int i = 0; i < count; i++) {
          if (m_op == T_UNSET) {
            if (i > 0) cg_printf(", ");
            (*exps)[i]->outputCPPUnset(cg, ar);
          } else {
            if (i > 0) cg_printf(" && ");
            (*exps)[i]->outputCPPExistTest(cg, ar, m_op);
          }
        }
        if (exps->getCount() > 1) {
          cg_printf(")");
        }
        return;
      }
    }
    if (m_op == T_UNSET) {
      m_exp->outputCPPUnset(cg, ar);
    } else {
      m_exp->outputCPPExistTest(cg, ar, m_op);
    }
    return;
  }

  if (m_front) {
    switch (m_op) {
    case T_CLONE:         cg_printf("f_clone(");   break;
    case T_INC:           cg_printf("++");         break;
    case T_DEC:           cg_printf("--");         break;
    case '+':             cg_printf("+");          break;
    case '-':             cg_printf("negate(");    break;
    case '!':             cg_printf("!(");         break;
    case '~':             cg_printf("~");          break;
    case '(':             cg_printf("(");          break;
    case T_INT_CAST:      cg_printf("(");          break;
    case T_DOUBLE_CAST:   cg_printf("(");          break;
    case T_STRING_CAST:   cg_printf("(");          break;
    case T_ARRAY_CAST:    cg_printf("(");          break;
    case T_OBJECT_CAST:   cg_printf("(");          break;
    case T_BOOL_CAST:     cg_printf("(");          break;
    case T_UNSET_CAST:
      if (m_exp->hasCPPTemp()) {
        cg_printf("(id(");
      } else {
        cg_printf("(");
      }
      break;
    case T_EXIT:          cg_printf("f_exit(");    break;
    case T_ARRAY:
      cg_printf("Array(");
      break;
    case T_PRINT:         cg_printf("print(");     break;
    case T_EVAL:
      if (Option::EnableEval > Option::NoEval) {
        bool instance;
        if (getClassScope()) {
          FunctionScopePtr fs = getFunctionScope();
          instance = fs && !fs->isStatic();
        } else {
          instance = false;
        }
        cg_printf("eval(%s, Object(%s), ",
                  getScope()->inPseudoMain() ?
                  "get_variable_table()" : "variables",
                  instance ? "this" : "");
      } else {
        cg_printf("f_eval(");
      }
      break;
    case '@':
      if (m_silencer >= 0) {
        cg_printf("(%s%d.enable(),%s%d.disable(",
                  Option::SilencerPrefix, m_silencer,
                  Option::SilencerPrefix, m_silencer);
      }
      break;
    case T_FILE:
      cg_printf("get_source_filename(\"%s\")", getLocation()->file);
      break;
      break;
    default:
      ASSERT(false);
    }
  }


  if (m_exp) {
    switch (m_op) {
    case '+':
    case '-':
      if (m_exp->getActualType() &&
          (m_exp->getActualType()->is(Type::KindOfString) ||
           m_exp->getActualType()->is(Type::KindOfArray))) {
        cg_printf("(Variant)(");
        m_exp->outputCPP(cg, ar);
        cg_printf(")");
      } else {
        m_exp->outputCPP(cg, ar);
      }
      break;
    case '@':
      if (m_silencer < 0 && isUnused()) {
        m_exp->outputCPPUnneeded(cg, ar);
      } else if (!m_exp->hasCPPTemp() && !m_exp->getActualType()) {
        // Void needs to return something to silenceDec
        cg_printf("(");
        m_exp->outputCPP(cg, ar);
        cg_printf(",null)");
      } else {
        m_exp->outputCPP(cg, ar);
      }
      break;
    default:
      m_exp->outputCPP(cg, ar);
      break;
    }
  }

  if (m_front) {
    switch (m_op) {
    case T_ARRAY:
      {
        ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
        if (!exps) {
          cg_printf("ArrayData::Create()");
        }
        cg_printf(")");
      }
      break;
    case T_UNSET_CAST:
      if (m_exp->hasCPPTemp()) {
        cg_printf("),null");
      } else {
        cg_printf(",null");
      }
    case T_CLONE:
    case '!':
    case '(':
    case '-':
    case T_INT_CAST:
    case T_DOUBLE_CAST:
    case T_STRING_CAST:
    case T_ARRAY_CAST:
    case T_OBJECT_CAST:
    case T_BOOL_CAST:
    case T_EXIT:
    case T_PRINT:
    case T_EVAL:
    case T_INCLUDE:
    case T_INCLUDE_ONCE:
    case T_REQUIRE:
    case T_REQUIRE_ONCE:
      cg_printf(")");
      break;
    case '@':
      if (m_silencer >= 0) {
        cg_printf("))");
      }
      break;
    default:
      break;
    }
  } else {
    switch (m_op) {
    case T_INC:           cg_printf("++"); break;
    case T_DEC:           cg_printf("--"); break;
    default:
      ASSERT(false);
    }
  }
}
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  if ((m_op == T_INC || m_op == T_DEC) && outputCPPImplOpEqual(cg, ar)) {
    return;
  }
  if (m_op == T_ARRAY &&
      (getContext() & (RefValue|LValue)) == 0 &&
      !cg.getInsideScalarArray()) {
    int id = -1;
    int hash = -1;
    int index = -1;
    string text;
    if (m_exp) {
      ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
      Variant v;
      if (pairs && pairs->isScalarArrayPairs() && pairs->getScalarValue(v)) {
        id = ar->registerScalarArray(cg.getInsideScalarArray(), getFileScope(),
                                     m_exp, hash, index, text);
      }
    } else {
      id = ar->registerScalarArray(cg.getInsideScalarArray(), getFileScope(),
                                   m_exp, hash, index, text); // empty array
    }
    if (id != -1) {
      bool scalarVariant =
        Option::UseScalarVariant && cg.hasScalarVariant();
      if (scalarVariant) {
        ar->addNamedScalarVarArray(text);
        getFileScope()->addUsedScalarVarArray(text);
      }
      if (Option::UseNamedScalarArray && cg.isFileOrClassHeader()) {
        if (getClassScope()) {
          getClassScope()->addUsedDefaultValueScalarArray(text);
          if (scalarVariant) {
            getClassScope()->addUsedDefaultValueScalarVarArray(text);
          }
        } else {
          getFileScope()->addUsedDefaultValueScalarArray(text);
          if (scalarVariant) {
            getFileScope()->addUsedDefaultValueScalarVarArray(text);
          }
        }
      }
      ar->outputCPPScalarArrayId(cg, id, hash, index, scalarVariant);
      return;
    }
  }

  if ((m_op == T_ISSET || m_op == T_EMPTY || m_op == T_UNSET) && m_exp) {
    if (m_exp->is(Expression::KindOfExpressionList)) {
      ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
      if (exps->getListKind() == ExpressionList::ListKindParam) {
        int count = exps->getCount();
        if (count > 1) {
          cg_printf("(");
        }
        for (int i = 0; i < count; i++) {
          if (m_op == T_UNSET) {
            if (i > 0) cg_printf(", ");
            (*exps)[i]->outputCPPUnset(cg, ar);
          } else {
            if (i > 0) cg_printf(" && ");
            (*exps)[i]->outputCPPExistTest(cg, ar, m_op);
          }
        }
        if (exps->getCount() > 1) {
          cg_printf(")");
        }
        return;
      }
    }
    if (m_op == T_UNSET) {
      m_exp->outputCPPUnset(cg, ar);
    } else {
      m_exp->outputCPPExistTest(cg, ar, m_op);
    }
    return;
  }

  ASSERT(m_op != T_CLASS && m_op != T_FUNCTION);

  const char *cstr = 0;
  if (m_front) {
    switch (m_op) {
      case T_CLONE:         cg_printf("f_clone(");   break;
      case T_INC:           cg_printf("++");         break;
      case T_DEC:           cg_printf("--");         break;
      case '+':             cg_printf("+");          break;
      case '-':             cg_printf("negate(");    break;
      case '!':             cg_printf("!(");         break;
      case '~':             cg_printf("~");          break;
      case T_INT_CAST:      cg_printf("(");          break;
      case T_DOUBLE_CAST:   cg_printf("(");          break;
      case T_STRING_CAST:   cstr = "String"; goto null_cast;
      case T_ARRAY_CAST:    cstr = "Array"; goto null_cast;
      case T_OBJECT_CAST:   cstr = "Object"; goto null_cast;
      null_cast: {
        TypePtr at = m_exp->getActualType();
        TypePtr et = m_exp->getType();
        TypePtr it = m_exp->getCPPType();
        if (at && Type::SameType(at, et) && Type::SameType(it, at)) {
          cg_printf("to%s(", cstr);
        } else {
          cg_printf("(");
        }
        break;
      }
      case T_BOOL_CAST:     cg_printf("(");          break;
      case T_UNSET_CAST:
        if (m_exp->isScalar()) {
          cg_printf("(null)");
          return;
        }
        if (m_exp->hasCPPTemp()) {
          cg_printf("(id(");
        } else {
          cg_printf("(");
        }
        break;
      case T_EXIT:          cg_printf("f_exit(");    break;
      case T_ARRAY:
        cg_printf("Array(");
        break;
      case T_PRINT:         cg_printf("print(");     break;
      case T_EVAL:
        if (Option::EnableEval > Option::NoEval) {
          bool instance;
          if (getClassScope()) {
            FunctionScopePtr fs = getFunctionScope();
            instance = fs && !fs->isStatic();
          } else {
            instance = false;
          }
          cg_printf("eval(%s, Object(%s), ",
                    getScope()->inPseudoMain() ?
                    "get_variable_table()" : "variables",
                    instance ? "this" : "");
        } else {
          cg_printf("f_eval(");
        }
        break;
      case '@':
        break;
      case T_FILE:
        cg_printf("get_source_filename(\"%s\")", getLocation()->file);
        break;
      case T_DIR:
        cg_printf("get_source_filename(\"%s\", true)", getLocation()->file);
        break;
      default:
        ASSERT(false);
    }
  }

  if (m_exp) {
    switch (m_op) {
      case '+':
      case '-':
        if (!m_exp->outputCPPArithArg(cg, ar, false)) {
          m_exp->outputCPP(cg, ar);
        }
        break;
      case '@':
        if (isUnused()) {
          m_exp->outputCPPUnneeded(cg, ar);
        } else {
          m_exp->outputCPP(cg, ar);
        }
        break;
      default:
        m_exp->outputCPP(cg, ar);
        break;
    }
  }

  if (m_front) {
    switch (m_op) {
    case T_ARRAY:
      {
        ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
        if (!exps) {
          cg_printf("ArrayData::Create()");
        }
        cg_printf(")");
      }
      break;
    case T_UNSET_CAST:
      if (m_exp->hasCPPTemp()) {
        cg_printf("),null");
      } else {
        cg_printf(",null");
      }
    case T_CLONE:
    case '!':
    case '-':
    case T_INT_CAST:
    case T_DOUBLE_CAST:
    case T_STRING_CAST:
    case T_ARRAY_CAST:
    case T_OBJECT_CAST:
    case T_BOOL_CAST:
    case T_EXIT:
    case T_PRINT:
    case T_EVAL:
    case T_INCLUDE:
    case T_INCLUDE_ONCE:
    case T_REQUIRE:
    case T_REQUIRE_ONCE:
      cg_printf(")");
      break;
    case '@':
      break;
    default:
      break;
    }
  } else {
    switch (m_op) {
    case T_INC:           cg_printf("++"); break;
    case T_DEC:           cg_printf("--"); break;
    default:
      ASSERT(false);
    }
  }
}