void NewObjectExpression::outputCPPImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  string &cname = (m_origName == "self" || m_origName == "parent") ?
    m_name : m_origName;
  bool outsideClass = !ar->checkClassPresent(shared_from_this(), m_origName);
  if (!m_name.empty() && !m_redeclared && m_validClass && !m_dynamic) {
    ClassScopePtr cls = ar->resolveClass(shared_from_this(), m_name);
    ASSERT(cls);
    if (m_receiverTemp.empty()) {
      if (outsideClass) {
        cls->outputVolatileCheckBegin(cg, ar, getScope(), cname);
      }
      cg_printf("%s%s((NEWOBJ(%s%s)())->create(",
                Option::SmartPtrPrefix, cls->getId(cg).c_str(),
                Option::ClassPrefix, cls->getId(cg).c_str());
    } else {
      cg_printf("(%s->create(", m_receiverTemp.c_str());
    }

    FunctionScopePtr dummy;
    FunctionScope::OutputCPPArguments(m_params, dummy, cg, ar, m_extraArg,
                                      m_variableArgument, m_argArrayId,
                                      m_argArrayHash, m_argArrayIndex);
    if (m_receiverTemp.empty()) {
      cg_printf("))");
      if (outsideClass) {
        cls->outputVolatileCheckEnd(cg);
      }
    } else {
      cg_printf(")");
      if (!isUnused()) {
        cg_printf(", %s", m_receiverTemp.c_str());
      }
      cg_printf(")");
    }
  } else {
    bool wrap = false;
    wrap = m_actualType && m_actualType->is(Type::KindOfVariant) &&
      !m_expectedType && !m_implementedType;
    if (wrap) {
      cg_printf("((Variant)");
    }
    cg_printf("id(obj%d)", m_objectTemp);
    if (wrap) {
      cg_printf(")");
    }
  }
}
bool NewObjectExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                       int state) {
  bool tempRcvr = true;

  if (m_name.empty() || m_redeclared || !m_validClass || m_dynamic) {
    tempRcvr = false;
  }

  bool paramEffect = false;
  if (m_params && m_params->getCount() > 0) {
    for (int i = m_params->getCount(); i--; ) {
      if (!(*m_params)[i]->isScalar()) {
        paramEffect = true;
        break;
      }
    }
  }

  if (!paramEffect) {
    tempRcvr = false;
  }

  if (tempRcvr && ar->inExpression()) {
    ar->wrapExpressionBegin(cg);
    m_receiverTemp = genCPPTemp(cg, ar);
    bool outsideClass = !ar->checkClassPresent(m_origName);
    cg.printf("%s%s *%s = ", Option::ClassPrefix, m_name.c_str(),
              m_receiverTemp.c_str());
    ClassScopePtr cls = ar->resolveClass(m_name);
    ASSERT(cls);
    if (outsideClass) {
      cls->outputVolatileCheckBegin(cg, ar, m_origName);
    }
    cg.printf("NEWOBJ(%s%s)()", Option::ClassPrefix, m_name.c_str());
    if (outsideClass) {
      cls->outputVolatileCheckEnd(cg);
    }
    cg.printf(";\n");
  }

  bool tempParams = FunctionCall::preOutputCPP(cg, ar, state);
  return tempRcvr || tempParams;
}
bool NewObjectExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                       int state) {
  string &cname = (m_origName == "self" || m_origName == "parent") ?
    m_name : m_origName;
  if (m_name.empty() || m_redeclared || !m_validClass || m_dynamic) {
    // Short circuit out if inExpression() returns false
    if (!ar->inExpression()) return true;

    if (m_nameExp) m_nameExp->preOutputCPP(cg, ar, state);
    ar->wrapExpressionBegin(cg);
    m_ciTemp = cg.createNewId(ar);
    m_objectTemp = cg.createNewId(ar);
    cg_printf("Object obj%d(", m_objectTemp);
    if (m_redeclared) {
      bool outsideClass = !ar->checkClassPresent(m_origName);
      ClassScopePtr cls = ar->resolveClass(m_name);
      ASSERT(cls);
      if (outsideClass) {
        cls->outputVolatileCheckBegin(cg, ar, cname);
      }
      cg_printf("g->%s%s->createOnly()", Option::ClassStaticsObjectPrefix,
                m_name.c_str());
      if (outsideClass) {
        cls->outputVolatileCheckEnd(cg);
      }
    } else {
      cg_printf("create_object_only(");
      if (!cname.empty()) {
        cg_printf("\"%s\"", cname.c_str());
      } else if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
        m_nameExp->outputCPP(cg, ar);
      } else {
        cg_printf("(");
        m_nameExp->outputCPP(cg, ar);
        cg_printf(")");
      }
      cg_printf(")");
    }
    cg_printf(");\n");
    cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp,
        m_objectTemp);
    cg_printf("mcp%d.construct(obj%d);\n", m_ciTemp, m_objectTemp);
    cg_printf("const CallInfo *cit%d = mcp%d.ci;\n", m_ciTemp, m_ciTemp);

    if (m_params && m_params->getCount() > 0) {
      ar->pushCallInfo(m_ciTemp);
      m_params->preOutputCPP(cg, ar, state);
      ar->popCallInfo();
    }
    cg_printf("(cit%d->getMeth())(mcp%d, ", m_ciTemp, m_ciTemp);
    if (m_params && m_params->getOutputCount()) {
      ar->pushCallInfo(m_ciTemp);
      FunctionScope::outputCPPArguments(m_params, cg, ar, -1, false);
      ar->popCallInfo();
    } else {
      cg_printf("Array()");
    }
    cg_printf(");\n");

    if (state & FixOrder) {
      ar->pushCallInfo(m_ciTemp);
      preOutputStash(cg, ar, state);
      ar->popCallInfo();
    }

    if (hasCPPTemp() && !(state & FixOrder)) {
      cg_printf("id(%s);\n", cppTemp().c_str());
    }
    return true;
  } else {
    bool tempRcvr = true;

    bool paramEffect = false;
    if (m_params && m_params->getCount() > 0) {
      for (int i = m_params->getCount(); i--; ) {
        if (!(*m_params)[i]->isScalar()) {
          paramEffect = true;
          break;
        }
      }
    }

    if (!paramEffect) {
      tempRcvr = false;
    }

    if (tempRcvr && ar->inExpression()) {
      bool outsideClass = !ar->checkClassPresent(m_origName);
      ClassScopePtr cls = ar->resolveClass(m_name);
      ASSERT(cls);
      ar->wrapExpressionBegin(cg);
      m_receiverTemp = genCPPTemp(cg, ar);
      cg_printf("%s%s %s = ", Option::SmartPtrPrefix, cls->getId(cg).c_str(),
          m_receiverTemp.c_str());
      if (outsideClass) {
        cls->outputVolatileCheckBegin(cg, ar, cname);
      }
      cg_printf("NEWOBJ(%s%s)()", Option::ClassPrefix, cls->getId(cg).c_str());
      if (outsideClass) {
        cls->outputVolatileCheckEnd(cg);
      }
      cg_printf(";\n");
    }

    bool tempParams = FunctionCall::preOutputCPP(cg, ar, state);
    return tempRcvr || tempParams;
  }
}
void SimpleFunctionCall::outputCPPParamOrderControlled(CodeGenerator &cg,
                                                       AnalysisResultPtr ar) {
  if (m_className.empty()) {
    switch (m_type) {
    case ExtractFunction:
      cg.printf("extract(variables, ");
      FunctionScope::outputCPPArguments(m_params, cg, ar, 0, false);
      cg.printf(")");
      return;
    case CompactFunction:
      cg.printf("compact(variables, ");
      FunctionScope::outputCPPArguments(m_params, cg, ar, -1, true);
      cg.printf(")");
      return;
    default:
      break;
    }
  }
  bool volatileCheck = false;
  ClassScopePtr cls;
  if (!m_className.empty()) {
    cls = ar->findClass(m_className);
    if (cls && !ar->checkClassPresent(m_origClassName)) {
      volatileCheck = true;
      cls->outputVolatileCheckBegin(cg, ar, cls->getOriginalName());
    }
  }
  if (m_valid) {
    bool tooManyArgs =
      (m_params && m_params->outputCPPTooManyArgsPre(cg, ar, m_name));
    if (!m_className.empty()) {
      cg.printf("%s%s::", Option::ClassPrefix, m_className.c_str());
      if (m_name == "__construct" && cls) {
        FunctionScopePtr func = cls->findConstructor(ar, true);
        cg.printf("%s%s(", Option::MethodPrefix, func->getName().c_str());
      } else {
        cg.printf("%s%s(", Option::MethodPrefix, m_name.c_str());
      }
    } else {
      int paramCount = m_params ? m_params->getCount() : 0;
      if (m_name == "get_class" && ar->getClassScope() && paramCount == 0) {
        cg.printf("(\"%s\"", ar->getClassScope()->getOriginalName());
      } else if (m_name == "get_parent_class" && ar->getClassScope() &&
                 paramCount == 0) {
        const std::string parentClass = ar->getClassScope()->getParent();
        if (!parentClass.empty()) {
          cg.printf("(\"%s\"", ar->getClassScope()->getParent().c_str());
        } else {
          cg.printf("(false");
        }
      } else {
        if (m_noPrefix) {
          cg.printf("%s(", m_name.c_str());
        }
        else {
         cg.printf("%s%s(", m_builtinFunction ? Option::BuiltinFunctionPrefix :
                   Option::FunctionPrefix, m_name.c_str());
        }
      }
    }
    FunctionScope::outputCPPArguments(m_params, cg, ar, m_extraArg,
                                      m_variableArgument, m_argArrayId);
    cg.printf(")");
    if (tooManyArgs) {
      m_params->outputCPPTooManyArgsPost(cg, ar, m_voidReturn);
    }
  } else {
    if (m_className.empty()) {
      if (m_redeclared && !m_dynamicInvoke) {
        if (canInvokeFewArgs()) {
          cg.printf("%s->%s%s_few_args(", cg.getGlobals(ar),
                    Option::InvokePrefix, m_name.c_str());
          int left = Option::InvokeFewArgsCount;
          if (m_params && m_params->getCount()) {
            left -= m_params->getCount();
            cg.printf("%d, ", m_params->getCount());
            FunctionScope::outputCPPArguments(m_params, cg, ar, 0, false);
          } else {
            cg.printf("0");
          }
          for (int i = 0; i < left; i++) {
            cg.printf(", null_variant");
          }
          cg.printf(")");
          return;
        } else {
          cg.printf("%s->%s%s(", cg.getGlobals(ar), Option::InvokePrefix,
                    m_name.c_str());
        }
      } else {
        cg.printf("invoke(\"%s\", ", m_name.c_str());
      }
    } else {
      bool inObj = m_parentClass && ar->getClassScope() &&
        !dynamic_pointer_cast<FunctionScope>(ar->getScope())->isStatic();
      if (m_redeclaredClass) {
        if (inObj) {  // parent is redeclared
          cg.printf("parent->%sinvoke(\"%s\",", Option::ObjectPrefix,
                    m_name.c_str());
        } else {
          cg.printf("%s->%s%s->%sinvoke(\"%s\", \"%s\",",
                    cg.getGlobals(ar),
                    Option::ClassStaticsObjectPrefix,
                    m_className.c_str(), Option::ObjectStaticPrefix,
                    m_className.c_str(),
                    m_name.c_str());
        }
      } else if (m_validClass) {
        if (inObj) {
          cg.printf("%s%s::%sinvoke(\"%s\",",
                    Option::ClassPrefix, m_className.c_str(),
                    Option::ObjectPrefix, m_name.c_str());
        } else {
          cg.printf("%s%s::%sinvoke(\"%s\", \"%s\",",
                    Option::ClassPrefix, m_className.c_str(),
                    Option::ObjectStaticPrefix,
                    m_className.c_str(),
                    m_name.c_str());
        }
      } else {
        cg.printf("invoke_static_method(\"%s\", \"%s\",",
                  m_className.c_str(), m_name.c_str());
      }
    }
    if ((!m_params) || (m_params->getCount() == 0)) {
      cg.printf("Array()");
    } else {
      FunctionScope::outputCPPArguments(m_params, cg, ar, -1, false);
    }
    bool needHash = true;
    if (m_className.empty()) {
      needHash = !(m_redeclared && !m_dynamicInvoke);
    } else {
      needHash = m_validClass || m_redeclaredClass;
    }
    if (!needHash) {
      cg.printf(")");
    } else {
      cg.printf(", 0x%.16lXLL)", hash_string_i(m_name.data(), m_name.size()));
    }
  }
  if (volatileCheck) {
    cls->outputVolatileCheckEnd(cg);
  }
}
void NewObjectExpression::outputCPPImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  bool linemap = outputLineMap(cg, ar, true);
  bool outsideClass = !ar->checkClassPresent(m_origName);
  if (!m_name.empty() && !m_redeclared && m_validClass && !m_dynamic) {
    bool tooManyArgs =
      (m_params && m_params->outputCPPTooManyArgsPre(cg, ar, m_name));
    ClassScopePtr cls = ar->resolveClass(m_name);
    ASSERT(cls);
    if (m_receiverTemp.empty()) {
      if (outsideClass) {
        cls->outputVolatileCheckBegin(cg, ar, m_origName);
      }
      cg.printf("%s%s((NEWOBJ(%s%s)())->create(",
                Option::SmartPtrPrefix, m_name.c_str(),
                Option::ClassPrefix, m_name.c_str());
    } else {
      cg.printf("%s%s(%s->create(",
                Option::SmartPtrPrefix, m_name.c_str(),
                m_receiverTemp.c_str());
    }

    FunctionScope::outputCPPArguments(m_params, cg, ar, m_extraArg,
                                      m_variableArgument, m_argArrayId);
    cg.printf("))");
    if (m_receiverTemp.empty()) {
      if (outsideClass) {
        cls->outputVolatileCheckEnd(cg);
      }
    }
    if (tooManyArgs) {
      m_params->outputCPPTooManyArgsPost(cg, ar, m_voidReturn);
    }
  } else {
    if (m_redeclared) {
      if (outsideClass) {
        ClassScope::OutputVolatileCheckBegin(cg, ar, m_origName);
      }
      cg.printf("g->%s%s->create(", Option::ClassStaticsObjectPrefix,
                m_name.c_str());
    } else {
      cg.printf("create_object(");
      if (!m_name.empty()) {
        cg.printf("\"%s\"", m_name.c_str());
      } else if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
        m_nameExp->outputCPP(cg, ar);
      } else {
        cg.printf("(");
        m_nameExp->outputCPP(cg, ar);
        cg.printf(")");
      }
      cg.printf(", ");
    }
    if (m_params && m_params->getOutputCount()) {
      FunctionScope::outputCPPArguments(m_params, cg, ar, -1, false);
    } else {
      cg.printf("Array()");
    }
    cg.printf(")");
    if (m_redeclared && outsideClass) {
      ClassScope::OutputVolatileCheckEnd(cg);
    }
  }
  if (linemap) cg.printf(")");
}