Пример #1
0
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) {
  Expression::analyzeProgram(ar);
  if (m_name == "argc" || m_name == "argv") {
    // special case: they are NOT superglobals when not in global scope
    if (ar->getScope() == ar) {
      m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name);
      m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name);
    }
  } else {
    m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name);
    m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name);
  }

  if (m_superGlobal) {
    ar->getScope()->getVariables()->
      setAttribute(VariableTable::NeedGlobalPointer);
  }

  if (m_name == "this" && ar->getClassScope()) {
    FunctionScopePtr func =
      dynamic_pointer_cast<FunctionScope>(ar->getScope());
    func->setContainsThis();
    m_this = true;
  } else if (m_name == "GLOBALS") {
    m_globals = true;
  }
  if (!(m_context & AssignmentLHS)) {
    BlockScopePtr scope = ar->getScope();
    FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope);
    if (func) {
      func->getVariables()->addUsed(m_name);
    }
  }
}
Пример #2
0
void MethodStatement::addParamRTTI(AnalysisResultPtr ar) {
  FunctionScopePtr func =
    dynamic_pointer_cast<FunctionScope>(ar->getScope());
  VariableTablePtr variables = func->getVariables();
  if (variables->getAttribute(VariableTable::ContainsDynamicVariable) ||
      variables->getAttribute(VariableTable::ContainsExtract)) {
    return;
  }
  for (int i = 0; i < m_params->getCount(); i++) {
    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
    const string &paramName = param->getName();
    if (variables->isLvalParam(paramName)) continue;
    TypePtr paramType = param->getActualType();
    if ((paramType->is(Type::KindOfVariant) ||
         paramType->is(Type::KindOfSome)) &&
        !param->isRef()) {
      param->setHasRTTI();
      ClassScopePtr cls = ar->getClassScope();
      ar->addParamRTTIEntry(cls, func, paramName);
      const string funcId = ar->getFuncId(cls, func);
      ar->addRTTIFunction(funcId);
    }
  }
}
Пример #3
0
TypePtr AssignmentExpression::
inferTypesImpl(AnalysisResultPtr ar, TypePtr type, bool coerce,
               ExpressionPtr variable,
               ExpressionPtr value /* = ExpressionPtr() */) {
  TypePtr ret = type;
  if (value) {
    if (coerce) {
      ret = value->inferAndCheck(ar, type, coerce);
    } else {
      ret = value->inferAndCheck(ar, NEW_TYPE(Some), coerce);
    }
  }

  BlockScopePtr scope = ar->getScope();
  if (variable->is(Expression::KindOfConstantExpression)) {
    // ...as in ClassConstant statement
    ConstantExpressionPtr exp =
      dynamic_pointer_cast<ConstantExpression>(variable);
    bool p;
    scope->getConstants()->check(exp->getName(), ret, true, ar, variable, p);
  } else if (variable->is(Expression::KindOfDynamicVariable)) {
    // simptodo: not too sure about this
    ar->getFileScope()->setAttribute(FileScope::ContainsLDynamicVariable);
  } else if (variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable);
    if (var->getName() == "this" && ar->getClassScope()) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(variable, CodeError::ReassignThis,
                                   variable);
      }
    }
    if (ar->getPhase() == AnalysisResult::LastInference && value) {
      if (!value->getExpectedType()) {
        value->setExpectedType(variable->getActualType());
      }
    }
  }
  // if the value may involve object, consider the variable as "referenced"
  // so that objects are not destructed prematurely.
  bool referenced = true;
  if (value && value->isScalar()) referenced = false;
  if (ret && ret->isNoObjectInvolved()) referenced = false;
  if (referenced && variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(variable);
    const std::string &name = var->getName();
    VariableTablePtr variables = ar->getScope()->getVariables();
    variables->addReferenced(name);
  }

  TypePtr vt = variable->inferAndCheck(ar, ret, true);
  if (!coerce && type->is(Type::KindOfAny)) {
    ret = vt;
  }

  return ret;
}
Пример #4
0
void ListAssignment::outputCPPAssignment(CodeGenerator &cg,
    AnalysisResultPtr ar, const string &arrTmp) {
  if (!m_variables) return;

  for (int i = m_variables->getCount() - 1; i >= 0; --i) {
    ExpressionPtr exp = (*m_variables)[i];
    if (exp) {
      if (exp->is(Expression::KindOfListAssignment)) {
        ListAssignmentPtr sublist = dynamic_pointer_cast<ListAssignment>(exp);
        string subTmp = genCPPTemp(cg, ar);
        cg_printf("Variant %s((ref(%s[%d])));\n", subTmp.c_str(),
                  arrTmp.c_str(), i);
        sublist->outputCPPAssignment(cg, ar, subTmp);
      } else {
        bool done = false;
        if (exp->is(Expression::KindOfArrayElementExpression)) {
          ArrayElementExpressionPtr arrExp =
            dynamic_pointer_cast<ArrayElementExpression>(exp);
          if (!arrExp->isSuperGlobal() && !arrExp->isDynamicGlobal()) {
            arrExp->getVariable()->outputCPP(cg, ar);
            if (arrExp->getOffset()) {
              cg_printf(".set(");
              arrExp->getOffset()->outputCPP(cg, ar);
              cg_printf(", ");
            } else {
              cg_printf(".append(");
            }
            cg_printf("%s[%d]);\n", arrTmp.c_str(), i);
            done = true;
          }
        } else if (exp->is(Expression::KindOfObjectPropertyExpression)) {
          ObjectPropertyExpressionPtr var(
            dynamic_pointer_cast<ObjectPropertyExpression>(exp));
          if (!var->isValid()) {
            var->outputCPPObject(cg, ar);
            cg_printf("o_set(");
            var->outputCPPProperty(cg, ar);
            cg_printf(", %s[%d], %s);\n",
                      arrTmp.c_str(), i,
                      ar->getClassScope() ? "s_class_name" : "empty_string");
            done = true;
          }
        }
        if (!done) {
          exp->outputCPP(cg, ar);
          if (arrTmp == "null") {
            cg_printf(" = null;\n");
          } else {
            cg_printf(" = %s[%d];\n", arrTmp.c_str(), i);
          }
        }
      }
    }
  }
}
Пример #5
0
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr func = ar->getFunctionScope();
  bool inPseudoMain = func && func->inPseudoMain();
  std::vector<bool> isDeclaration;

  if (inPseudoMain) {
    // We need these declarations to go first, because PHP allows top level
    // function and class declarations to appear after usage.
    for (unsigned int i = 0; i < m_stmts.size(); i++) {
      StatementPtr stmt = m_stmts[i];
      bool isDecl = false;
      if (stmt->is(Statement::KindOfFunctionStatement)) {
        isDecl = true;
      } else if (stmt->is(Statement::KindOfClassStatement) ||
                 stmt->is(Statement::KindOfInterfaceStatement)) {
        ClassScopePtr cls =
          (dynamic_pointer_cast<InterfaceStatement>(stmt))->getClassScope();
        isDecl = cls->isBaseClass() || !cls->isVolatile();
      }
      if (isDecl) stmt->outputCPP(cg,ar);
      isDeclaration.push_back(isDecl);
    }
  }

  for (unsigned int i = 0; i < m_stmts.size(); i++) {
    StatementPtr stmt = m_stmts[i];
    if (stmt->is(Statement::KindOfClassStatement)) {
      if (!inPseudoMain || !isDeclaration[i]) stmt->outputCPP(cg, ar);
    } else if (!(stmt->is(Statement::KindOfFunctionStatement) ||
                 stmt->is(Statement::KindOfInterfaceStatement)) ||
               (!inPseudoMain || !isDeclaration[i])) {
      stmt->outputCPP(cg, ar);
      if (stmt->is(Statement::KindOfMethodStatement)) {
        MethodStatementPtr methodStmt =
          dynamic_pointer_cast<MethodStatement>(stmt);
        std::string methodName = methodStmt->getName();
        if (methodName == "offsetget") {
          ClassScopePtr cls = ar->getClassScope();
          std::string arrayAccess("arrayaccess");
          if (cls->derivesFrom(ar, arrayAccess, false, false)) {
            FunctionScopePtr funcScope = methodStmt->getFunctionScope();
            std::string name = funcScope->getName();
            funcScope->setName("__offsetget_lval");
            methodStmt->setName("__offsetget_lval");
            methodStmt->outputCPP(cg, ar);
            funcScope->setName(name);
            methodStmt->setName("offsetget");
          }
        }
      }
    }
  }
}
Пример #6
0
void MethodStatement::outputCPPStmt(CodeGenerator &cg, AnalysisResultPtr ar) {
  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
    if (!m_stmt->hasRetExp()) {
      FunctionScopePtr funcScope = m_funcScope.lock();
      ClassScopePtr cls = ar->getClassScope();
      if (funcScope->isConstructor(cls)) {
        cg.printf("gasInCtor(oldInCtor);\n");
      }
    }
  }
}
Пример #7
0
void FunctionScope::outputCPPCreateImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  ClassScopePtr scope = ar->getClassScope();
  string clsNameStr = scope->getId(cg);
  const char *clsName = clsNameStr.c_str();
  const char *consName = scope->classNameCtor() ? scope->getName().c_str()
                                                : "__construct";

  cg_printf("%s%s *%s%s::create(",
            Option::ClassPrefix, clsName, Option::ClassPrefix, clsName);
  outputCPPParamsImpl(cg, ar);
  cg_indentBegin(") {\n");
  cg_printf("CountableHelper h(this);\n");
  cg_printf("init();\n");
  cg_printf("%s%s(", Option::MethodPrefix, consName);
  outputCPPParamsCall(cg, ar, false);
  cg_printf(");\n");
  cg_printf("return this;\n");
  cg_indentEnd("}\n");
  cg_indentBegin("ObjectData *%s%s::dynCreate(CArrRef params, "
                 "bool construct /* = true */) {\n",
                 Option::ClassPrefix, clsName);
  cg_printf("init();\n");
  cg_indentBegin("if (construct) {\n");
  cg_printf("CountableHelper h(this);\n");
  OutputCPPDynamicInvokeCount(cg);
  outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix,
                         cg.formatLabel(consName).c_str(),
                         true, false, false, NULL, true);
  cg_indentEnd("}\n");
  cg_printf("return this;\n");
  cg_indentEnd("}\n");
  if (isDynamic() || isSepExtension()) {
    cg_indentBegin("void %s%s::dynConstruct(CArrRef params) {\n",
                   Option::ClassPrefix, clsName);
    OutputCPPDynamicInvokeCount(cg);
    outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix,
                           cg.formatLabel(consName).c_str(),
                           true, false, false, NULL, true);
    cg_indentEnd("}\n");
    if (cg.getOutput() == CodeGenerator::SystemCPP ||
        Option::EnableEval >= Option::LimitedEval) {
      cg_indentBegin("void %s%s::dynConstructFromEval("
                     "Eval::VariableEnvironment &env, "
                     "const Eval::FunctionCallExpression *caller) {\n",
                     Option::ClassPrefix, clsName);
      outputCPPEvalInvoke(cg, ar, Option::MethodPrefix,
                          cg.formatLabel(consName).c_str(), NULL, false);
      cg_indentEnd("}\n");
    }
  }
}
void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_params->analyzeProgram(ar);
  m_object->analyzeProgram(ar);
  m_nameExp->analyzeProgram(ar);

  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    FunctionScopePtr func = m_funcScope;
    if (!func && m_object->isThis() && !m_name.empty()) {
      ClassScopePtr cls = ar->getClassScope();
      if (cls) {
        m_classScope = cls;
        m_funcScope = func = cls->findFunction(ar, m_name, true, true);
        if (!func) {
          cls->addMissingMethod(m_name);
        }
      }
    }

    ExpressionList &params = *m_params;
    if (func) {
      int mpc = func->getMaxParamCount();
      for (int i = params.getCount(); i--; ) {
        ExpressionPtr p = params[i];
        if (i < mpc ? func->isRefParam(i) :
            func->isReferenceVariableArgument()) {
          p->setContext(Expression::RefValue);
        }
      }
    } else if (!m_name.empty()) {
      FunctionScope::RefParamInfoPtr info =
        FunctionScope::GetRefParamInfo(m_name);
      if (info) {
        for (int i = params.getCount(); i--; ) {
          if (info->isRefParam(i)) {
            m_params->markParam(i, canInvokeFewArgs());
          }
        }
      }
      // If we cannot find information of the so-named function, it might not
      // exist, or it might go through __call(), either of which cannot have
      // reference parameters.
    } else {
      for (int i = params.getCount(); i--; ) {
        m_params->markParam(i, canInvokeFewArgs());
      }
    }
  }
}
Пример #9
0
void ClassVariable::analyzeProgramImpl(AnalysisResultPtr ar) {
  m_declaration->analyzeProgram(ar);
  if (ar->getPhase() != AnalysisResult::AnalyzeInclude) return;
  ClassScopePtr scope = ar->getClassScope();
  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
      ExpressionPtr value = assignment->getValue();
      scope->getVariables()->setClassInitVal(var->getName(), value);
    }
  }
}
Пример #10
0
bool UnaryOpExpression::outputCPPImplOpEqual(CodeGenerator &cg,
                                             AnalysisResultPtr ar) {
  if (m_exp->is(Expression::KindOfObjectPropertyExpression)) {
    ObjectPropertyExpressionPtr var(
      dynamic_pointer_cast<ObjectPropertyExpression>(m_exp));
    if (var->isValid()) return false;
    var->outputCPPObject(cg, ar);
    cg_printf("o_assign_op<%s,%d>(",
              isUnused() ? "void" : "Variant", m_op);
    var->outputCPPProperty(cg, ar);
    cg_printf(", %s, %s)",
              isUnused() || m_front ? "null_variant" : "Variant(0)",
              ar->getClassScope() ? "s_class_name" : "empty_string");
    return true;
  }
  return false;
}
Пример #11
0
void MethodStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();

  // registering myself as a parent in dependency graph, so that
  // (1) we can tell orphaned parents
  // (2) overwrite non-master copy of function declarations
  if (ar->isFirstPass()) {
    ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall,
                                        "", getFullName(), shared_from_this());
    if (Option::AllDynamic || hasHphpNote("Dynamic") ||
        funcScope->isSepExtension() ||
        BuiltinSymbols::IsDeclaredDynamic(m_name) ||
        Option::IsDynamicFunction(m_method, m_name)) {
      funcScope->setDynamic();
    }
    if (hasHphpNote("Volatile")) funcScope->setVolatile();
  }

  funcScope->setIncludeLevel(ar->getIncludeLevel());
  ar->pushScope(funcScope);
  if (m_params) {
    m_params->analyzeProgram(ar);
    if (Option::GenRTTIProfileData &&
        ar->getPhase() == AnalysisResult::AnalyzeFinal) {
      addParamRTTI(ar);
    }
  }
  if (m_stmt) m_stmt->analyzeProgram(ar);

  if (ar->isFirstPass()) {
    if (!funcScope->isStatic() && ar->getClassScope() &&
        funcScope->getVariables()->
        getAttribute(VariableTable::ContainsDynamicVariable)) {
      // Add this to variable table if we'll need it in a lookup table
      // Use object because there's no point to specializing, just makes
      // code gen harder when dealing with redeclared classes.
      TypePtr tp(NEW_TYPE(Object));
      funcScope->getVariables()->add("this", tp, true, ar, shared_from_this(),
                                     ModifierExpressionPtr());
    }
    FunctionScope::RecordRefParamInfo(m_name, funcScope);
  }
  ar->popScope();
}
Пример #12
0
bool MethodStatement::outputFFI(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  ClassScopePtr clsScope = ar->getClassScope();
  bool pseudoMain = funcScope->inPseudoMain();
  bool inClass = !m_className.empty();
  // only expose public methods, and ignore those in redeclared classes
  bool inaccessible =
    inClass && (!m_modifiers->isPublic() || clsScope->isRedeclaring());
  // skip constructors
  bool isConstructor = inClass && funcScope->isConstructor(clsScope);
  bool valid = !pseudoMain && !inaccessible && !isConstructor;

  if (cg.getContext() == CodeGenerator::CppFFIDecl ||
      cg.getContext() == CodeGenerator::CppFFIImpl) {
    if (valid) outputCPPFFIStub(cg, ar);
    return true;
  }

  if (cg.getContext() == CodeGenerator::HsFFI) {
    if (valid) outputHSFFIStub(cg, ar);
    return true;
  }

  if (cg.getContext() == CodeGenerator::JavaFFI
   || cg.getContext() == CodeGenerator::JavaFFIInterface) {
    if (valid) outputJavaFFIStub(cg, ar);
    return true;
  }

  if (cg.getContext() == CodeGenerator::JavaFFICppDecl
   || cg.getContext() == CodeGenerator::JavaFFICppImpl) {
    if (valid) outputJavaFFICPPStub(cg, ar);
    return true;
  }

  if (cg.getContext() == CodeGenerator::SwigFFIDecl
   || cg.getContext() == CodeGenerator::SwigFFIImpl) {
    if (valid) outputSwigFFIStub(cg, ar);
    return true;
  }

  return false;
}
Пример #13
0
bool FunctionScope::outputCPPInvokeArgCountCheck(CodeGenerator &cg,
    AnalysisResultPtr ar, bool ret, bool constructor) {
  bool variable = isVariableArgument();
  // system function has different handling of argument counts
  bool system = (m_system || m_sep ||
                 cg.getOutput() == CodeGenerator::SystemCPP);
  if (!system) {
    ClassScopePtr scope = ar->getClassScope();
    if (scope) system = (!scope->isUserClass() || scope->isExtensionClass() ||
                         scope->isSepExtension());
  }

  bool checkMissing = (m_minParam > 0);
  bool checkTooMany = (!variable && (system ||
                                     RuntimeOption::ThrowTooManyArguments));
  const char *sysret = (system && ret) ? "return " : "";
  const char *level = (system ? (constructor ? ", 2" : ", 1") : "");
  bool guarded = system && (ret || constructor);
  string fullname = getOriginalFullName();
  if (checkMissing && checkTooMany) {
    if (!variable && m_minParam == m_maxParam) {
      cg_printf("if (count != %d)"
                " %sthrow_wrong_arguments(\"%s\", count, %d, %d%s);\n",
                m_minParam, sysret, fullname.c_str(), m_minParam, m_maxParam,
                level);
    } else {
      cg_printf("if (count < %d || count > %d)"
                " %sthrow_wrong_arguments(\"%s\", count, %d, %d%s);\n",
                m_minParam, m_maxParam, sysret, fullname.c_str(),
                m_minParam, variable ? -1 : m_maxParam, level);
    }
  } else if (checkMissing) {
    cg_printf("if (count < %d)"
              " %sthrow_missing_arguments(\"%s\", count+1%s);\n",
              m_minParam, sysret, fullname.c_str(), level);
  } else if (checkTooMany) {
    cg_printf("if (count > %d)"
              " %sthrow_toomany_arguments(\"%s\", %d%s);\n",
              m_maxParam, sysret, fullname.c_str(), m_maxParam, level);
  }
  return guarded;
}
Пример #14
0
void ClassVariable::inferTypes(AnalysisResultPtr ar) {
  m_declaration->inferAndCheck(ar, NEW_TYPE(Some), false);

  if (m_modifiers->isStatic()) {
    ClassScopePtr scope = ar->getClassScope();
    for (int i = 0; i < m_declaration->getCount(); i++) {
      ExpressionPtr exp = (*m_declaration)[i];
      if (exp->is(Expression::KindOfAssignmentExpression)) {
        scope->setNeedStaticInitializer();
        AssignmentExpressionPtr assignment =
          dynamic_pointer_cast<AssignmentExpression>(exp);
        // If the class variable's type is Object, we have to
        // force it to be a Variant, because we don't include
        // the class header files in global_variables.h
        SimpleVariablePtr var =
          dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
        if (var) {
          TypePtr type = scope->getVariables()->getFinalType(var->getName());
          if (type->is(Type::KindOfObject)) {
            scope->getVariables()->forceVariant(ar, var->getName());
          }
        }
        ExpressionPtr value = assignment->getValue();
        if (value->containsDynamicConstant(ar)) {
          scope->getVariables()->
            setAttribute(VariableTable::ContainsDynamicStatic);
        }
      } else {
        SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp);
        TypePtr type = scope->getVariables()->getFinalType(var->getName());
        // If the class variable's type is Object, we have to
        // force it to be a Variant, because we don't include
        // the class header files in global_variables.h
        if (type->is(Type::KindOfObject)) {
          scope->getVariables()->forceVariant(ar, var->getName());
        }
        const char *initializer = type->getCPPInitializer();
        if (initializer) scope->setNeedStaticInitializer();
      }
    }
  }
}
Пример #15
0
void ConstantTable::outputCPPDynamicDecl(CodeGenerator &cg,
                                         AnalysisResultPtr ar) {
  const char *prefix = Option::ConstantPrefix;
  string classId;
  const char *fmt = "Variant %s%s%s;\n";
  ClassScopePtr scope = ar->getClassScope();
  if (scope) {
    prefix = Option::ClassConstantPrefix;
    classId = scope->getId();
    fmt = "Variant %s%s_%s;\n";
  }

  for (StringToConstructPtrMap::const_iterator iter = m_declarations.begin();
       iter != m_declarations.end(); ++iter) {
    const string &name = iter->first;
    if (isDynamic(name)) {
      cg.printf(fmt, prefix, classId.c_str(), name.c_str());
    }
  }
}
Пример #16
0
void ConstantTable::outputCPPDynamicDecl(CodeGenerator &cg,
                                         AnalysisResultPtr ar) {
  const char *prefix = Option::ConstantPrefix;
  string classId;
  const char *fmt = "Variant %s%s%s;\n";
  ClassScopePtr scope = ar->getClassScope();
  if (scope) {
    prefix = Option::ClassConstantPrefix;
    classId = scope->getId(cg);
    fmt = "Variant %s%s_%s;\n";
  }

  for (StringToSymbolMap::iterator iter = m_symbolMap.begin(),
         end = m_symbolMap.end(); iter != end; ++iter) {
    Symbol *sym = &iter->second;
    if (sym->declarationSet() && sym->isDynamic()) {
      cg_printf(fmt, prefix, classId.c_str(),
                cg.formatLabel(sym->getName()).c_str());
    }
  }
}
Пример #17
0
void FunctionScope::outputCPPCreateDecl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  ClassScopePtr scope = ar->getClassScope();

  cg.printf("public: %s%s *create(",
            Option::ClassPrefix, scope->getId().c_str());
  outputCPPParamsDecl(cg, ar,
                      dynamic_pointer_cast<MethodStatement>(getStmt())
                      ->getParams(), true);
  cg.printf(");\n");
  cg.printf("public: ObjectData *dynCreate(CArrRef params, bool init = true);"
            "\n");
  if (isDynamic()) {
    cg.printf("public: void dynConstruct(CArrRef params);\n");
    if (cg.getOutput() == CodeGenerator::SystemCPP ||
        Option::EnableEval >= Option::LimitedEval) {
      cg.printf("public: void dynConstructFromEval(Eval::VariableEnvironment "
                "&env, const Eval::FunctionCallExpression *call);\n");
    }
  }
}
Пример #18
0
void AssignmentExpression::onParse(AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();

  // This is that much we can do during parse phase.
  TypePtr type;
  if (m_value->is(Expression::KindOfScalarExpression)) {
    type = m_value->inferAndCheck(ar, NEW_TYPE(Some), false);
  } else if (m_value->is(Expression::KindOfUnaryOpExpression)) {
    UnaryOpExpressionPtr uexp =
      dynamic_pointer_cast<UnaryOpExpression>(m_value);
    if (uexp->getOp() == T_ARRAY) {
      type = Type::Array;
    }
  }
  if (!type) type = NEW_TYPE(Some);

  if (m_variable->is(Expression::KindOfConstantExpression)) {
    // ...as in ClassConstant statement
    // We are handling this one here, not in ClassConstant, purely because
    // we need "value" to store in constant table.
    ConstantExpressionPtr exp =
      dynamic_pointer_cast<ConstantExpression>(m_variable);
    scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable);

    string name = ar->getClassScope()->getName() + "::" + exp->getName();
    ar->getDependencyGraph()->
      addParent(DependencyGraph::KindOfConstant, "", name, exp);
  } else if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable);
    scope->getVariables()->add(var->getName(), type, true, ar,
                               shared_from_this(), scope->getModifiers());
    var->clearContext(Declaration); // to avoid wrong CodeError
  } else {
    ASSERT(false); // parse phase shouldn't handle anything else
  }
}
Пример #19
0
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  ClassScopePtr scope = ar->getClassScope();
  string origFuncName;
  ar->pushScope(funcScope);

  if (outputFFI(cg, ar)) return;

  cg.setPHPLineNo(-1);

  if (cg.getContext() == CodeGenerator::CppImplementation) {
    printSource(cg);
  }

  switch (cg.getContext()) {
  case CodeGenerator::CppDeclaration:
    {
      if (!m_stmt) {
        cg.printf("// ");
      }
      m_modifiers->outputCPP(cg, ar);

      if (m_name == "__offsetget_lval") {
        cg.printf("virtual ");
      }
      TypePtr type = funcScope->getReturnType();
      if (type) {
        type->outputCPPDecl(cg, ar);
      } else {
        cg.printf("void");
      }
      if (m_name == "__lval") {
        cg.printf(" &___lval(");
      } else if (m_name == "__offsetget_lval") {
        cg.printf(" &___offsetget_lval(");
      } else if (m_modifiers->isStatic() && m_stmt) {
        // Static method wrappers get generated as support methods
        cg.printf(" %s%s(const char* cls%s", Option::MethodImplPrefix,
                  m_name.c_str(),
                  funcScope->isVariableArgument() ||
                  (m_params && m_params->getCount()) ? ", " : "");
      } else {
        cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str());
      }
      funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
      if (m_stmt) {
        cg.printf(");\n");
      } else {
        cg.printf(") = 0;\n");
      }

      if (funcScope->isConstructor(scope)
       && !funcScope->isAbstract() && !scope->isInterface()) {
        funcScope->outputCPPCreateDecl(cg, ar);
      }
    }
    break;
  case CodeGenerator::CppImplementation:
    if (m_stmt) {
      TypePtr type = funcScope->getReturnType();
      if (type) {
        type->outputCPPDecl(cg, ar);
      } else {
        cg.printf("void");
      }
      origFuncName = std::string(scope->getOriginalName()) +
                     "::" + m_originalName;
      if (Option::HotFunctions.find(origFuncName) !=
          Option::HotFunctions.end()) {
        cg.printf(" __attribute((__section__(\".text.hot\")))");
      } else if (Option::ColdFunctions.find(origFuncName) !=
                 Option::ColdFunctions.end()) {
        cg.printf(" __attribute((__section__(\".text.cold\")))");
      }
      if (m_name == "__lval") {
        cg.printf(" &%s%s::___lval(",
                  Option::ClassPrefix, scope->getId().c_str());
      } else if (m_name == "__offsetget_lval") {
        cg.printf(" &%s%s::___offsetget_lval(",
                  Option::ClassPrefix, scope->getId().c_str());
      } else if (m_modifiers->isStatic()) {
        cg.printf(" %s%s::%s%s(const char* cls%s", Option::ClassPrefix,
                  scope->getId().c_str(),
                  Option::MethodImplPrefix, m_name.c_str(),
                  funcScope->isVariableArgument() ||
                  (m_params && m_params->getCount()) ? ", " : "");
      } else {
        cg.printf(" %s%s::%s%s(", Option::ClassPrefix, scope->getId().c_str(),
                  Option::MethodPrefix, m_name.c_str());
      }
      funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
      cg.indentBegin(") {\n");
      if (m_modifiers->isStatic()) {
        cg.printf("STATIC_METHOD_INJECTION(%s, %s::%s);\n",
                  scope->getOriginalName(), scope->getOriginalName(),
                  m_originalName.c_str());
      } else {
        cg.printf("INSTANCE_METHOD_INJECTION(%s, %s::%s);\n",
                  scope->getOriginalName(), scope->getOriginalName(),
                  m_originalName.c_str());
      }
      if (Option::GenRTTIProfileData && m_params) {
        for (int i = 0; i < m_params->getCount(); i++) {
          ParameterExpressionPtr param =
            dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
          if (param->hasRTTI()) {
            const string &paramName = param->getName();
            int id = ar->getParamRTTIEntryId(ar->getClassScope(), funcScope,
                                             paramName);
            if (id != -1) {
              cg.printf("RTTI_INJECTION(%s%s, %d);\n",
                        Option::VariablePrefix, paramName.c_str(), id);
            }
          }
        }
      }
      if (m_name == "__lval" || m_name == "__offsetget_lval") {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_params)[0]);
        cg.printf("Variant &v = %s->__lvalProxy;\n",
                  cg.getOutput() == CodeGenerator::SystemCPP ?
                  "get_system_globals()" : "get_global_variables()");
        string lowered = Util::toLower(m_originalName);
        cg.printf("v = %s%s(%s%s);\n",
                  Option::MethodPrefix, lowered.c_str(),
                  Option::VariablePrefix, param->getName().c_str());
        cg.printf("return v;\n");
      } else {
        if (funcScope->isConstructor(scope)) {
          cg.printf("bool oldInCtor = gasInCtor(true);\n");
        } else if (m_name == "__destruct") {
          cg.printf("setInDtor();\n");
        } else if (m_name == "__call") {
          ParameterExpressionPtr param;
          if (m_params->getCount() > 0) {
            param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]);
            cg.printf("INCALL_HELPER(%s%s);\n",
                      Option::VariablePrefix, param->getName().c_str());
          } else {
            cg.printf("INCALL_HELPER(\"\");\n");
          }
        }
        funcScope->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
        if (!funcScope->isStatic() && funcScope->getVariables()->
            getAttribute(VariableTable::ContainsDynamicVariable)) {
          cg.printf("%sthis = this;\n", Option::VariablePrefix);
        }
        outputCPPStmt(cg, ar);
        cg.setContext(CodeGenerator::CppImplementation);
      }
      cg.indentEnd("} /* function */\n");
    }
    break;
  default:
    break;
  }

  ar->popScope();
}
Пример #20
0
void ClassVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr scope = ar->getClassScope();
  bool derivFromRedec = scope->derivesFromRedeclaring() &&
    !m_modifiers->isPrivate();
  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];

    SimpleVariablePtr var;
    TypePtr type;

    switch (cg.getContext()) {
    case CodeGenerator::CppConstructor:
      if (m_modifiers->isStatic()) continue;

      if (exp->is(Expression::KindOfAssignmentExpression)) {
        AssignmentExpressionPtr assignment =
          dynamic_pointer_cast<AssignmentExpression>(exp);

        var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
        ExpressionPtr value = assignment->getValue();
        value->outputCPPBegin(cg, ar);
        if (derivFromRedec) {
          cg_printf("%sset(\"%s\",-1, ", Option::ObjectPrefix,
                    var->getName().c_str());
          value->outputCPP(cg, ar);
          cg_printf(")");
        } else {
          cg_printf("%s%s = ", Option::PropertyPrefix, var->getName().c_str());
          value->outputCPP(cg, ar);
        }
        cg_printf(";\n");
        value->outputCPPEnd(cg, ar);
      } else {
        var = dynamic_pointer_cast<SimpleVariable>(exp);
        if (derivFromRedec) {
          cg_printf("%sset(\"%s\",-1, null);\n", Option::ObjectPrefix,
                    var->getName().c_str());
        } else  {
          type = scope->getVariables()->getFinalType(var->getName());
          const char *initializer = type->getCPPInitializer();
          if (initializer) {
            cg_printf("%s%s = %s;\n", Option::PropertyPrefix,
                      var->getName().c_str(), initializer);
          }
        }
      }
      break;

    case CodeGenerator::CppStaticInitializer:
      {
        if (!m_modifiers->isStatic()) continue;

        VariableTablePtr variables = scope->getVariables();
        if (exp->is(Expression::KindOfAssignmentExpression)) {
          AssignmentExpressionPtr assignment =
            dynamic_pointer_cast<AssignmentExpression>(exp);

          var = dynamic_pointer_cast<SimpleVariable>
            (assignment->getVariable());
          ExpressionPtr value = assignment->getValue();
          if (value->containsDynamicConstant(ar)) continue;
          cg_printf("g->%s%s%s%s = ",
                    Option::StaticPropertyPrefix, scope->getId(cg).c_str(),
                    Option::IdPrefix.c_str(), var->getName().c_str());

          value->outputCPP(cg, ar);
        } else {
          var = dynamic_pointer_cast<SimpleVariable>(exp);
          type = scope->getVariables()->getFinalType(var->getName());
          const char *initializer = type->getCPPInitializer();
          if (initializer) {
            cg_printf("g->%s%s%s%s = %s",
                      Option::StaticPropertyPrefix, scope->getId(cg).c_str(),
                      Option::IdPrefix.c_str(), var->getName().c_str(),
                      initializer);
          }
        }
        cg_printf(";\n");
      }
      break;
    case CodeGenerator::CppLazyStaticInitializer:
      {
        if (!m_modifiers->isStatic()) continue;
        if (!exp->is(Expression::KindOfAssignmentExpression)) continue;
        VariableTablePtr variables = scope->getVariables();
        AssignmentExpressionPtr assignment =
          dynamic_pointer_cast<AssignmentExpression>(exp);
        var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
        ExpressionPtr value = assignment->getValue();
        if (!value->containsDynamicConstant(ar)) continue;
        value->outputCPPBegin(cg, ar);
        cg_printf("g->%s%s%s%s = ",
                  Option::StaticPropertyPrefix, scope->getId(cg).c_str(),
                  Option::IdPrefix.c_str(), var->getName().c_str());
        value->outputCPP(cg, ar);
        cg_printf(";\n");
        value->outputCPPEnd(cg, ar);
      }
      break;
    default:
      break;
    }
  }
}
Пример #21
0
TypePtr SimpleFunctionCall::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
                                          bool coerce) {
  reset();

  ConstructPtr self = shared_from_this();

  // handling define("CONSTANT", ...);
  if (m_className.empty()) {
    if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
      ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
      string varName;
      if (name) {
        varName = name->getIdentifier();
        if (!varName.empty()) {
          ExpressionPtr value = (*m_params)[1];
          TypePtr varType = value->inferAndCheck(ar, NEW_TYPE(Some), false);
          ar->getDependencyGraph()->
            addParent(DependencyGraph::KindOfConstant,
                      ar->getName(), varName, self);
          ConstantTablePtr constants =
            ar->findConstantDeclarer(varName)->getConstants();
          if (constants != ar->getConstants()) {
            if (value && !value->isScalar()) {
              constants->setDynamic(ar, varName);
              varType = Type::Variant;
            }
            if (constants->isDynamic(varName)) {
              m_dynamicConstant = true;
              ar->getScope()->getVariables()->
                setAttribute(VariableTable::NeedGlobalPointer);
            } else {
              constants->setType(ar, varName, varType, true);
            }
            // in case the old 'value' has been optimized
            constants->setValue(ar, varName, value);
          }
          return checkTypesImpl(ar, type, Type::Boolean, coerce);
        }
      }
      if (varName.empty() && ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::BadDefine, self);
      }
    } else if (m_type == ExtractFunction) {
      ar->getScope()->getVariables()->forceVariants(ar);
    }
  }

  FunctionScopePtr func;

  // avoid raising both MissingObjectContext and UnknownFunction
  bool errorFlagged = false;

  if (m_className.empty()) {
    func = ar->findFunction(m_name);
  } else {
    ClassScopePtr cls = ar->resolveClass(m_className);
    if (cls && cls->isVolatile()) {
      ar->getScope()->getVariables()
        ->setAttribute(VariableTable::NeedGlobalPointer);
    }
    if (!cls || cls->isRedeclaring()) {
      if (cls) {
        m_redeclaredClass = true;
      }
      if (!cls && ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::UnknownClass, self);
      }
      if (m_params) {
        m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
      }
      return checkTypesImpl(ar, type, Type::Variant, coerce);
    }
    m_derivedFromRedeclaring = cls->derivesFromRedeclaring();
    m_validClass = true;

    if (m_name == "__construct") {
      // if the class is known, php will try to identify class-name ctor
      func = cls->findConstructor(ar, true);
    }
    else {
      func = cls->findFunction(ar, m_name, true, true);
    }

    if (func && !func->isStatic()) {
      ClassScopePtr clsThis = ar->getClassScope();
      FunctionScopePtr funcThis = ar->getFunctionScope();
      if (!clsThis ||
          (clsThis->getName() != m_className &&
           !clsThis->derivesFrom(ar, m_className)) ||
          funcThis->isStatic()) {
        // set the method static to avoid "unknown method" runtime exception
        if (Option::StaticMethodAutoFix && !func->containsThis()) {
          func->setStatic();
        }
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::MissingObjectContext,
                                     self);
          errorFlagged = true;
        }
        func.reset();
      }
    }
  }
  if (!func || func->isRedeclaring()) {
    if (func) {
      m_redeclared = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
    }
    if (!func && !errorFlagged && ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UnknownFunction, self);
    }
    if (m_params) {
      if (func) {
        FunctionScope::RefParamInfoPtr info =
          FunctionScope::GetRefParamInfo(m_name);
        ASSERT(info);
        for (int i = m_params->getCount(); i--; ) {
          if (info->isRefParam(i)) {
            m_params->markParam(i, canInvokeFewArgs());
          }
        }
      }
      m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
    }
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }
  m_builtinFunction = !func->isUserFunction();

  if (m_redeclared) {
    if (m_params) {
      m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
    }
    return checkTypesImpl(ar, type, type, coerce);
  }

  CHECK_HOOK(beforeSimpleFunctionCallCheck);

  m_valid = true;
  type = checkParamsAndReturn(ar, type, coerce, func);

  if (!m_valid && m_params) {
    m_params->markParams(false);
  }

  CHECK_HOOK(afterSimpleFunctionCallCheck);

  return type;
}
Пример #22
0
void AssignmentExpression::outputCPPImpl(CodeGenerator &cg,
                                         AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();
  bool ref = (m_ref && m_value->isRefable());

  bool setNull = false;
  bool arrayLike = false;

  if (m_variable->is(Expression::KindOfArrayElementExpression)) {
    ArrayElementExpressionPtr exp =
      dynamic_pointer_cast<ArrayElementExpression>(m_variable);
    if (!exp->isSuperGlobal() && !exp->isDynamicGlobal()) {
      exp->getVariable()->outputCPP(cg, ar);
      if (exp->getOffset()) {
        cg_printf(".set(");
        exp->getOffset()->outputCPP(cg, ar);
        cg_printf(", (");
      } else {
        cg_printf(".append((");
      }
      wrapValue(cg, ar, m_value, ref, true);
      cg_printf(")");
      ExpressionPtr off = exp->getOffset();
      if (off) {
        ScalarExpressionPtr sc =
          dynamic_pointer_cast<ScalarExpression>(off);
        if (sc) {
          if (sc->isLiteralString()) {
            String s(sc->getLiteralString());
            int64 n;
            if (!s.get()->isStrictlyInteger(n)) {
              cg_printf(", true"); // skip toKey() at run time
            }
          }
        }
      }
      cg_printf(")");
      return;
    }
  } else if (m_variable->is(Expression::KindOfObjectPropertyExpression)) {
    ObjectPropertyExpressionPtr var(
      dynamic_pointer_cast<ObjectPropertyExpression>(m_variable));
    if (!var->isValid()) {
      var->outputCPPObject(cg, ar);
      cg_printf("o_set(");
      var->outputCPPProperty(cg, ar);
      cg_printf(", %s", ref ? "ref(" : "");
      m_value->outputCPP(cg, ar);
      cg_printf("%s, %s)",
                ref ? ")" : "",
                ar->getClassScope() ? "s_class_name" : "empty_string");
      return;
    }
  } else if (m_variable->is(Expression::KindOfSimpleVariable) &&
      m_value->is(Expression::KindOfConstantExpression)) {
    ConstantExpressionPtr exp =
      dynamic_pointer_cast<ConstantExpression>(m_value);
    if (exp->isNull()) setNull = true;
  }

  bool wrapped = true;
  if (setNull) {
    cg_printf("setNull(");
    m_variable->outputCPP(cg, ar);
  } else {
    if ((wrapped = !isUnused())) {
      cg_printf("(");
    }
    m_variable->outputCPP(cg, ar);
    cg_printf(" = ");

    wrapValue(cg, ar, m_value, ref, arrayLike);
  }
  if (wrapped) {
    cg_printf(")");
  }
}
Пример #23
0
FunctionScopePtr MethodStatement::onParseImpl(AnalysisResultPtr ar) {
  int minParam, maxParam;
  ConstructPtr self = shared_from_this();
  minParam = maxParam = 0;
  bool hasRef = false;
  if (m_params) {
    set<string> names;
    int i = 0;
    maxParam = m_params->getCount();
    for (; i < maxParam; i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (param->isRef()) hasRef = true;
      if (param->isOptional()) break;
      minParam++;
    }
    for (i++; i < maxParam; i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (param->isRef()) hasRef = true;
      if (!param->isOptional()) {
        ar->getCodeError()->record(self, CodeError::RequiredAfterOptionalParam,
                                   param);
        param->defaultToNull(ar);
      }
    }

    if (ar->isFirstPass()) {
      for (i = 0; i < maxParam; i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
        if (names.find(param->getName()) == names.end()) {
          names.insert(param->getName());
        } else {
          ar->getCodeError()->record(self,
                                     CodeError::RedundantParameter, param);
          for (int j = 0; j < 1000; j++) {
            string name = param->getName() + lexical_cast<string>(j);
            if (names.find(name) == names.end()) {
              param->rename(name);
              break;
            }
          }
        }
      }
    }
  }

  if (hasRef || m_ref) {
    m_attribute |= FileScope::ContainsReference;
  }

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  FunctionScopePtr funcScope
    (new FunctionScope(ar, m_method, m_name, stmt, m_ref, minParam, maxParam,
                       m_modifiers, m_attribute, m_docComment,
                       ar->getFileScope()));
  if (!m_stmt) {
    funcScope->setVirtual();
  }
  m_funcScope = funcScope;

  // TODO: this may have to expand to a concept of "virtual" functions...
  if (ar->getClassScope()) {
    funcScope->disableInline();
    if (m_name.length() > 2 && m_name.substr(0,2) == "__") {
      bool magic = true;
      int paramCount = 0;
      if (m_name == "__destruct") {
        funcScope->setOverriding(Type::Variant);
      } else if (m_name == "__call") {
        funcScope->setOverriding(Type::Variant, Type::String, Type::Array);
        paramCount = 2;
      } else if (m_name == "__set") {
        funcScope->setOverriding(Type::Variant, Type::String, Type::Variant);
        paramCount = 2;
      } else if (m_name == "__get") {
        funcScope->setOverriding(Type::Variant, Type::String);
        paramCount = 1;
      } else if (m_name == "__isset") {
        funcScope->setOverriding(Type::Boolean, Type::String);
        paramCount = 1;
      } else if (m_name == "__unset") {
        funcScope->setOverriding(Type::Variant, Type::String);
        paramCount = 1;
      } else if (m_name == "__sleep") {
        funcScope->setOverriding(Type::Variant);
      } else if (m_name == "__wakeup") {
        funcScope->setOverriding(Type::Variant);
      } else if (m_name == "__set_state") {
        funcScope->setOverriding(Type::Variant, Type::Variant);
        paramCount = 1;
      } else if (m_name == "__tostring") {
        funcScope->setOverriding(Type::String);
      } else if (m_name == "__clone") {
        funcScope->setOverriding(Type::Variant);
      } else {
        paramCount = -1;
        if (m_name != "__construct") {
          ar->getCodeError()->record(self, CodeError::UnknownMagicMethod,
                                     self);
          magic = false;
        }
      }
      if (paramCount >= 0 &&
          (paramCount != minParam || paramCount != maxParam)) {
        ar->getCodeError()->record(self, CodeError::InvalidMagicMethod,
                                   self);
        magic = false;
      }
      if (magic) funcScope->setMagicMethod();
    }
    // ArrayAccess methods
    else if (m_name.length() > 6 && m_name.substr(0, 6) == "offset") {
      if (m_name == "offsetexists") {
        funcScope->setOverriding(Type::Boolean, Type::Variant);
      } else if (m_name == "offsetget") {
        funcScope->setOverriding(Type::Variant, Type::Variant);
      } else if (m_name == "offsetset") {
        funcScope->setOverriding(Type::Variant, Type::Variant, Type::Variant);
      } else if (m_name == "offsetunset") {
        funcScope->setOverriding(Type::Variant, Type::Variant);
      }
    }
  }

  return funcScope;
}
Пример #24
0
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);
  }
}
Пример #25
0
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;
    if (m_exp) {
      ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
      Variant v;
      if (pairs && pairs->isScalarArrayPairs() && pairs->getScalarValue(v)) {
        id = ar->registerScalarArray(m_exp, hash, index);
      }
    } else {
      id = ar->registerScalarArray(m_exp, hash, index); // empty array
    }
    if (id != -1) {
      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 (ar->getClassScope()) {
          FunctionScopePtr fs = ar->getFunctionScope();
          instance = fs && !fs->isStatic();
        } else {
          instance = false;
        }
        cg_printf("eval(%s, Object(%s), ",
                  ar->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 '@':
      // Void needs to return something to silenceDec
      if (!m_exp->hasCPPTemp() && !m_exp->getActualType()) {
        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);
    }
  }
}
Пример #26
0
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
    if (m_arrayId != -1) {
        if (cg.getOutput() == CodeGenerator::SystemCPP) {
            cg.printf("SystemScalarArrays::%s[%d]",
                      Option::SystemScalarArrayName, m_arrayId);
        } else {
            cg.printf("ScalarArrays::%s[%d]",
                      Option::ScalarArrayName, m_arrayId);
        }
        return;
    }

    if ((m_op == T_ISSET || m_op == T_EMPTY) && m_exp) {
        if (m_exp->is(Expression::KindOfExpressionList)) {
            ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
            if (exps->getCount() > 1) {
                cg.printf("(");
            }
            for (int i = 0; i < exps->getCount(); i++) {
                if (i > 0) cg.printf(" && ");
                (*exps)[i]->outputCPPExistTest(cg, ar, m_op);
            }
            if (exps->getCount() > 1) {
                cg.printf(")");
            }
        } 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:
            cg.printf("unset(");
            break;
        case T_EXIT:
            cg.printf("f_exit(");
            break;
        case T_ARRAY:
            if (ar->getInsideScalarArray()) {
                cg.printf("StaticArray(");
            } else {
                cg.printf("Array(");
            }
            break;
        case T_PRINT:
            cg.printf("print(");
            break;
        case T_EVAL:
            if (Option::EnableEval > Option::NoEval) {
                cg.printf("eval(%s, Object(%s), ",
                          ar->getScope()->inPseudoMain() ?
                          "get_variable_table()" : "variables",
                          ar->getClassScope() ? "this" : "");
            } else {
                cg.printf("f_eval(");
            }
            break;
        case '@':
            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 '@':
            // Void needs to return something to silenceDec
            if (!m_exp->getActualType()) {
                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_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_UNSET_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 '@':
            cg.printf("))");
            break;
        default:
            break;
        }
    } else {
        switch (m_op) {
        case T_INC:
            cg.printf("++");
            break;
        case T_DEC:
            cg.printf("--");
            break;
        default:
            ASSERT(false);
        }
    }
}
Пример #27
0
void FunctionScope::outputCPPDynamicInvoke(CodeGenerator &cg,
                                           AnalysisResultPtr ar,
                                           const char *funcPrefix,
                                           const char *name,
                                           bool voidWrapperOff /* = false */,
                                           bool fewArgs /* = false */,
                                           bool ret /* = true */,
                                           const char *extraArg /* = NULL */,
                                           bool constructor /* = false */) {
  const char *voidWrapper = (m_returnType || voidWrapperOff) ? "" : ", null";
  const char *retrn = ret ? "return " : "";
  int maxParam = fewArgs && m_maxParam > Option::InvokeFewArgsCount ?
    Option::InvokeFewArgsCount : m_maxParam;

  bool variable = isVariableArgument();

  ASSERT(m_minParam >= 0);

  bool guarded = outputCPPInvokeArgCountCheck(cg, ar, ret, constructor);
  bool do_while = !ret && !fewArgs && maxParam > m_minParam;

  if (!fewArgs && maxParam) {
    for (int i = 0; i < maxParam; i++) {
      if (isRefParam(i)) {
        cg_printf("const_cast<Array&>(params).escalate(true);\n");
        break;
      }
    }
    if (do_while) cg_printf("do ");
    cg_indentBegin("{\n");
    cg_printf("ArrayData *ad(params.get());\n");
    cg_printf("ssize_t pos = ad ? ad->iter_begin() : "
              "ArrayData::invalid_index;\n");
    for (int i = 0; i < m_minParam; i++) {
      cg_printf("CVarRef arg%d(", i);
      if (!guarded) cg_printf("count <= %d ? null_variant : ", i);
      cg_printf("%s(ad->getValue%s(pos%s)));\n",
                isRefParam(i) ? "ref" : "",
                isRefParam(i) ? "Ref" : "",
                i ? " = ad->iter_advance(pos)" : "");
    }
  }

  if (variable || getOptionalParamCount()) {
    if (!fewArgs || m_minParam < Option::InvokeFewArgsCount) {
      cg_printf("if (count <= %d) ", m_minParam);
      if (do_while) cg_indentBegin("{\n");
    }
  }

  stringstream callss;
  callss << retrn << (m_refReturn ? "ref(" : "(");
  if (m_perfectVirtual) {
    ClassScopePtr cls = ar->getClassScope();
    callss << Option::ClassPrefix << cls->getId(cg) << "::";
  }
  callss << funcPrefix << name << "(";
  if (extraArg) {
    callss << extraArg;
    if (variable) {
      callss << ",";
    }
  }
  if (variable) {
    callss << "count";
  }
  bool preArgs = variable || extraArg;
  string call = callss.str();

  cg_printf("%s", call.c_str());
  for (int i = 0; i < m_minParam; i++) {
    if (preArgs || i > 0) cg_printf(", ");
    if (isRefParam(i)) {
      if (fewArgs) {
        if (i < Option::InvokeFewArgsCount) {
          cg_printf("ref(a%d)", i);
        } else {
          cg_printf("null_variant");
        }
      } else {
        cg_printf("arg%d", i);
      }
    } else {
      if (fewArgs) {
        if (i < Option::InvokeFewArgsCount) {
          cg_printf("a%d", i);
        } else {
          cg_printf("null");
        }
      } else {
        cg_printf("arg%d", i);
      }
    }
  }
  cg_printf(")%s);\n", voidWrapper);

  for (int iMax = m_minParam; iMax < maxParam; ) {
    if (!ret) {
      if (do_while) {
        cg_printf("break;\n");
        cg_indentEnd("}\n");
      } else {
        cg_printf("else ");
      }
    }
    if (!fewArgs) {
      cg_printf("CVarRef arg%d(%s(ad->getValue%s(pos%s)));\n",
                iMax,
                isRefParam(iMax) ? "ref" : "",
                isRefParam(iMax) ? "Ref" : "",
                iMax ? " = ad->iter_advance(pos)" : "");
    }
    if (++iMax < maxParam || variable) {
      cg_printf("if (count == %d) ", iMax);
      if (do_while) cg_indentBegin("{\n");
    }
    cg_printf("%s", call.c_str());
    for (int i = 0; i < iMax; i++) {
      if (preArgs || i > 0) cg_printf(", ");
      if (isRefParam(i)) {
        if (fewArgs) {
          if (i < Option::InvokeFewArgsCount) {
            cg_printf("ref(a%d)", i);
          } else {
            cg_printf("null_variant");
          }
        } else {
          cg_printf("arg%d", i);
        }
      } else {
        if (fewArgs) {
          if (i < Option::InvokeFewArgsCount) {
            cg_printf("a%d", i);
          } else {
            cg_printf("null_variant");
          }
        } else {
          cg_printf("arg%d", i);
        }
      }
    }
    cg_printf(")%s);\n", voidWrapper);
  }

  if (variable) {
    if (do_while) {
      cg_printf("break;\n");
      cg_indentEnd("}\n");
    }
    if (fewArgs) {
      if (maxParam == Option::InvokeFewArgsCount) return;
      cg_printf("Array params;\n");
      for (int i = maxParam; i < Option::InvokeFewArgsCount; i++) {
        cg_printf("if (count >= %d) params.append(a%d);\n", i + 1, i);
      }
    }
    cg_printf("%s,", call.c_str());
    for (int i = 0; i < maxParam; i++) {
      if (isRefParam(i)) {
        if (fewArgs) {
          if (i < Option::InvokeFewArgsCount) {
            cg_printf("ref(a%d), ", i);
          } else {
            cg_printf("null_variant, ");
          }
        } else {
          cg_printf("ref(arg%d), ", i);
        }
      } else {
        if (fewArgs) {
          if (i < Option::InvokeFewArgsCount) {
            cg_printf("a%d, ", i);
          } else {
            cg_printf("null_variant, ");
          }
        } else {
          cg_printf("arg%d, ", i);
        }
      }
    }
    if (fewArgs) {
      cg_printf("params)%s);\n", voidWrapper);
    }
    else {
      cg_printf("params.slice(%d, count - %d, false))%s);\n",
                maxParam, maxParam, voidWrapper);
    }
  }

  if (!fewArgs && maxParam) {
    if (do_while) {
      cg_indentEnd("} while (false);\n");
    } else {
      cg_indentEnd("}\n");
    }
  }
}
Пример #28
0
void ForEachStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  cg_indentBegin("{\n");
  int labelId = cg.createNewLocalId(ar);
  cg.pushBreakScope(labelId);

  int mapId = cg.createNewLocalId(ar);
  bool passTemp = true;
  bool isArray = false;

  if (m_ref ||
      !m_array->is(Expression::KindOfSimpleVariable) ||
      m_array->isThis()) {
    cg_printf("Variant %s%d", Option::MapPrefix, mapId);
    bool wrap = m_array->preOutputCPP(cg, ar, 0);
    if (wrap) {
      cg_printf(";\n");
      m_array->outputCPPBegin(cg, ar);
      cg_printf("%s%d", Option::MapPrefix, mapId);
    }
    if (m_ref) {
      cg_printf(" = ref(");
      m_array->outputCPPImpl(cg, ar);
      cg.printf(");\n");
      cg.printf("%s%d.escalate(true);\n", Option::MapPrefix, mapId);
    } else {
      TypePtr expectedType = m_array->getExpectedType();
      // Clear m_expectedType to avoid type cast (toArray).
      m_array->setExpectedType(TypePtr());
      cg_printf(" = ");
      m_array->outputCPP(cg, ar);
      cg_printf(";\n");
      m_array->setExpectedType(expectedType);
    }
    if (wrap) {
      m_array->outputCPPEnd(cg, ar);
    }
  } else {
    passTemp = false;
  }

  cppDeclareBufs(cg, ar);
  int iterId = cg.createNewLocalId(ar);
  cg_printf("for (");
  if (m_ref) {
    cg_printf("MutableArrayIterPtr %s%d = %s%d.begin(",
              Option::IterPrefix, iterId, Option::MapPrefix, mapId);
    if (m_name) {
      cg_printf("&");
      m_name->outputCPP(cg, ar);
    } else {
      cg_printf("NULL");
    }
    cg_printf(", ");
    m_value->outputCPP(cg, ar);
    cg_printf("); %s%d->advance();", Option::IterPrefix, iterId);
  } else {
    if (passTemp) {
      cg_printf("ArrayIterPtr %s%d = %s%d.begin(",
                Option::IterPrefix, iterId,
                Option::MapPrefix, mapId);
      ClassScopePtr cls = ar->getClassScope();
      if (cls) {
        cg_printf("%sclass_name", Option::StaticPropertyPrefix);
      }
      cg_printf("); ");
      cg_printf("!%s%d->end(); %s%d->next()",
                Option::IterPrefix, iterId,
                Option::IterPrefix, iterId);
    } else {
      TypePtr actualType = m_array->getActualType();
      if (actualType && actualType->is(Type::KindOfArray)) {
        isArray = true;
        cg_printf("ArrayIter %s%d = ", Option::IterPrefix, iterId);
      } else {
        cg_printf("ArrayIterPtr %s%d = ", Option::IterPrefix, iterId);
      }
      TypePtr expectedType = m_array->getExpectedType();
      // Clear m_expectedType to avoid type cast (toArray).
      m_array->setExpectedType(TypePtr());
      m_array->outputCPP(cg, ar);
      m_array->setExpectedType(expectedType);
      cg_printf(".begin(");
      ClassScopePtr cls = ar->getClassScope();
      if (cls) {
        cg_printf("%sclass_name", Option::StaticPropertyPrefix);
      }
      cg_printf("); ");
      if (isArray) {
        cg_printf("!%s%d.end(); ", Option::IterPrefix, iterId);
        cg_printf("++%s%d", Option::IterPrefix, iterId);
      } else {
        cg_printf("!%s%d->end(); ", Option::IterPrefix, iterId);
        cg_printf("%s%d->next()", Option::IterPrefix, iterId);
      }
    }
  }
  cg_indentBegin(") {\n");
  cg_printf("LOOP_COUNTER_CHECK(%d);\n", labelId);

  if (!m_ref) {
    cg_printf(isArray ? "%s%d.second(" : "%s%d->second(",
              Option::IterPrefix, iterId);
    m_value->outputCPP(cg, ar);
    cg_printf(");\n");
    if (m_name) {
      m_name->outputCPP(cg, ar);
      cg_printf(isArray ? " = %s%d.first();\n" : " = %s%d->first();\n",
                Option::IterPrefix, iterId);
    }
  }
  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
  }
  if (cg.findLabelId("continue", labelId)) {
    cg_printf("continue%d:;\n", labelId);
  }
  cg_indentEnd("}\n");
  if (cg.findLabelId("break", labelId)) {
    cg_printf("break%d:;\n", labelId);
  }
  cg.popBreakScope();
  cppEndBufs(cg, ar);
  cg_indentEnd("}\n");
}
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
                                                    AnalysisResultPtr ar,
                                                    bool directVariant,
                                                    int doExist) {
  bool bThis = m_object->isThis();
  bool useGetThis = false;
  FunctionScopePtr funcScope = ar->getFunctionScope();
  if (bThis) {
    if (funcScope && funcScope->isStatic()) {
      cg_printf("GET_THIS_ARROW()");
    } else {
      // in order for __set() and __get() to be called
      useGetThis = true;
    }
  }

  const char *op = ".";
  string func = Option::ObjectPrefix;
  const char *error = ", true";
  ClassScopePtr cls = ar->getClassScope();
  const char *context = "";
  if (cg.getOutput() != CodeGenerator::SystemCPP) {
    if (cls) {
      context = ", s_class_name";
    } else if (funcScope && !funcScope->inPseudoMain()) {
      context = ", empty_string";
    }
  }
  if (doExist) {
    func = doExist > 0 ? "doIsSet" : "doEmpty";
    error = "";
  } else {
    if (bThis && funcScope && funcScope->isStatic()) {
      func = Option::ObjectStaticPrefix;
      error = "";
      context = "";
    } else if (m_context & ExistContext) {
      error = ", false";
    }
    if (m_context & (LValue | RefValue | UnsetContext)) {
      func += "lval";
      error = "";
    } else {
      func += "get";
    }
  }

  if (m_property->getKindOf() == Expression::KindOfScalarExpression) {
    ScalarExpressionPtr name =
      dynamic_pointer_cast<ScalarExpression>(m_property);
    const char *propName = name->getString().c_str();
    if (m_valid && m_object->getType()->isSpecificObject()) {
      if (m_static) {
        if (!bThis) {
          ASSERT(m_class);
          if (doExist) cg_printf(doExist > 0 ? "isset(" : "empty(");
          cg_printf("g->%s%s%s%s",
                    Option::StaticPropertyPrefix, m_class->getName().c_str(),
                    Option::IdPrefix.c_str(), propName);
          if (doExist) cg_printf(")");
        } else {
          // if $val is a class static variable (static $val), then $val
          // cannot be declared as a class variable (var $val), $this->val
          // refers to a non-static class variable and has to use get/lval.
          if (useGetThis) cg_printf("GET_THIS_DOT()");
          cg_printf("%s(", func.c_str());
          cg_printString(propName, ar);
          cg_printf("%s%s)", error, context);
        }
      } else {
        if (doExist) cg_printf(doExist > 0 ? "isset(" : "empty(");
        if (!bThis) {
          ASSERT(!directVariant);
          m_object->outputCPP(cg, ar);
          cg_printf("->");
        }
        cg_printf("%s%s", Option::PropertyPrefix, propName);
        if (doExist) cg_printf(")");
      }
    } else {
      if (!bThis) {
        if (directVariant) {
          TypePtr expectedType = m_object->getExpectedType();
          ASSERT(expectedType->is(Type::KindOfObject));
          // Clear m_expectedType to avoid type cast (toObject).
          m_object->setExpectedType(TypePtr());
          m_object->outputCPP(cg, ar);
          m_object->setExpectedType(expectedType);
        } else {
          m_object->outputCPP(cg, ar);
        }
        cg_printf(op);
      } else {
        if (useGetThis) cg_printf("GET_THIS_DOT()");
      }
      cg_printf("%s(", func.c_str());
      cg_printString(propName, ar);
      cg_printf("%s%s)", error, context);
    }
  } else {
    if (!bThis) {
      if (directVariant) {
        TypePtr expectedType = m_object->getExpectedType();
        ASSERT(expectedType->is(Type::KindOfObject));
        // Clear m_expectedType to avoid type cast (toObject).
        m_object->setExpectedType(TypePtr());
        m_object->outputCPP(cg, ar);
        m_object->setExpectedType(expectedType);
      } else {
        m_object->outputCPP(cg, ar);
      }
      cg_printf(op);
    } else {
      if (useGetThis) cg_printf("GET_THIS_DOT()");
    }
    cg_printf("%s(", func.c_str());
    m_property->outputCPP(cg, ar);
    cg_printf("%s%s)", error, context);
  }
}
TypePtr ObjectPropertyExpression::inferTypes(AnalysisResultPtr ar,
                                             TypePtr type, bool coerce) {
  m_valid = false;

  ConstructPtr self = shared_from_this();
  TypePtr objectType = m_object->inferAndCheck(ar, NEW_TYPE(Object), true);

  if (!m_property->is(Expression::KindOfScalarExpression)) {
    // if dynamic property or method, we have nothing to find out
    if (ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UseDynamicProperty, self);
    }
    m_property->inferAndCheck(ar, Type::String, false);

    // we also lost track of which class variable an expression is about, hence
    // any type inference could be wrong. Instead, we just force variants on
    // all class variables.
    if (m_context & (LValue | RefValue)) {
      ar->forceClassVariants();
    }

    return Type::Variant; // we have to use a variant to hold dynamic value
  }

  ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(m_property);
  string name = exp->getString();
  ASSERT(!name.empty());

  ClassScopePtr cls;
  if (objectType && !objectType->getName().empty()) {
    // what object-> has told us
    cls = ar->findClass(objectType->getName());
    ASSERT(cls);
  } else {
    // what ->property has told us
    cls = ar->findClass(name, AnalysisResult::PropertyName);
    if (!cls) {
      if (m_context & (LValue | RefValue)) {
        ar->forceClassVariants(name);
      }
      return Type::Variant;
    }

    m_object->inferAndCheck(ar, Type::CreateObjectType(cls->getName()), true);
  }

  const char *accessorName = hasContext(DeepAssignmentLHS) ? "__set" :
    hasContext(ExistContext) ? "__isset" :
    hasContext(UnsetContext) ? "__unset" : "__get";
  if (!cls->implementsAccessor(ar, accessorName)) {
    if (m_localEffects & AccessorEffect) {
      recomputeEffects();
    }
    m_localEffects &= ~AccessorEffect;
  }

  // resolved to this class
  int present = 0;
  if (m_context & RefValue) {
    type = Type::Variant;
    coerce = true;
  }

  // use $this inside a static function
  if (m_object->isThis()) {
    FunctionScopePtr func = ar->getFunctionScope();
    if (func->isStatic()) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::MissingObjectContext,
                                   self);
      }
      m_actualType = Type::Variant;
      return m_actualType;
    }
  }

  TypePtr ret = cls->checkProperty(name, type, coerce, ar, self, present);
  if (!cls->derivesFromRedeclaring()) { // Have to use dynamic.
    // Private only valid if in the defining class
    if (present && (ar->getClassScope().get() == cls.get() ||
          !(present & VariableTable::VariablePrivate))) {
      m_valid = true;
      m_static = present & VariableTable::VariableStatic;
      if (m_static) {
        ar->getScope()->getVariables()->
          setAttribute(VariableTable::NeedGlobalPointer);
      }
      m_class = cls;
    }
  }

  // get() will return Variant
  if (!m_valid || !m_object->getType()->isSpecificObject()) {
    m_actualType = Type::Variant;
    return m_actualType;
  }

  if (m_localEffects & AccessorEffect) {
    recomputeEffects();
    m_localEffects &= ~AccessorEffect;
  }

  if (ar->getPhase() == AnalysisResult::LastInference) {
    if (!(m_context & ObjectContext)) {
      m_object->clearContext(Expression::LValue);
    }
    setContext(Expression::NoLValueWrapper);
  }
  return ret;
}