static void wrapValue(CodeGenerator &cg, AnalysisResultPtr ar,
                      ExpressionPtr exp, bool ref, bool array, bool varnr) {
  bool close = false;
  if (ref) {
    cg_printf("ref(");
    close = true;
  } else if (array && !exp->hasCPPTemp() &&
             !exp->isTemporary() && !exp->isScalar() &&
             exp->getActualType() && !exp->getActualType()->isPrimitive() &&
             exp->getActualType()->getKindOf() != Type::KindOfString) {
    cg_printf("wrap_variant(");
    close = true;
  } else if (varnr && exp->getCPPType()->isExactType()) {
    bool isScalar = exp->isScalar();
    if (!isScalar || !Option::UseScalarVariant) {
      cg_printf("VarNR(");
      close = true;
    } else if (isScalar) {
      ASSERT(!cg.hasScalarVariant());
      cg.setScalarVariant();
    }
  }
  exp->outputCPP(cg, ar);
  cg.clearScalarVariant();
  if (close) cg_printf(")");
}
void ExpressionList::outputCPPUniqLitKeyArrayInit(
  CodeGenerator &cg, AnalysisResultPtr ar, bool litstrKeys, int64 num,
  bool arrayElements /* = true */, unsigned int start /* = 0 */) {
  if (arrayElements) ASSERT(m_arrayElements);
  unsigned int n =  m_exps.size();
  cg_printf("array_createv%c(%lld, ", litstrKeys ? 's' : 'i', num);
  assert(n - start == num);
  for (unsigned int i = start; i < n; i++) {
    ExpressionPtr exp = m_exps[i];
    assert(exp);
    ExpressionPtr name;
    ExpressionPtr value = exp;
    if (arrayElements) {
      ArrayPairExpressionPtr ap =
        dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
      name = ap->getName();
      value = ap->getValue();
    }
    if (name) {
      assert(litstrKeys);
      cg_printf("toSPOD(");
      name->outputCPP(cg, ar);
      cg_printf("), ");
    }
    cg_printf("toVPOD(");
    if (value->isScalar()) {
      assert(!cg.hasScalarVariant());
      cg.setScalarVariant();
      if (!Option::UseScalarVariant) cg_printf("VarNR(");
      value->outputCPP(cg, ar);
      if (!Option::UseScalarVariant) cg_printf(")");
      cg.clearScalarVariant();
    } else {
      bool wrap = Expression::CheckVarNR(value, Type::Variant);
      if (wrap) cg_printf("VarNR(");
      value->outputCPP(cg, ar);
      if (wrap) cg_printf(")");
    }
    cg_printf(")");
    if (i < n-1) {
      cg_printf(", ");
    } else {
      cg_printf(")");
    }
  }
}
void ParameterExpression::outputCPPImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  FunctionScopePtr func = getFunctionScope();
  VariableTablePtr variables = func->getVariables();
  Symbol *sym = variables->getSymbol(m_name);
  assert(sym && sym->isParameter());

  bool inHeader = cg.isFileOrClassHeader();
  cg.setFileOrClassHeader(true);
  CodeGenerator::Context context = cg.getContext();
  bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl ||
                       context == CodeGenerator::CppTypedParamsWrapperDecl);

  TypePtr paramType =
    typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ?
    Type::Variant : func->getParamType(sym->getParameterIndex());
  bool wrapper = typedWrapper ||
    context == CodeGenerator::CppFunctionWrapperImpl ||
    context == CodeGenerator::CppFunctionWrapperDecl;

  bool isCVarRef = false;
  const char *prefix = "";
  if (m_ref) {
    cg_printf("VRefParam");
    if (!wrapper) {
      prefix = "r";
    }
  } else if (wrapper ||
      (!variables->isLvalParam(m_name) &&
       !variables->getAttribute(VariableTable::ContainsDynamicVariable) &&
       !variables->getAttribute(VariableTable::ContainsExtract))) {
    if (paramType->is(Type::KindOfVariant) ||
        paramType->is(Type::KindOfSome)) {
      cg_printf("CVarRef");
      isCVarRef = true;
    }
    else if (paramType->is(Type::KindOfArray))  cg_printf("CArrRef");
    else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef");
    else paramType->outputCPPDecl(cg, ar, getScope());
  } else {
    paramType->outputCPPDecl(cg, ar, getScope());
  }

  cg_printf(" %s%s%s",
            prefix, Option::VariablePrefix,
            CodeGenerator::FormatLabel(m_name).c_str());
  if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) {
    bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl ||
      context == CodeGenerator::CppFunctionWrapperImpl ||
      context == CodeGenerator::CppImplementation ||
      (context == CodeGenerator::CppDeclaration && func->isInlined());
    if (comment) {
      cg_printf(" // ");
    }
    cg_printf(" = ");
    ConstantExpressionPtr con =
      dynamic_pointer_cast<ConstantExpression>(m_defaultValue);

    bool done = false;
    if (con && con->isNull()) {
      done = true;
      if (isCVarRef) {
        cg_printf("null_variant");
      } else if (paramType->is(Type::KindOfVariant) ||
                 paramType->is(Type::KindOfSome)) {
        cg_printf("null");
      } else if (paramType->is(Type::KindOfObject)) {
        cg_printf("Object()");
      } else if (paramType->is(Type::KindOfArray)) {
        cg_printf("Array()");
      } else if (paramType->is(Type::KindOfString)) {
        cg_printf("String()");
      } else {
        done = false;
      }
    }
    if (!done) {
      if (comment) {
        cg.setContext(CodeGenerator::CppParameterDefaultValueImpl);
      } else {
        cg.setContext(CodeGenerator::CppParameterDefaultValueDecl);
      }
      bool isScalar = m_defaultValue->isScalar();
      if (isCVarRef && isScalar) {
        ASSERT(!cg.hasScalarVariant());
        cg.setScalarVariant();
      }
      m_defaultValue->outputCPP(cg, ar);
      if (isCVarRef && isScalar) cg.clearScalarVariant();
      ASSERT(!cg.hasScalarVariant());
      cg.setContext(context);
    }
    if (comment) {
      cg_printf("\n");
    }
  }
  cg.setFileOrClassHeader(inHeader);
}
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);
    }
  }
}